From 5f58937588b2e1fcc1e6cef3a55c645e44de9044 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Mon, 20 Sep 2021 19:41:24 +0800 Subject: [PATCH] add hitTestVisible logic --- examples/minimal/flwindow.cpp | 57 +++++++++++++++++++++++++++++++++-- examples/minimal/flwindow.h | 9 ++++++ examples/widget/widget.cpp | 1 + framelesshelper.cpp | 48 +++++++++++++++++++++++++++-- framelesshelper.h | 5 +++ 5 files changed, 116 insertions(+), 4 deletions(-) diff --git a/examples/minimal/flwindow.cpp b/examples/minimal/flwindow.cpp index d361418..0a998d4 100644 --- a/examples/minimal/flwindow.cpp +++ b/examples/minimal/flwindow.cpp @@ -2,13 +2,15 @@ #include "../../framelesshelper.h" #include +#include +#include FRAMELESSHELPER_USE_NAMESPACE FLWindow::FLWindow(QWidget *parent) : QWidget(parent) { setWindowFlags(Qt::FramelessWindowHint); - setStyleSheet(QString::fromLatin1("background:blue")); + setupUi(); move(screen()->geometry().center() - frameGeometry().center()); } @@ -22,8 +24,11 @@ void FLWindow::initFramelessWindow() { FramelessHelper* helper = new FramelessHelper(windowHandle()); helper->setResizeBorderThickness(4); - helper->setTitleBarHeight(40); + helper->setTitleBarHeight(m_titleBarWidget->height()); helper->setResizable(true); + helper->setHitTestVisible(m_minimizeButton); + helper->setHitTestVisible(m_maximizeButton); + helper->setHitTestVisible(m_closeButton); helper->install(); } @@ -36,4 +41,52 @@ void FLWindow::showEvent(QShowEvent *event) inited = true; initFramelessWindow(); } +} + +void FLWindow::setupUi() +{ + resize(800, 600); + + m_titleBarWidget = new QWidget(this); + m_titleBarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + m_titleBarWidget->setFixedHeight(40); + m_titleBarWidget->setStyleSheet(QString::fromLatin1("background:grey")); + + m_minimizeButton = new QPushButton(m_titleBarWidget); + m_minimizeButton->setText(QStringLiteral("Min")); + m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton")); + connect(m_minimizeButton, &QPushButton::clicked, this, &QWidget::showMinimized); + + m_maximizeButton = new QPushButton(m_titleBarWidget); + m_maximizeButton->setText(QStringLiteral("Max")); + m_maximizeButton->setObjectName(QStringLiteral("MaximizeButton")); + connect(m_maximizeButton, &QPushButton::clicked, this, [this](){ + if (isMaximized() || isFullScreen()) { + showNormal(); + } else { + showMaximized(); + } + }); + + m_closeButton = new QPushButton(m_titleBarWidget); + m_closeButton->setText(QStringLiteral("Close")); + m_closeButton->setObjectName(QStringLiteral("CloseButton")); + connect(m_closeButton, &QPushButton::clicked, this, &QWidget::close); + + const auto titleBarLayout = new QHBoxLayout(m_titleBarWidget); + titleBarLayout->setContentsMargins(0, 0, 0, 0); + titleBarLayout->setSpacing(10); + titleBarLayout->addStretch(); + titleBarLayout->addWidget(m_minimizeButton); + titleBarLayout->addWidget(m_maximizeButton); + titleBarLayout->addWidget(m_closeButton); + titleBarLayout->addStretch(); + m_titleBarWidget->setLayout(titleBarLayout); + + const auto mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->setSpacing(0); + mainLayout->addWidget(m_titleBarWidget); + mainLayout->addStretch(); + setLayout(mainLayout); } \ No newline at end of file diff --git a/examples/minimal/flwindow.h b/examples/minimal/flwindow.h index 2fb26b0..e4507a8 100644 --- a/examples/minimal/flwindow.h +++ b/examples/minimal/flwindow.h @@ -2,6 +2,8 @@ #include +class QPushButton; + class FLWindow : public QWidget { Q_OBJECT @@ -14,4 +16,11 @@ protected: private: void initFramelessWindow(); + void setupUi(); + +private: + QWidget *m_titleBarWidget = nullptr; + QPushButton *m_minimizeButton = nullptr; + QPushButton *m_maximizeButton = nullptr; + QPushButton *m_closeButton = nullptr; }; \ No newline at end of file diff --git a/examples/widget/widget.cpp b/examples/widget/widget.cpp index 4bca9da..9718982 100644 --- a/examples/widget/widget.cpp +++ b/examples/widget/widget.cpp @@ -31,6 +31,7 @@ #include #include "../../utilities.h" #include "../../framelesswindowsmanager.h" +#include "../../framelesshelper.h" FRAMELESSHELPER_USE_NAMESPACE diff --git a/framelesshelper.cpp b/framelesshelper.cpp index 1b5c3aa..24547a4 100644 --- a/framelesshelper.cpp +++ b/framelesshelper.cpp @@ -94,8 +94,20 @@ QRect FramelessHelper::titleBarRect() QRegion FramelessHelper::titleBarRegion() { - // TODO: consider HitTestVisibleObject QRegion region(titleBarRect()); + + for (const auto obj : m_HTVObjects) { + if (!obj || !(obj->isWidgetType() || obj->inherits("QQuickItem"))) { + continue; + } + + if (!obj->property("visible").toBool()) { + continue; + } + + region -= getHTVObjectRect(obj); + } + return region; } @@ -111,9 +123,21 @@ QRect FramelessHelper::clientRect() QRegion FramelessHelper::nonClientRegion() { - // TODO: consider HitTestVisibleObject QRegion region(QRect(QPoint(0, 0), windowSize())); region -= clientRect(); + + for (const auto obj : m_HTVObjects) { + if (!obj || !(obj->isWidgetType() || obj->inherits("QQuickItem"))) { + continue; + } + + if (!obj->property("visible").toBool()) { + continue; + } + + region -= getHTVObjectRect(obj); + } + return region; } @@ -309,6 +333,26 @@ void FramelessHelper::startResize(QMouseEvent* event, Qt::WindowFrameSection fra #endif } +void FramelessHelper::setHitTestVisible(QObject *obj) +{ + m_HTVObjects.push_back(obj); +} + +bool FramelessHelper::isHitTestVisible(QObject *obj) +{ + return m_HTVObjects.contains(obj); +} + +QRect FramelessHelper::getHTVObjectRect(QObject *obj) +{ + const QPoint originPoint = m_window->mapFromGlobal( + Utilities::mapOriginPointToWindow(obj).toPoint()); + const int width = obj->property("width").toInt(); + const int height = obj->property("height").toInt(); + + return QRect(originPoint, QSize(width, height)); +} + bool FramelessHelper::eventFilter(QObject *object, QEvent *event) { bool filterOut = false; diff --git a/framelesshelper.h b/framelesshelper.h index 104f7a8..518d755 100644 --- a/framelesshelper.h +++ b/framelesshelper.h @@ -87,6 +87,10 @@ public: void startMove(QMouseEvent* event); void startResize(QMouseEvent* event, Qt::WindowFrameSection frameSection); + void setHitTestVisible(QObject *obj); + bool isHitTestVisible(QObject *obj); + QRect getHTVObjectRect(QObject *obj); + protected: bool eventFilter(QObject *object, QEvent *event) override; @@ -100,6 +104,7 @@ private: bool m_cursorChanged; Qt::WindowFrameSection m_hoveredFrameSection; Qt::WindowFrameSection m_clickedFrameSection; + QList m_HTVObjects; }; FRAMELESSHELPER_END_NAMESPACE