forked from github_mirror/framelesshelper
code tidies, prepare for the 2.1 release
Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
parent
cfb0842726
commit
1c6e02d81b
|
@ -25,8 +25,8 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(FramelessHelper
|
||||
VERSION 2.0.0.0
|
||||
DESCRIPTION "Window customization framework for Qt Widgets and Qt Quick."
|
||||
VERSION 2.1.0.0
|
||||
DESCRIPTION "Cross-platform window customization framework for Qt Widgets and Qt Quick."
|
||||
HOMEPAGE_URL "https://github.com/wangwenx190/framelesshelper/"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
@ -78,6 +78,8 @@ set(CMAKE_AUTOUIC ON)
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui)
|
||||
|
||||
|
|
50
README.md
50
README.md
|
@ -12,7 +12,7 @@
|
|||
- Windows: Added support for the snap layout feature introduced in Windows 11.
|
||||
- Widgets: Redesigned the public interface, the use of FramelessHelper is now more elegant.
|
||||
- Quick: Redesigned the public interface, the use of FramelessHelper is now more elegant.
|
||||
- Common: Redesigned the standard title bar interface, it's now possible to customize it from outside. Previously there's no standard title bar in the widgets module, now it's added and exported.
|
||||
- Common: Redesigned the standard title bar interface, it's now possible to customize it from outside. Previously there's no standard title bar in the widgets module, it's now added and exported.
|
||||
- Misc: Removed bundled Qt internal classes that are licensed under Commercial/GPL/LGPL. This library is now pure MIT licensed.
|
||||
- Bug fixes and internal refactorings.
|
||||
|
||||
|
@ -82,12 +82,48 @@ instantiate a new object if it can't find one. It's safe to call it multiple tim
|
|||
not matter where you call that function as long as the top level widget is the same. The internally created object will always be parented to the top level widget. Once you get
|
||||
the `FramelessWidgetsHelper` object, you should call `void FramelessWidgetsHelper::attach()` to let it attach to the top level widget. The window frame
|
||||
will be removed automatically once it has attached to the top level widget successfully. In order to make sure `FramelessWidgetsHelper` can find the correct top level widget,
|
||||
you should call the `get` function on a widget which has a complete parent-chain. After these two steps, the window frame should be removed now. However, it can't be moved by
|
||||
dragging because it doesn't have a title bar now. You should set a title bar widget to make the window be movable, the title bar doesn't need to be a rectangle, it also doesn't need to be on the top of the window. Call `void FramelessWidgetsHelper::setTitleBarWidget(QWidget *)` to do that. By default, all the widgets in the title bar area won't be responsible due to the mouse events are intercepted by FramelessHelper. To make them still work normally, you should make them visible to hit test. Call `void FramelessWidgetsHelper::setHitTestVisible(QWidget* )` to do that. You can of course call it on a widget that is not inside the title bar at all, but it won't have any effect. Due to Qt's own limitations, you need to make sure your widget has a complete parent-chain which the root parent is the top level widget.
|
||||
you should call the `FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *)` function on a widget which has a complete parent-chain. After these two steps, the window frame should be removed now. However, it can't be moved by
|
||||
dragging because it doesn't have a title bar now. You should set a title bar widget to make the window be movable, the title bar doesn't need to be a rectangle, it also doesn't need to be on the top of the window. Call `void FramelessWidgetsHelper::setTitleBarWidget(QWidget *)` to do that. By default, all the widgets in the title bar area won't be responsible due to the mouse events are intercepted by FramelessHelper. To make them still work normally, you should make them visible to hit test. Call `void FramelessWidgetsHelper::setHitTestVisible(QWidget* )` to do that. You can of course call it on a widget that is not inside the title bar at all, but it won't have any effect. Due to Qt's own limitations, you need to make sure your widget has a complete parent-chain which the root parent is the top level widget. Do not ever try to delete the `FramelessWidgetsHelper` instance, it may still monitoring and controlling your widget, and Qt will delete it for you automatically.
|
||||
|
||||
There are also two classes called `FramelessWidget` and `FramelessMainWindow`, they are only simple wrappers of `FramelessWidgetsHelper`, which just saves the call of the `void FramelessWidgetsHelper::attach()` function for you. You can absolutely use plain `QWidget` instead.
|
||||
|
||||
### Qt Quick
|
||||
|
||||
TODO
|
||||
First of all, you should import FramelessHelper from the URI `org.wangwenx190.FramelessHelper`. You should specify a version just behind it if you are using Qt5:
|
||||
|
||||
```qml
|
||||
import org.wangwenx190.FramelessHelper 1.0 // You can omit the version number in Qt6.
|
||||
```
|
||||
|
||||
And then you can use the attached properties from the QML type `FramelessHelper`:
|
||||
|
||||
```qml
|
||||
Window {
|
||||
Item {
|
||||
id: myTitleBar
|
||||
// Don't access FramelessHelper too early! Make sure when you use it,
|
||||
// the root window has been initialized!
|
||||
Component.onCompleted: FramelessHelper.titleBarItem = myTitleBar
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
It's the same with the `FramelessWidgetsHelper`, the QML type `FramelessHelper` will be instantiated only once for each `Window`, no matter when and where you use attached properties from it. However, due to the special design of the `FramelessHelper` type, you can also use it just like a normal QML type:
|
||||
|
||||
```qml
|
||||
Window {
|
||||
Item {
|
||||
id: myTitleBar
|
||||
}
|
||||
FramelessHelper {
|
||||
titleBarItem: myTitleBar
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In theory it's possible to instantiate multiple `FramelessHelper` instances for the same `Window`, in this case only one of them will keep functional, all other instances will become a simple wrapper of it, but doing so is not recommended and may cause unexpected behavior or bugs, so please avoid trying to do that in any case.
|
||||
|
||||
There's also a QML type called `FramelessWindow`, it's only a simple wrapper of `FramelessHelper`, you can absolutely use plain `Window` instead.
|
||||
|
||||
Please refer to the demo applications to see more detailed usages: [examples](./examples/)
|
||||
|
||||
|
@ -104,11 +140,11 @@ Please refer to the demo applications to see more detailed usages: [examples](./
|
|||
- Force your application use pure software rendering instead of rendering through OpenGL.
|
||||
- Or just don't use OpenGL at all, try to use Direct3D/Vulkan/Metal instead.
|
||||
- Due to there are many sub-versions of Windows 10, it's highly recommended to use the latest version of Windows 10, at least no older than Windows 10 1809. If you try to use this framework on some very old Windows 10 versions such as 1507 or 1607, there may be some compatibility issues. Using this framework on Windows 7 is also supported but not recommended. To get the most stable behavior and the best appearance, you should use it on the latest version of Windows 10 or Windows 11.
|
||||
- To make the snap layout work as expected, there are some additional requirements for your homemade system buttons to follow:
|
||||
- Make sure there are two public invokable functions (slot functions are always invokable): `void setHovered(bool)` and `void setPressed(bool)`. These two functions will be invoked by FramelessHelper when the button is being hovered or pressed. You should change the button's visual state inside these functions.
|
||||
- To make the snap layout work as expected, there are some additional rules for your homemade system buttons to follow:
|
||||
- Make sure there are two public invokable functions (slot functions are always invokable): `void setHovered(bool)` and `void setPressed(bool)`. These two functions will be invoked by FramelessHelper when the button is being hovered or pressed. You should change the button's visual state inside these functions. If you need to show tooltips, you'll have to do it manually in these functions.
|
||||
- Make sure there's a public signal: `void clicked()`. When the button is being clicked, that signal will be triggered by FramelessHelper. You should connect your event handler to that signal.
|
||||
- Don't forget to call `setSystemButton()` for each button to let FramelessHelper know which is the minimize/maximize/close button.
|
||||
- System buttons will not be able to receive any actual mouse events so there's no need to handle any mouse events inside these buttons. That's also why we need to set the button's visual state manually.
|
||||
- System buttons will not be able to receive any actual mouse and keyboard events so there's no need to handle these events inside these buttons. That's also why we need to set the button's visual state manually.
|
||||
- I know this is making everything complicated but unfortunately we can't avoid this mess if we need to support the snap layout feature. Snap layout is really only designed for the original standard window frame, so if we want to forcely support it without a standard window frame, many black magic will be needed.
|
||||
|
||||
### Linux
|
||||
|
|
|
@ -56,12 +56,11 @@ FramelessWindow {
|
|||
StandardTitleBar {
|
||||
id: titleBar
|
||||
anchors {
|
||||
top: window.topBorderBottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
Component.onCompleted: {
|
||||
// Make our homemade title bar snap to the window top frame border.
|
||||
window.snapToTopBorder(titleBar, FramelessHelperConstants.Top, FramelessHelperConstants.Bottom);
|
||||
// Make our homemade title bar draggable, and open the system menu
|
||||
// when the user right clicks on the title bar area.
|
||||
FramelessHelper.titleBarItem = titleBar;
|
||||
|
|
|
@ -45,12 +45,15 @@ public:
|
|||
explicit FramelessQuickHelper(QQuickItem *parent = nullptr);
|
||||
~FramelessQuickHelper() override;
|
||||
|
||||
Q_NODISCARD static FramelessQuickHelper *get(QObject *object);
|
||||
Q_NODISCARD static FramelessQuickHelper *qmlAttachedProperties(QObject *parentObject);
|
||||
|
||||
Q_NODISCARD QQuickItem *titleBarItem() const;
|
||||
Q_NODISCARD bool isWindowFixedSize() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void attach();
|
||||
|
||||
void setTitleBarItem(QQuickItem *value);
|
||||
void setSystemButton(QQuickItem *item, const QuickGlobal::SystemButtonType buttonType);
|
||||
void setHitTestVisible(QQuickItem *item);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelperquick_global.h"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
@ -44,6 +45,7 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow
|
|||
Q_PROPERTY(bool minimized READ isMinimized NOTIFY minimizedChanged FINAL)
|
||||
Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL)
|
||||
Q_PROPERTY(bool fullScreen READ isFullScreen NOTIFY fullScreenChanged FINAL)
|
||||
Q_PRIVATE_PROPERTY(FramelessQuickWindow::d_func(), QQuickAnchorLine topBorderBottom READ getTopBorderBottom CONSTANT FINAL)
|
||||
|
||||
public:
|
||||
explicit FramelessQuickWindow(QWindow *parent = nullptr);
|
||||
|
@ -59,7 +61,6 @@ public Q_SLOTS:
|
|||
void showMinimized2();
|
||||
void toggleMaximized();
|
||||
void toggleFullScreen();
|
||||
void snapToTopBorder(QQuickItem *item, const QuickGlobal::Anchor itemAnchor, const QuickGlobal::Anchor topBorderAnchor);
|
||||
|
||||
Q_SIGNALS:
|
||||
void hiddenChanged();
|
||||
|
@ -75,3 +76,6 @@ private:
|
|||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
QML_DECLARE_TYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindow))
|
||||
|
||||
Q_MOC_INCLUDE("framelessquickwindow_p.h")
|
||||
#endif
|
||||
|
|
|
@ -29,11 +29,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class WidgetsSharedHelper;
|
||||
class FramelessMainWindowPrivate;
|
||||
|
||||
class FRAMELESSHELPER_WIDGETS_API FramelessMainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_PRIVATE(FramelessMainWindow)
|
||||
Q_DISABLE_COPY_MOVE(FramelessMainWindow)
|
||||
Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL)
|
||||
Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL)
|
||||
|
@ -56,8 +57,7 @@ Q_SIGNALS:
|
|||
void zoomedChanged();
|
||||
|
||||
private:
|
||||
QScopedPointer<WidgetsSharedHelper> m_helper;
|
||||
Qt::WindowState m_savedWindowState = Qt::WindowNoState;
|
||||
QScopedPointer<FramelessMainWindowPrivate> d_ptr;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -29,11 +29,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class WidgetsSharedHelper;
|
||||
class FramelessWidgetPrivate;
|
||||
|
||||
class FRAMELESSHELPER_WIDGETS_API FramelessWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_PRIVATE(FramelessWidget)
|
||||
Q_DISABLE_COPY_MOVE(FramelessWidget)
|
||||
Q_PROPERTY(bool hidden READ isHidden NOTIFY hiddenChanged FINAL)
|
||||
Q_PROPERTY(bool normal READ isNormal NOTIFY normalChanged FINAL)
|
||||
|
@ -56,8 +57,7 @@ Q_SIGNALS:
|
|||
void zoomedChanged();
|
||||
|
||||
private:
|
||||
QScopedPointer<WidgetsSharedHelper> m_helper;
|
||||
Qt::WindowState m_savedWindowState = Qt::WindowNoState;
|
||||
QScopedPointer<FramelessWidgetPrivate> d_ptr;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -364,7 +364,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
qWarning() << Utils::getSystemErrorMessage(kGetModuleHandleW);
|
||||
return false;
|
||||
}
|
||||
static const QString dragBarWindowClassName = QUuid::createUuid().toString();
|
||||
static const QString dragBarWindowClassName = QUuid::createUuid().toString().toUpper();
|
||||
Q_ASSERT(!dragBarWindowClassName.isEmpty());
|
||||
if (dragBarWindowClassName.isEmpty()) {
|
||||
qWarning() << "Failed to generate a new UUID.";
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,0,0,0
|
||||
PRODUCTVERSION 2,0,0,0
|
||||
PRODUCTVERSION 2,1,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
|
@ -51,7 +51,7 @@ BEGIN
|
|||
VALUE "OriginalFilename", "FramelessHelperCore.dll"
|
||||
#endif
|
||||
VALUE "ProductName", "FramelessHelper"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
VALUE "ProductVersion", "2.1.0.0"
|
||||
VALUE "InternalName", "FramelessHelperCore"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,0,0,0
|
||||
PRODUCTVERSION 2,0,0,0
|
||||
PRODUCTVERSION 2,1,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
|
@ -42,7 +42,7 @@ BEGIN
|
|||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "wangwenx190"
|
||||
VALUE "FileDescription", "FramelessHelper QtQuick Module"
|
||||
VALUE "FileDescription", "FramelessHelper Quick Module"
|
||||
VALUE "FileVersion", "0.0.0.0"
|
||||
VALUE "LegalCopyright", "MIT License"
|
||||
#ifdef _DEBUG
|
||||
|
@ -51,7 +51,7 @@ BEGIN
|
|||
VALUE "OriginalFilename", "FramelessHelperQuick.dll"
|
||||
#endif
|
||||
VALUE "ProductName", "FramelessHelper"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
VALUE "ProductVersion", "2.1.0.0"
|
||||
VALUE "InternalName", "FramelessHelperQuick"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -60,8 +60,43 @@ struct QuickHelper
|
|||
|
||||
Q_GLOBAL_STATIC(QuickHelper, g_quickHelper)
|
||||
|
||||
static constexpr const char QTQUICK_ITEM_CLASS_NAME[] = "QQuickItem";
|
||||
static constexpr const char QTQUICK_BUTTON_CLASS_NAME[] = "QQuickAbstractButton";
|
||||
|
||||
[[nodiscard]] static inline bool isItem(const QObject * const object)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
|
||||
return object->isQuickItemType();
|
||||
#else
|
||||
if (object->inherits(QTQUICK_ITEM_CLASS_NAME)) {
|
||||
return true;
|
||||
}
|
||||
if (const auto mo = object->metaObject()) {
|
||||
return (qstrcmp(mo->className(), QTQUICK_ITEM_CLASS_NAME) == 0);
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline bool isButton(const QObject * const object)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
if (object->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
|
||||
return true;
|
||||
}
|
||||
if (const auto mo = object->metaObject()) {
|
||||
return (qstrcmp(mo->className(), QTQUICK_BUTTON_CLASS_NAME) == 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FramelessQuickHelperPrivate::FramelessQuickHelperPrivate(FramelessQuickHelper *q) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
|
@ -104,6 +139,9 @@ void FramelessQuickHelperPrivate::setTitleBarItem(QQuickItem *value)
|
|||
}
|
||||
QMutexLocker locker(&g_quickHelper()->mutex);
|
||||
QuickHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
if (data->titleBarItem == value) {
|
||||
return;
|
||||
}
|
||||
|
@ -123,6 +161,10 @@ void FramelessQuickHelperPrivate::attachToWindow()
|
|||
|
||||
g_quickHelper()->mutex.lock();
|
||||
QuickHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
g_quickHelper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
const bool attached = data->attached;
|
||||
g_quickHelper()->mutex.unlock();
|
||||
|
||||
|
@ -178,6 +220,9 @@ void FramelessQuickHelperPrivate::setSystemButton(QQuickItem *item, const QuickG
|
|||
}
|
||||
QMutexLocker locker(&g_quickHelper()->mutex);
|
||||
QuickHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
switch (buttonType) {
|
||||
case QuickGlobal::SystemButtonType::Unknown:
|
||||
Q_ASSERT(false);
|
||||
|
@ -209,6 +254,9 @@ void FramelessQuickHelperPrivate::setHitTestVisible(QQuickItem *item)
|
|||
}
|
||||
QMutexLocker locker(&g_quickHelper()->mutex);
|
||||
QuickHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
static constexpr const bool visible = true;
|
||||
const bool exists = data->hitTestVisibleItems.contains(item);
|
||||
if (visible && !exists) {
|
||||
|
@ -448,28 +496,28 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System
|
|||
Q_ASSERT(false);
|
||||
} break;
|
||||
case QuickGlobal::SystemButtonType::WindowIcon: {
|
||||
if (data.windowIconButton && data.windowIconButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
|
||||
if (data.windowIconButton && isButton(data.windowIconButton)) {
|
||||
quickButton = qobject_cast<QQuickAbstractButton *>(data.windowIconButton);
|
||||
}
|
||||
} break;
|
||||
case QuickGlobal::SystemButtonType::Help: {
|
||||
if (data.contextHelpButton && data.contextHelpButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
|
||||
if (data.contextHelpButton && isButton(data.contextHelpButton)) {
|
||||
quickButton = qobject_cast<QQuickAbstractButton *>(data.contextHelpButton);
|
||||
}
|
||||
} break;
|
||||
case QuickGlobal::SystemButtonType::Minimize: {
|
||||
if (data.minimizeButton && data.minimizeButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
|
||||
if (data.minimizeButton && isButton(data.minimizeButton)) {
|
||||
quickButton = qobject_cast<QQuickAbstractButton *>(data.minimizeButton);
|
||||
}
|
||||
} break;
|
||||
case QuickGlobal::SystemButtonType::Maximize:
|
||||
case QuickGlobal::SystemButtonType::Restore: {
|
||||
if (data.maximizeButton && data.maximizeButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
|
||||
if (data.maximizeButton && isButton(data.maximizeButton)) {
|
||||
quickButton = qobject_cast<QQuickAbstractButton *>(data.maximizeButton);
|
||||
}
|
||||
} break;
|
||||
case QuickGlobal::SystemButtonType::Close: {
|
||||
if (data.closeButton && data.closeButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
|
||||
if (data.closeButton && isButton(data.closeButton)) {
|
||||
quickButton = qobject_cast<QQuickAbstractButton *>(data.closeButton);
|
||||
}
|
||||
} break;
|
||||
|
@ -512,7 +560,7 @@ QuickHelperData FramelessQuickHelperPrivate::getWindowData() const
|
|||
{
|
||||
Q_Q(const FramelessQuickHelper);
|
||||
const QQuickWindow * const window = q->window();
|
||||
Q_ASSERT(window);
|
||||
//Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return {};
|
||||
}
|
||||
|
@ -528,7 +576,7 @@ QuickHelperData *FramelessQuickHelperPrivate::getWindowDataMutable() const
|
|||
{
|
||||
Q_Q(const FramelessQuickHelper);
|
||||
const QQuickWindow * const window = q->window();
|
||||
Q_ASSERT(window);
|
||||
//Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -546,20 +594,41 @@ FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent)
|
|||
|
||||
FramelessQuickHelper::~FramelessQuickHelper() = default;
|
||||
|
||||
FramelessQuickHelper *FramelessQuickHelper::get(QObject *object)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
if (!object) {
|
||||
return nullptr;
|
||||
}
|
||||
FramelessQuickHelper *instance = nullptr;
|
||||
QObject *parent = nullptr;
|
||||
if (isItem(object)) {
|
||||
const auto item = qobject_cast<QQuickItem *>(object);
|
||||
parent = (item->window() ? item->window()->contentItem() : item);
|
||||
} else {
|
||||
parent = object;
|
||||
}
|
||||
instance = parent->findChild<FramelessQuickHelper *>();
|
||||
if (!instance) {
|
||||
instance = new FramelessQuickHelper;
|
||||
if (isItem(parent)) {
|
||||
instance->setParentItem(qobject_cast<QQuickItem *>(parent));
|
||||
} else {
|
||||
instance->setParent(parent);
|
||||
}
|
||||
// No need to do this here, we'll do it once the item has been assigned to a specific window.
|
||||
//instance->d_func()->attachToWindow();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
FramelessQuickHelper *FramelessQuickHelper::qmlAttachedProperties(QObject *parentObject)
|
||||
{
|
||||
Q_ASSERT(parentObject);
|
||||
if (!parentObject) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto instance = new FramelessQuickHelper;
|
||||
const auto parentItem = qobject_cast<QQuickItem *>(parentObject);
|
||||
if (parentItem) {
|
||||
instance->setParentItem(parentItem);
|
||||
} else {
|
||||
instance->setParent(parentObject);
|
||||
}
|
||||
return instance;
|
||||
return get(parentObject);
|
||||
}
|
||||
|
||||
QQuickItem *FramelessQuickHelper::titleBarItem() const
|
||||
|
@ -574,6 +643,12 @@ bool FramelessQuickHelper::isWindowFixedSize() const
|
|||
return d->isWindowFixedSize();
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::attach()
|
||||
{
|
||||
// Intentionally not doing anything here, we'll attach to window
|
||||
// automatically when this class is instantiated.
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::setTitleBarItem(QQuickItem *value)
|
||||
{
|
||||
Q_ASSERT(value);
|
||||
|
@ -648,6 +723,9 @@ void FramelessQuickHelper::itemChange(const ItemChange change, const ItemChangeD
|
|||
{
|
||||
QQuickItem::itemChange(change, value);
|
||||
if ((change == ItemSceneChange) && value.window) {
|
||||
if (parentItem() != value.window->contentItem()) {
|
||||
setParentItem(value.window->contentItem());
|
||||
}
|
||||
Q_D(FramelessQuickHelper);
|
||||
d->attachToWindow();
|
||||
}
|
||||
|
|
|
@ -25,12 +25,14 @@
|
|||
#include "framelessquickmodule.h"
|
||||
#include "framelessquickhelper.h"
|
||||
#include "framelessquickutils.h"
|
||||
#include "framelessquickwindow.h"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
# include "quickstandardminimizebutton_p.h"
|
||||
# include "quickstandardmaximizebutton_p.h"
|
||||
# include "quickstandardclosebutton_p.h"
|
||||
# include "quickstandardtitlebar_p.h"
|
||||
# include "framelessquickwindow.h"
|
||||
#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
# include <QtQuick/qquickwindow.h>
|
||||
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
|
||||
#ifndef QUICK_URI_SHORT
|
||||
|
@ -53,11 +55,6 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
|||
if (!engine) {
|
||||
return;
|
||||
}
|
||||
static bool inited = false;
|
||||
if (inited) {
|
||||
return;
|
||||
}
|
||||
inited = true;
|
||||
qRegisterMetaType<QuickGlobal::SystemTheme>();
|
||||
qRegisterMetaType<QuickGlobal::SystemButtonType>();
|
||||
qRegisterMetaType<QuickGlobal::ResourceType>();
|
||||
|
@ -72,16 +69,15 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
|||
Q_UNUSED(scriptEngine);
|
||||
return new FramelessQuickUtils;
|
||||
});
|
||||
qmlRegisterRevision<QWindow, 254>(QUICK_URI_FULL);
|
||||
qmlRegisterRevision<QQuickWindow, 254>(QUICK_URI_FULL);
|
||||
qmlRegisterRevision<QQuickItem, 254>(QUICK_URI_FULL);
|
||||
qmlRegisterType<FramelessQuickHelper>(QUICK_URI_EXPAND("FramelessHelper"));
|
||||
qmlRegisterType<FramelessQuickWindow>(QUICK_URI_EXPAND("FramelessWindow"));
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
qmlRegisterType<QuickStandardMinimizeButton>(QUICK_URI_EXPAND("StandardMinimizeButton"));
|
||||
qmlRegisterType<QuickStandardMaximizeButton>(QUICK_URI_EXPAND("StandardMaximizeButton"));
|
||||
qmlRegisterType<QuickStandardCloseButton>(QUICK_URI_EXPAND("StandardCloseButton"));
|
||||
qmlRegisterType<QuickStandardTitleBar>(QUICK_URI_EXPAND("StandardTitleBar"));
|
||||
qmlRegisterType<FramelessQuickWindow>(QUICK_URI_EXPAND("FramelessWindow"));
|
||||
#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
qmlRegisterTypeNotAvailable(QUICK_URI_EXPAND("StandardMinimizeButton"),
|
||||
FRAMELESSHELPER_STRING_LITERAL("StandardMinimizeButton is not available until Qt6."));
|
||||
|
@ -91,6 +87,8 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
|||
FRAMELESSHELPER_STRING_LITERAL("StandardCloseButton is not available until Qt6."));
|
||||
qmlRegisterTypeNotAvailable(QUICK_URI_EXPAND("StandardTitleBar"),
|
||||
FRAMELESSHELPER_STRING_LITERAL("StandardTitleBar is not available until Qt6."));
|
||||
qmlRegisterTypeNotAvailable(QUICK_URI_EXPAND("FramelessWindow"),
|
||||
FRAMELESSHELPER_STRING_LITERAL("FramelessWindow is not available until Qt6."));
|
||||
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
qmlRegisterModule(QUICK_URI_FULL);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
*/
|
||||
|
||||
#include "framelessquickwindow.h"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
#include "framelessquickwindow_p.h"
|
||||
#include "framelessquickhelper.h"
|
||||
#include <QtQuick/private/qquickitem_p.h>
|
||||
#include <QtQuick/private/qquickrectangle_p.h>
|
||||
#include <QtQuick/private/qquickanchors_p.h>
|
||||
|
@ -106,88 +108,11 @@ QColor FramelessQuickWindowPrivate::getFrameBorderColor() const
|
|||
#endif
|
||||
}
|
||||
|
||||
QQuickAnchorLine FramelessQuickWindowPrivate::getTopBorderTop() const
|
||||
{
|
||||
return QQuickAnchorLine(m_topBorderRectangle.data(), QQuickAnchors::TopAnchor);
|
||||
}
|
||||
|
||||
QQuickAnchorLine FramelessQuickWindowPrivate::getTopBorderBottom() const
|
||||
{
|
||||
return QQuickAnchorLine(m_topBorderRectangle.data(), QQuickAnchors::BottomAnchor);
|
||||
}
|
||||
|
||||
QQuickAnchorLine FramelessQuickWindowPrivate::getTopBorderLeft() const
|
||||
{
|
||||
return QQuickAnchorLine(m_topBorderRectangle.data(), QQuickAnchors::LeftAnchor);
|
||||
}
|
||||
|
||||
QQuickAnchorLine FramelessQuickWindowPrivate::getTopBorderRight() const
|
||||
{
|
||||
return QQuickAnchorLine(m_topBorderRectangle.data(), QQuickAnchors::RightAnchor);
|
||||
}
|
||||
|
||||
QQuickAnchorLine FramelessQuickWindowPrivate::getTopBorderHorizontalCenter() const
|
||||
{
|
||||
return QQuickAnchorLine(m_topBorderRectangle.data(), QQuickAnchors::HCenterAnchor);
|
||||
}
|
||||
|
||||
QQuickAnchorLine FramelessQuickWindowPrivate::getTopBorderVerticalCenter() const
|
||||
{
|
||||
return QQuickAnchorLine(m_topBorderRectangle.data(), QQuickAnchors::VCenterAnchor);
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::snapToTopBorder(QQuickItem *item, const QuickGlobal::Anchor itemAnchor, const QuickGlobal::Anchor topBorderAnchor)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const QQuickAnchorLine targetAnchorLine = [this, topBorderAnchor]() -> QQuickAnchorLine {
|
||||
switch (topBorderAnchor) {
|
||||
case QuickGlobal::Anchor::Top:
|
||||
return getTopBorderTop();
|
||||
case QuickGlobal::Anchor::Bottom:
|
||||
return getTopBorderBottom();
|
||||
case QuickGlobal::Anchor::Left:
|
||||
return getTopBorderLeft();
|
||||
case QuickGlobal::Anchor::Right:
|
||||
return getTopBorderRight();
|
||||
case QuickGlobal::Anchor::HorizontalCenter:
|
||||
return getTopBorderHorizontalCenter();
|
||||
case QuickGlobal::Anchor::VerticalCenter:
|
||||
return getTopBorderVerticalCenter();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}();
|
||||
const QQuickItemPrivate * const itemPrivate = QQuickItemPrivate::get(item);
|
||||
QQuickAnchors * const anchors = itemPrivate->anchors();
|
||||
switch (itemAnchor) {
|
||||
case QuickGlobal::Anchor::Top:
|
||||
anchors->setTop(targetAnchorLine);
|
||||
break;
|
||||
case QuickGlobal::Anchor::Bottom:
|
||||
anchors->setBottom(targetAnchorLine);
|
||||
break;
|
||||
case QuickGlobal::Anchor::Left:
|
||||
anchors->setLeft(targetAnchorLine);
|
||||
break;
|
||||
case QuickGlobal::Anchor::Right:
|
||||
anchors->setRight(targetAnchorLine);
|
||||
break;
|
||||
case QuickGlobal::Anchor::HorizontalCenter:
|
||||
anchors->setHorizontalCenter(targetAnchorLine);
|
||||
break;
|
||||
case QuickGlobal::Anchor::VerticalCenter:
|
||||
anchors->setVerticalCenter(targetAnchorLine);
|
||||
break;
|
||||
case QuickGlobal::Anchor::Center:
|
||||
anchors->setCenterIn(m_topBorderRectangle.data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessQuickWindowPrivate::showMinimized2()
|
||||
{
|
||||
Q_Q(FramelessQuickWindow);
|
||||
|
@ -227,7 +152,7 @@ void FramelessQuickWindowPrivate::initialize()
|
|||
{
|
||||
Q_Q(FramelessQuickWindow);
|
||||
QQuickItem * const rootItem = q->contentItem();
|
||||
const QQuickItemPrivate * const rootItemPrivate = QQuickItemPrivate::get(rootItem);
|
||||
FramelessQuickHelper::get(rootItem)->attach();
|
||||
m_topBorderRectangle.reset(new QQuickRectangle(rootItem));
|
||||
m_topBorderRectangle->setColor(kDefaultTransparentColor);
|
||||
m_topBorderRectangle->setHeight(0.0);
|
||||
|
@ -237,6 +162,7 @@ void FramelessQuickWindowPrivate::initialize()
|
|||
updateTopBorderHeight();
|
||||
updateTopBorderColor();
|
||||
m_topBorderAnchors.reset(new QQuickAnchors(m_topBorderRectangle.data(), m_topBorderRectangle.data()));
|
||||
const QQuickItemPrivate * const rootItemPrivate = QQuickItemPrivate::get(rootItem);
|
||||
m_topBorderAnchors->setTop(rootItemPrivate->top());
|
||||
m_topBorderAnchors->setLeft(rootItemPrivate->left());
|
||||
m_topBorderAnchors->setRight(rootItemPrivate->right());
|
||||
|
@ -319,16 +245,6 @@ bool FramelessQuickWindow::isFullScreen() const
|
|||
return d->isFullScreen();
|
||||
}
|
||||
|
||||
void FramelessQuickWindow::snapToTopBorder(QQuickItem *item, const QuickGlobal::Anchor itemAnchor, const QuickGlobal::Anchor topBorderAnchor)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
Q_D(FramelessQuickWindow);
|
||||
d->snapToTopBorder(item, itemAnchor, topBorderAnchor);
|
||||
}
|
||||
|
||||
void FramelessQuickWindow::showMinimized2()
|
||||
{
|
||||
Q_D(FramelessQuickWindow);
|
||||
|
@ -348,3 +264,4 @@ void FramelessQuickWindow::toggleFullScreen()
|
|||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelperquick_global.h"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <QtQuick/private/qquickanchors_p_p.h>
|
||||
|
@ -57,18 +58,12 @@ public:
|
|||
Q_INVOKABLE Q_NODISCARD bool isFullScreen() const;
|
||||
|
||||
Q_INVOKABLE Q_NODISCARD QColor getFrameBorderColor() const;
|
||||
Q_INVOKABLE Q_NODISCARD QQuickAnchorLine getTopBorderTop() const;
|
||||
Q_INVOKABLE Q_NODISCARD QQuickAnchorLine getTopBorderBottom() const;
|
||||
Q_INVOKABLE Q_NODISCARD QQuickAnchorLine getTopBorderLeft() const;
|
||||
Q_INVOKABLE Q_NODISCARD QQuickAnchorLine getTopBorderRight() const;
|
||||
Q_INVOKABLE Q_NODISCARD QQuickAnchorLine getTopBorderHorizontalCenter() const;
|
||||
Q_INVOKABLE Q_NODISCARD QQuickAnchorLine getTopBorderVerticalCenter() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void showMinimized2();
|
||||
void toggleMaximized();
|
||||
void toggleFullScreen();
|
||||
void snapToTopBorder(QQuickItem *item, const QuickGlobal::Anchor itemAnchor, const QuickGlobal::Anchor topBorderAnchor);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
@ -86,3 +81,4 @@ private:
|
|||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
#endif
|
||||
|
|
|
@ -36,6 +36,8 @@ set(SOURCES
|
|||
framelesswidgetshelper_p.h
|
||||
standardsystembutton_p.h
|
||||
standardtitlebar_p.h
|
||||
framelesswidget_p.h
|
||||
framelessmainwindow_p.h
|
||||
framelessmainwindow.cpp
|
||||
framelesswidgetshelper.cpp
|
||||
framelesswidget.cpp
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,0,0,0
|
||||
PRODUCTVERSION 2,0,0,0
|
||||
PRODUCTVERSION 2,1,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
|
@ -42,7 +42,7 @@ BEGIN
|
|||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "wangwenx190"
|
||||
VALUE "FileDescription", "FramelessHelper QtWidgets Module"
|
||||
VALUE "FileDescription", "FramelessHelper Widgets Module"
|
||||
VALUE "FileVersion", "0.0.0.0"
|
||||
VALUE "LegalCopyright", "MIT License"
|
||||
#ifdef _DEBUG
|
||||
|
@ -51,7 +51,7 @@ BEGIN
|
|||
VALUE "OriginalFilename", "FramelessHelperWidgets.dll"
|
||||
#endif
|
||||
VALUE "ProductName", "FramelessHelper"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
VALUE "ProductVersion", "2.1.0.0"
|
||||
VALUE "InternalName", "FramelessHelperWidgets"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "framelessmainwindow.h"
|
||||
#include "framelessmainwindow_p.h"
|
||||
#include "framelesswidgetshelper.h"
|
||||
#include "widgetssharedhelper_p.h"
|
||||
#include <utils.h>
|
||||
|
@ -31,42 +32,106 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
FramelessMainWindow::FramelessMainWindow(QWidget *parent, const Qt::WindowFlags flags) : QMainWindow(parent, flags)
|
||||
FramelessMainWindowPrivate::FramelessMainWindowPrivate(FramelessMainWindow *q) : QObject(q)
|
||||
{
|
||||
FramelessWidgetsHelper::get(this)->attach();
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
q_ptr = q;
|
||||
initialize();
|
||||
}
|
||||
|
||||
FramelessMainWindowPrivate::~FramelessMainWindowPrivate() = default;
|
||||
|
||||
FramelessMainWindowPrivate *FramelessMainWindowPrivate::get(FramelessMainWindow *pub)
|
||||
{
|
||||
Q_ASSERT(pub);
|
||||
if (!pub) {
|
||||
return nullptr;
|
||||
}
|
||||
return pub->d_func();
|
||||
}
|
||||
|
||||
const FramelessMainWindowPrivate *FramelessMainWindowPrivate::get(const FramelessMainWindow *pub)
|
||||
{
|
||||
Q_ASSERT(pub);
|
||||
if (!pub) {
|
||||
return nullptr;
|
||||
}
|
||||
return pub->d_func();
|
||||
}
|
||||
|
||||
void FramelessMainWindowPrivate::initialize()
|
||||
{
|
||||
Q_Q(FramelessMainWindow);
|
||||
FramelessWidgetsHelper::get(q)->attach();
|
||||
m_helper.reset(new WidgetsSharedHelper(this));
|
||||
m_helper->setup(this);
|
||||
m_helper->setup(q);
|
||||
}
|
||||
|
||||
bool FramelessMainWindowPrivate::isNormal() const
|
||||
{
|
||||
Q_Q(const FramelessMainWindow);
|
||||
return (Utils::windowStatesToWindowState(q->windowState()) == Qt::WindowNoState);
|
||||
}
|
||||
|
||||
bool FramelessMainWindowPrivate::isZoomed() const
|
||||
{
|
||||
Q_Q(const FramelessMainWindow);
|
||||
return (q->isMaximized() || q->isFullScreen());
|
||||
}
|
||||
|
||||
void FramelessMainWindowPrivate::toggleMaximized()
|
||||
{
|
||||
Q_Q(FramelessMainWindow);
|
||||
if (q->isMaximized()) {
|
||||
q->showNormal();
|
||||
} else {
|
||||
q->showMaximized();
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessMainWindowPrivate::toggleFullScreen()
|
||||
{
|
||||
Q_Q(FramelessMainWindow);
|
||||
if (q->isFullScreen()) {
|
||||
q->setWindowState(m_savedWindowState);
|
||||
} else {
|
||||
m_savedWindowState = Utils::windowStatesToWindowState(q->windowState());
|
||||
q->showFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
FramelessMainWindow::FramelessMainWindow(QWidget *parent, const Qt::WindowFlags flags)
|
||||
: QMainWindow(parent, flags), d_ptr(new FramelessMainWindowPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
FramelessMainWindow::~FramelessMainWindow() = default;
|
||||
|
||||
bool FramelessMainWindow::isNormal() const
|
||||
{
|
||||
return (Utils::windowStatesToWindowState(windowState()) == Qt::WindowNoState);
|
||||
Q_D(const FramelessMainWindow);
|
||||
return d->isNormal();
|
||||
}
|
||||
|
||||
bool FramelessMainWindow::isZoomed() const
|
||||
{
|
||||
return (isMaximized() || isFullScreen());
|
||||
Q_D(const FramelessMainWindow);
|
||||
return d->isZoomed();
|
||||
}
|
||||
|
||||
void FramelessMainWindow::toggleMaximized()
|
||||
{
|
||||
if (isMaximized()) {
|
||||
showNormal();
|
||||
} else {
|
||||
showMaximized();
|
||||
}
|
||||
Q_D(FramelessMainWindow);
|
||||
d->toggleMaximized();
|
||||
}
|
||||
|
||||
void FramelessMainWindow::toggleFullScreen()
|
||||
{
|
||||
if (isFullScreen()) {
|
||||
setWindowState(m_savedWindowState);
|
||||
} else {
|
||||
m_savedWindowState = Utils::windowStatesToWindowState(windowState());
|
||||
showFullScreen();
|
||||
}
|
||||
Q_D(FramelessMainWindow);
|
||||
d->toggleFullScreen();
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class FramelessMainWindow;
|
||||
class WidgetsSharedHelper;
|
||||
|
||||
class FRAMELESSHELPER_WIDGETS_API FramelessMainWindowPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_PUBLIC(FramelessMainWindow)
|
||||
Q_DISABLE_COPY_MOVE(FramelessMainWindowPrivate)
|
||||
|
||||
public:
|
||||
explicit FramelessMainWindowPrivate(FramelessMainWindow *q);
|
||||
~FramelessMainWindowPrivate() override;
|
||||
|
||||
Q_NODISCARD static FramelessMainWindowPrivate *get(FramelessMainWindow *pub);
|
||||
Q_NODISCARD static const FramelessMainWindowPrivate *get(const FramelessMainWindow *pub);
|
||||
|
||||
Q_NODISCARD bool isNormal() const;
|
||||
Q_NODISCARD bool isZoomed() const;
|
||||
|
||||
void toggleMaximized();
|
||||
void toggleFullScreen();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
FramelessMainWindow *q_ptr = nullptr;
|
||||
Qt::WindowState m_savedWindowState = Qt::WindowNoState;
|
||||
QScopedPointer<WidgetsSharedHelper> m_helper;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "framelesswidget.h"
|
||||
#include "framelesswidget_p.h"
|
||||
#include "framelesswidgetshelper.h"
|
||||
#include "widgetssharedhelper_p.h"
|
||||
#include <utils.h>
|
||||
|
@ -31,42 +32,106 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
FramelessWidget::FramelessWidget(QWidget *parent) : QWidget(parent)
|
||||
FramelessWidgetPrivate::FramelessWidgetPrivate(FramelessWidget *q) : QObject(q)
|
||||
{
|
||||
FramelessWidgetsHelper::get(this)->attach();
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
q_ptr = q;
|
||||
initialize();
|
||||
}
|
||||
|
||||
FramelessWidgetPrivate::~FramelessWidgetPrivate() = default;
|
||||
|
||||
FramelessWidgetPrivate *FramelessWidgetPrivate::get(FramelessWidget *pub)
|
||||
{
|
||||
Q_ASSERT(pub);
|
||||
if (!pub) {
|
||||
return nullptr;
|
||||
}
|
||||
return pub->d_func();
|
||||
}
|
||||
|
||||
const FramelessWidgetPrivate *FramelessWidgetPrivate::get(const FramelessWidget *pub)
|
||||
{
|
||||
Q_ASSERT(pub);
|
||||
if (!pub) {
|
||||
return nullptr;
|
||||
}
|
||||
return pub->d_func();
|
||||
}
|
||||
|
||||
void FramelessWidgetPrivate::initialize()
|
||||
{
|
||||
Q_Q(FramelessWidget);
|
||||
FramelessWidgetsHelper::get(q)->attach();
|
||||
m_helper.reset(new WidgetsSharedHelper(this));
|
||||
m_helper->setup(this);
|
||||
m_helper->setup(q);
|
||||
}
|
||||
|
||||
bool FramelessWidgetPrivate::isNormal() const
|
||||
{
|
||||
Q_Q(const FramelessWidget);
|
||||
return (Utils::windowStatesToWindowState(q->windowState()) == Qt::WindowNoState);
|
||||
}
|
||||
|
||||
bool FramelessWidgetPrivate::isZoomed() const
|
||||
{
|
||||
Q_Q(const FramelessWidget);
|
||||
return (q->isMaximized() || q->isFullScreen());
|
||||
}
|
||||
|
||||
void FramelessWidgetPrivate::toggleMaximized()
|
||||
{
|
||||
Q_Q(FramelessWidget);
|
||||
if (q->isMaximized()) {
|
||||
q->showNormal();
|
||||
} else {
|
||||
q->showMaximized();
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessWidgetPrivate::toggleFullScreen()
|
||||
{
|
||||
Q_Q(FramelessWidget);
|
||||
if (q->isFullScreen()) {
|
||||
q->setWindowState(m_savedWindowState);
|
||||
} else {
|
||||
m_savedWindowState = Utils::windowStatesToWindowState(q->windowState());
|
||||
q->showFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
FramelessWidget::FramelessWidget(QWidget *parent)
|
||||
: QWidget(parent), d_ptr(new FramelessWidgetPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
FramelessWidget::~FramelessWidget() = default;
|
||||
|
||||
bool FramelessWidget::isNormal() const
|
||||
{
|
||||
return (Utils::windowStatesToWindowState(windowState()) == Qt::WindowNoState);
|
||||
Q_D(const FramelessWidget);
|
||||
return d->isNormal();
|
||||
}
|
||||
|
||||
bool FramelessWidget::isZoomed() const
|
||||
{
|
||||
return (isMaximized() || isFullScreen());
|
||||
Q_D(const FramelessWidget);
|
||||
return d->isZoomed();
|
||||
}
|
||||
|
||||
void FramelessWidget::toggleMaximized()
|
||||
{
|
||||
if (isMaximized()) {
|
||||
showNormal();
|
||||
} else {
|
||||
showMaximized();
|
||||
}
|
||||
Q_D(FramelessWidget);
|
||||
d->toggleMaximized();
|
||||
}
|
||||
|
||||
void FramelessWidget::toggleFullScreen()
|
||||
{
|
||||
if (isFullScreen()) {
|
||||
setWindowState(m_savedWindowState);
|
||||
} else {
|
||||
m_savedWindowState = Utils::windowStatesToWindowState(windowState());
|
||||
showFullScreen();
|
||||
}
|
||||
Q_D(FramelessWidget);
|
||||
d->toggleFullScreen();
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class FramelessWidget;
|
||||
class WidgetsSharedHelper;
|
||||
|
||||
class FRAMELESSHELPER_WIDGETS_API FramelessWidgetPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_PUBLIC(FramelessWidget)
|
||||
Q_DISABLE_COPY_MOVE(FramelessWidgetPrivate)
|
||||
|
||||
public:
|
||||
explicit FramelessWidgetPrivate(FramelessWidget *q);
|
||||
~FramelessWidgetPrivate() override;
|
||||
|
||||
Q_NODISCARD static FramelessWidgetPrivate *get(FramelessWidget *pub);
|
||||
Q_NODISCARD static const FramelessWidgetPrivate *get(const FramelessWidget *pub);
|
||||
|
||||
Q_NODISCARD bool isNormal() const;
|
||||
Q_NODISCARD bool isZoomed() const;
|
||||
|
||||
void toggleMaximized();
|
||||
void toggleFullScreen();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
FramelessWidget *q_ptr = nullptr;
|
||||
Qt::WindowState m_savedWindowState = Qt::WindowNoState;
|
||||
QScopedPointer<WidgetsSharedHelper> m_helper;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -135,6 +135,9 @@ void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
|
|||
}
|
||||
QMutexLocker locker(&g_widgetsHelper()->mutex);
|
||||
WidgetsHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
if (data->titleBarWidget == widget) {
|
||||
return;
|
||||
}
|
||||
|
@ -156,6 +159,9 @@ void FramelessWidgetsHelperPrivate::setHitTestVisible(QWidget *widget)
|
|||
}
|
||||
QMutexLocker locker(&g_widgetsHelper()->mutex);
|
||||
WidgetsHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
static constexpr const bool visible = true;
|
||||
const bool exists = data->hitTestVisibleWidgets.contains(widget);
|
||||
if (visible && !exists) {
|
||||
|
@ -176,6 +182,10 @@ void FramelessWidgetsHelperPrivate::attachToWindow()
|
|||
|
||||
g_widgetsHelper()->mutex.lock();
|
||||
WidgetsHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
g_widgetsHelper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
const bool attached = data->attached;
|
||||
g_widgetsHelper()->mutex.unlock();
|
||||
|
||||
|
@ -246,7 +256,7 @@ QWidget *FramelessWidgetsHelperPrivate::getWindow() const
|
|||
WidgetsHelperData FramelessWidgetsHelperPrivate::getWindowData() const
|
||||
{
|
||||
const QWidget * const window = getWindow();
|
||||
Q_ASSERT(window);
|
||||
//Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return {};
|
||||
}
|
||||
|
@ -261,7 +271,7 @@ WidgetsHelperData FramelessWidgetsHelperPrivate::getWindowData() const
|
|||
WidgetsHelperData *FramelessWidgetsHelperPrivate::getWindowDataMutable() const
|
||||
{
|
||||
const QWidget * const window = getWindow();
|
||||
Q_ASSERT(window);
|
||||
//Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -441,7 +451,14 @@ void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType
|
|||
} break;
|
||||
}
|
||||
};
|
||||
updateButtonState(widgetButton);
|
||||
if (const auto mo = widgetButton->metaObject()) {
|
||||
const int pressedIndex = mo->indexOfSlot(QMetaObject::normalizedSignature("setPressed(bool)").constData());
|
||||
const int hoveredIndex = mo->indexOfSlot(QMetaObject::normalizedSignature("setHovered(bool)").constData());
|
||||
const int clickedIndex = mo->indexOfSignal(QMetaObject::normalizedSignature("clicked()").constData());
|
||||
if ((pressedIndex != -1) && (hoveredIndex != -1) && (clickedIndex != -1)) {
|
||||
updateButtonState(widgetButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,6 +540,9 @@ void FramelessWidgetsHelperPrivate::setSystemButton(QWidget *widget, const Syste
|
|||
}
|
||||
QMutexLocker locker(&g_widgetsHelper()->mutex);
|
||||
WidgetsHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
switch (buttonType) {
|
||||
case SystemButtonType::Unknown:
|
||||
Q_ASSERT(false);
|
||||
|
@ -559,22 +579,20 @@ FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *object)
|
|||
if (!object) {
|
||||
return nullptr;
|
||||
}
|
||||
FramelessWidgetsHelper *instance = nullptr;
|
||||
QObject *parent = nullptr;
|
||||
if (object->isWidgetType()) {
|
||||
const auto widget = qobject_cast<QWidget *>(object);
|
||||
QWidget * const parentWidget = (widget->nativeParentWidget() ? widget->nativeParentWidget() : widget->window());
|
||||
Q_ASSERT(parentWidget);
|
||||
auto instance = parentWidget->findChild<FramelessWidgetsHelper *>();
|
||||
if (!instance) {
|
||||
instance = new FramelessWidgetsHelper(parentWidget);
|
||||
}
|
||||
return instance;
|
||||
parent = (widget->nativeParentWidget() ? widget->nativeParentWidget() : widget->window());
|
||||
} else {
|
||||
auto instance = object->findChild<FramelessWidgetsHelper *>();
|
||||
if (!instance) {
|
||||
instance = new FramelessWidgetsHelper(object);
|
||||
}
|
||||
return instance;
|
||||
parent = object;
|
||||
}
|
||||
instance = parent->findChild<FramelessWidgetsHelper *>();
|
||||
if (!instance) {
|
||||
instance = new FramelessWidgetsHelper(parent);
|
||||
instance->d_func()->attachToWindow();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
QWidget *FramelessWidgetsHelper::titleBarWidget() const
|
||||
|
@ -591,8 +609,8 @@ bool FramelessWidgetsHelper::isWindowFixedSize() const
|
|||
|
||||
void FramelessWidgetsHelper::attach()
|
||||
{
|
||||
Q_D(FramelessWidgetsHelper);
|
||||
d->attachToWindow();
|
||||
// Intentionally not doing anything here, we'll attach to window
|
||||
// automatically when this class is instantiated.
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelper::setTitleBarWidget(QWidget *widget)
|
||||
|
|
Loading…
Reference in New Issue