mirror of
https://github.com/zhuzichu520/FluentUI.git
synced 2025-01-23 04:14:35 +08:00
update
This commit is contained in:
parent
dc37a151c8
commit
6b6dbf27a1
288
src/FluFrameless.cpp
Normal file
288
src/FluFrameless.cpp
Normal file
@ -0,0 +1,288 @@
|
||||
#include "FluFrameless.h"
|
||||
|
||||
#include "FluFrameless.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#pragma comment(lib, "dwmapi.lib")
|
||||
#pragma comment(lib, "user32.lib")
|
||||
#pragma comment(lib, "shcore.lib")
|
||||
#pragma comment(lib, "Gdi32.lib")
|
||||
#include <Windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <winuser.h>
|
||||
#include <dwmapi.h>
|
||||
#include <codecvt>
|
||||
|
||||
static inline QByteArray qtNativeEventType()
|
||||
{
|
||||
static const auto result = "windows_generic_MSG";
|
||||
return result;
|
||||
}
|
||||
|
||||
int getSystemMetrics2(const WId windowId, const int index, const bool scaled){
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return 0;
|
||||
}
|
||||
const UINT realDpi = GetDpiForWindow(reinterpret_cast<HWND>(windowId));
|
||||
{
|
||||
const UINT dpi = (scaled ? realDpi : USER_DEFAULT_SCREEN_DPI);
|
||||
if (const int result = GetSystemMetricsForDpi(index, dpi); result > 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
const qreal dpr = (scaled ? qreal(1) : (qreal(realDpi) / qreal(USER_DEFAULT_SCREEN_DPI)));
|
||||
return std::round(qreal(::GetSystemMetrics(index)) / dpr);
|
||||
}
|
||||
|
||||
quint32 getResizeBorderThickness(const WId windowId, const bool scaled){
|
||||
if (!windowId) {
|
||||
return 0;
|
||||
}
|
||||
return getSystemMetrics2(windowId, SM_CXSIZEFRAME, scaled) + getSystemMetrics2(windowId, SM_CXPADDEDBORDER, scaled);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
FramelessEventFilter::FramelessEventFilter(QQuickWindow* window){
|
||||
_window = window;
|
||||
_current = window->winId();
|
||||
}
|
||||
|
||||
bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result){
|
||||
#ifdef Q_OS_WIN
|
||||
if ((eventType != qtNativeEventType()) || !message || !result || !_window) {
|
||||
return false;
|
||||
}
|
||||
const auto msg = static_cast<const MSG *>(message);
|
||||
const HWND hWnd = msg->hwnd;
|
||||
if (!hWnd) {
|
||||
return false;
|
||||
}
|
||||
const qint64 wid = reinterpret_cast<qint64>(hWnd);
|
||||
if(wid != _current){
|
||||
return false;
|
||||
}
|
||||
const UINT uMsg = msg->message;
|
||||
if (!msg || !msg->hwnd)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const LPARAM lParam = msg->lParam;
|
||||
const int borderPadding = getResizeBorderThickness(_window->winId(), true);
|
||||
if (uMsg == WM_NCCALCSIZE) {
|
||||
if (_window->visibility() == QWindow::FullScreen) {
|
||||
NCCALCSIZE_PARAMS* sz = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
|
||||
sz->rgrc[0].left += borderPadding;
|
||||
sz->rgrc[0].top += borderPadding;
|
||||
sz->rgrc[0].right -= borderPadding;
|
||||
sz->rgrc[0].bottom -= borderPadding;
|
||||
*result = WVR_REDRAW;
|
||||
return true;
|
||||
}
|
||||
NCCALCSIZE_PARAMS* sz = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
|
||||
if ( _window->visibility() == QWindow::Maximized) {
|
||||
sz->rgrc[0].top += borderPadding;
|
||||
} else {
|
||||
sz->rgrc[0].top += 0;
|
||||
}
|
||||
sz->rgrc[0].right -= borderPadding;
|
||||
sz->rgrc[0].bottom -= borderPadding;
|
||||
sz->rgrc[0].left -= -borderPadding;
|
||||
*result = WVR_REDRAW;
|
||||
return true;
|
||||
}else if (uMsg == WM_NCHITTEST){
|
||||
const bool isResizable = !(_window->height()==_window->maximumHeight()&&_window->height()==_window->minimumHeight()&&_window->width()==_window->maximumWidth()&&_window->width()==_window->minimumWidth());
|
||||
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 + borderPadding &&
|
||||
y < winrect.bottom && y >= winrect.bottom - borderPadding && isResizable) {
|
||||
*result = HTBOTTOMLEFT;
|
||||
return true;
|
||||
}
|
||||
if (x < winrect.right && x >= winrect.right - borderPadding &&
|
||||
y < winrect.bottom && y >= winrect.bottom - borderPadding && isResizable) {
|
||||
*result = HTBOTTOMRIGHT;
|
||||
return true;
|
||||
}
|
||||
if (x >= winrect.left && x < winrect.left + borderPadding &&
|
||||
y >= winrect.top && y < winrect.top + borderPadding && isResizable) {
|
||||
*result = HTTOPLEFT;
|
||||
return true;
|
||||
}
|
||||
if (x < winrect.right && x >= winrect.right - borderPadding &&
|
||||
y >= winrect.top && y < winrect.top + borderPadding && isResizable) {
|
||||
*result = HTTOPRIGHT;
|
||||
return true;
|
||||
}
|
||||
if (x >= winrect.left && x < winrect.left + borderPadding && isResizable) {
|
||||
*result = HTLEFT;
|
||||
return true;
|
||||
}
|
||||
if (x < winrect.right && x >= winrect.right - borderPadding && isResizable) {
|
||||
*result = HTRIGHT;
|
||||
return true;
|
||||
}
|
||||
if (y < winrect.bottom && y >= winrect.bottom - borderPadding && isResizable) {
|
||||
*result = HTBOTTOM;
|
||||
return true;
|
||||
}
|
||||
if (y >= winrect.top && y < winrect.top + borderPadding && isResizable) {
|
||||
*result = HTTOP;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}else if(uMsg == WM_COMMAND){
|
||||
SendMessage(msg->hwnd, WM_SYSCOMMAND, msg->wParam, msg->lParam);
|
||||
*result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
|
||||
return true;
|
||||
}else if(uMsg == WM_WINDOWPOSCHANGING){
|
||||
WINDOWPOS* wp = reinterpret_cast<WINDOWPOS*>(msg->lParam);
|
||||
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0)
|
||||
{
|
||||
wp->flags |= SWP_NOCOPYBITS;
|
||||
*result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
FluFrameless::FluFrameless(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
}
|
||||
|
||||
void FluFrameless::classBegin(){
|
||||
}
|
||||
|
||||
void FluFrameless::refresLayout(){
|
||||
#ifdef Q_OS_WIN
|
||||
if(!_window.isNull()){
|
||||
HWND hWnd = reinterpret_cast<HWND>(_window->winId());
|
||||
RECT rect;
|
||||
GetWindowRect(hWnd, &rect);
|
||||
SetWindowPos(hWnd, nullptr, rect.left, rect.top, rect.right - rect.left,rect.bottom - rect.top,SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE |SWP_FRAMECHANGED);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FluFrameless::updateCursor(Qt::Edges edges){
|
||||
switch (edges) {
|
||||
case 0:
|
||||
_window->setCursor(Qt::ArrowCursor);
|
||||
break;
|
||||
case Qt::LeftEdge:
|
||||
case Qt::RightEdge:
|
||||
_window->setCursor(Qt::SizeHorCursor);
|
||||
break;
|
||||
case Qt::TopEdge:
|
||||
case Qt::BottomEdge:
|
||||
_window->setCursor(Qt::SizeVerCursor);
|
||||
break;
|
||||
case Qt::LeftEdge | Qt::TopEdge:
|
||||
case Qt::RightEdge | Qt::BottomEdge:
|
||||
_window->setCursor(Qt::SizeFDiagCursor);
|
||||
break;
|
||||
case Qt::RightEdge | Qt::TopEdge:
|
||||
case Qt::LeftEdge | Qt::BottomEdge:
|
||||
_window->setCursor(Qt::SizeBDiagCursor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool FluFrameless::eventFilter(QObject *obj, QEvent *ev){
|
||||
if (_window->flags()& Qt::FramelessWindowHint) {
|
||||
static Qt::Edges edges = Qt::Edges();
|
||||
const int margin = 8;
|
||||
switch (ev->type()) {
|
||||
case QEvent::MouseButtonPress:
|
||||
updateCursor(edges);
|
||||
_window->startSystemResize(edges);
|
||||
break;
|
||||
case QEvent::MouseButtonRelease:
|
||||
qDebug() << Q_FUNC_INFO << ev;
|
||||
edges = Qt::Edges();
|
||||
updateCursor(edges);
|
||||
break;
|
||||
case QEvent::MouseMove: {
|
||||
edges = Qt::Edges();
|
||||
QMouseEvent *event = static_cast<QMouseEvent*>(ev);
|
||||
QPoint p =
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
||||
event->pos();
|
||||
#else
|
||||
event->position().toPoint();
|
||||
#endif
|
||||
if ( p.x() < margin ) {
|
||||
edges |= Qt::LeftEdge;
|
||||
}
|
||||
if ( p.x() > (_window->width() - margin) ) {
|
||||
edges |= Qt::RightEdge;
|
||||
}
|
||||
if ( p.y() < margin ) {
|
||||
edges |= Qt::TopEdge;
|
||||
}
|
||||
if ( p.y() > (_window->height() - margin) ) {
|
||||
edges |= Qt::BottomEdge;
|
||||
}
|
||||
updateCursor(edges);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
void FluFrameless::componentComplete(){
|
||||
auto o = parent();
|
||||
while (nullptr != o) {
|
||||
_window = (QQuickWindow*)o;
|
||||
o = o->parent();
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
if(!_window.isNull()){
|
||||
_nativeEvent =new FramelessEventFilter(_window);
|
||||
qApp->installNativeEventFilter(_nativeEvent);
|
||||
MARGINS margins[2]{{0, 0, 0, 0}, {0, 0, 1, 0}};
|
||||
HWND hWnd = reinterpret_cast<HWND>(_window->winId());
|
||||
DwmExtendFrameIntoClientArea(hWnd, &margins[false]);
|
||||
refresLayout();
|
||||
connect(_window,&QWindow::visibilityChanged,this,[=](QWindow::Visibility visibility){ refresLayout(); });
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
if(!_window.isNull()){
|
||||
_window->setFlag(Qt::FramelessWindowHint,true);
|
||||
_window->installEventFilter(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
FluFrameless::~FluFrameless(){
|
||||
#ifdef Q_OS_WIN
|
||||
if (_nativeEvent) {
|
||||
delete _nativeEvent;
|
||||
_nativeEvent = nullptr;
|
||||
refresLayout();
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
if (!_window.isNull()) {
|
||||
_window->removeEventFilter(this);
|
||||
_window->setFlag(Qt::FramelessWindowHint,false);
|
||||
}
|
||||
#endif
|
||||
}
|
47
src/FluFrameless.h
Normal file
47
src/FluFrameless.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef FLUFRAMELESS_H
|
||||
#define FLUFRAMELESS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QQuickWindow>
|
||||
#include <QtQml/qqml.h>
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include "stdafx.h"
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
using QT_NATIVE_EVENT_RESULT_TYPE = qintptr;
|
||||
using QT_ENTER_EVENT_TYPE = QEnterEvent;
|
||||
#else
|
||||
using QT_NATIVE_EVENT_RESULT_TYPE = long;
|
||||
using QT_ENTER_EVENT_TYPE = QEvent;
|
||||
#endif
|
||||
|
||||
class FramelessEventFilter : public QAbstractNativeEventFilter
|
||||
{
|
||||
public:
|
||||
FramelessEventFilter(QQuickWindow* window);
|
||||
bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override;
|
||||
public:
|
||||
QQuickWindow* _window = nullptr;
|
||||
qint64 _current = 0;
|
||||
};
|
||||
|
||||
class FluFrameless : public QObject, public QQmlParserStatus
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_NAMED_ELEMENT(FluFrameless)
|
||||
public:
|
||||
explicit FluFrameless(QObject *parent = nullptr);
|
||||
~FluFrameless();
|
||||
void classBegin() override;
|
||||
void componentComplete() override;
|
||||
Q_INVOKABLE void refresLayout();
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
private:
|
||||
void updateCursor(Qt::Edges edges);
|
||||
private:
|
||||
QPointer<QQuickWindow> _window = nullptr;
|
||||
FramelessEventFilter* _nativeEvent = nullptr;
|
||||
};
|
||||
|
||||
#endif // FLUFRAMELESS_H
|
Loading…
Reference in New Issue
Block a user