diff --git a/example/App.qml b/example/App.qml index d92e882..7bbb1cd 100644 --- a/example/App.qml +++ b/example/App.qml @@ -11,7 +11,7 @@ Window { //初始化一个MediaPlayer,解决macos切换到T_MediaPalyer页面崩溃问题 MediaPlayer{} Component.onCompleted: { - FluApp.init(app,properties) + FluApp.init(app) FluTheme.frameless = ("windows" === Qt.platform.os) FluTheme.dark = false FluApp.routes = { diff --git a/example/example.pro b/example/example.pro index 19c57ce..6b026c6 100644 --- a/example/example.pro +++ b/example/example.pro @@ -3,10 +3,12 @@ CONFIG += c++17 DEFINES += QT_DEPRECATED_WARNINGS QT_NO_WARNING_OUTPUT HEADERS += \ - ChatController.h + ChatController.h \ + AppInfo.h SOURCES += \ ChatController.cpp \ + AppInfo.cpp \ main.cpp RESOURCES += qml.qrc diff --git a/example/global/MainEvent.qml b/example/global/MainEvent.qml index f2cc5fa..d4a72c4 100644 --- a/example/global/MainEvent.qml +++ b/example/global/MainEvent.qml @@ -1,10 +1,9 @@ pragma Singleton import QtQuick +import QtQuick.Controls import FluentUI QtObject { - property int displayMode : FluNavigationView.Auto - } diff --git a/example/main.cpp b/example/main.cpp index e67f076..38244a2 100644 --- a/example/main.cpp +++ b/example/main.cpp @@ -5,14 +5,9 @@ #include #include #include +#include "AppInfo.h" #include "ChatController.h" -QMap properties(){ - QMap map; - // map["installHelper"] = QVariant::fromValue(QVariant::fromValue(InstallHelper::getInstance())); - return map; -} - int main(int argc, char *argv[]) { QCoreApplication::setOrganizationName("ZhuZiChu"); @@ -21,17 +16,8 @@ int main(int argc, char *argv[]) QQuickStyle::setStyle("Basic"); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; - qmlRegisterType("Controller",1,0,"ChatController"); - - QMapIterator iterator(properties()); - while (iterator.hasNext()) { - iterator.next(); - QString key = iterator.key(); - QVariant value = iterator.value(); - engine.rootContext()->setContextProperty(key,value); - } - engine.rootContext()->setContextProperty("properties",properties()); + engine.rootContext()->setContextProperty("appInfo",new AppInfo()); const QUrl url(QStringLiteral("qrc:/App.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { diff --git a/example/page/AboutPage.qml b/example/page/AboutPage.qml index 5be0d98..36eb76c 100644 --- a/example/page/AboutPage.qml +++ b/example/page/AboutPage.qml @@ -5,6 +5,8 @@ import FluentUI FluWindow { + id:window + width: 500 height: 600 minimumWidth: 500 @@ -36,7 +38,7 @@ FluWindow { fontStyle: FluText.Title } FluText{ - text:"v1.2.4" + text:"v%1".arg(appInfo.version) fontStyle: FluText.Body Layout.alignment: Qt.AlignBottom } @@ -67,7 +69,8 @@ FluWindow { text:"https://github.com/zhuzichu520/FluentUI" Layout.alignment: Qt.AlignBottom onClicked: { - Qt.openUrlExternally(text_hublink.text) + console.debug(window.width) +// Qt.openUrlExternally(text_hublink.text) } } } diff --git a/example/page/LoginPage.qml b/example/page/LoginPage.qml index 626e06b..951120e 100644 --- a/example/page/LoginPage.qml +++ b/example/page/LoginPage.qml @@ -12,8 +12,6 @@ FluWindow { minimumHeight: 400 maximumWidth: 400 maximumHeight: 400 - modality:2 - title:"登录" onInitArgument: diff --git a/src/FluApp.cpp b/src/FluApp.cpp index 3499228..f21a50e 100644 --- a/src/FluApp.cpp +++ b/src/FluApp.cpp @@ -7,8 +7,20 @@ #include #include #include +#include "FluTheme.h" #include "Def.h" +#ifdef Q_OS_WIN +#include +#include +#include +static bool isCompositionEnabled() +{ + BOOL composition_enabled = FALSE; + bool success = ::DwmIsCompositionEnabled(&composition_enabled) == S_OK; + return composition_enabled && success; +} +#endif FluApp* FluApp::m_instance = nullptr; @@ -25,12 +37,16 @@ FluApp::FluApp(QObject *parent) { } -void FluApp::init(QWindow *window,QMap properties){ +void FluApp::init(QQuickWindow *window){ this->appWindow = window; - this->properties = properties; } void FluApp::run(){ +#ifdef Q_OS_WIN + if(!isCompositionEnabled()){ + FluTheme::getInstance()->frameless(false); + } +#endif navigate(initialRoute()); } @@ -39,38 +55,23 @@ void FluApp::navigate(const QString& route,const QJsonObject& argument,FluRegist qErrnoWarning("没有找到当前路由"); return; } - bool isAppWindow = route == initialRoute(); - FramelessView *view = new FramelessView(); + QQmlEngine *engine = qmlEngine(appWindow); + QQmlComponent component(engine, routes().value(route).toString()); + QVariantMap properties; + if(fluRegister){ + properties.insert("pageRegister",QVariant::fromValue(fluRegister)); + } + properties.insert("argument",argument); + QQuickWindow *view = qobject_cast(component.createWithInitialProperties(properties)); + wnds.insert(view->winId(),view); if(fluRegister){ fluRegister->to(view); - view->setProperty("pageRegister",QVariant::fromValue(fluRegister)); - } - view->setProperty("argument",argument); - QMapIterator iterator(properties); - while (iterator.hasNext()) { - iterator.next(); - QString key = iterator.key(); - QVariant value = iterator.value(); - view->engine()->rootContext()->setContextProperty(key,value); } view->setColor(QColor(Qt::transparent)); - QObject::connect(view, &QQuickView::statusChanged, view, [&](QQuickView::Status status) { - if (status == QQuickView::Status::Ready) { - Q_EMIT windowReady(view); - view->moveToScreenCenter(); - view->show(); - } - }); - view->setSource((routes().value(route).toString())); - if(isAppWindow){ - QObject::connect(view->engine(), &QQmlEngine::quit, qApp, &QCoreApplication::quit); - }else{ - view->closeDeleteLater(); + if(view->maximumWidth()==view->minimumWidth()&&view->maximumHeight()==view->minimumHeight()){ + view->resize(view->minimumSize()); } -} - -bool FluApp::equalsWindow(FramelessView *view,QWindow *window){ - return view->winId() == window->winId(); + view->show(); } QJsonArray FluApp::awesomelist(const QString& keyword) diff --git a/src/FluApp.h b/src/FluApp.h index b886bf0..7c9ad28 100644 --- a/src/FluApp.h +++ b/src/FluApp.h @@ -8,7 +8,6 @@ #include #include #include "FluRegister.h" -#include "FramelessView.h" #include "stdafx.h" class FluApp : public QObject @@ -27,11 +26,7 @@ public: Q_INVOKABLE void navigate(const QString& route,const QJsonObject& argument = {},FluRegister* fluRegister = nullptr); - Q_INVOKABLE void init(QWindow *window,QMap properties); - - Q_SIGNAL void windowReady(FramelessView *view); - - Q_INVOKABLE bool equalsWindow(FramelessView *view,QWindow *window); + Q_INVOKABLE void init(QQuickWindow *window); Q_INVOKABLE QJsonArray awesomelist(const QString& keyword = ""); @@ -39,11 +34,11 @@ public: Q_INVOKABLE QString uuid(); +public: + QMap wnds; private: - QMap properties; static FluApp* m_instance; QWindow *appWindow; - }; #endif // FLUAPP_H diff --git a/src/FluRegister.h b/src/FluRegister.h index ba4231b..19abbd0 100644 --- a/src/FluRegister.h +++ b/src/FluRegister.h @@ -2,15 +2,15 @@ #define FLUREGISTER_H #include -#include +#include #include #include "stdafx.h" class FluRegister : public QObject { Q_OBJECT - Q_PROPERTY_AUTO(FramelessView*,from) - Q_PROPERTY_AUTO(FramelessView*,to) + Q_PROPERTY_AUTO(QQuickWindow*,from) + Q_PROPERTY_AUTO(QQuickWindow*,to) Q_PROPERTY_AUTO(QString,path); public: explicit FluRegister(QObject *parent = nullptr); diff --git a/src/Fluent.cpp b/src/Fluent.cpp index 7551241..f31d56f 100644 --- a/src/Fluent.cpp +++ b/src/Fluent.cpp @@ -5,6 +5,7 @@ #include #include #include "FluColors.h" +#include "NativeEventFilter.h" #include "FluTheme.h" #include "WindowHelper.h" #include "FluApp.h" @@ -95,6 +96,8 @@ void Fluent::registerTypes(const char *uri){ void Fluent::initializeEngine(QQmlEngine *engine, const char *uri) { + nativeEvent = new NativeEventFilter(); + qApp->installNativeEventFilter(nativeEvent); Q_UNUSED(engine) Q_UNUSED(uri) #ifdef Q_OS_WIN diff --git a/src/Fluent.h b/src/Fluent.h index a245a15..a1540e5 100644 --- a/src/Fluent.h +++ b/src/Fluent.h @@ -3,17 +3,25 @@ #include #include +#include "NativeEventFilter.h" class Fluent: public QObject { Q_OBJECT public: Q_INVOKABLE QString version() const; + ~Fluent(){ + if (nativeEvent != Q_NULLPTR) { + delete nativeEvent; + nativeEvent = Q_NULLPTR; + } + } void registerTypes(const char *uri); void initializeEngine(QQmlEngine *engine, const char *uri); static Fluent *getInstance(); private: static Fluent* m_instance; + NativeEventFilter *nativeEvent = Q_NULLPTR; }; #endif // FLUENT_H diff --git a/src/FluentUI.pro b/src/FluentUI.pro index 6ae7580..a35c781 100644 --- a/src/FluentUI.pro +++ b/src/FluentUI.pro @@ -19,7 +19,7 @@ HEADERS += \ FluTheme.h \ Fluent.h \ FluentUI.h \ - FramelessView.h \ + NativeEventFilter.h \ WindowHelper.h \ qml_plugin.h \ stdafx.h @@ -33,16 +33,12 @@ SOURCES += \ FluTheme.cpp \ Fluent.cpp \ FluentUI.cpp \ + NativeEventFilter.cpp \ WindowHelper.cpp \ qml_plugin.cpp \ win32 { LIBS += -ldwmapi -luser32 - SOURCES += \ - FramelessView_win.cpp -} else { - SOURCES += \ - FramelessView_unix.cpp } DEFINES += VERSION_IN=\\\"1.0.0\\\" diff --git a/src/FramelessView.h b/src/FramelessView.h deleted file mode 100644 index bf485d8..0000000 --- a/src/FramelessView.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include -#include - -class FramelessViewPrivate; -class FramelessView : public QQuickView -{ - Q_OBJECT - using Super = QQuickView; - Q_PROPERTY(bool isMax READ isMax NOTIFY isMaxChanged) - Q_PROPERTY(bool isFull READ isFull NOTIFY isFullChanged) -public: - explicit FramelessView(QWindow *parent = nullptr); - ~FramelessView(); - void moveToScreenCenter(); - void closeDeleteLater(); - bool isMax() const; - bool isFull() const; - QQuickItem *titleItem() const; - - static QMap *windowCache; - static QRect calcCenterGeo(const QRect &screenGeo, const QSize &normalSize); -public slots: - void setIsMax(bool isMax); - void setIsFull(bool isFull); - void setTitleItem(QQuickItem* item); - -signals: - void isMaxChanged(bool isMax); - void isFullChanged(bool isFull); - void mousePressed(int xPos, int yPos, int button); - -protected: - void showEvent(QShowEvent *e) override; - void resizeEvent(QResizeEvent *e) override; - bool event(QEvent *ev) override; -# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override; -# else - bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; -# endif - void mousePressEvent(QMouseEvent* event) override - { -# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - emit mousePressed(event->position().x(), event->position().y(), event->button()); -#else - emit mousePressed(event->x(), event->y(), event->button()); -#endif - Super::mousePressEvent(event); - } - -private: - FramelessViewPrivate *d; -}; diff --git a/src/FramelessView_unix.cpp b/src/FramelessView_unix.cpp deleted file mode 100644 index 9c24c70..0000000 --- a/src/FramelessView_unix.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "FramelessView.h" -#include -#include -#include -#include -#include - -class FramelessViewPrivate -{ -public: - bool m_isMax = false; - bool m_isFull = false; - bool m_deleteLater = false; - QQuickItem *m_titleItem = nullptr; -}; - -FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate) -{ - if(FluTheme::getInstance()->frameless()){ - setFlags( Qt::Window | Qt::FramelessWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); - } - setResizeMode(SizeRootObjectToView); - setIsMax(windowState() == Qt::WindowMaximized); - setIsFull(windowState() == Qt::WindowFullScreen); - connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) { - (void)state; - setIsMax(windowState() == Qt::WindowMaximized); - setIsFull(windowState() == Qt::WindowFullScreen); - }); - connect(FluTheme::getInstance(),&FluTheme::framelessChanged,this,[=](){ - setFlag(Qt::Window,false); - setFlag(Qt::Window,true); - }); -} - -FramelessView::~FramelessView() -{ - delete d; -} - -void FramelessView::showEvent(QShowEvent *e) -{ - Super::showEvent(e); -} - -QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize) -{ - int w = normalSize.width(); - int h = normalSize.height(); - int x = screenGeo.x() + (screenGeo.width() - w) / 2; - int y = screenGeo.y() + (screenGeo.height() - h) / 2; - if (screenGeo.width() < w) { - x = screenGeo.x(); - w = screenGeo.width(); - } - if (screenGeo.height() < h) { - y = screenGeo.y(); - h = screenGeo.height(); - } - return { x, y, w, h }; -} - -void FramelessView::moveToScreenCenter() -{ - auto geo = calcCenterGeo(screen()->availableGeometry(), size()); - if (minimumWidth() > geo.width() || minimumHeight() > geo.height()) { - setMinimumSize(geo.size()); - } - setGeometry(geo); - update(); -} - -void FramelessView::closeDeleteLater(){ - 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) -{ - if (d->m_isMax == isMax) - return; - - d->m_isMax = isMax; - emit isMaxChanged(d->m_isMax); -} - -void FramelessView::setIsFull(bool isFull) -{ - if(d->m_isFull == isFull) - return; - - d->m_isFull = isFull; - emit isFullChanged(d->m_isFull); -} - -void FramelessView::setTitleItem(QQuickItem *item) -{ - d->m_titleItem = item; -} -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) -#else -bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result) -#endif -{ - return Super::nativeEvent(eventType, message, result); -} - -void FramelessView::resizeEvent(QResizeEvent *e) -{ - Super::resizeEvent(e); -} - -bool FramelessView::event(QEvent *ev) -{ - if (ev->type() == QEvent::Close) { - if(d->m_deleteLater){ - deleteLater(); - ev->setAccepted(false); - } - } - return QQuickWindow::event(ev); -} - diff --git a/src/FramelessView_win.cpp b/src/FramelessView_win.cpp deleted file mode 100644 index 259305e..0000000 --- a/src/FramelessView_win.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include "FramelessView.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#pragma comment(lib, "Dwmapi.lib") -#pragma comment(lib, "User32.lib") - - -static bool isCompositionEnabled() -{ - BOOL composition_enabled = FALSE; - bool success = ::DwmIsCompositionEnabled(&composition_enabled) == S_OK; - return composition_enabled && success; -} - -static bool isMaxWin(QWindow* win) -{ - return win->windowState() == Qt::WindowMaximized; -} -static bool isFullWin(QQuickView* win) -{ - return win->windowState() == Qt::WindowFullScreen; -} -static bool isFixWin(QQuickView* win) -{ - return win->minimumWidth() == win->maximumWidth() && win->minimumHeight() == win->maximumHeight(); -} -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; - } -} - -class FramelessViewPrivate -{ -public: - bool m_isMax = false; - bool m_isFull = false; - bool m_deleteLater = false; - bool m_isFirst = true; - QQuickItem *m_titleItem = nullptr; -}; - -FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate) -{ - if(!isCompositionEnabled()){ - FluTheme::getInstance()->frameless(false); - } - if(FluTheme::getInstance()->frameless()){ - setFlag(Qt::FramelessWindowHint,true); - } - setResizeMode(SizeRootObjectToView); - setIsMax(windowState() == Qt::WindowMaximized); - setIsFull(windowState() == Qt::WindowFullScreen); - connect(this, &QWindow::windowStateChanged, this, [=](Qt::WindowState state) { - (void)state; - setIsMax(windowState() == Qt::WindowMaximized); - setIsFull(windowState() == Qt::WindowFullScreen); - }); - connect(FluTheme::getInstance(),&FluTheme::framelessChanged,this,[=](){ - setFlag(Qt::Window,false); - setFlag(Qt::Window,true); - }); -} - -FramelessView::~FramelessView() -{ - delete d; -} - -void FramelessView::showEvent(QShowEvent *e) -{ - static const MARGINS shadow_state[2] { { 0, 0, 0, 0 }, { 1, 1, 1, 1 } }; - ::DwmExtendFrameIntoClientArea((HWND)(winId()), &shadow_state[true]); - if(FluTheme::getInstance()->frameless()){ - setFlag(Qt::FramelessWindowHint,false); - } - Super::showEvent(e); -} - -QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize) -{ - int w = normalSize.width(); - int h = normalSize.height(); - int x = screenGeo.x() + (screenGeo.width() - w) / 2; - int y = screenGeo.y() + (screenGeo.height() - h) / 2; - if (screenGeo.width() < w) { - x = screenGeo.x(); - w = screenGeo.width(); - } - if (screenGeo.height() < h) { - y = screenGeo.y(); - h = screenGeo.height(); - } - return { x, y, w, h }; -} - -void FramelessView::moveToScreenCenter() -{ - auto geo = calcCenterGeo(screen()->availableGeometry(), size()); - if (minimumWidth() > geo.width() || minimumHeight() > geo.height()) { - setMinimumSize(geo.size()); - } - setGeometry(geo); - update(); -} - -void FramelessView::closeDeleteLater(){ - 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) -{ - if (d->m_isMax == isMax) - return; - - d->m_isMax = isMax; - emit isMaxChanged(d->m_isMax); -} - -void FramelessView::setIsFull(bool isFull) -{ - if(d->m_isFull == isFull) - return; - - d->m_isFull = isFull; - emit isFullChanged(d->m_isFull); -} - -int count = 1; - -void FramelessView::setTitleItem(QQuickItem *item) -{ - d->m_titleItem = item; -} -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) -#else -bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result) -#endif -{ - MSG* msg = static_cast(message); - if (!msg || !msg->hwnd) - { - return false; - } - if (msg->message == WM_NCHITTEST && FluTheme::getInstance()->frameless()) - { - 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) && !isFixWin(this)) - { - *result = hitTest(winrect, x, y, 4); - if (0 != *result) - { - return true; - } - } - }else if (msg->message == WM_NCCALCSIZE && FluTheme::getInstance()->frameless()) - { - const auto mode = static_cast(msg->wParam); - const auto clientRect = mode ? &(reinterpret_cast(msg->lParam)->rgrc[0]) : reinterpret_cast(msg->lParam); - if (mode == TRUE) - { - *result = WVR_REDRAW; - if (!isMaxWin(this) && !isFullWin(this)) - { - if (clientRect->top != 0) - { - clientRect->top -= 0.1; - } - } - else - { - if (clientRect->top != 0) - { - clientRect->top += 0.1; - } - } - return true; - } - }else if (msg->message == WM_WINDOWPOSCHANGING) - { - WINDOWPOS* wp = reinterpret_cast(msg->lParam); - if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0) - { - wp->flags |= SWP_NOCOPYBITS; - *result = 0; - return true; - } - } - return Super::nativeEvent(eventType, message, result); -} - -void FramelessView::resizeEvent(QResizeEvent *e) -{ - Super::resizeEvent(e); -} - -bool FramelessView::event(QEvent *ev) -{ - if (ev->type() == QEvent::Close) { - if(d->m_deleteLater){ - deleteLater(); - ev->setAccepted(false); - } - } - return QQuickWindow::event(ev); -} - diff --git a/src/NativeEventFilter.cpp b/src/NativeEventFilter.cpp new file mode 100644 index 0000000..dc715a8 --- /dev/null +++ b/src/NativeEventFilter.cpp @@ -0,0 +1,81 @@ +#include "NativeEventFilter.h" +#include "FluTheme.h" +#include "FluApp.h" +#ifdef Q_OS_WIN +#include +#include +#endif + +bool NativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) +{ +#ifdef Q_OS_WIN + if (eventType == "windows_generic_MSG" && FluTheme::getInstance()->frameless()) { + MSG* msg = static_cast(message); + if (msg == Q_NULLPTR) + return false; + switch(msg->message) { + case WM_COMMAND: { + SendMessage(msg->hwnd, WM_SYSCOMMAND, msg->wParam, msg->lParam); + *result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam); + return true; + } + case WM_NCCALCSIZE:{ + NCCALCSIZE_PARAMS& params = *reinterpret_cast(msg->lParam); + if (params.rgrc[0].top != 0) + params.rgrc[0].top -= 1; + *result = WVR_REDRAW; + return true; + } + case WM_NCHITTEST: { + auto view = FluApp::getInstance()->wnds[(WId)msg->hwnd]; + bool isResize = !(view->maximumWidth()==view->minimumWidth()&&view->maximumHeight()==view->minimumHeight()); + const LONG borderWidth = 8; + RECT winrect; + GetWindowRect(msg->hwnd, &winrect); + long x = GET_X_LPARAM(msg->lParam); + long y = GET_Y_LPARAM(msg->lParam); + if (x >= winrect.left && x < winrect.left + borderWidth && + y < winrect.bottom && y >= winrect.bottom - borderWidth && isResize) { + *result = HTBOTTOMLEFT; + return true; + } + if (x < winrect.right && x >= winrect.right - borderWidth && + y < winrect.bottom && y >= winrect.bottom - borderWidth && isResize) { + *result = HTBOTTOMRIGHT; + return true; + } + if (x >= winrect.left && x < winrect.left + borderWidth && + y >= winrect.top && y < winrect.top + borderWidth && isResize) { + *result = HTTOPLEFT; + return true; + } + if (x < winrect.right && x >= winrect.right - borderWidth && + y >= winrect.top && y < winrect.top + borderWidth && isResize) { + *result = HTTOPRIGHT; + return true; + } + if (x >= winrect.left && x < winrect.left + borderWidth && isResize) { + *result = HTLEFT; + return true; + } + if (x < winrect.right && x >= winrect.right - borderWidth && isResize) { + *result = HTRIGHT; + return true; + } + if (y < winrect.bottom && y >= winrect.bottom - borderWidth && isResize) { + *result = HTBOTTOM; + return true; + } + if (y >= winrect.top && y < winrect.top + borderWidth && isResize) { + *result = HTTOP; + return true; + } + return false; + } + default: + break; + } + } +#endif + return false; +} diff --git a/src/NativeEventFilter.h b/src/NativeEventFilter.h new file mode 100644 index 0000000..c767796 --- /dev/null +++ b/src/NativeEventFilter.h @@ -0,0 +1,14 @@ +#ifndef NATIVEEVENTFILTER_H +#define NATIVEEVENTFILTER_H + +#include +#include + +class NativeEventFilter : public QAbstractNativeEventFilter +{ + +public: + bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; +}; + +#endif // NATIVEEVENTFILTER_H diff --git a/src/WindowHelper.cpp b/src/WindowHelper.cpp index 5767b94..0d89d50 100644 --- a/src/WindowHelper.cpp +++ b/src/WindowHelper.cpp @@ -1,6 +1,19 @@ #include "WindowHelper.h" #include "FluRegister.h" +#include "FluApp.h" +#include "FluTheme.h" + +#ifdef Q_OS_WIN +#include +#include +#include +enum class Style : DWORD +{ + windowed = (WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN), + aero_borderless = (WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN) +}; +#endif WindowHelper::WindowHelper(QObject *parent) : QObject{parent} @@ -8,51 +21,18 @@ WindowHelper::WindowHelper(QObject *parent) } -void WindowHelper::setTitle(const QString& text){ - window->setTitle(text); -} - -void WindowHelper::initWindow(FramelessView* window){ +void WindowHelper::initWindow(QQuickWindow* window){ this->window = window; -} - -QJsonObject WindowHelper::getArgument(){ - return window->property("argument").toJsonObject(); -} - -QVariant WindowHelper::getPageRegister(){ - return window->property("pageRegister"); -} - -void WindowHelper::setMinimumWidth(int width){ - this->window->setMinimumWidth(width); -} -void WindowHelper::setMaximumWidth(int width){ - this->window->setMaximumWidth(width); -} -void WindowHelper::setMinimumHeight(int height){ - this->window->setMinimumHeight(height); -} -void WindowHelper::setMaximumHeight(int height){ - this->window->setMaximumHeight(height); -} -void WindowHelper::updateWindow(){ - this->window->setFlag(Qt::Window,false); - this->window->setFlag(Qt::Window,true); -} -void WindowHelper::setOpacity(qreal opacity){ - this->window->setOpacity(opacity); -} -void WindowHelper::setModality(int type){ - if(type == 0){ - this->window->setModality(Qt::NonModal); - }else if(type == 1){ - this->window->setModality(Qt::WindowModal); - }else if(type == 2){ - this->window->setModality(Qt::ApplicationModal); - }else{ - this->window->setModality(Qt::NonModal); +#ifdef Q_OS_WIN + if(FluTheme::getInstance()->frameless()){ + HWND wnd = (HWND)window->winId(); + SetWindowLongPtr(wnd, GWL_STYLE, static_cast(Style::aero_borderless)); + const MARGINS shadow_on = { 1, 1, 1, 1 }; + DwmExtendFrameIntoClientArea(wnd, &shadow_on); + SetWindowPos(wnd, Q_NULLPTR, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); + ShowWindow(wnd, SW_SHOW); } +#endif } QVariant WindowHelper::createRegister(const QString& path){ @@ -61,3 +41,10 @@ QVariant WindowHelper::createRegister(const QString& path){ p->path(path); return QVariant::fromValue(p); } + +void WindowHelper::destoryWindow(){ + if(this->window){ + FluApp::getInstance()->wnds.remove(this->window->winId()); + this->window->deleteLater(); + } +} diff --git a/src/WindowHelper.h b/src/WindowHelper.h index 8a6a97e..23aa98e 100644 --- a/src/WindowHelper.h +++ b/src/WindowHelper.h @@ -6,7 +6,6 @@ #include #include #include -#include "FramelessView.h" class WindowHelper : public QObject { @@ -15,22 +14,12 @@ class WindowHelper : public QObject public: explicit WindowHelper(QObject *parent = nullptr); - Q_INVOKABLE void initWindow(FramelessView* window); - Q_INVOKABLE void setTitle(const QString& text); - Q_INVOKABLE void setMinimumWidth(int width); - Q_INVOKABLE void setMaximumWidth(int width); - Q_INVOKABLE void setMinimumHeight(int height); - Q_INVOKABLE void setMaximumHeight(int height); - Q_INVOKABLE QJsonObject getArgument(); - Q_INVOKABLE QVariant getPageRegister(); - Q_INVOKABLE void updateWindow(); - Q_INVOKABLE void setOpacity(qreal opacity); - Q_INVOKABLE void setModality(int type); + Q_INVOKABLE void initWindow(QQuickWindow* window); + Q_INVOKABLE void destoryWindow(); Q_INVOKABLE QVariant createRegister(const QString& path); private: - FramelessView* window; - + QQuickWindow* window; }; #endif // WINDOWHELPER_H diff --git a/src/controls/FluWindow.qml b/src/controls/FluWindow.qml index 32f0633..376e0e6 100644 --- a/src/controls/FluWindow.qml +++ b/src/controls/FluWindow.qml @@ -1,46 +1,23 @@ import QtQuick import QtQuick.Window +import QtQuick.Controls import QtQuick.Layouts import FluentUI -Item { +ApplicationWindow { - property string title: "FluentUI" - property int minimumWidth - property int maximumWidth - property int minimumHeight - property int maximumHeight - property int modality:0 - signal initArgument(var argument) - property var pageRegister + id:window default property alias content: container.data - property var window : { - if(Window.window == null) - return null - return Window.window - } - - property color color: { - if(window && window.active){ - return FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(238/255,244/255,249/255,1) + property var argument:({}) + property var pageRegister + signal initArgument(var argument) + background: Rectangle{ + color: { + if(active){ + return FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(238/255,244/255,249/255,1) + } + return FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1) } - return FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1) - } - - id:root - - Behavior on opacity{ - NumberAnimation{ - duration: 100 - } - } - - Rectangle{ - id:container - color:root.color - anchors.fill: parent - anchors.margins: (window && (window.visibility === Window.Maximized) && FluTheme.frameless) ? 8/Screen.devicePixelRatio : 0 - clip: true Behavior on color{ ColorAnimation { duration: 300 @@ -48,47 +25,31 @@ Item { } } - Rectangle{ - border.width: 1 + Item{ + id:container anchors.fill: parent - color: Qt.rgba(0,0,0,0,) - border.color:FluTheme.dark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,230/255,234/255,1) + anchors.margins: window.visibility === Window.Maximized && FluTheme.frameless ? 8/Screen.devicePixelRatio : 0 + clip: true } - - Connections{ - target: FluApp - function onWindowReady(view){ - if(FluApp.equalsWindow(view,window)){ - helper.initWindow(view) - initArgument(helper.getArgument()) - pageRegister = helper.getPageRegister() - helper.setTitle(title) - if(minimumWidth){ - helper.setMinimumWidth(minimumWidth) - } - if(maximumWidth){ - helper.setMaximumWidth(maximumWidth) - } - if(minimumHeight){ - helper.setMinimumHeight(minimumHeight) - } - if(maximumHeight){ - helper.setMaximumHeight(maximumHeight) - } - helper.setModality(root.modality); - helper.updateWindow() - } + onClosing: + (event)=>{ + //销毁窗口,释放资源 + helper.destoryWindow() } + + FluInfoBar{ + id:infoBar + root: window } WindowHelper{ id:helper } - FluInfoBar{ - id:infoBar - root: root + Component.onCompleted: { + helper.initWindow(window) + initArgument(argument) } function showSuccess(text,duration,moremsg){ @@ -107,10 +68,6 @@ Item { infoBar.showError(text,duration,moremsg); } - function close(){ - window.close() - } - function registerForPageResult(path){ return helper.createRegister(path) }