update .gitignore
commit
62500af1bb
|
@ -0,0 +1,12 @@
|
||||||
|
#include "InstallHelper.h"
|
||||||
|
|
||||||
|
InstallHelper::InstallHelper(QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
{
|
||||||
|
installing(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstallHelper::install(const QString& path,bool isHome,bool isStartMenu){
|
||||||
|
installing(true);
|
||||||
|
qDebug()<<path;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef INSTALLHELPER_H
|
||||||
|
#define INSTALLHELPER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
class InstallHelper : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY_AUTO(bool,installing)
|
||||||
|
public:
|
||||||
|
explicit InstallHelper(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
Q_INVOKABLE void install(const QString& path,bool isHome,bool isStartMenu);
|
||||||
|
signals:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INSTALLHELPER_H
|
|
@ -1,5 +1,8 @@
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
|
import QtQuick.Dialogs 1.3 as Dialogs
|
||||||
|
import Qt.labs.platform 1.1
|
||||||
|
import UI 1.0
|
||||||
import FluentUI 1.0
|
import FluentUI 1.0
|
||||||
|
|
||||||
FluWindow {
|
FluWindow {
|
||||||
|
@ -7,15 +10,37 @@ FluWindow {
|
||||||
id:window
|
id:window
|
||||||
width: 800
|
width: 800
|
||||||
height: 400
|
height: 400
|
||||||
maximumSize: Qt.size(800,400)
|
minimumWidth:800
|
||||||
minimumSize: Qt.size(800,400)
|
maximumWidth:800
|
||||||
|
minimumHeight:400
|
||||||
|
maximumHeight:400
|
||||||
title:"安装向导"
|
title:"安装向导"
|
||||||
|
|
||||||
|
property string installPath: "C:\\Program Files"
|
||||||
|
property string installName: "FluentUI"
|
||||||
|
|
||||||
FluAppBar{
|
FluAppBar{
|
||||||
id:appbar
|
id:appbar
|
||||||
title: "安装向导"
|
title: "安装向导"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item{
|
||||||
|
id:data
|
||||||
|
InstallHelper{
|
||||||
|
id:helper
|
||||||
|
}
|
||||||
|
Dialogs.FileDialog {
|
||||||
|
id: fileDialog
|
||||||
|
selectFolder: true
|
||||||
|
folder: "file:///"+installPath
|
||||||
|
onAccepted: {
|
||||||
|
installPath = String(fileDialog.fileUrls[0]).replace("file:///","").replace(RegExp("/",'g'),"\\")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ColumnLayout{
|
ColumnLayout{
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
@ -36,17 +61,36 @@ FluWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
FluTextBox{
|
FluTextBox{
|
||||||
|
id:textbox_path
|
||||||
Layout.preferredHeight: 40
|
Layout.preferredHeight: 40
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text:"C:\\Program Files\\RustDesk"
|
text:installPath+ "\\" +installName
|
||||||
readOnly:true
|
readOnly:true
|
||||||
}
|
}
|
||||||
|
|
||||||
FluButton{
|
FluButton{
|
||||||
text:"更改路径"
|
text:"更改路径"
|
||||||
Layout.rightMargin: 30
|
Layout.rightMargin: 30
|
||||||
|
onClicked: {
|
||||||
|
fileDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FluCheckBox{
|
||||||
|
id:checkbox_startmenu
|
||||||
|
Layout.topMargin: 20
|
||||||
|
Layout.leftMargin: 30
|
||||||
|
checked: true
|
||||||
|
text:"创建启动菜单快捷方式"
|
||||||
|
}
|
||||||
|
FluCheckBox{
|
||||||
|
id:checkbox_home
|
||||||
|
Layout.leftMargin: 30
|
||||||
|
Layout.topMargin: 5
|
||||||
|
checked: true
|
||||||
|
text:"创建桌面图标"
|
||||||
|
}
|
||||||
|
|
||||||
Item{
|
Item{
|
||||||
width: 1
|
width: 1
|
||||||
|
@ -77,6 +121,9 @@ FluWindow {
|
||||||
}
|
}
|
||||||
FluFilledButton{
|
FluFilledButton{
|
||||||
text:"同意并安装"
|
text:"同意并安装"
|
||||||
|
onClicked: {
|
||||||
|
helper.install(textbox_path.text,checkbox_home.checked,checkbox_startmenu.checked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FluButton{
|
FluButton{
|
||||||
text:"不安装直接运行"
|
text:"不安装直接运行"
|
||||||
|
@ -88,4 +135,34 @@ FluWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle{
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: helper.installing
|
||||||
|
color: "#80000000"
|
||||||
|
|
||||||
|
MouseArea{
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
FluProgressBar{
|
||||||
|
id:progress
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
FluText{
|
||||||
|
text:"正在安装..."
|
||||||
|
color:"#FFFFFF"
|
||||||
|
font.pixelSize: 20
|
||||||
|
anchors{
|
||||||
|
horizontalCenter: progress.horizontalCenter
|
||||||
|
bottom: progress.top
|
||||||
|
bottomMargin: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import QtQuick.Window 2.15
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
import QtGraphicalEffects 1.15
|
import QtGraphicalEffects 1.15
|
||||||
|
|
||||||
import FluentUI 1.0
|
import FluentUI 1.0
|
||||||
|
|
||||||
FluWindow {
|
FluWindow {
|
||||||
|
@ -10,14 +11,17 @@ FluWindow {
|
||||||
width: 800
|
width: 800
|
||||||
height: 600
|
height: 600
|
||||||
title: "FluentUI"
|
title: "FluentUI"
|
||||||
minimumSize: Qt.size(600,400)
|
minimumWidth: 600
|
||||||
// property var maximumSize
|
minimumHeight: 400
|
||||||
|
|
||||||
FluAppBar{
|
FluAppBar{
|
||||||
id:appbar
|
id:appbar
|
||||||
title: "FluentUI"
|
title: "FluentUI"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item{
|
||||||
|
id:data
|
||||||
|
|
||||||
ListModel{
|
ListModel{
|
||||||
id:nav_items
|
id:nav_items
|
||||||
ListElement{
|
ListElement{
|
||||||
|
@ -58,14 +62,40 @@ FluWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FluMenu{
|
||||||
|
id:menu
|
||||||
|
FluMenuItem{
|
||||||
|
text:"123"
|
||||||
|
}
|
||||||
|
FluMenuItem{
|
||||||
|
text:"456"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FluIconButton{
|
||||||
|
icon:FluentIcons.FA_navicon
|
||||||
|
anchors{
|
||||||
|
left: parent.left
|
||||||
|
bottom: parent.bottom
|
||||||
|
leftMargin: 12
|
||||||
|
bottomMargin: 12
|
||||||
|
}
|
||||||
|
onClicked:{
|
||||||
|
menu.popup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ListView{
|
ListView{
|
||||||
id:nav_list
|
id:nav_list
|
||||||
anchors{
|
anchors{
|
||||||
top: appbar.bottom
|
top: appbar.bottom
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
bottomMargin: 20
|
bottomMargin: 52
|
||||||
}
|
}
|
||||||
|
clip: true
|
||||||
width: 160
|
width: 160
|
||||||
model: nav_items
|
model: nav_items
|
||||||
delegate: Item{
|
delegate: Item{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
import QtQuick.Window 2.15
|
import QtQuick.Window 2.15
|
||||||
import FluentUI 1.0
|
import FluentUI 1.0
|
||||||
|
@ -13,18 +14,32 @@ Item {
|
||||||
|
|
||||||
FluTextBox{
|
FluTextBox{
|
||||||
id:text_box
|
id:text_box
|
||||||
placeholderText: "搜索"
|
placeholderText: "请输入关键字"
|
||||||
anchors{
|
anchors{
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
top:title.bottom
|
top:title.bottom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FluFilledButton{
|
||||||
|
text:"搜索"
|
||||||
|
anchors{
|
||||||
|
left: text_box.right
|
||||||
|
verticalCenter: text_box.verticalCenter
|
||||||
|
leftMargin: 14
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
grid_view.model = FluApp.awesomelist(text_box.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GridView{
|
GridView{
|
||||||
|
id:grid_view
|
||||||
cellWidth: 120
|
cellWidth: 120
|
||||||
cellHeight: 60
|
cellHeight: 60
|
||||||
clip: true
|
clip: true
|
||||||
model:FluApp.awesomelist()
|
model:FluApp.awesomelist()
|
||||||
|
ScrollBar.vertical: FluScrollBar {}
|
||||||
anchors{
|
anchors{
|
||||||
topMargin: 10
|
topMargin: 10
|
||||||
top:text_box.bottom
|
top:text_box.bottom
|
||||||
|
|
|
@ -4,6 +4,7 @@ CONFIG += c++11
|
||||||
DEFINES += QT_DEPRECATED_WARNINGS QT_NO_WARNING_OUTPUT
|
DEFINES += QT_DEPRECATED_WARNINGS QT_NO_WARNING_OUTPUT
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
InstallHelper.cpp \
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
||||||
RESOURCES += qml.qrc
|
RESOURCES += qml.qrc
|
||||||
|
@ -42,3 +43,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||||
# PRE_TARGETDEPS += $$OUT_PWD/../bin/FluentUI/lib$${LIBNAME}.a
|
# PRE_TARGETDEPS += $$OUT_PWD/../bin/FluentUI/lib$${LIBNAME}.a
|
||||||
|
|
||||||
### 注意:静态库 .so .dylib .dll 是自动安装的Qt qml plugin目录中,不需要此步配置
|
### 注意:静态库 .so .dylib .dll 是自动安装的Qt qml plugin目录中,不需要此步配置
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
InstallHelper.h \
|
||||||
|
stdafx.h
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
|
#include "InstallHelper.h"
|
||||||
|
|
||||||
#if defined(STATICLIB)
|
#if defined(STATICLIB)
|
||||||
#include <FluentUI.h>
|
#include <FluentUI.h>
|
||||||
|
@ -7,6 +8,10 @@
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
QCoreApplication::setOrganizationName("ZhuZiChu");
|
||||||
|
QCoreApplication::setOrganizationDomain("https://zhuzichu520.github.io");
|
||||||
|
QCoreApplication::setApplicationName("FluentUI");
|
||||||
|
|
||||||
qputenv("QSG_RENDER_LOOP","basic");
|
qputenv("QSG_RENDER_LOOP","basic");
|
||||||
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
||||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||||
|
@ -16,12 +21,15 @@ int main(int argc, char *argv[])
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round);
|
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round);
|
||||||
#endif
|
#endif
|
||||||
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
#if defined(STATICLIB)
|
|
||||||
|
qmlRegisterType<InstallHelper>("UI",1,0,"InstallHelper");
|
||||||
|
|
||||||
|
#if defined(STATICLIB)
|
||||||
FluentUI::create(&engine);
|
FluentUI::create(&engine);
|
||||||
#endif
|
#endif
|
||||||
const QUrl url(QStringLiteral("qrc:/App.qml"));
|
const QUrl url(QStringLiteral("qrc:/App.qml"));
|
||||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||||
&app, [url](QObject *obj, const QUrl &objUrl) {
|
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef STDAFX_H
|
||||||
|
#define STDAFX_H
|
||||||
|
|
||||||
|
#define Q_PROPERTY_AUTO(TYPE, M) \
|
||||||
|
Q_PROPERTY(TYPE M MEMBER _##M NOTIFY M##Changed) \
|
||||||
|
public: \
|
||||||
|
Q_SIGNAL void M##Changed(); \
|
||||||
|
void M(TYPE in_##M) \
|
||||||
|
{ \
|
||||||
|
_##M = in_##M; \
|
||||||
|
Q_EMIT M##Changed(); \
|
||||||
|
} \
|
||||||
|
TYPE M() \
|
||||||
|
{ \
|
||||||
|
return _##M; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
TYPE _##M;
|
||||||
|
|
||||||
|
#endif // STDAFX_H
|
|
@ -26,8 +26,6 @@ FluApp::FluApp(QObject *parent)
|
||||||
isFps(true);
|
isFps(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void FluApp::setAppWindow(QWindow *window){
|
void FluApp::setAppWindow(QWindow *window){
|
||||||
appWindow = window;
|
appWindow = window;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +41,7 @@ void FluApp::navigate(const QString& route){
|
||||||
}
|
}
|
||||||
bool isAppWindow = route==initialRoute();
|
bool isAppWindow = route==initialRoute();
|
||||||
FramelessView *view = new FramelessView();
|
FramelessView *view = new FramelessView();
|
||||||
view->setColor(isDark() ? QColor(0,0,0,1) : QColor(255, 255, 255, 1));
|
view->setColor(QColor(0,0,0,0));
|
||||||
QObject::connect(view, &QQuickView::statusChanged, view, [&](QQuickView::Status status) {
|
QObject::connect(view, &QQuickView::statusChanged, view, [&](QQuickView::Status status) {
|
||||||
if (status == QQuickView::Status::Ready) {
|
if (status == QQuickView::Status::Ready) {
|
||||||
Q_EMIT windowReady(view);
|
Q_EMIT windowReady(view);
|
||||||
|
@ -65,17 +63,26 @@ bool FluApp::equalsWindow(FramelessView *view,QWindow *window){
|
||||||
return view->winId() == window->winId();
|
return view->winId() == window->winId();
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray FluApp::awesomelist()
|
QJsonArray FluApp::awesomelist(const QString& keyword)
|
||||||
{
|
{
|
||||||
QJsonArray arr;
|
QJsonArray arr;
|
||||||
QMetaEnum enumType = Fluent_Awesome::staticMetaObject.enumerator(Fluent_Awesome::staticMetaObject.indexOfEnumerator("Fluent_AwesomeType"));
|
QMetaEnum enumType = Fluent_Awesome::staticMetaObject.enumerator(Fluent_Awesome::staticMetaObject.indexOfEnumerator("Fluent_AwesomeType"));
|
||||||
for(int i=0; i < enumType.keyCount(); ++i){
|
for(int i=0; i < enumType.keyCount(); ++i){
|
||||||
QJsonObject obj;
|
|
||||||
QString name = enumType.key(i);
|
QString name = enumType.key(i);
|
||||||
int icon = enumType.value(i);
|
int icon = enumType.value(i);
|
||||||
|
if(keyword.isEmpty()){
|
||||||
|
QJsonObject obj;
|
||||||
obj.insert("name",name);
|
obj.insert("name",name);
|
||||||
obj.insert("icon",icon);
|
obj.insert("icon",icon);
|
||||||
arr.append(obj);
|
arr.append(obj);
|
||||||
|
}else{
|
||||||
|
if(name.mid(3).contains(keyword)){
|
||||||
|
QJsonObject obj;
|
||||||
|
obj.insert("name",name);
|
||||||
|
obj.insert("icon",icon);
|
||||||
|
arr.append(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE bool equalsWindow(FramelessView *view,QWindow *window);
|
Q_INVOKABLE bool equalsWindow(FramelessView *view,QWindow *window);
|
||||||
|
|
||||||
Q_INVOKABLE QJsonArray awesomelist();
|
Q_INVOKABLE QJsonArray awesomelist(const QString& keyword = "");
|
||||||
|
|
||||||
Q_INVOKABLE void clipText(const QString& text);
|
Q_INVOKABLE void clipText(const QString& text);
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,10 @@ void Fluent::registerTypes(const char *uri){
|
||||||
|
|
||||||
qmlRegisterType<WindowHelper>(uri,major,minor,"WindowHelper");
|
qmlRegisterType<WindowHelper>(uri,major,minor,"WindowHelper");
|
||||||
|
|
||||||
|
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMenu.qml"),uri,major,minor,"FluMenu");
|
||||||
|
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMenuItem.qml"),uri,major,minor,"FluMenuItem");
|
||||||
|
|
||||||
|
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluScrollBar.qml"),uri,major,minor,"FluScrollBar");
|
||||||
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMultiLineTextBox.qml"),uri,major,minor,"FluMultiLineTextBox");
|
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMultiLineTextBox.qml"),uri,major,minor,"FluMultiLineTextBox");
|
||||||
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluDropShadow.qml"),uri,major,minor,"FluDropShadow");
|
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluDropShadow.qml"),uri,major,minor,"FluDropShadow");
|
||||||
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTooltip.qml"),uri,major,minor,"FluTooltip");
|
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTooltip.qml"),uri,major,minor,"FluTooltip");
|
||||||
|
|
|
@ -9,6 +9,7 @@ class FramelessViewPrivate
|
||||||
public:
|
public:
|
||||||
bool m_isMax = false;
|
bool m_isMax = false;
|
||||||
bool m_isFull = false;
|
bool m_isFull = false;
|
||||||
|
bool m_deleteLater = false;
|
||||||
QQuickItem *m_titleItem = nullptr;
|
QQuickItem *m_titleItem = nullptr;
|
||||||
};
|
};
|
||||||
FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate)
|
FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate)
|
||||||
|
@ -58,6 +59,10 @@ void FramelessView::moveToScreenCenter()
|
||||||
setGeometry(geo);
|
setGeometry(geo);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
void FramelessView::closeDeleteLater(){
|
||||||
|
d->m_deleteLater = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool FramelessView::isMax() const
|
bool FramelessView::isMax() const
|
||||||
{
|
{
|
||||||
return d->m_isMax;
|
return d->m_isMax;
|
||||||
|
@ -95,7 +100,6 @@ bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qint
|
||||||
#else
|
#else
|
||||||
bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
return Super::nativeEvent(eventType, message, result);
|
return Super::nativeEvent(eventType, message, result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,93 +1,17 @@
|
||||||
#include "FramelessView.h"
|
#include "FramelessView.h"
|
||||||
|
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
|
|
||||||
#include <VersionHelpers.h>
|
class FramelessViewPrivate
|
||||||
#include <WinUser.h>
|
|
||||||
#include <dwmapi.h>
|
|
||||||
#include <objidl.h> // Fixes error C2504: 'IUnknown' : base class undefined
|
|
||||||
#include <windows.h>
|
|
||||||
#include <windowsx.h>
|
|
||||||
#include <wtypes.h>
|
|
||||||
#pragma comment(lib, "Dwmapi.lib") // Adds missing library, fixes error LNK2019: unresolved
|
|
||||||
#pragma comment(lib, "User32.lib")
|
|
||||||
#pragma comment(lib, "Gdi32.lib")
|
|
||||||
// we cannot just use WS_POPUP style
|
|
||||||
// WS_THICKFRAME: without this the window cannot be resized and so aero snap, de-maximizing and minimizing won't work
|
|
||||||
// WS_SYSMENU: enables the context menu with the move, close, maximize, minize... commands (shift + right-click on the task bar item)
|
|
||||||
// WS_CAPTION: enables aero minimize animation/transition
|
|
||||||
// WS_MAXIMIZEBOX, WS_MINIMIZEBOX: enable minimize/maximize
|
|
||||||
|
|
||||||
QMap<WId,FramelessView*>* FramelessView::windowCache = new QMap<WId,FramelessView*>;
|
|
||||||
|
|
||||||
|
|
||||||
enum class Style : DWORD
|
|
||||||
{
|
{
|
||||||
windowed = WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
public:
|
||||||
aero_borderless = WS_POPUP | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
bool m_isMax = false;
|
||||||
basic_borderless = WS_POPUP | WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX
|
bool m_isFull = false;
|
||||||
|
bool m_deleteLater = false;
|
||||||
|
QQuickItem *m_titleItem = nullptr;
|
||||||
};
|
};
|
||||||
static bool isCompositionEnabled()
|
|
||||||
{
|
|
||||||
BOOL composition_enabled = FALSE;
|
|
||||||
bool success = ::DwmIsCompositionEnabled(&composition_enabled) == S_OK;
|
|
||||||
return composition_enabled && success;
|
|
||||||
}
|
|
||||||
static Style selectBorderLessStyle()
|
|
||||||
{
|
|
||||||
return isCompositionEnabled() ? Style::aero_borderless : Style::basic_borderless;
|
|
||||||
}
|
|
||||||
static void setShadow(HWND handle, bool enabled)
|
|
||||||
{
|
|
||||||
if (isCompositionEnabled())
|
|
||||||
{
|
|
||||||
static const MARGINS shadow_state[2] { { 0, 0, 0, 0 }, { 1, 1, 1, 1 } };
|
|
||||||
::DwmExtendFrameIntoClientArea(handle, &shadow_state[enabled]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static long hitTest(RECT winrect, long x, long y, int borderWidth)
|
|
||||||
{
|
|
||||||
// 鼠标区域位于窗体边框,进行缩放
|
|
||||||
if ((x >= winrect.left) && (x < winrect.left + borderWidth) && (y >= winrect.top) && (y < winrect.top + borderWidth))
|
|
||||||
{
|
|
||||||
return HTTOPLEFT;
|
|
||||||
}
|
|
||||||
else if (x < winrect.right && x >= winrect.right - borderWidth && y >= winrect.top && y < winrect.top + borderWidth)
|
|
||||||
{
|
|
||||||
return HTTOPRIGHT;
|
|
||||||
}
|
|
||||||
else if (x >= winrect.left && x < winrect.left + borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth)
|
|
||||||
{
|
|
||||||
return HTBOTTOMLEFT;
|
|
||||||
}
|
|
||||||
else if (x < winrect.right && x >= winrect.right - borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth)
|
|
||||||
{
|
|
||||||
return HTBOTTOMRIGHT;
|
|
||||||
}
|
|
||||||
else if (x >= winrect.left && x < winrect.left + borderWidth)
|
|
||||||
{
|
|
||||||
return HTLEFT;
|
|
||||||
}
|
|
||||||
else if (x < winrect.right && x >= winrect.right - borderWidth)
|
|
||||||
{
|
|
||||||
return HTRIGHT;
|
|
||||||
}
|
|
||||||
else if (y >= winrect.top && y < winrect.top + borderWidth)
|
|
||||||
{
|
|
||||||
return HTTOP;
|
|
||||||
}
|
|
||||||
else if (y < winrect.bottom && y >= winrect.bottom - borderWidth)
|
|
||||||
{
|
|
||||||
return HTBOTTOM;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isMaxWin(QWindow* win)
|
static bool isMaxWin(QWindow* win)
|
||||||
{
|
{
|
||||||
|
@ -98,53 +22,10 @@ static bool isFullWin(QQuickView* win)
|
||||||
return win->windowState() == Qt::WindowFullScreen;
|
return win->windowState() == Qt::WindowFullScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FramelessViewPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool m_firstRun = true;
|
|
||||||
bool m_isMax = false;
|
|
||||||
bool m_isFull = false;
|
|
||||||
bool m_deleteLater = false;
|
|
||||||
QQuickItem* m_titleItem = nullptr;
|
|
||||||
HMENU mMenuHandler = NULL;
|
|
||||||
bool borderless = true; // is the window currently borderless
|
|
||||||
bool borderless_resize = true; // should the window allow resizing by dragging the borders while borderless
|
|
||||||
bool borderless_drag = true; // should the window allow moving my dragging the client area
|
|
||||||
bool borderless_shadow = true; // should the window display a native aero shadow while borderless
|
|
||||||
void setBorderLess(HWND handle, bool enabled)
|
|
||||||
{
|
|
||||||
auto newStyle = enabled ? selectBorderLessStyle() : Style::windowed;
|
|
||||||
auto oldStyle = static_cast<Style>(::GetWindowLongPtrW(handle, GWL_STYLE));
|
|
||||||
if (oldStyle != newStyle)
|
|
||||||
{
|
|
||||||
borderless = enabled;
|
|
||||||
//todo 有待研究这个
|
|
||||||
// ::SetWindowLongPtrW(handle, GWL_STYLE, static_cast<LONG>(newStyle));
|
|
||||||
|
|
||||||
// when switching between borderless and windowed, restore appropriate shadow state
|
FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate)
|
||||||
setShadow(handle, borderless_shadow && (newStyle != Style::windowed));
|
|
||||||
|
|
||||||
// redraw frame
|
|
||||||
::SetWindowPos(handle, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
|
|
||||||
::ShowWindow(handle, SW_SHOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void setBorderLessShadow(HWND handle, bool enabled)
|
|
||||||
{
|
|
||||||
if (borderless)
|
|
||||||
{
|
|
||||||
borderless_shadow = enabled;
|
|
||||||
setShadow(handle, enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FramelessView::FramelessView(QWindow* parent)
|
|
||||||
: QQuickView(parent)
|
|
||||||
, d(new FramelessViewPrivate)
|
|
||||||
{
|
{
|
||||||
//此处不需要设置flags
|
setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
|
||||||
// setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint |
|
|
||||||
// Qt::WindowSystemMenuHint);
|
|
||||||
setResizeMode(SizeRootObjectToView);
|
setResizeMode(SizeRootObjectToView);
|
||||||
|
|
||||||
setIsMax(windowState() == Qt::WindowMaximized);
|
setIsMax(windowState() == Qt::WindowMaximized);
|
||||||
|
@ -154,79 +35,26 @@ FramelessView::FramelessView(QWindow* parent)
|
||||||
setIsMax(windowState() == Qt::WindowMaximized);
|
setIsMax(windowState() == Qt::WindowMaximized);
|
||||||
setIsFull(windowState() == Qt::WindowFullScreen);
|
setIsFull(windowState() == Qt::WindowFullScreen);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(this, &QQuickView::statusChanged, this, [&](QQuickView::Status status) {
|
|
||||||
if (status == QQuickView::Status::Ready) {
|
|
||||||
FramelessView::windowCache->insert(this->winId(),this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
void FramelessView::showEvent(QShowEvent* e)
|
|
||||||
{
|
|
||||||
if (d->m_firstRun)
|
|
||||||
{
|
|
||||||
d->m_firstRun = false;
|
|
||||||
//第一次show的时候,设置无边框。不在构造函数中设置。取winId会触发QWindowsWindow::create,直接创建win32窗口,引起错乱(win7 或者虚拟机启动即黑屏)。
|
|
||||||
d->setBorderLess((HWND)(winId()), d->borderless);
|
|
||||||
{
|
|
||||||
// Qt 5.15.2 的bug; 问题复现及解决方法:当使用WM_NCCALCSIZE 修改非客户区大小后,移动窗口到其他屏幕时,qwindows.dll 源码 qwindowswindow.cpp:2447
|
|
||||||
// updateFullFrameMargins() 函数 处会调用qwindowswindow.cpp:2453 的
|
|
||||||
// calculateFullFrameMargins函数重新获取默认的非客户区大小,导致最外层窗口移动屏幕时会触发resize消息,引起40像素左右的黑边;故此处创建Menu
|
|
||||||
// 使其调用qwindowswindow.cpp:2451 的 QWindowsContext::forceNcCalcSize() 函数计算非客户区大小
|
|
||||||
|
|
||||||
//已知负面效果: 引入win32 MENU后,Qt程序中如果有alt开头的快捷键,会不生效,被Qt滤掉了,需要修改Qt源码
|
|
||||||
// QWindowsKeyMapper::translateKeyEventInternal 中的
|
|
||||||
// if (msgType == WM_SYSKEYDOWN && (nModifiers & AltAny) != 0 && GetMenu(msg.hwnd) != nullptr)
|
|
||||||
// return false;
|
|
||||||
// 这两行屏蔽掉
|
|
||||||
|
|
||||||
d->mMenuHandler = ::CreateMenu();
|
|
||||||
::SetMenu((HWND)winId(), d->mMenuHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Super::showEvent(e);
|
|
||||||
}
|
}
|
||||||
FramelessView::~FramelessView()
|
FramelessView::~FramelessView()
|
||||||
{
|
{
|
||||||
if (d->mMenuHandler != NULL)
|
|
||||||
{
|
|
||||||
::DestroyMenu(d->mMenuHandler);
|
|
||||||
}
|
|
||||||
FramelessView::windowCache->remove(this->winId());
|
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
void FramelessView::showEvent(QShowEvent *e)
|
||||||
bool FramelessView::isMax() const
|
|
||||||
{
|
{
|
||||||
return d->m_isMax;
|
Super::showEvent(e);
|
||||||
}
|
}
|
||||||
|
QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize)
|
||||||
bool FramelessView::isFull() const
|
|
||||||
{
|
|
||||||
return d->m_isFull;
|
|
||||||
}
|
|
||||||
QQuickItem* FramelessView::titleItem() const
|
|
||||||
{
|
|
||||||
return d->m_titleItem;
|
|
||||||
}
|
|
||||||
void FramelessView::setTitleItem(QQuickItem* item)
|
|
||||||
{
|
|
||||||
d->m_titleItem = item;
|
|
||||||
}
|
|
||||||
QRect FramelessView::calcCenterGeo(const QRect& screenGeo, const QSize& normalSize)
|
|
||||||
{
|
{
|
||||||
int w = normalSize.width();
|
int w = normalSize.width();
|
||||||
int h = normalSize.height();
|
int h = normalSize.height();
|
||||||
int x = screenGeo.x() + (screenGeo.width() - w) / 2;
|
int x = screenGeo.x() + (screenGeo.width() - w) / 2;
|
||||||
int y = screenGeo.y() + (screenGeo.height() - h) / 2;
|
int y = screenGeo.y() + (screenGeo.height() - h) / 2;
|
||||||
if (screenGeo.width() < w)
|
if (screenGeo.width() < w) {
|
||||||
{
|
|
||||||
x = screenGeo.x();
|
x = screenGeo.x();
|
||||||
w = screenGeo.width();
|
w = screenGeo.width();
|
||||||
}
|
}
|
||||||
if (screenGeo.height() < h)
|
if (screenGeo.height() < h) {
|
||||||
{
|
|
||||||
y = screenGeo.y();
|
y = screenGeo.y();
|
||||||
h = screenGeo.height();
|
h = screenGeo.height();
|
||||||
}
|
}
|
||||||
|
@ -236,18 +64,28 @@ QRect FramelessView::calcCenterGeo(const QRect& screenGeo, const QSize& normalSi
|
||||||
void FramelessView::moveToScreenCenter()
|
void FramelessView::moveToScreenCenter()
|
||||||
{
|
{
|
||||||
auto geo = calcCenterGeo(screen()->availableGeometry(), size());
|
auto geo = calcCenterGeo(screen()->availableGeometry(), size());
|
||||||
if (minimumWidth() > geo.width() || minimumHeight() > geo.height())
|
if (minimumWidth() > geo.width() || minimumHeight() > geo.height()) {
|
||||||
{
|
|
||||||
setMinimumSize(geo.size());
|
setMinimumSize(geo.size());
|
||||||
}
|
}
|
||||||
setGeometry(geo);
|
setGeometry(geo);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramelessView::closeDeleteLater(){
|
void FramelessView::closeDeleteLater(){
|
||||||
d->m_deleteLater = true;
|
d->m_deleteLater = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FramelessView::isMax() const
|
||||||
|
{
|
||||||
|
return d->m_isMax;
|
||||||
|
}
|
||||||
|
bool FramelessView::isFull() const
|
||||||
|
{
|
||||||
|
return d->m_isFull;
|
||||||
|
}
|
||||||
|
QQuickItem *FramelessView::titleItem() const
|
||||||
|
{
|
||||||
|
return d->m_titleItem;
|
||||||
|
}
|
||||||
void FramelessView::setIsMax(bool isMax)
|
void FramelessView::setIsMax(bool isMax)
|
||||||
{
|
{
|
||||||
if (d->m_isMax == isMax)
|
if (d->m_isMax == isMax)
|
||||||
|
@ -258,56 +96,43 @@ void FramelessView::setIsMax(bool isMax)
|
||||||
}
|
}
|
||||||
void FramelessView::setIsFull(bool isFull)
|
void FramelessView::setIsFull(bool isFull)
|
||||||
{
|
{
|
||||||
if (d->m_isFull == isFull)
|
if(d->m_isFull == isFull)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
d->m_isFull = isFull;
|
d->m_isFull = isFull;
|
||||||
emit isFullChanged(d->m_isFull);
|
emit isFullChanged(d->m_isFull);
|
||||||
}
|
}
|
||||||
void FramelessView::resizeEvent(QResizeEvent* e)
|
void FramelessView::setTitleItem(QQuickItem *item)
|
||||||
{
|
{
|
||||||
// SetWindowRgn(HWND(winId()), CreateRoundRectRgn(0, 0, width(), height(), 4, 4), true);
|
d->m_titleItem = item;
|
||||||
Super::resizeEvent(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
bool FramelessView::nativeEvent(const QByteArray& eventType, void* message, qintptr* result)
|
bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
|
||||||
#else
|
#else
|
||||||
bool FramelessView::nativeEvent(const QByteArray& eventType, void* message, long* result)
|
bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
const long border_width = 4;
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
//防御式编程
|
|
||||||
//一般不会发生这种情况,win7一些极端情况,会传空指针进来。解决方案是升级驱动、切换到basic主题。
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
|
#if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
|
||||||
// Work-around a bug caused by typo which only exists in Qt 5.11.1
|
|
||||||
const auto msg = *reinterpret_cast<MSG**>(message);
|
const auto msg = *reinterpret_cast<MSG**>(message);
|
||||||
#else
|
#else
|
||||||
const auto msg = static_cast<LPMSG>(message);
|
const auto msg = static_cast<LPMSG>(message);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!msg || !msg->hwnd)
|
if (!msg || !msg->hwnd)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (msg->message)
|
switch (msg->message)
|
||||||
{
|
{
|
||||||
case WM_CLOSE:{
|
|
||||||
if(d->m_deleteLater){
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case WM_NCCALCSIZE: {
|
case WM_NCCALCSIZE: {
|
||||||
#if 1
|
#if 1
|
||||||
const auto mode = static_cast<BOOL>(msg->wParam);
|
const auto mode = static_cast<BOOL>(msg->wParam);
|
||||||
const auto clientRect = mode ? &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam)->rgrc[0]) : reinterpret_cast<LPRECT>(msg->lParam);
|
const auto clientRect = mode ? &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam)->rgrc[0]) : reinterpret_cast<LPRECT>(msg->lParam);
|
||||||
if (mode == TRUE && d->borderless)
|
if (mode == TRUE)
|
||||||
{
|
{
|
||||||
*result = WVR_REDRAW;
|
*result = WVR_REDRAW;
|
||||||
//规避 拖动border进行resize时界面闪烁
|
//规避 拖动border进行resize时界面闪烁
|
||||||
|
@ -333,51 +158,11 @@ bool FramelessView::nativeEvent(const QByteArray& eventType, void* message, long
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WM_NCACTIVATE: {
|
|
||||||
if (!isCompositionEnabled())
|
|
||||||
{
|
|
||||||
// Prevents window frame reappearing on window activation
|
|
||||||
// in "basic" theme, where no aero shadow is present.
|
|
||||||
*result = 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_NCHITTEST: {
|
|
||||||
if (d->borderless)
|
|
||||||
{
|
|
||||||
RECT winrect;
|
|
||||||
GetWindowRect(HWND(winId()), &winrect);
|
|
||||||
long x = GET_X_LPARAM(msg->lParam);
|
|
||||||
long y = GET_Y_LPARAM(msg->lParam);
|
|
||||||
*result = 0;
|
|
||||||
if (!isMaxWin(this) && !isFullWin(this))
|
|
||||||
{ //非最大化、非全屏时,进行命中测试,处理边框拖拽
|
|
||||||
if(!((maximumHeight()==minimumHeight())&&(maximumWidth()==minimumWidth()))){
|
|
||||||
*result = hitTest(winrect, x, y, border_width);
|
|
||||||
if (0 != *result)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d->m_titleItem)
|
|
||||||
{
|
|
||||||
auto titlePos = d->m_titleItem->mapToGlobal({ 0, 0 });
|
|
||||||
titlePos = mapFromGlobal(titlePos.toPoint());
|
|
||||||
auto titleRect = QRect(titlePos.x(), titlePos.y(), d->m_titleItem->width(), d->m_titleItem->height());
|
|
||||||
double dpr = qApp->devicePixelRatio();
|
|
||||||
QPoint pos = mapFromGlobal(QPoint(x / dpr, y / dpr));
|
|
||||||
if (titleRect.contains(pos))
|
|
||||||
{
|
|
||||||
*result = HTCAPTION;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} // end case WM_NCHITTEST
|
|
||||||
}
|
}
|
||||||
return Super::nativeEvent(eventType, message, result);
|
return Super::nativeEvent(eventType, message, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FramelessView::resizeEvent(QResizeEvent *e)
|
||||||
|
{
|
||||||
|
Super::resizeEvent(e);
|
||||||
|
}
|
||||||
|
|
|
@ -15,14 +15,15 @@ void WindowHelper::initWindow(FramelessView* window){
|
||||||
this->window = window;
|
this->window = window;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowHelper::setMinimumSize(const QSize &size){
|
void WindowHelper::setMinimumWidth(int width){
|
||||||
this->window->setMinimumSize(size);
|
this->window->setMinimumWidth(width);
|
||||||
}
|
}
|
||||||
void WindowHelper::setMaximumSize(const QSize &size){
|
void WindowHelper::setMaximumWidth(int width){
|
||||||
this->window->setMaximumSize(size);
|
this->window->setMaximumWidth(width);
|
||||||
}
|
}
|
||||||
|
void WindowHelper::setMinimumHeight(int height){
|
||||||
void WindowHelper::refreshWindow(){
|
this->window->setMinimumHeight(height);
|
||||||
this->window->setFlag(Qt::NoDropShadowWindowHint,true);
|
}
|
||||||
this->window->setFlag(Qt::NoDropShadowWindowHint,false);
|
void WindowHelper::setMaximumHeight(int height){
|
||||||
|
this->window->setMaximumHeight(height);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,10 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void initWindow(FramelessView* window);
|
Q_INVOKABLE void initWindow(FramelessView* window);
|
||||||
Q_INVOKABLE void setTitle(const QString& text);
|
Q_INVOKABLE void setTitle(const QString& text);
|
||||||
Q_INVOKABLE void setMinimumSize(const QSize &size);
|
Q_INVOKABLE void setMinimumWidth(int width);
|
||||||
Q_INVOKABLE void setMaximumSize(const QSize &size);
|
Q_INVOKABLE void setMaximumWidth(int width);
|
||||||
Q_INVOKABLE void refreshWindow();
|
Q_INVOKABLE void setMinimumHeight(int height);
|
||||||
|
Q_INVOKABLE void setMaximumHeight(int height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FramelessView* window;
|
FramelessView* window;
|
||||||
|
|
|
@ -1,6 +1,85 @@
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
import FluentUI 1.0
|
import FluentUI 1.0
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|
||||||
|
id:root
|
||||||
|
property bool checked: false
|
||||||
|
property string text: "Check Box"
|
||||||
|
width: childrenRect.width
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
RowLayout{
|
||||||
|
spacing: 4
|
||||||
|
Rectangle{
|
||||||
|
width: 22
|
||||||
|
height: 22
|
||||||
|
radius: 4
|
||||||
|
border.color: {
|
||||||
|
if(FluApp.isDark){
|
||||||
|
if(checked){
|
||||||
|
return Qt.rgba(76/255,160/255,224/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(160/255,160/255,160/255,1)
|
||||||
|
}else{
|
||||||
|
if(checked){
|
||||||
|
if(mouse_area.containsMouse){
|
||||||
|
return Qt.rgba(25/255,117/255,187/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(0/255,102/255,180/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(136/255,136/255,136/255,1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
border.width: 1
|
||||||
|
color: {
|
||||||
|
if(FluApp.isDark){
|
||||||
|
if(checked){
|
||||||
|
if(mouse_area.containsMouse){
|
||||||
|
return Qt.rgba(74/255,149/255,207/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(76/255,160/255,224/255,1)
|
||||||
|
}
|
||||||
|
if(mouse_area.containsMouse){
|
||||||
|
return Qt.rgba(62/255,62/255,62/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(45/255,45/255,45/255,1)
|
||||||
|
}else{
|
||||||
|
if(checked){
|
||||||
|
if(mouse_area.containsMouse){
|
||||||
|
return Qt.rgba(25/255,117/255,187/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(0/255,102/255,180/255,1)
|
||||||
|
}
|
||||||
|
if(mouse_area.containsMouse){
|
||||||
|
return Qt.rgba(244/255,244/255,244/255,1)
|
||||||
|
}
|
||||||
|
return Qt.rgba(247/255,247/255,247/255,1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FluIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
icon: FluentIcons.FA_check
|
||||||
|
iconSize: 15
|
||||||
|
visible: checked
|
||||||
|
color: FluApp.isDark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FluText{
|
||||||
|
text:root.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MouseArea{
|
||||||
|
id:mouse_area
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: {
|
||||||
|
checked = !checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Controls.impl 2.15
|
||||||
|
import QtQuick.Templates 2.15 as T
|
||||||
|
import QtQuick.Window 2.15
|
||||||
|
import QtGraphicalEffects 1.15
|
||||||
|
|
||||||
|
T.Menu {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||||
|
contentWidth + leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||||
|
contentHeight + topPadding + bottomPadding)
|
||||||
|
margins: 0
|
||||||
|
delegate: FluMenuItem { }
|
||||||
|
|
||||||
|
contentItem: ListView {
|
||||||
|
implicitHeight: contentHeight
|
||||||
|
model: control.contentModel
|
||||||
|
interactive: Window.window ? contentHeight > Window.window.height : false
|
||||||
|
clip: true
|
||||||
|
currentIndex: control.currentIndex
|
||||||
|
ScrollIndicator.vertical: ScrollIndicator {}
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Item {
|
||||||
|
implicitWidth: 122
|
||||||
|
implicitHeight: 30
|
||||||
|
Rectangle{
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#FFFFFF"
|
||||||
|
layer.effect: FluDropShadow{}
|
||||||
|
layer.enabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Controls.impl 2.15
|
||||||
|
import QtQuick.Templates 2.15 as T
|
||||||
|
import QtQuick.Shapes 1.15
|
||||||
|
|
||||||
|
T.MenuItem {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||||
|
implicitContentWidth + leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||||
|
implicitContentHeight + topPadding + bottomPadding,
|
||||||
|
implicitIndicatorHeight + topPadding + bottomPadding)
|
||||||
|
padding: 0
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
contentItem: FluText {
|
||||||
|
text: control.text
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
implicitWidth: 120
|
||||||
|
implicitHeight: 30
|
||||||
|
width: control.width
|
||||||
|
height: control.height
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import FluentUI 1.0
|
||||||
|
|
||||||
|
ScrollBar {
|
||||||
|
|
||||||
|
}
|
|
@ -2,27 +2,11 @@
|
||||||
import QtQuick.Window 2.15
|
import QtQuick.Window 2.15
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
import FluentUI 1.0
|
import FluentUI 1.0
|
||||||
|
import QtGraphicalEffects 1.15
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
|
|
||||||
id:root
|
id:root
|
||||||
property bool isMax: {
|
|
||||||
if(Window.window == null)
|
|
||||||
return false
|
|
||||||
return Window.Maximized === Window.window.visibility
|
|
||||||
}
|
|
||||||
property string title: "FluentUI"
|
|
||||||
|
|
||||||
property string winId
|
|
||||||
|
|
||||||
property var minimumSize
|
|
||||||
property var maximumSize
|
|
||||||
|
|
||||||
Behavior on opacity{
|
|
||||||
NumberAnimation{
|
|
||||||
duration: 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property var window : {
|
property var window : {
|
||||||
if(Window.window == null)
|
if(Window.window == null)
|
||||||
|
@ -30,17 +14,42 @@ Rectangle {
|
||||||
return Window.window
|
return Window.window
|
||||||
}
|
}
|
||||||
|
|
||||||
onIsMaxChanged: {
|
property color color: FluApp.isDark ? "#202020" : "#F3F3F3"
|
||||||
if(isMax){
|
property string title: "FluentUI"
|
||||||
root.anchors.margins = 8*(1/Screen.devicePixelRatio)
|
property int minimumWidth
|
||||||
root.anchors.fill = parent
|
property int maximumWidth
|
||||||
}else{
|
property int minimumHeight
|
||||||
root.anchors.margins = 0
|
property int maximumHeight
|
||||||
root.anchors.fill = null
|
property int borderless:{
|
||||||
|
if(Window.window == null)
|
||||||
|
return 4
|
||||||
|
if(Window.window.visibility === Window.Maximized){
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
default property alias content: container.children
|
||||||
|
|
||||||
|
FluWindowResize{}
|
||||||
|
|
||||||
|
Behavior on opacity{
|
||||||
|
NumberAnimation{
|
||||||
|
duration: 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
color : FluApp.isDark ? "#202020" : "#F3F3F3"
|
Rectangle{
|
||||||
|
id:container
|
||||||
|
color:root.color
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: borderless
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: DropShadow {
|
||||||
|
radius: 5
|
||||||
|
samples: 4
|
||||||
|
color: "#40000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|
||||||
|
@ -52,13 +61,18 @@ Rectangle {
|
||||||
if(FluApp.equalsWindow(view,window)){
|
if(FluApp.equalsWindow(view,window)){
|
||||||
helper.initWindow(view);
|
helper.initWindow(view);
|
||||||
helper.setTitle(title);
|
helper.setTitle(title);
|
||||||
if(minimumSize){
|
if(minimumWidth){
|
||||||
helper.setMinimumSize(minimumSize)
|
helper.setMinimumWidth(minimumWidth)
|
||||||
}
|
}
|
||||||
if(maximumSize){
|
if(maximumWidth){
|
||||||
helper.setMaximumSize(maximumSize)
|
helper.setMaximumWidth(maximumWidth)
|
||||||
|
}
|
||||||
|
if(minimumHeight){
|
||||||
|
helper.setMinimumHeight(minimumHeight)
|
||||||
|
}
|
||||||
|
if(maximumHeight){
|
||||||
|
helper.setMaximumHeight(maximumHeight)
|
||||||
}
|
}
|
||||||
helper.refreshWindow()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Window 2.15
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
|
||||||
|
property int border: 4
|
||||||
|
property bool fixedSize: {
|
||||||
|
if(Window.window == null)
|
||||||
|
return true
|
||||||
|
if(Window.window.visibility === Window.Maximized || Window.window.visibility === Window.FullScreen){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return (Window.window.minimumWidth === Window.window.maximumWidth && Window.window.minimumHeight === Window.window.maximumHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
hoverEnabled: true
|
||||||
|
preventStealing: true
|
||||||
|
propagateComposedEvents: true
|
||||||
|
z: -65535
|
||||||
|
|
||||||
|
onReleased: {
|
||||||
|
Window.window.width = Window.window.width+1
|
||||||
|
Window.window.width = Window.window.width-1
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressed :
|
||||||
|
(mouse)=> {
|
||||||
|
if (fixedSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rc = Qt.rect(0, 0, 0, 0);
|
||||||
|
let e = 0;
|
||||||
|
|
||||||
|
//top-left
|
||||||
|
rc = Qt.rect(0, 0, border, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
e = Qt.TopEdge | Qt.LeftEdge;
|
||||||
|
window.startSystemResize(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//top
|
||||||
|
rc = Qt.rect(border, 0, window.width-border*2, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
e = Qt.TopEdge;
|
||||||
|
window.startSystemResize(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//top-right
|
||||||
|
rc = Qt.rect(window.width-border, 0, border, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
e = Qt.TopEdge | Qt.RightEdge;
|
||||||
|
window.startSystemResize(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//right
|
||||||
|
rc = Qt.rect(window.width-border, border, border, window.height-border*2);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
e = Qt.RightEdge;
|
||||||
|
window.startSystemResize(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bottom-right
|
||||||
|
rc = Qt.rect(window.width-border, window.height-border, border, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
e = Qt.BottomEdge | Qt.RightEdge;
|
||||||
|
window.startSystemResize(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bottom
|
||||||
|
rc = Qt.rect(border, window.height-border, window.width-border*2, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
e = Qt.BottomEdge;
|
||||||
|
window.startSystemResize(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bottom_left
|
||||||
|
rc = Qt.rect(0, window.height-border,border, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
e = Qt.BottomEdge | Qt.LeftEdge;
|
||||||
|
window.startSystemResize(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//left
|
||||||
|
rc = Qt.rect(0, border,border, window.height-border*2);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
e = Qt.LeftEdge;
|
||||||
|
window.startSystemResize(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPositionChanged:
|
||||||
|
(mouse)=> {
|
||||||
|
if (fixedSize) {
|
||||||
|
cursorShape = Qt.ArrowCursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rc = Qt.rect(0, 0, 0, 0);
|
||||||
|
|
||||||
|
//top-left
|
||||||
|
rc = Qt.rect(0, 0, border, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
cursorShape = Qt.SizeFDiagCursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//top
|
||||||
|
rc = Qt.rect(border, 0, window.width-border*2, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
cursorShape = Qt.SizeVerCursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//top-right
|
||||||
|
rc = Qt.rect(window.width-border, 0, border, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
cursorShape = Qt.SizeBDiagCursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//right
|
||||||
|
rc = Qt.rect(window.width-border, border, border, window.height-border*2);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
cursorShape = Qt.SizeHorCursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bottom-right
|
||||||
|
rc = Qt.rect(window.width-border, window.height-border, border, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
cursorShape = Qt.SizeFDiagCursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bottom
|
||||||
|
rc = Qt.rect(border, window.height-border, window.width-border*2, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
cursorShape = Qt.SizeVerCursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bottom_left
|
||||||
|
rc = Qt.rect(0, window.height-border,border, border);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
cursorShape = Qt.SizeBDiagCursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//left
|
||||||
|
rc = Qt.rect(0, border,border, window.height-border*2);
|
||||||
|
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||||
|
cursorShape = Qt.SizeHorCursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//default
|
||||||
|
cursorShape = Qt.ArrowCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
onExited: {
|
||||||
|
cursorShape = Qt.ArrowCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ptInRect(rc, x, y)
|
||||||
|
{
|
||||||
|
if ((rc.x <= x && x <= (rc.x + rc.width)) &&
|
||||||
|
(rc.y <= y && y <= (rc.y + rc.height))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -27,5 +27,9 @@
|
||||||
<file>controls/TFpsMonitor.qml</file>
|
<file>controls/TFpsMonitor.qml</file>
|
||||||
<file>controls/FluTextBoxBackground.qml</file>
|
<file>controls/FluTextBoxBackground.qml</file>
|
||||||
<file>controls/FluMultiLineTextBox.qml</file>
|
<file>controls/FluMultiLineTextBox.qml</file>
|
||||||
|
<file>controls/FluWindowResize.qml</file>
|
||||||
|
<file>controls/FluScrollBar.qml</file>
|
||||||
|
<file>controls/FluMenu.qml</file>
|
||||||
|
<file>controls/FluMenuItem.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
Loading…
Reference in New Issue