forked from github_mirror/framelesshelper
parent
ebc20e23b6
commit
4d277a5eac
|
@ -115,22 +115,32 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
|||
}
|
||||
const auto mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPointF localPos = mouseEvent->position();
|
||||
const QPointF scenePos = mouseEvent->scenePosition();
|
||||
#else
|
||||
const QPointF localPos = mouseEvent->windowPos();
|
||||
const QPointF scenePos = mouseEvent->windowPos();
|
||||
#endif
|
||||
if (type == QEvent::MouseMove) {
|
||||
const Qt::CursorShape cs = Utils::calculateCursorShape(window, localPos);
|
||||
switch (type) {
|
||||
case QEvent::MouseMove: {
|
||||
const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos);
|
||||
if (cs == Qt::ArrowCursor) {
|
||||
window->unsetCursor();
|
||||
} else {
|
||||
window->setCursor(cs);
|
||||
}
|
||||
} else if (type == QEvent::MouseButtonPress) {
|
||||
const Qt::Edges edges = Utils::calculateWindowEdges(window, localPos);
|
||||
if (edges != Qt::Edges{}) {
|
||||
Utils::startSystemResize(window, edges);
|
||||
} break;
|
||||
case QEvent::MouseButtonPress: {
|
||||
if (mouseEvent->button() != Qt::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
const Qt::Edges edges = Utils::calculateWindowEdges(window, scenePos);
|
||||
if (edges == Qt::Edges{}) {
|
||||
return false;
|
||||
}
|
||||
Utils::startSystemResize(window, edges);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -222,9 +222,6 @@
|
|||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include "mainwindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
#include "ui_TitleBar.h"
|
||||
#include <utils.h>
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) : FramelessMainWindow(parent, flags)
|
||||
{
|
||||
|
@ -43,6 +46,14 @@ MainWindow::~MainWindow()
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::changeEvent(QEvent *event)
|
||||
{
|
||||
FramelessMainWindow::changeEvent(event);
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
Q_EMIT windowStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setupUi()
|
||||
{
|
||||
mainWindow = new Ui::MainWindow;
|
||||
|
@ -52,6 +63,12 @@ void MainWindow::setupUi()
|
|||
titleBar = new Ui::TitleBar;
|
||||
titleBar->setupUi(titleBarWidget);
|
||||
|
||||
const SystemTheme theme = SystemTheme::Light;
|
||||
const ResourceType resource = ResourceType::Icon;
|
||||
titleBar->minimizeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Minimize, theme, resource)));
|
||||
titleBar->maximizeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Maximize, theme, resource)));
|
||||
titleBar->closeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Close, theme, resource)));
|
||||
|
||||
QMenuBar *mb = menuBar();
|
||||
titleBar->horizontalLayout->insertWidget(1, mb);
|
||||
|
||||
|
@ -65,19 +82,18 @@ void MainWindow::setupUi()
|
|||
setHitTestVisible(titleBar->closeButton, true);
|
||||
|
||||
connect(titleBar->minimizeButton, &QPushButton::clicked, this, &MainWindow::showMinimized);
|
||||
connect(titleBar->maximizeButton, &QPushButton::clicked, this, [this](){
|
||||
if (isZoomed()) {
|
||||
showNormal();
|
||||
} else {
|
||||
showMaximized();
|
||||
}
|
||||
});
|
||||
connect(titleBar->maximizeButton, &QPushButton::clicked, this, &MainWindow::toggleMaximized);
|
||||
connect(titleBar->closeButton, &QPushButton::clicked, this, &MainWindow::close);
|
||||
connect(this, &MainWindow::windowIconChanged, titleBar->iconButton, &QPushButton::setIcon);
|
||||
connect(this, &MainWindow::windowTitleChanged, titleBar->titleLabel, &QLabel::setText);
|
||||
connect(this, &MainWindow::windowStateChanged, this, [this](){
|
||||
const bool zoomed = isZoomed();
|
||||
titleBar->maximizeButton->setChecked(zoomed);
|
||||
const SystemTheme theme = SystemTheme::Light;
|
||||
const SystemButtonType button = (zoomed ? SystemButtonType::Restore : SystemButtonType::Maximize);
|
||||
const ResourceType resource = ResourceType::Icon;
|
||||
titleBar->maximizeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(button, theme, resource)));
|
||||
titleBar->maximizeButton->setToolTip(zoomed ? tr("Restore") : tr("Maximize"));
|
||||
});
|
||||
|
||||
setWindowTitle(tr("Hello, World! - Qt MainWindow"));
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ public:
|
|||
explicit MainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = {});
|
||||
~MainWindow() override;
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *event) override;
|
||||
|
||||
private:
|
||||
void setupUi();
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <QtQml/qqmlapplicationengine.h>
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <QtQuickControls2/qquickstyle.h>
|
||||
#include <framelessquickhelper.h>
|
||||
#include <framelesshelper_quick.h>
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
|
@ -60,7 +60,7 @@ int main(int argc, char *argv[])
|
|||
QQuickStyle::setStyle(QStringLiteral("Default"));
|
||||
#endif
|
||||
|
||||
FramelessQuickHelper::registerTypes(&engine);
|
||||
FramelessHelper::Quick::registerTypes(&engine);
|
||||
|
||||
const QUrl homepageUrl(QStringLiteral("qrc:///qml/MainWindow.qml"));
|
||||
const QMetaObject::Connection connection = QObject::connect(
|
||||
|
|
|
@ -67,33 +67,12 @@ Window {
|
|||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 30 * 1.5 * 3
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
FramelessUtils.showSystemMenu(window, Qt.point(mouse.x, mouse.y));
|
||||
}
|
||||
}
|
||||
onDoubleClicked: {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
maximizeButton.clicked();
|
||||
}
|
||||
}
|
||||
onPositionChanged: {
|
||||
if (containsPress && (window.visibility !== Window.FullScreen)) {
|
||||
FramelessUtils.startSystemMove2(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
MinimizeButton {
|
||||
id: minimizeButton
|
||||
onClicked: FramelessUtils.showMinimized2(window)
|
||||
}
|
||||
|
||||
|
@ -110,6 +89,7 @@ Window {
|
|||
}
|
||||
|
||||
CloseButton {
|
||||
id: closeButton
|
||||
onClicked: window.close()
|
||||
}
|
||||
}
|
||||
|
@ -136,5 +116,11 @@ Window {
|
|||
color: window.active ? FramelessUtils.frameBorderActiveColor : FramelessUtils.frameBorderInactiveColor
|
||||
}
|
||||
|
||||
Component.onCompleted: FramelessHelper.addWindow(window)
|
||||
Component.onCompleted: {
|
||||
FramelessHelper.addWindow(window);
|
||||
FramelessHelper.setTitleBarItem(window, titleBar);
|
||||
FramelessHelper.setHitTestVisible(window, minimizeButton, true);
|
||||
FramelessHelper.setHitTestVisible(window, maximizeButton, true);
|
||||
FramelessHelper.setHitTestVisible(window, closeButton, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,11 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
Widget::Widget(QWidget *parent) : FramelessWidget(parent)
|
||||
Widget::Widget(QWidget *parent) : FramelessWidget(parent, WindowLayout::Standard)
|
||||
{
|
||||
setupUi();
|
||||
connect(this, &Widget::systemThemeChanged, this, &Widget::updateStyleSheet);
|
||||
startTimer(500);
|
||||
connect(this, &Widget::systemThemeChanged, this, &Widget::updateStyleSheet);
|
||||
}
|
||||
|
||||
Widget::~Widget() = default;
|
||||
|
|
|
@ -8,6 +8,10 @@ set(SOURCES
|
|||
framelessquickutils.cpp
|
||||
framelesshelperimageprovider.h
|
||||
framelesshelperimageprovider.cpp
|
||||
framelessquickeventfilter.h
|
||||
framelessquickeventfilter.cpp
|
||||
framelesshelper_quick.h
|
||||
framelesshelper_quick.cpp
|
||||
)
|
||||
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "framelesshelper_quick.h"
|
||||
#include <QtQml/qqmlengine.h>
|
||||
#include "framelesshelperimageprovider.h"
|
||||
#include "framelessquickhelper.h"
|
||||
#include "framelessquickutils.h"
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
static constexpr const char FRAMELESSHELPER_QUICK_URI[] = "org.wangwenx190.FramelessHelper";
|
||||
|
||||
void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
||||
{
|
||||
Q_ASSERT(engine);
|
||||
if (!engine) {
|
||||
return;
|
||||
}
|
||||
engine->addImageProvider(QStringLiteral("framelesshelper"), new FramelessHelperImageProvider);
|
||||
qmlRegisterSingletonType<FramelessQuickHelper>(FRAMELESSHELPER_QUICK_URI, 1, 0, "FramelessHelper", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
|
||||
Q_UNUSED(engine);
|
||||
Q_UNUSED(scriptEngine);
|
||||
return new FramelessQuickHelper;
|
||||
});
|
||||
qmlRegisterSingletonType<FramelessQuickUtils>(FRAMELESSHELPER_QUICK_URI, 1, 0, "FramelessUtils", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
|
||||
Q_UNUSED(engine);
|
||||
Q_UNUSED(scriptEngine);
|
||||
return new FramelessQuickUtils;
|
||||
});
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framelesshelperquick_global.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QQmlEngine;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
namespace FramelessHelper::Quick
|
||||
{
|
||||
|
||||
FRAMELESSHELPER_QUICK_API void registerTypes(QQmlEngine *engine);
|
||||
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -94,7 +94,7 @@ QPixmap FramelessHelperImageProvider::requestPixmap(const QString &id, QSize *si
|
|||
if (!pixmapVar.isValid()) {
|
||||
return {};
|
||||
}
|
||||
if (static_cast<QMetaType::Type>(pixmapVar.typeId()) != QMetaType::QPixmap) {
|
||||
if (static_cast<QMetaType::Type>(pixmapVar.userType()) != QMetaType::QPixmap) {
|
||||
return {};
|
||||
}
|
||||
if (size) {
|
||||
|
|
|
@ -31,14 +31,16 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
class FRAMELESSHELPER_QUICK_API FramelessHelperImageProvider : public QQuickImageProvider
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
Q_OBJECT
|
||||
#endif
|
||||
Q_DISABLE_COPY_MOVE(FramelessHelperImageProvider)
|
||||
|
||||
public:
|
||||
explicit FramelessHelperImageProvider();
|
||||
~FramelessHelperImageProvider() override;
|
||||
|
||||
Q_NODISCARD QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) override;
|
||||
Q_NODISCARD QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "framelessquickeventfilter.h"
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <QtQuick/qquickitem.h>
|
||||
#include <utils.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
struct EventFilterDataInternal
|
||||
{
|
||||
QQuickWindow *window = nullptr;
|
||||
FramelessQuickEventFilter *eventFilter = nullptr;
|
||||
QQuickItem *titleBarItem = nullptr;
|
||||
QList<QQuickItem *> hitTestVisibleItems = {};
|
||||
};
|
||||
|
||||
struct EventFilterData
|
||||
{
|
||||
QMutex mutex = {};
|
||||
QHash<QQuickWindow *, EventFilterDataInternal> data = {};
|
||||
|
||||
explicit EventFilterData() = default;
|
||||
~EventFilterData() = default;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY_MOVE(EventFilterData)
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(EventFilterData, g_data)
|
||||
|
||||
[[nodiscard]] static inline bool isInTitleBarDraggableArea(QQuickWindow *window, const QPointF &pos)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
g_data()->mutex.lock();
|
||||
if (!g_data()->data.contains(window)) {
|
||||
g_data()->mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
const EventFilterDataInternal data = g_data()->data.value(window);
|
||||
g_data()->mutex.unlock();
|
||||
if (!data.titleBarItem) {
|
||||
return false;
|
||||
}
|
||||
const auto mapGeometryToScene = [](const QQuickItem * const item) -> QRectF {
|
||||
Q_ASSERT(item);
|
||||
if (!item) {
|
||||
return {};
|
||||
}
|
||||
return QRectF(item->mapToScene(QPointF(0.0, 0.0)), item->size());
|
||||
};
|
||||
QRegion region = mapGeometryToScene(data.titleBarItem).toRect();
|
||||
if (!data.hitTestVisibleItems.isEmpty()) {
|
||||
for (auto &&item : qAsConst(data.hitTestVisibleItems)) {
|
||||
Q_ASSERT(item);
|
||||
if (item) {
|
||||
region -= mapGeometryToScene(item).toRect();
|
||||
}
|
||||
}
|
||||
}
|
||||
return region.contains(pos.toPoint());
|
||||
}
|
||||
|
||||
FramelessQuickEventFilter::FramelessQuickEventFilter(QObject *parent) : QObject(parent) {}
|
||||
|
||||
FramelessQuickEventFilter::~FramelessQuickEventFilter() = default;
|
||||
|
||||
void FramelessQuickEventFilter::addWindow(QQuickWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
g_data()->mutex.lock();
|
||||
if (g_data()->data.contains(window)) {
|
||||
g_data()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
auto data = EventFilterDataInternal{};
|
||||
data.window = window;
|
||||
data.eventFilter = new FramelessQuickEventFilter(window);
|
||||
g_data()->data.insert(window, data);
|
||||
g_data()->mutex.unlock();
|
||||
window->installEventFilter(data.eventFilter);
|
||||
}
|
||||
|
||||
void FramelessQuickEventFilter::removeWindow(QQuickWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
g_data()->mutex.lock();
|
||||
if (!g_data()->data.contains(window)) {
|
||||
g_data()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
const EventFilterDataInternal data = g_data()->data.value(window);
|
||||
g_data()->data.remove(window);
|
||||
g_data()->mutex.unlock();
|
||||
window->removeEventFilter(data.eventFilter);
|
||||
delete data.eventFilter;
|
||||
}
|
||||
|
||||
void FramelessQuickEventFilter::setTitleBarItem(QQuickWindow *window, QQuickItem *item)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
Q_ASSERT(item);
|
||||
if (!window || !item) {
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&g_data()->mutex);
|
||||
if (!g_data()->data.contains(window)) {
|
||||
return;
|
||||
}
|
||||
g_data()->data[window].titleBarItem = item;
|
||||
}
|
||||
|
||||
void FramelessQuickEventFilter::setHitTestVisible(QQuickWindow *window, QQuickItem *item, const bool visible)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
Q_ASSERT(item);
|
||||
if (!window || !item) {
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&g_data()->mutex);
|
||||
if (!g_data()->data.contains(window)) {
|
||||
return;
|
||||
}
|
||||
auto &items = g_data()->data[window].hitTestVisibleItems;
|
||||
const bool exists = items.contains(item);
|
||||
if (visible && !exists) {
|
||||
items.append(item);
|
||||
}
|
||||
if (!visible && exists) {
|
||||
items.removeAll(item);
|
||||
}
|
||||
}
|
||||
|
||||
bool FramelessQuickEventFilter::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
Q_ASSERT(event);
|
||||
if (!object || !event) {
|
||||
return false;
|
||||
}
|
||||
if (!object->isWindowType()) {
|
||||
return false;
|
||||
}
|
||||
const auto window = qobject_cast<QQuickWindow *>(object);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
g_data()->mutex.lock();
|
||||
if (!g_data()->data.contains(window)) {
|
||||
g_data()->mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
g_data()->mutex.unlock();
|
||||
const QEvent::Type eventType = event->type();
|
||||
if ((eventType != QEvent::MouseButtonPress)
|
||||
&& (eventType != QEvent::MouseButtonRelease) && (eventType != QEvent::MouseButtonDblClick)) {
|
||||
return false;
|
||||
}
|
||||
const auto mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
const Qt::MouseButton button = mouseEvent->button();
|
||||
if ((button != Qt::LeftButton) && (button != Qt::RightButton)) {
|
||||
return false;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPointF scenePos = mouseEvent->scenePosition();
|
||||
#else
|
||||
const QPointF scenePos = mouseEvent->windowPos();
|
||||
#endif
|
||||
const bool titleBar = isInTitleBarDraggableArea(window, scenePos);
|
||||
switch (eventType) {
|
||||
case QEvent::MouseButtonPress: {
|
||||
if (button != Qt::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
if (!titleBar) {
|
||||
return false;
|
||||
}
|
||||
Utils::startSystemMove(window);
|
||||
return true;
|
||||
}
|
||||
case QEvent::MouseButtonRelease: {
|
||||
if (button != Qt::RightButton) {
|
||||
return false;
|
||||
}
|
||||
if (!titleBar) {
|
||||
return false;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPointF globalPos = mouseEvent->globalPosition();
|
||||
#else
|
||||
const QPointF globalPos = mouseEvent->globalPos();
|
||||
#endif
|
||||
const QPointF nativePos = QPointF(globalPos * window->effectiveDevicePixelRatio());
|
||||
Utils::showSystemMenu(window->winId(), nativePos);
|
||||
return true;
|
||||
}
|
||||
case QEvent::MouseButtonDblClick: {
|
||||
if (button != Qt::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
if (!titleBar) {
|
||||
return false;
|
||||
}
|
||||
const QQuickWindow::Visibility visibility = window->visibility();
|
||||
if ((visibility == QQuickWindow::Maximized) || (visibility == QQuickWindow::FullScreen)) {
|
||||
window->showNormal();
|
||||
} else {
|
||||
window->showMaximized();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framelesshelperquick_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QQuickWindow;
|
||||
class QQuickItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class FRAMELESSHELPER_QUICK_API FramelessQuickEventFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(FramelessQuickEventFilter)
|
||||
|
||||
public:
|
||||
explicit FramelessQuickEventFilter(QObject *parent = nullptr);
|
||||
~FramelessQuickEventFilter() override;
|
||||
|
||||
Q_INVOKABLE static void addWindow(QQuickWindow *window);
|
||||
Q_INVOKABLE static void removeWindow(QQuickWindow *window);
|
||||
Q_INVOKABLE static void setTitleBarItem(QQuickWindow *window, QQuickItem *item);
|
||||
Q_INVOKABLE static void setHitTestVisible(QQuickWindow *window, QQuickItem *item, const bool visible);
|
||||
|
||||
protected:
|
||||
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -23,56 +23,54 @@
|
|||
*/
|
||||
|
||||
#include "framelessquickhelper.h"
|
||||
#include <QtQml/qqmlengine.h>
|
||||
#include "framelesshelperimageprovider.h"
|
||||
#include "framelessquickutils.h"
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <framelesswindowsmanager.h>
|
||||
#include "framelessquickeventfilter.h"
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
static constexpr const char FRAMELESSHELPER_QUICK_URI[] = "org.wangwenx190.FramelessHelper";
|
||||
|
||||
FramelessQuickHelper::FramelessQuickHelper(QObject *parent) : QObject(parent) {}
|
||||
|
||||
FramelessQuickHelper::~FramelessQuickHelper() = default;
|
||||
|
||||
void FramelessQuickHelper::registerTypes(QQmlEngine *engine)
|
||||
{
|
||||
Q_ASSERT(engine);
|
||||
if (!engine) {
|
||||
return;
|
||||
}
|
||||
engine->addImageProvider(QStringLiteral("framelesshelper"), new FramelessHelperImageProvider);
|
||||
qmlRegisterSingletonType<FramelessQuickHelper>(FRAMELESSHELPER_QUICK_URI, 1, 0, "FramelessHelper", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
|
||||
Q_UNUSED(engine);
|
||||
Q_UNUSED(scriptEngine);
|
||||
const auto framelessHelper = new FramelessQuickHelper;
|
||||
return framelessHelper;
|
||||
});
|
||||
qmlRegisterSingletonType<FramelessQuickUtils>(FRAMELESSHELPER_QUICK_URI, 1, 0, "FramelessUtils", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
|
||||
Q_UNUSED(engine);
|
||||
Q_UNUSED(scriptEngine);
|
||||
const auto framelessUtils = new FramelessQuickUtils;
|
||||
return framelessUtils;
|
||||
});
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::addWindow(QWindow *window)
|
||||
void FramelessQuickHelper::addWindow(QQuickWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
FramelessWindowsManager::instance()->addWindow(window);
|
||||
FramelessQuickEventFilter::addWindow(window);
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::removeWindow(QWindow *window)
|
||||
void FramelessQuickHelper::removeWindow(QQuickWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
FramelessQuickEventFilter::removeWindow(window);
|
||||
FramelessWindowsManager::instance()->removeWindow(window);
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::setTitleBarItem(QQuickWindow *window, QQuickItem *item)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
Q_ASSERT(item);
|
||||
if (!window || !item) {
|
||||
return;
|
||||
}
|
||||
FramelessQuickEventFilter::setTitleBarItem(window, item);
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::setHitTestVisible(QQuickWindow *window, QQuickItem *item, const bool visible)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
Q_ASSERT(item);
|
||||
if (!window || !item) {
|
||||
return;
|
||||
}
|
||||
FramelessQuickEventFilter::setHitTestVisible(window, item, visible);
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
#include <QtCore/qobject.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWindow;
|
||||
class QQmlEngine;
|
||||
class QQuickWindow;
|
||||
class QQuickItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
@ -49,10 +49,10 @@ public:
|
|||
explicit FramelessQuickHelper(QObject *parent = nullptr);
|
||||
~FramelessQuickHelper() override;
|
||||
|
||||
Q_INVOKABLE static void registerTypes(QQmlEngine *engine);
|
||||
|
||||
Q_INVOKABLE static void addWindow(QWindow *window);
|
||||
Q_INVOKABLE static void removeWindow(QWindow *window);
|
||||
Q_INVOKABLE static void addWindow(QQuickWindow *window);
|
||||
Q_INVOKABLE static void removeWindow(QQuickWindow *window);
|
||||
Q_INVOKABLE static void setTitleBarItem(QQuickWindow *window, QQuickItem *item);
|
||||
Q_INVOKABLE static void setHitTestVisible(QQuickWindow *window, QQuickItem *item, const bool visible);
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "framelessquickutils.h"
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1))
|
||||
# include <QtGui/qpa/qplatformtheme.h>
|
||||
# include <QtGui/private/qguiapplication_p.h>
|
||||
|
@ -119,7 +120,7 @@ bool FramelessQuickUtils::titleBarColorVisible()
|
|||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickUtils::showMinimized2(QWindow *window)
|
||||
void FramelessQuickUtils::showMinimized2(QQuickWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
|
@ -136,7 +137,7 @@ void FramelessQuickUtils::showMinimized2(QWindow *window)
|
|||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickUtils::showSystemMenu(QWindow *window, const QPointF &pos)
|
||||
void FramelessQuickUtils::showSystemMenu(QQuickWindow *window, const QPointF &pos)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
|
@ -144,15 +145,16 @@ void FramelessQuickUtils::showSystemMenu(QWindow *window, const QPointF &pos)
|
|||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPointF globalPos = window->mapToGlobal(pos) * window->devicePixelRatio();
|
||||
const QPointF globalPos = window->mapToGlobal(pos);
|
||||
# else
|
||||
const QPointF globalPos = QPointF(window->mapToGlobal(pos.toPoint())) * window->devicePixelRatio();
|
||||
const QPointF globalPos = window->mapToGlobal(pos.toPoint());
|
||||
# endif
|
||||
Utils::showSystemMenu(window->winId(), globalPos);
|
||||
const QPointF nativePos = QPointF(globalPos * window->effectiveDevicePixelRatio());
|
||||
Utils::showSystemMenu(window->winId(), nativePos);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickUtils::startSystemMove2(QWindow *window)
|
||||
void FramelessQuickUtils::startSystemMove2(QQuickWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
|
@ -165,7 +167,7 @@ void FramelessQuickUtils::startSystemMove2(QWindow *window)
|
|||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickUtils::startSystemResize2(QWindow *window, const Qt::Edges edges)
|
||||
void FramelessQuickUtils::startSystemResize2(QQuickWindow *window, const Qt::Edges edges)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include <QtGui/qcolor.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWindow;
|
||||
class QQuickWindow;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
@ -66,10 +66,10 @@ public:
|
|||
Q_NODISCARD static QColor systemAccentColor();
|
||||
Q_NODISCARD static bool titleBarColorVisible();
|
||||
|
||||
Q_INVOKABLE static void showMinimized2(QWindow *window);
|
||||
Q_INVOKABLE static void showSystemMenu(QWindow *window, const QPointF &pos);
|
||||
Q_INVOKABLE static void startSystemMove2(QWindow *window);
|
||||
Q_INVOKABLE static void startSystemResize2(QWindow *window, const Qt::Edges edges);
|
||||
Q_INVOKABLE static void showMinimized2(QQuickWindow *window);
|
||||
Q_INVOKABLE static void showSystemMenu(QQuickWindow *window, const QPointF &pos);
|
||||
Q_INVOKABLE static void startSystemMove2(QQuickWindow *window);
|
||||
Q_INVOKABLE static void startSystemResize2(QQuickWindow *window, const Qt::Edges edges);
|
||||
|
||||
Q_SIGNALS:
|
||||
void frameBorderActiveColorChanged();
|
||||
|
|
|
@ -29,8 +29,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
FramelessMainWindow::FramelessMainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags)
|
||||
{
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, this));
|
||||
m_helper->initialize();
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, WindowLayout::Custom));
|
||||
}
|
||||
|
||||
FramelessMainWindow::~FramelessMainWindow() = default;
|
||||
|
@ -60,6 +59,11 @@ void FramelessMainWindow::setHitTestVisible(QWidget *widget, const bool visible)
|
|||
m_helper->setHitTestVisible(widget, visible);
|
||||
}
|
||||
|
||||
void FramelessMainWindow::toggleMaximized()
|
||||
{
|
||||
m_helper->toggleMaximized();
|
||||
}
|
||||
|
||||
void FramelessMainWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
QMainWindow::showEvent(event);
|
||||
|
@ -84,6 +88,12 @@ void FramelessMainWindow::mousePressEvent(QMouseEvent *event)
|
|||
m_helper->mousePressEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessMainWindow::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QMainWindow::mouseReleaseEvent(event);
|
||||
m_helper->mouseReleaseEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessMainWindow::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
QMainWindow::mouseDoubleClickEvent(event);
|
||||
|
|
|
@ -38,23 +38,25 @@ class FRAMELESSHELPER_WIDGETS_API FramelessMainWindow : public QMainWindow
|
|||
Q_PROPERTY(QWidget* titleBarWidget READ titleBarWidget WRITE setTitleBarWidget NOTIFY titleBarWidgetChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit FramelessMainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = {},
|
||||
const WindowLayout wl = WindowLayout::Standard);
|
||||
explicit FramelessMainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = {});
|
||||
~FramelessMainWindow() override;
|
||||
|
||||
Q_NODISCARD bool isNormal() const;
|
||||
Q_NODISCARD bool isZoomed() const;
|
||||
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
|
||||
Q_NODISCARD Q_INVOKABLE bool isZoomed() const;
|
||||
|
||||
void setTitleBarWidget(QWidget *widget);
|
||||
Q_NODISCARD QWidget *titleBarWidget() const;
|
||||
|
||||
Q_INVOKABLE void setHitTestVisible(QWidget *widget, const bool visible);
|
||||
|
||||
Q_INVOKABLE void toggleMaximized();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void changeEvent(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
|
|
@ -27,10 +27,9 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
FramelessWidget::FramelessWidget(QWidget *parent) : QWidget(parent)
|
||||
FramelessWidget::FramelessWidget(QWidget *parent, const WindowLayout wl) : QWidget(parent)
|
||||
{
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, this));
|
||||
m_helper->initialize();
|
||||
m_helper.reset(new FramelessWidgetsHelper(this, wl));
|
||||
}
|
||||
|
||||
FramelessWidget::~FramelessWidget() = default;
|
||||
|
@ -70,6 +69,11 @@ void FramelessWidget::setHitTestVisible(QWidget *widget, const bool visible)
|
|||
m_helper->setHitTestVisible(widget, visible);
|
||||
}
|
||||
|
||||
void FramelessWidget::toggleMaximized()
|
||||
{
|
||||
m_helper->toggleMaximized();
|
||||
}
|
||||
|
||||
void FramelessWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
QWidget::showEvent(event);
|
||||
|
@ -94,6 +98,12 @@ void FramelessWidget::mousePressEvent(QMouseEvent *event)
|
|||
m_helper->mousePressEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
m_helper->mouseReleaseEventHandler(event);
|
||||
}
|
||||
|
||||
void FramelessWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
QWidget::mouseDoubleClickEvent(event);
|
||||
|
|
|
@ -42,8 +42,8 @@ public:
|
|||
explicit FramelessWidget(QWidget *parent = nullptr, const WindowLayout wl = WindowLayout::Standard);
|
||||
~FramelessWidget() override;
|
||||
|
||||
Q_NODISCARD bool isNormal() const;
|
||||
Q_NODISCARD bool isZoomed() const;
|
||||
Q_NODISCARD Q_INVOKABLE bool isNormal() const;
|
||||
Q_NODISCARD Q_INVOKABLE bool isZoomed() const;
|
||||
|
||||
void setTitleBarWidget(QWidget *widget);
|
||||
Q_NODISCARD QWidget *titleBarWidget() const;
|
||||
|
@ -53,11 +53,14 @@ public:
|
|||
|
||||
Q_INVOKABLE void setHitTestVisible(QWidget *widget, const bool visible);
|
||||
|
||||
Q_INVOKABLE void toggleMaximized();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void changeEvent(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
static constexpr const char QT_MAINWINDOW_CLASS_NAME[] = "QMainWindow";
|
||||
|
||||
static const QString kSystemButtonStyleSheet = QStringLiteral(R"(
|
||||
QPushButton {
|
||||
border-style: none;
|
||||
|
@ -82,18 +80,19 @@ void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
|
|||
if (m_userTitleBarWidget == widget) {
|
||||
return;
|
||||
}
|
||||
if (isStandardLayout()) {
|
||||
if (m_systemTitleBarWidget && m_systemTitleBarWidget->isVisible()) {
|
||||
m_mainLayout->removeWidget(m_systemTitleBarWidget);
|
||||
m_systemTitleBarWidget->hide();
|
||||
}
|
||||
if (isMainWindow()) {
|
||||
m_userTitleBarWidget = widget;
|
||||
} else {
|
||||
if (m_userTitleBarWidget) {
|
||||
m_mainLayout->removeWidget(m_userTitleBarWidget);
|
||||
m_userTitleBarWidget = nullptr;
|
||||
}
|
||||
m_userTitleBarWidget = widget;
|
||||
m_mainLayout->insertWidget(0, m_userTitleBarWidget);
|
||||
} else {
|
||||
m_userTitleBarWidget = widget;
|
||||
}
|
||||
QMetaObject::invokeMethod(q, "titleBarWidgetChanged");
|
||||
}
|
||||
|
@ -109,7 +108,7 @@ void FramelessWidgetsHelper::setContentWidget(QWidget *widget)
|
|||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
if (isMainWindow()) {
|
||||
if (isCustomLayout()) {
|
||||
return;
|
||||
}
|
||||
if (m_userContentWidget == widget) {
|
||||
|
@ -126,9 +125,6 @@ void FramelessWidgetsHelper::setContentWidget(QWidget *widget)
|
|||
|
||||
QWidget *FramelessWidgetsHelper::contentWidget() const
|
||||
{
|
||||
if (isMainWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_userContentWidget;
|
||||
}
|
||||
|
||||
|
@ -149,33 +145,46 @@ void FramelessWidgetsHelper::setHitTestVisible(QWidget *widget, const bool visib
|
|||
|
||||
void FramelessWidgetsHelper::showEventHandler(QShowEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
setupFramelessHelperOnce();
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::changeEventHandler(QEvent *event)
|
||||
{
|
||||
bool shouldUpdate = false;
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
const QEvent::Type type = event->type();
|
||||
if ((type != QEvent::WindowStateChange) && (type != QEvent::ActivationChange)) {
|
||||
return;
|
||||
}
|
||||
if (type == QEvent::WindowStateChange) {
|
||||
if (isStandardLayout()) {
|
||||
if (isZoomed()) {
|
||||
m_systemMaximizeButton->setToolTip(tr("Restore"));
|
||||
} else {
|
||||
m_systemMaximizeButton->setToolTip(tr("Maximize"));
|
||||
}
|
||||
updateContentsMargins();
|
||||
updateSystemButtonsIcon();
|
||||
shouldUpdate = true;
|
||||
} else if (event->type() == QEvent::ActivationChange) {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
if (shouldUpdate) {
|
||||
updateContentsMargins();
|
||||
}
|
||||
if (isStandardLayout()) {
|
||||
updateSystemTitleBarStyleSheet();
|
||||
}
|
||||
q->update();
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::paintEventHandler(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (!shouldDrawFrameBorder()) {
|
||||
return;
|
||||
}
|
||||
|
@ -191,39 +200,63 @@ void FramelessWidgetsHelper::paintEventHandler(QPaintEvent *event)
|
|||
|
||||
void FramelessWidgetsHelper::mousePressEventHandler(QMouseEvent *event)
|
||||
{
|
||||
const Qt::MouseButton button = event->button();
|
||||
if ((button != Qt::LeftButton) && (button != Qt::RightButton)) {
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
if (!isInTitleBarDraggableArea(event->pos())) {
|
||||
return;
|
||||
}
|
||||
if (isInTitleBarDraggableArea(event->pos())) {
|
||||
if (button == Qt::LeftButton) {
|
||||
Utils::startSystemMove(q->windowHandle());
|
||||
} else {
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::RightButton) {
|
||||
return;
|
||||
}
|
||||
if (!isInTitleBarDraggableArea(event->pos())) {
|
||||
return;
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPointF globalPos = event->globalPosition();
|
||||
# else
|
||||
const QPointF globalPos = event->globalPos();
|
||||
# endif
|
||||
const QPointF pos = globalPos * q->devicePixelRatioF();
|
||||
Utils::showSystemMenu(q->winId(), pos);
|
||||
const QPointF nativePos = QPointF(globalPos * q->devicePixelRatioF());
|
||||
Utils::showSystemMenu(q->winId(), nativePos);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::mouseDoubleClickEventHandler(QMouseEvent *event)
|
||||
{
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
if (isInTitleBarDraggableArea(event->pos())) {
|
||||
m_systemMaximizeButton->click();
|
||||
if (!isInTitleBarDraggableArea(event->pos())) {
|
||||
return;
|
||||
}
|
||||
toggleMaximized();
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::initialize()
|
||||
{
|
||||
if (m_initialized) {
|
||||
return;
|
||||
}
|
||||
m_initialized = true;
|
||||
q->setAttribute(Qt::WA_DontCreateNativeAncestors);
|
||||
q->createWinId();
|
||||
setupInitialUi();
|
||||
|
@ -231,15 +264,18 @@ void FramelessWidgetsHelper::initialize()
|
|||
|
||||
void FramelessWidgetsHelper::setupFramelessHelperOnce()
|
||||
{
|
||||
if (m_framelessHelperInited) {
|
||||
if (m_framelessHelperSetup) {
|
||||
return;
|
||||
}
|
||||
m_framelessHelperInited = true;
|
||||
m_framelessHelperSetup = true;
|
||||
FramelessWindowsManager *manager = FramelessWindowsManager::instance();
|
||||
manager->addWindow(q->windowHandle());
|
||||
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this](){
|
||||
if (isStandardLayout()) {
|
||||
updateSystemTitleBarStyleSheet();
|
||||
updateSystemButtonsIcon();
|
||||
q->update();
|
||||
}
|
||||
QMetaObject::invokeMethod(q, "systemThemeChanged");
|
||||
});
|
||||
connect(manager, &FramelessWindowsManager::systemMenuRequested, this, [this](const QPointF &pos){
|
||||
|
@ -249,7 +285,7 @@ void FramelessWidgetsHelper::setupFramelessHelperOnce()
|
|||
|
||||
void FramelessWidgetsHelper::createSystemTitleBar()
|
||||
{
|
||||
if (isCustomWindow()) {
|
||||
if (isCustomLayout()) {
|
||||
return;
|
||||
}
|
||||
m_systemTitleBarWidget = new QWidget(q);
|
||||
|
@ -271,14 +307,7 @@ void FramelessWidgetsHelper::createSystemTitleBar()
|
|||
m_systemMaximizeButton->setFixedSize(kDefaultSystemButtonSize);
|
||||
m_systemMaximizeButton->setIconSize(kDefaultSystemButtonIconSize);
|
||||
m_systemMaximizeButton->setToolTip(tr("Maximize"));
|
||||
connect(m_systemMaximizeButton, &QPushButton::clicked, this, [this](){
|
||||
if (isZoomed()) {
|
||||
q->showNormal();
|
||||
} else {
|
||||
q->showMaximized();
|
||||
}
|
||||
updateSystemButtonsIcon();
|
||||
});
|
||||
connect(m_systemMaximizeButton, &QPushButton::clicked, this, &FramelessWidgetsHelper::toggleMaximized);
|
||||
m_systemCloseButton = new QPushButton(m_systemTitleBarWidget);
|
||||
m_systemCloseButton->setFixedSize(kDefaultSystemButtonSize);
|
||||
m_systemCloseButton->setIconSize(kDefaultSystemButtonIconSize);
|
||||
|
@ -299,7 +328,7 @@ void FramelessWidgetsHelper::createSystemTitleBar()
|
|||
|
||||
void FramelessWidgetsHelper::createUserContentContainer()
|
||||
{
|
||||
if (isCustomWindow() || isMainWindow()) {
|
||||
if (isCustomLayout()) {
|
||||
return;
|
||||
}
|
||||
m_userContentContainerWidget = new QWidget(q);
|
||||
|
@ -312,11 +341,8 @@ void FramelessWidgetsHelper::createUserContentContainer()
|
|||
|
||||
void FramelessWidgetsHelper::setupInitialUi()
|
||||
{
|
||||
if (isStandardWindow()) {
|
||||
if (isStandardLayout()) {
|
||||
createSystemTitleBar();
|
||||
if (isMainWindow()) {
|
||||
// ### TODO
|
||||
} else {
|
||||
createUserContentContainer();
|
||||
m_mainLayout = new QVBoxLayout(q);
|
||||
m_mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
@ -324,8 +350,8 @@ void FramelessWidgetsHelper::setupInitialUi()
|
|||
m_mainLayout->addWidget(m_systemTitleBarWidget);
|
||||
m_mainLayout->addWidget(m_userContentContainerWidget);
|
||||
q->setLayout(m_mainLayout);
|
||||
}
|
||||
updateSystemTitleBarStyleSheet();
|
||||
q->update();
|
||||
}
|
||||
updateContentsMargins();
|
||||
}
|
||||
|
@ -333,23 +359,30 @@ void FramelessWidgetsHelper::setupInitialUi()
|
|||
bool FramelessWidgetsHelper::isInTitleBarDraggableArea(const QPoint &pos) const
|
||||
{
|
||||
const QRegion draggableRegion = [this]() -> QRegion {
|
||||
const auto mapGeometryToScene = [this](const QWidget * const widget) -> QRect {
|
||||
Q_ASSERT(widget);
|
||||
if (!widget) {
|
||||
return {};
|
||||
}
|
||||
return QRect(widget->mapTo(q, QPoint(0, 0)), widget->size());
|
||||
};
|
||||
if (m_userTitleBarWidget) {
|
||||
QRegion region = {QRect(QPoint(0, 0), m_userTitleBarWidget->size())};
|
||||
QRegion region = mapGeometryToScene(m_userTitleBarWidget);
|
||||
if (!m_hitTestVisibleWidgets.isEmpty()) {
|
||||
for (auto &&widget : qAsConst(m_hitTestVisibleWidgets)) {
|
||||
Q_ASSERT(widget);
|
||||
if (widget) {
|
||||
region -= widget->geometry();
|
||||
region -= mapGeometryToScene(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
return region;
|
||||
}
|
||||
if (isStandardWindow()) {
|
||||
QRegion region = {QRect(QPoint(0, 0), m_systemTitleBarWidget->size())};
|
||||
region -= m_systemMinimizeButton->geometry();
|
||||
region -= m_systemMaximizeButton->geometry();
|
||||
region -= m_systemCloseButton->geometry();
|
||||
if (isStandardLayout()) {
|
||||
QRegion region = mapGeometryToScene(m_systemTitleBarWidget);
|
||||
region -= mapGeometryToScene(m_systemMinimizeButton);
|
||||
region -= mapGeometryToScene(m_systemMaximizeButton);
|
||||
region -= mapGeometryToScene(m_systemCloseButton);
|
||||
return region;
|
||||
}
|
||||
return {};
|
||||
|
@ -366,20 +399,12 @@ bool FramelessWidgetsHelper::shouldDrawFrameBorder() const
|
|||
#endif
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::isMainWindow() const
|
||||
{
|
||||
if (!q) {
|
||||
return false;
|
||||
}
|
||||
return q->inherits(QT_MAINWINDOW_CLASS_NAME);
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::isStandardWindow() const
|
||||
bool FramelessWidgetsHelper::isStandardLayout() const
|
||||
{
|
||||
return (m_windowLayout == WindowLayout::Standard);
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::isCustomWindow()
|
||||
bool FramelessWidgetsHelper::isCustomLayout() const
|
||||
{
|
||||
return (m_windowLayout == WindowLayout::Custom);
|
||||
}
|
||||
|
@ -393,7 +418,7 @@ void FramelessWidgetsHelper::updateContentsMargins()
|
|||
|
||||
void FramelessWidgetsHelper::updateSystemTitleBarStyleSheet()
|
||||
{
|
||||
if (isCustomWindow()) {
|
||||
if (isCustomLayout()) {
|
||||
return;
|
||||
}
|
||||
const bool active = q->isActiveWindow();
|
||||
|
@ -424,22 +449,31 @@ void FramelessWidgetsHelper::updateSystemTitleBarStyleSheet()
|
|||
m_systemMaximizeButton->setStyleSheet(kSystemButtonStyleSheet);
|
||||
m_systemCloseButton->setStyleSheet(kSystemButtonStyleSheet);
|
||||
m_systemTitleBarWidget->setStyleSheet(QStringLiteral("background-color: %1;").arg(systemTitleBarWidgetBackgroundColor.name()));
|
||||
q->update();
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::updateSystemButtonsIcon()
|
||||
{
|
||||
if (isCustomWindow()) {
|
||||
if (isCustomLayout()) {
|
||||
return;
|
||||
}
|
||||
const SystemTheme theme = ((Utils::shouldAppsUseDarkMode() || Utils::isTitleBarColorized()) ? SystemTheme::Dark : SystemTheme::Light);
|
||||
m_systemMinimizeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Minimize, theme, ResourceType::Icon)));
|
||||
const ResourceType resource = ResourceType::Icon;
|
||||
m_systemMinimizeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Minimize, theme, resource)));
|
||||
if (isZoomed()) {
|
||||
m_systemMaximizeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Restore, theme, ResourceType::Icon)));
|
||||
m_systemMaximizeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Restore, theme, resource)));
|
||||
} else {
|
||||
m_systemMaximizeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Maximize, theme, ResourceType::Icon)));
|
||||
m_systemMaximizeButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Maximize, theme, resource)));
|
||||
}
|
||||
m_systemCloseButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Close, theme, resource)));
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::toggleMaximized()
|
||||
{
|
||||
if (isZoomed()) {
|
||||
q->showNormal();
|
||||
} else {
|
||||
q->showMaximized();
|
||||
}
|
||||
m_systemCloseButton->setIcon(qvariant_cast<QIcon>(Utils::getSystemButtonIconResource(SystemButtonType::Close, theme, ResourceType::Icon)));
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -59,11 +59,14 @@ public:
|
|||
|
||||
Q_INVOKABLE void setHitTestVisible(QWidget *widget, const bool visible);
|
||||
|
||||
void showEventHandler(QShowEvent *event);
|
||||
void changeEventHandler(QEvent *event);
|
||||
void paintEventHandler(QPaintEvent *event);
|
||||
void mousePressEventHandler(QMouseEvent *event);
|
||||
void mouseDoubleClickEventHandler(QMouseEvent *event);
|
||||
Q_INVOKABLE void toggleMaximized();
|
||||
|
||||
Q_INVOKABLE void showEventHandler(QShowEvent *event);
|
||||
Q_INVOKABLE void changeEventHandler(QEvent *event);
|
||||
Q_INVOKABLE void paintEventHandler(QPaintEvent *event);
|
||||
Q_INVOKABLE void mousePressEventHandler(QMouseEvent *event);
|
||||
Q_INVOKABLE void mouseReleaseEventHandler(QMouseEvent *event);
|
||||
Q_INVOKABLE void mouseDoubleClickEventHandler(QMouseEvent *event);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
@ -73,9 +76,8 @@ private:
|
|||
void setupInitialUi();
|
||||
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
|
||||
Q_NODISCARD bool shouldDrawFrameBorder() const;
|
||||
Q_NODISCARD bool isMainWindow() const;
|
||||
Q_NODISCARD bool isStandardWindow() const;
|
||||
Q_NODISCARD bool isCustomWindow();
|
||||
Q_NODISCARD bool isStandardLayout() const;
|
||||
Q_NODISCARD bool isCustomLayout() const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateContentsMargins();
|
||||
|
@ -84,7 +86,8 @@ private Q_SLOTS:
|
|||
|
||||
private:
|
||||
QWidget *q = nullptr;
|
||||
bool m_framelessHelperInited = false;
|
||||
bool m_initialized = false;
|
||||
bool m_framelessHelperSetup = false;
|
||||
WindowLayout m_windowLayout = WindowLayout::Standard;
|
||||
QWidget *m_systemTitleBarWidget = nullptr;
|
||||
QLabel *m_systemWindowTitleLabel = nullptr;
|
||||
|
|
Loading…
Reference in New Issue