Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-03-21 16:53:18 +08:00
parent 0e75f12089
commit 1ed6e2fb01
13 changed files with 274 additions and 138 deletions

View File

@ -1,8 +1,5 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>qml/MainWindow.qml</file> <file>qml/MainWindow.qml</file>
<file>qml/MinimizeButton.qml</file>
<file>qml/MaximizeButton.qml</file>
<file>qml/CloseButton.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -22,79 +22,32 @@
* SOFTWARE. * SOFTWARE.
*/ */
import QtQuick 2.12 import QtQuick 2.0
import QtQuick.Window 2.12 import QtQuick.Window 2.0
import QtQuick.Controls 2.12 import QtQuick.Controls 2.0
import org.wangwenx190.FramelessHelper 1.0 import org.wangwenx190.FramelessHelper 1.0
Window { FramelessWindow {
id: window id: window
visible: true visible: true
width: 800 width: 800
height: 600 height: 600
title: qsTr("Hello, World! - Qt Quick") title: qsTr("Hello, World! - Qt Quick")
color: FramelessUtils.darkModeEnabled ? "#202020" : "#f0f0f0" color: FramelessUtils.darkModeEnabled ? FramelessUtils.defaultSystemDarkColor : FramelessUtils.defaultSystemLightColor
Component.onCompleted: {
FramelessHelper.setTitleBarItem(window, titleBar);
FramelessHelper.setHitTestVisible(window, minimizeButton, true);
FramelessHelper.setHitTestVisible(window, maximizeButton, true);
FramelessHelper.setHitTestVisible(window, closeButton, true);
}
Timer { Timer {
id: timer
interval: 500 interval: 500
running: true running: true
repeat: true repeat: true
onTriggered: timeLabel.text = Qt.formatTime(new Date(), "hh:mm:ss") onTriggered: timeLabel.text = Qt.formatTime(new Date(), "hh:mm:ss")
} }
Rectangle {
id: titleBar
height: 30
color: window.active ? (FramelessUtils.titleBarColorVisible ? FramelessUtils.systemAccentColor
: (FramelessUtils.darkModeEnabled ? "black" : "white"))
: (FramelessUtils.darkModeEnabled ? "#202020" : "white")
anchors {
top: parent.top
topMargin: windowTopBorder.height
left: parent.left
right: parent.right
}
Text {
id: titleBarText
text: window.title
font.pointSize: 11
color: window.active ? ((FramelessUtils.darkModeEnabled
|| FramelessUtils.titleBarColorVisible) ? "white" : "black") : "darkGray"
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
}
Row {
anchors.top: parent.top
anchors.right: parent.right
MinimizeButton {
id: minimizeButton
onClicked: FramelessUtils.showMinimized2(window)
}
MaximizeButton {
id: maximizeButton
maximized: ((window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen))
onClicked: {
if (maximized) {
window.showNormal();
} else {
window.showMaximized();
}
}
}
CloseButton {
id: closeButton
onClicked: window.close()
}
}
}
Label { Label {
id: timeLabel id: timeLabel
anchors.centerIn: parent anchors.centerIn: parent
@ -105,22 +58,28 @@ Window {
color: FramelessUtils.darkModeEnabled ? "white" : "black" color: FramelessUtils.darkModeEnabled ? "white" : "black"
} }
Rectangle { StandardTitleBar {
id: windowTopBorder id: titleBar
anchors { anchors {
top: parent.top top: parent.top
topMargin: window.windowTopBorder.height
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
height: ((window.visibility === Window.Windowed) && FramelessUtils.frameBorderVisible) ? 1 : 0 active: window.active
color: window.active ? FramelessUtils.frameBorderActiveColor : FramelessUtils.frameBorderInactiveColor maximized: (window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen)
} title: window.title
minimizeButton {
Component.onCompleted: { id: minimizeButton
FramelessHelper.addWindow(window); onClicked: FramelessUtils.showMinimized2(window)
FramelessHelper.setTitleBarItem(window, titleBar); }
FramelessHelper.setHitTestVisible(window, minimizeButton, true); maximizeButton {
FramelessHelper.setHitTestVisible(window, maximizeButton, true); id: maximizeButton
FramelessHelper.setHitTestVisible(window, closeButton, true); onClicked: FramelessUtils.toggleMaximize(window)
}
closeButton {
id: closeButton
onClicked: window.close()
}
} }
} }

View File

@ -37,3 +37,7 @@
# endif # endif
# endif # endif
#endif #endif
FRAMELESSHELPER_BEGIN_NAMESPACE
[[maybe_unused]] static constexpr const char FRAMELESSHELPER_QUICK_URI[] = "org.wangwenx190.FramelessHelper";
FRAMELESSHELPER_END_NAMESPACE

View File

@ -52,6 +52,10 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickUtils : public QObject
Q_PROPERTY(bool darkModeEnabled READ darkModeEnabled NOTIFY darkModeEnabledChanged FINAL) Q_PROPERTY(bool darkModeEnabled READ darkModeEnabled NOTIFY darkModeEnabledChanged FINAL)
Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemAccentColorChanged FINAL) Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemAccentColorChanged FINAL)
Q_PROPERTY(bool titleBarColorVisible READ titleBarColorVisible NOTIFY titleBarColorVisibleChanged FINAL) Q_PROPERTY(bool titleBarColorVisible READ titleBarColorVisible NOTIFY titleBarColorVisibleChanged FINAL)
Q_PROPERTY(QColor defaultSystemLightColor READ defaultSystemLightColor CONSTANT FINAL)
Q_PROPERTY(QColor defaultSystemDarkColor READ defaultSystemDarkColor CONSTANT FINAL)
Q_PROPERTY(QSizeF defaultSystemButtonSize READ defaultSystemButtonSize CONSTANT FINAL)
Q_PROPERTY(QSizeF defaultSystemButtonIconSize READ defaultSystemButtonIconSize CONSTANT FINAL)
public: public:
explicit FramelessQuickUtils(QObject *parent = nullptr); explicit FramelessQuickUtils(QObject *parent = nullptr);
@ -65,8 +69,13 @@ public:
Q_NODISCARD static bool darkModeEnabled(); Q_NODISCARD static bool darkModeEnabled();
Q_NODISCARD static QColor systemAccentColor(); Q_NODISCARD static QColor systemAccentColor();
Q_NODISCARD static bool titleBarColorVisible(); Q_NODISCARD static bool titleBarColorVisible();
Q_NODISCARD static QColor defaultSystemLightColor();
Q_NODISCARD static QColor defaultSystemDarkColor();
Q_NODISCARD static QSizeF defaultSystemButtonSize();
Q_NODISCARD static QSizeF defaultSystemButtonIconSize();
Q_INVOKABLE static void showMinimized2(QQuickWindow *window); Q_INVOKABLE static void showMinimized2(QQuickWindow *window);
Q_INVOKABLE static void toggleMaximize(QQuickWindow *window);
Q_INVOKABLE static void showSystemMenu(QQuickWindow *window, const QPoint &pos); Q_INVOKABLE static void showSystemMenu(QQuickWindow *window, const QPoint &pos);
Q_INVOKABLE static void startSystemMove2(QQuickWindow *window); Q_INVOKABLE static void startSystemMove2(QQuickWindow *window);
Q_INVOKABLE static void startSystemResize2(QQuickWindow *window, const Qt::Edges edges); Q_INVOKABLE static void startSystemResize2(QQuickWindow *window, const Qt::Edges edges);

View File

@ -9,6 +9,7 @@ set(SOURCES
${INCLUDE_PREFIX}/framelesshelperimageprovider.h ${INCLUDE_PREFIX}/framelesshelperimageprovider.h
${INCLUDE_PREFIX}/framelessquickeventfilter.h ${INCLUDE_PREFIX}/framelessquickeventfilter.h
${INCLUDE_PREFIX}/framelesshelper_quick.h ${INCLUDE_PREFIX}/framelesshelper_quick.h
framelesshelperquick.qrc
framelesshelper_quick.cpp framelesshelper_quick.cpp
framelessquickhelper.cpp framelessquickhelper.cpp
framelessquickutils.cpp framelessquickutils.cpp

View File

@ -28,9 +28,15 @@
#include "framelessquickhelper.h" #include "framelessquickhelper.h"
#include "framelessquickutils.h" #include "framelessquickutils.h"
FRAMELESSHELPER_BEGIN_NAMESPACE // The "Q_INIT_RESOURCE()" macro can't be used inside a namespace,
// the official workaround is to wrap it into a global function
// and call the wrapper function inside the namespace.
static inline void initResource()
{
Q_INIT_RESOURCE(framelesshelperquick);
}
static constexpr const char FRAMELESSHELPER_QUICK_URI[] = "org.wangwenx190.FramelessHelper"; FRAMELESSHELPER_BEGIN_NAMESPACE
void FramelessHelper::Quick::registerTypes(QQmlEngine *engine) void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
{ {
@ -49,6 +55,12 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
Q_UNUSED(scriptEngine); Q_UNUSED(scriptEngine);
return new FramelessQuickUtils; return new FramelessQuickUtils;
}); });
initResource();
qmlRegisterType(QUrl(QStringLiteral("qrc:///qml/MinimizeButton.qml")), FRAMELESSHELPER_QUICK_URI, 1, 0, "MinimizeButton");
qmlRegisterType(QUrl(QStringLiteral("qrc:///qml/MaximizeButton.qml")), FRAMELESSHELPER_QUICK_URI, 1, 0, "MaximizeButton");
qmlRegisterType(QUrl(QStringLiteral("qrc:///qml/CloseButton.qml")), FRAMELESSHELPER_QUICK_URI, 1, 0, "CloseButton");
qmlRegisterType(QUrl(QStringLiteral("qrc:///qml/StandardTitleBar.qml")), FRAMELESSHELPER_QUICK_URI, 1, 0, "StandardTitleBar");
qmlRegisterType(QUrl(QStringLiteral("qrc:///qml/FramelessWindow.qml")), FRAMELESSHELPER_QUICK_URI, 1, 0, "FramelessWindow");
} }
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -0,0 +1,10 @@
<RCC>
<qresource prefix="/org.wangwenx190.FramelessHelper"/>
<qresource prefix="/">
<file>qml/CloseButton.qml</file>
<file>qml/FramelessWindow.qml</file>
<file>qml/MaximizeButton.qml</file>
<file>qml/MinimizeButton.qml</file>
<file>qml/StandardTitleBar.qml</file>
</qresource>
</RCC>

View File

@ -120,6 +120,26 @@ bool FramelessQuickUtils::titleBarColorVisible()
#endif #endif
} }
QColor FramelessQuickUtils::defaultSystemLightColor()
{
return kDefaultSystemLightColor;
}
QColor FramelessQuickUtils::defaultSystemDarkColor()
{
return kDefaultSystemDarkColor;
}
QSizeF FramelessQuickUtils::defaultSystemButtonSize()
{
return kDefaultSystemButtonSize;
}
QSizeF FramelessQuickUtils::defaultSystemButtonIconSize()
{
return kDefaultSystemButtonIconSize;
}
void FramelessQuickUtils::showMinimized2(QQuickWindow *window) void FramelessQuickUtils::showMinimized2(QQuickWindow *window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
@ -137,6 +157,20 @@ void FramelessQuickUtils::showMinimized2(QQuickWindow *window)
#endif #endif
} }
void FramelessQuickUtils::toggleMaximize(QQuickWindow *window)
{
Q_ASSERT(window);
if (!window) {
return;
}
const QQuickWindow::Visibility visibility = window->visibility();
if ((visibility == QQuickWindow::Maximized) || (visibility == QQuickWindow::FullScreen)) {
window->showNormal();
} else {
window->showMaximized();
}
}
void FramelessQuickUtils::showSystemMenu(QQuickWindow *window, const QPoint &pos) void FramelessQuickUtils::showSystemMenu(QQuickWindow *window, const QPoint &pos)
{ {
Q_ASSERT(window); Q_ASSERT(window);

View File

@ -28,30 +28,27 @@ import org.wangwenx190.FramelessHelper 1.0
Button { Button {
id: button id: button
implicitWidth: FramelessUtils.defaultSystemButtonSize.width
implicitHeight: FramelessUtils.defaultSystemButtonSize.height
contentItem: Item {
implicitWidth: FramelessUtils.defaultSystemButtonIconSize.width
implicitHeight: FramelessUtils.defaultSystemButtonIconSize.height
implicitHeight: 30 Image {
implicitWidth: implicitHeight * 1.5 anchors.centerIn: parent
source: (FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible)
? "image://framelesshelper/dark/close" : "image://framelesshelper/light/close"
}
}
background: Rectangle {
visible: button.hovered
color: "red"
opacity: 0.5
}
ToolTip { ToolTip {
visible: button.hovered && !button.down visible: button.hovered && !button.down
delay: Qt.styleHints.mousePressAndHoldInterval delay: Qt.styleHints.mousePressAndHoldInterval
text: qsTr("Close") text: qsTr("Close")
} }
contentItem: Item {
implicitWidth: 16
implicitHeight: implicitWidth
Image {
anchors.centerIn: parent
source: FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible
? "image://framelesshelper/dark/close" : "image://framelesshelper/light/close"
}
}
background: Rectangle {
visible: button.hovered
color: "red"
opacity: 0.5
}
} }

View File

@ -0,0 +1,45 @@
/*
* 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.
*/
import QtQuick 2.0
import QtQuick.Window 2.0
import org.wangwenx190.FramelessHelper 1.0
Window {
property alias windowTopBorder: windowTopBorder
id: window
Component.onCompleted: FramelessHelper.addWindow(window)
Rectangle {
id: windowTopBorder
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: ((window.visibility === Window.Windowed) && FramelessUtils.frameBorderVisible) ? 1 : 0
color: window.active ? FramelessUtils.frameBorderActiveColor : FramelessUtils.frameBorderInactiveColor
}
}

View File

@ -27,36 +27,33 @@ import QtQuick.Controls 2.0
import org.wangwenx190.FramelessHelper 1.0 import org.wangwenx190.FramelessHelper 1.0
Button { Button {
id: button
implicitHeight: 30
implicitWidth: implicitHeight * 1.5
property bool maximized: false property bool maximized: false
id: button
implicitWidth: FramelessUtils.defaultSystemButtonSize.width
implicitHeight: FramelessUtils.defaultSystemButtonSize.height
contentItem: Item {
implicitWidth: FramelessUtils.defaultSystemButtonIconSize.width
implicitHeight: FramelessUtils.defaultSystemButtonIconSize.height
Image {
anchors.centerIn: parent
source: button.maximized ?
((FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible)
? "image://framelesshelper/dark/restore" : "image://framelesshelper/light/restore") :
((FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible)
? "image://framelesshelper/dark/maximize" : "image://framelesshelper/light/maximize")
}
}
background: Rectangle {
visible: button.hovered
color: "gray"
opacity: 0.5
}
ToolTip { ToolTip {
visible: button.hovered && !button.down visible: button.hovered && !button.down
delay: Qt.styleHints.mousePressAndHoldInterval delay: Qt.styleHints.mousePressAndHoldInterval
text: button.maximized ? qsTr("Restore") : qsTr("Maximize") text: button.maximized ? qsTr("Restore") : qsTr("Maximize")
} }
contentItem: Item {
implicitWidth: 16
implicitHeight: implicitWidth
Image {
anchors.centerIn: parent
source: button.maximized ?
(FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible
? "image://framelesshelper/dark/restore" : "image://framelesshelper/light/restore") :
(FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible
? "image://framelesshelper/dark/maximize" : "image://framelesshelper/light/maximize")
}
}
background: Rectangle {
visible: button.hovered
color: "gray"
opacity: 0.5
}
} }

View File

@ -28,30 +28,27 @@ import org.wangwenx190.FramelessHelper 1.0
Button { Button {
id: button id: button
implicitWidth: FramelessUtils.defaultSystemButtonSize.width
implicitHeight: FramelessUtils.defaultSystemButtonSize.height
contentItem: Item {
implicitWidth: FramelessUtils.defaultSystemButtonIconSize.width
implicitHeight: FramelessUtils.defaultSystemButtonIconSize.height
implicitHeight: 30 Image {
implicitWidth: implicitHeight * 1.5 anchors.centerIn: parent
source: (FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible)
? "image://framelesshelper/dark/minimize" : "image://framelesshelper/light/minimize"
}
}
background: Rectangle {
visible: button.hovered
color: "gray"
opacity: 0.5
}
ToolTip { ToolTip {
visible: button.hovered && !button.down visible: button.hovered && !button.down
delay: Qt.styleHints.mousePressAndHoldInterval delay: Qt.styleHints.mousePressAndHoldInterval
text: qsTr("Minimize") text: qsTr("Minimize")
} }
contentItem: Item {
implicitWidth: 16
implicitHeight: implicitWidth
Image {
anchors.centerIn: parent
source: FramelessUtils.darkModeEnabled || FramelessUtils.titleBarColorVisible
? "image://framelesshelper/dark/minimize" : "image://framelesshelper/light/minimize"
}
}
background: Rectangle {
visible: button.hovered
color: "gray"
opacity: 0.5
}
} }

View File

@ -0,0 +1,74 @@
/*
* 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.
*/
import QtQuick 2.0
import QtQuick.Controls 2.0
import org.wangwenx190.FramelessHelper 1.0
Rectangle {
property bool active: true
property bool maximized: false
property alias title: windowTitleLabel.text
property alias minimizeButton: minimizeButton
property alias maximizeButton: maximizeButton
property alias closeButton: closeButton
id: titleBar
height: FramelessUtils.titleBarHeight
color: titleBar.active ? (FramelessUtils.titleBarColorVisible ? FramelessUtils.systemAccentColor
: (FramelessUtils.darkModeEnabled ? "black" : "white"))
: (FramelessUtils.darkModeEnabled ? FramelessUtils.defaultSystemDarkColor : "white")
Text {
id: windowTitleLabel
font.pointSize: 11
color: titleBar.active ? ((FramelessUtils.darkModeEnabled
|| FramelessUtils.titleBarColorVisible) ? "white" : "black") : "darkGray"
anchors {
left: parent.left
leftMargin: 10
verticalCenter: parent.verticalCenter
}
}
Row {
anchors {
top: parent.top
right: parent.right
}
MinimizeButton {
id: minimizeButton
}
MaximizeButton {
id: maximizeButton
maximized: titleBar.maximized
}
CloseButton {
id: closeButton
}
}
}