diff --git a/examples/quick/qml.qrc b/examples/quick/qml.qrc
index a1bf191..5c3ce85 100644
--- a/examples/quick/qml.qrc
+++ b/examples/quick/qml.qrc
@@ -1,8 +1,5 @@
qml/MainWindow.qml
- qml/MinimizeButton.qml
- qml/MaximizeButton.qml
- qml/CloseButton.qml
diff --git a/examples/quick/qml/MainWindow.qml b/examples/quick/qml/MainWindow.qml
index b98754e..583b13a 100644
--- a/examples/quick/qml/MainWindow.qml
+++ b/examples/quick/qml/MainWindow.qml
@@ -22,79 +22,32 @@
* SOFTWARE.
*/
-import QtQuick 2.12
-import QtQuick.Window 2.12
-import QtQuick.Controls 2.12
+import QtQuick 2.0
+import QtQuick.Window 2.0
+import QtQuick.Controls 2.0
import org.wangwenx190.FramelessHelper 1.0
-Window {
+FramelessWindow {
id: window
visible: true
width: 800
height: 600
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 {
- id: timer
interval: 500
running: true
repeat: true
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 {
id: timeLabel
anchors.centerIn: parent
@@ -105,22 +58,28 @@ Window {
color: FramelessUtils.darkModeEnabled ? "white" : "black"
}
- Rectangle {
- id: windowTopBorder
+ StandardTitleBar {
+ id: titleBar
anchors {
top: parent.top
+ topMargin: window.windowTopBorder.height
left: parent.left
right: parent.right
}
- height: ((window.visibility === Window.Windowed) && FramelessUtils.frameBorderVisible) ? 1 : 0
- color: window.active ? FramelessUtils.frameBorderActiveColor : FramelessUtils.frameBorderInactiveColor
- }
-
- Component.onCompleted: {
- FramelessHelper.addWindow(window);
- FramelessHelper.setTitleBarItem(window, titleBar);
- FramelessHelper.setHitTestVisible(window, minimizeButton, true);
- FramelessHelper.setHitTestVisible(window, maximizeButton, true);
- FramelessHelper.setHitTestVisible(window, closeButton, true);
+ active: window.active
+ maximized: (window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen)
+ title: window.title
+ minimizeButton {
+ id: minimizeButton
+ onClicked: FramelessUtils.showMinimized2(window)
+ }
+ maximizeButton {
+ id: maximizeButton
+ onClicked: FramelessUtils.toggleMaximize(window)
+ }
+ closeButton {
+ id: closeButton
+ onClicked: window.close()
+ }
}
}
diff --git a/include/FramelessHelper/Quick/framelesshelperquick_global.h b/include/FramelessHelper/Quick/framelesshelperquick_global.h
index 8f7c103..02b1e23 100644
--- a/include/FramelessHelper/Quick/framelesshelperquick_global.h
+++ b/include/FramelessHelper/Quick/framelesshelperquick_global.h
@@ -37,3 +37,7 @@
# endif
# endif
#endif
+
+FRAMELESSHELPER_BEGIN_NAMESPACE
+[[maybe_unused]] static constexpr const char FRAMELESSHELPER_QUICK_URI[] = "org.wangwenx190.FramelessHelper";
+FRAMELESSHELPER_END_NAMESPACE
diff --git a/include/FramelessHelper/Quick/framelessquickutils.h b/include/FramelessHelper/Quick/framelessquickutils.h
index e5ff7ed..d893918 100644
--- a/include/FramelessHelper/Quick/framelessquickutils.h
+++ b/include/FramelessHelper/Quick/framelessquickutils.h
@@ -52,6 +52,10 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickUtils : public QObject
Q_PROPERTY(bool darkModeEnabled READ darkModeEnabled NOTIFY darkModeEnabledChanged FINAL)
Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemAccentColorChanged 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:
explicit FramelessQuickUtils(QObject *parent = nullptr);
@@ -65,8 +69,13 @@ public:
Q_NODISCARD static bool darkModeEnabled();
Q_NODISCARD static QColor systemAccentColor();
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 toggleMaximize(QQuickWindow *window);
Q_INVOKABLE static void showSystemMenu(QQuickWindow *window, const QPoint &pos);
Q_INVOKABLE static void startSystemMove2(QQuickWindow *window);
Q_INVOKABLE static void startSystemResize2(QQuickWindow *window, const Qt::Edges edges);
diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt
index 203ed0b..31bf7d0 100644
--- a/src/quick/CMakeLists.txt
+++ b/src/quick/CMakeLists.txt
@@ -9,6 +9,7 @@ set(SOURCES
${INCLUDE_PREFIX}/framelesshelperimageprovider.h
${INCLUDE_PREFIX}/framelessquickeventfilter.h
${INCLUDE_PREFIX}/framelesshelper_quick.h
+ framelesshelperquick.qrc
framelesshelper_quick.cpp
framelessquickhelper.cpp
framelessquickutils.cpp
diff --git a/src/quick/framelesshelper_quick.cpp b/src/quick/framelesshelper_quick.cpp
index a842e0d..501b7a3 100644
--- a/src/quick/framelesshelper_quick.cpp
+++ b/src/quick/framelesshelper_quick.cpp
@@ -28,9 +28,15 @@
#include "framelessquickhelper.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)
{
@@ -49,6 +55,12 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
Q_UNUSED(scriptEngine);
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
diff --git a/src/quick/framelesshelperquick.qrc b/src/quick/framelesshelperquick.qrc
new file mode 100644
index 0000000..9282694
--- /dev/null
+++ b/src/quick/framelesshelperquick.qrc
@@ -0,0 +1,10 @@
+
+
+
+ qml/CloseButton.qml
+ qml/FramelessWindow.qml
+ qml/MaximizeButton.qml
+ qml/MinimizeButton.qml
+ qml/StandardTitleBar.qml
+
+
diff --git a/src/quick/framelessquickutils.cpp b/src/quick/framelessquickutils.cpp
index 04cba61..3fde495 100644
--- a/src/quick/framelessquickutils.cpp
+++ b/src/quick/framelessquickutils.cpp
@@ -120,6 +120,26 @@ bool FramelessQuickUtils::titleBarColorVisible()
#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)
{
Q_ASSERT(window);
@@ -137,6 +157,20 @@ void FramelessQuickUtils::showMinimized2(QQuickWindow *window)
#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)
{
Q_ASSERT(window);
diff --git a/examples/quick/qml/CloseButton.qml b/src/quick/qml/CloseButton.qml
similarity index 82%
rename from examples/quick/qml/CloseButton.qml
rename to src/quick/qml/CloseButton.qml
index 9618cc7..2fd1c6b 100644
--- a/examples/quick/qml/CloseButton.qml
+++ b/src/quick/qml/CloseButton.qml
@@ -28,30 +28,27 @@ import org.wangwenx190.FramelessHelper 1.0
Button {
id: button
+ implicitWidth: FramelessUtils.defaultSystemButtonSize.width
+ implicitHeight: FramelessUtils.defaultSystemButtonSize.height
+ contentItem: Item {
+ implicitWidth: FramelessUtils.defaultSystemButtonIconSize.width
+ implicitHeight: FramelessUtils.defaultSystemButtonIconSize.height
- implicitHeight: 30
- implicitWidth: implicitHeight * 1.5
+ 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
+ }
ToolTip {
visible: button.hovered && !button.down
delay: Qt.styleHints.mousePressAndHoldInterval
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
- }
}
diff --git a/src/quick/qml/FramelessWindow.qml b/src/quick/qml/FramelessWindow.qml
new file mode 100644
index 0000000..2ac0e62
--- /dev/null
+++ b/src/quick/qml/FramelessWindow.qml
@@ -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
+ }
+}
diff --git a/examples/quick/qml/MaximizeButton.qml b/src/quick/qml/MaximizeButton.qml
similarity index 80%
rename from examples/quick/qml/MaximizeButton.qml
rename to src/quick/qml/MaximizeButton.qml
index 5598b96..33ddfc1 100644
--- a/examples/quick/qml/MaximizeButton.qml
+++ b/src/quick/qml/MaximizeButton.qml
@@ -27,36 +27,33 @@ import QtQuick.Controls 2.0
import org.wangwenx190.FramelessHelper 1.0
Button {
- id: button
-
- implicitHeight: 30
- implicitWidth: implicitHeight * 1.5
-
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 {
visible: button.hovered && !button.down
delay: Qt.styleHints.mousePressAndHoldInterval
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
- }
}
diff --git a/examples/quick/qml/MinimizeButton.qml b/src/quick/qml/MinimizeButton.qml
similarity index 82%
rename from examples/quick/qml/MinimizeButton.qml
rename to src/quick/qml/MinimizeButton.qml
index bb8c83f..6e53e98 100644
--- a/examples/quick/qml/MinimizeButton.qml
+++ b/src/quick/qml/MinimizeButton.qml
@@ -28,30 +28,27 @@ import org.wangwenx190.FramelessHelper 1.0
Button {
id: button
+ implicitWidth: FramelessUtils.defaultSystemButtonSize.width
+ implicitHeight: FramelessUtils.defaultSystemButtonSize.height
+ contentItem: Item {
+ implicitWidth: FramelessUtils.defaultSystemButtonIconSize.width
+ implicitHeight: FramelessUtils.defaultSystemButtonIconSize.height
- implicitHeight: 30
- implicitWidth: implicitHeight * 1.5
+ 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
+ }
ToolTip {
visible: button.hovered && !button.down
delay: Qt.styleHints.mousePressAndHoldInterval
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
- }
}
diff --git a/src/quick/qml/StandardTitleBar.qml b/src/quick/qml/StandardTitleBar.qml
new file mode 100644
index 0000000..8d22071
--- /dev/null
+++ b/src/quick/qml/StandardTitleBar.qml
@@ -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
+ }
+ }
+}