parent
d0e19a2b1e
commit
556741cfb1
|
@ -2,11 +2,8 @@ cmake_minimum_required(VERSION 3.20)
|
|||
|
||||
project(FramelessHelper LANGUAGES CXX)
|
||||
|
||||
option(BUILD_EXAMPLES "Build examples." ON)
|
||||
|
||||
if(NOT DEFINED BUILD_SHARED_LIBS)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
option(FRAMELESSHELPER_BUILD_STATIC "Build FramelessHelper as a static library." OFF)
|
||||
option(FRAMELESSHELPER_BUILD_EXAMPLES "Build FramelessHelper demo applications." ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
@ -20,8 +17,8 @@ set(CMAKE_AUTORCC ON)
|
|||
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui REQUIRED)
|
||||
#find_package(QT NAMES Qt6 Qt5 COMPONENTS Quick)
|
||||
#find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick)
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Quick)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick)
|
||||
|
||||
set(SOURCES
|
||||
framelesshelper_global.h
|
||||
|
@ -34,12 +31,12 @@ set(SOURCES
|
|||
utilities.cpp
|
||||
)
|
||||
|
||||
#[[if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
list(APPEND SOURCES
|
||||
framelessquickhelper.h
|
||||
framelessquickhelper.cpp
|
||||
)
|
||||
endif()]]
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND SOURCES
|
||||
|
@ -56,15 +53,18 @@ elseif(UNIX)
|
|||
list(APPEND SOURCES utilities_linux.cpp)
|
||||
endif()
|
||||
|
||||
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
enable_language(RC)
|
||||
list(APPEND SOURCES framelesshelper.rc)
|
||||
endif()
|
||||
|
||||
add_library(${PROJECT_NAME} ${SOURCES})
|
||||
add_library(wangwenx190::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||
else()
|
||||
add_library(${PROJECT_NAME} SHARED ${SOURCES})
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC
|
||||
FRAMELESSHELPER_STATIC
|
||||
)
|
||||
|
@ -85,16 +85,16 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
|
|||
Qt${QT_VERSION_MAJOR}::GuiPrivate
|
||||
)
|
||||
|
||||
#[[if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Quick
|
||||
)
|
||||
endif()]]
|
||||
endif()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
|
||||
)
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
if(FRAMELESSHELPER_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
|
|
@ -7,5 +7,5 @@ if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
|
|||
endif()
|
||||
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
#add_subdirectory(quick)
|
||||
add_subdirectory(quick)
|
||||
endif()
|
||||
|
|
|
@ -25,7 +25,7 @@ add_executable(MainWindow WIN32 ${SOURCES})
|
|||
|
||||
target_link_libraries(MainWindow PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
wangwenx190::FramelessHelper
|
||||
FramelessHelper
|
||||
)
|
||||
|
||||
target_compile_definitions(MainWindow PRIVATE
|
||||
|
|
|
@ -23,7 +23,7 @@ add_executable(Quick WIN32 ${SOURCES})
|
|||
target_link_libraries(Quick PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Quick
|
||||
Qt${QT_VERSION_MAJOR}::QuickControls2
|
||||
wangwenx190::FramelessHelper
|
||||
FramelessHelper
|
||||
)
|
||||
|
||||
target_compile_definitions(Quick PRIVATE
|
||||
|
|
|
@ -22,77 +22,20 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "../../utilities.h"
|
||||
#include "../../framelessquickhelper.h"
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtQml/qqmlapplicationengine.h>
|
||||
#include <QtQuickControls2/qquickstyle.h>
|
||||
#include <framelessquickhelper.h>
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
static constexpr const char qtquicknamespace[] = "wangwenx190.Utils";
|
||||
|
||||
class UtilFunctions : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(UtilFunctions)
|
||||
Q_PROPERTY(bool isWindowsHost READ isWindowsHost CONSTANT)
|
||||
Q_PROPERTY(bool isWindows10OrGreater READ isWindows10OrGreater CONSTANT)
|
||||
Q_PROPERTY(bool isWindows11OrGreater READ isWindows11OrGreater CONSTANT)
|
||||
Q_PROPERTY(QColor activeFrameBorderColor READ activeFrameBorderColor CONSTANT)
|
||||
Q_PROPERTY(QColor inactiveFrameBorderColor READ inactiveFrameBorderColor CONSTANT)
|
||||
Q_PROPERTY(qreal frameBorderThickness READ frameBorderThickness CONSTANT)
|
||||
|
||||
public:
|
||||
explicit UtilFunctions(QObject *parent = nullptr) : QObject(parent) {}
|
||||
~UtilFunctions() override = default;
|
||||
|
||||
inline bool isWindowsHost() const {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool isWindows10OrGreater() const {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return Utilities::isWin10OrGreater();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool isWindows11OrGreater() const {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return Utilities::isWin11OrGreater();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline QColor activeFrameBorderColor() const {
|
||||
const ColorizationArea area = Utilities::getColorizationArea();
|
||||
const bool colorizedBorder = ((area == ColorizationArea::TitleBar_WindowBorder)
|
||||
|| (area == ColorizationArea::All));
|
||||
return (colorizedBorder ? Utilities::getColorizationColor() : Qt::black);
|
||||
}
|
||||
|
||||
inline QColor inactiveFrameBorderColor() const {
|
||||
return Qt::darkGray;
|
||||
}
|
||||
|
||||
inline qreal frameBorderThickness() const {
|
||||
return 1.0;
|
||||
}
|
||||
};
|
||||
static constexpr const char FRAMELESSHELPER_QUICK_URI[] = "org.wangwenx190.FramelessHelper";
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#endif
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round);
|
||||
|
@ -100,6 +43,9 @@ int main(int argc, char *argv[])
|
|||
|
||||
QGuiApplication application(argc, argv);
|
||||
|
||||
QScopedPointer<FramelessQuickHelper> framelessHelper(new FramelessQuickHelper);
|
||||
QScopedPointer<FramelessQuickUtils> framelessUtils(new FramelessQuickUtils);
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
|
@ -108,14 +54,10 @@ int main(int argc, char *argv[])
|
|||
QQuickStyle::setStyle(QStringLiteral("Default"));
|
||||
#endif
|
||||
|
||||
qmlRegisterSingletonType<UtilFunctions>(qtquicknamespace, 1, 0, "Utils", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
|
||||
Q_UNUSED(engine);
|
||||
Q_UNUSED(scriptEngine);
|
||||
return new UtilFunctions();
|
||||
});
|
||||
qmlRegisterType<FramelessQuickHelper>(qtquicknamespace, 1, 0, "FramelessHelper");
|
||||
qmlRegisterSingletonInstance(FRAMELESSHELPER_QUICK_URI, 1, 0, "FramelessHelper", framelessHelper.data());
|
||||
qmlRegisterSingletonInstance(FRAMELESSHELPER_QUICK_URI, 1, 0, "FramelessUtils", framelessUtils.data());
|
||||
|
||||
const QUrl mainQmlUrl(QStringLiteral("qrc:///qml/main.qml"));
|
||||
const QUrl mainQmlUrl(QStringLiteral("qrc:///qml/MainWindow.qml"));
|
||||
const QMetaObject::Connection connection = QObject::connect(
|
||||
&engine,
|
||||
&QQmlApplicationEngine::objectCreated,
|
||||
|
@ -124,17 +66,16 @@ int main(int argc, char *argv[])
|
|||
if (url != mainQmlUrl) {
|
||||
return;
|
||||
}
|
||||
if (!object) {
|
||||
QGuiApplication::exit(-1);
|
||||
} else {
|
||||
if (object) {
|
||||
QObject::disconnect(connection);
|
||||
|
||||
} else {
|
||||
QCoreApplication::exit(-1);
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
engine.load(mainQmlUrl);
|
||||
|
||||
return QGuiApplication::exec();
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
||||
#include "main.moc"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>qml/main.qml</file>
|
||||
<file>qml/MainWindow.qml</file>
|
||||
<file>qml/MinimizeButton.qml</file>
|
||||
<file>qml/MaximizeButton.qml</file>
|
||||
<file>qml/CloseButton.qml</file>
|
||||
|
|
|
@ -24,25 +24,33 @@
|
|||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
import org.wangwenx190.FramelessHelper 1.0
|
||||
|
||||
Button {
|
||||
id: button
|
||||
|
||||
implicitWidth: 45
|
||||
implicitHeight: 30
|
||||
implicitWidth: implicitHeight * 1.5
|
||||
|
||||
ToolTip.visible: hovered && !down
|
||||
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
ToolTip.text: qsTr("Close")
|
||||
ToolTip {
|
||||
visible: button.hovered && !button.down
|
||||
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
text: qsTr("Close")
|
||||
}
|
||||
|
||||
contentItem: Image {
|
||||
anchors.fill: parent
|
||||
source: button.down
|
||||
|| button.hovered ? "qrc:/images/button_close_white.svg" : "qrc:/images/button_close_black.svg"
|
||||
contentItem: Item {
|
||||
implicitWidth: 16
|
||||
implicitHeight: implicitWidth
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
source: FramelessUtils.darkModeEnabled ? "qrc:/images/light/chrome-close.svg" : "qrc:/images/dark/chrome-close.svg"
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
visible: button.down || button.hovered
|
||||
color: button.down ? "#8c0a15" : (button.hovered ? "#e81123" : "transparent")
|
||||
visible: button.hovered
|
||||
color: "red"
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,10 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Window 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
import wangwenx190.Utils 1.0
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Window 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import org.wangwenx190.FramelessHelper 1.0
|
||||
|
||||
Window {
|
||||
id: window
|
||||
|
@ -33,14 +33,7 @@ Window {
|
|||
width: 800
|
||||
height: 600
|
||||
title: qsTr("Hello, World!")
|
||||
color: "#f0f0f0"
|
||||
|
||||
property real _flh_margin: ((window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen)) ? 0 : (Utils.frameBorderThickness / Screen.devicePixelRatio)
|
||||
property var _win_prev_state: null
|
||||
|
||||
FramelessHelper {
|
||||
id: framelessHelper
|
||||
}
|
||||
color: FramelessUtils.darkModeEnabled ? "#202020" : "#f0f0f0"
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
|
@ -52,35 +45,46 @@ Window {
|
|||
|
||||
Rectangle {
|
||||
id: titleBar
|
||||
height: framelessHelper.titleBarHeight
|
||||
color: "white"
|
||||
height: 30
|
||||
color: window.active ? (FramelessUtils.titleBarColorVisible ? FramelessUtils.systemAccentColor :
|
||||
(FramelessUtils.darkModeEnabled ? "white" : "black")) :
|
||||
(FramelessUtils.darkModeEnabled ? "#202020" : "white")
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: window._flh_margin
|
||||
topMargin: windowTopBorder.height
|
||||
left: parent.left
|
||||
leftMargin: window._flh_margin
|
||||
right: parent.right
|
||||
rightMargin: window._flh_margin
|
||||
}
|
||||
|
||||
Text {
|
||||
id: titleBarText
|
||||
text: window.title
|
||||
font.pointSize: 13
|
||||
color: window.active ? "black" : "gray"
|
||||
color: window.active ? (FramelessUtils.darkModeEnabled ? "white" : "black") : "darkGray"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 15
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 30 * 1.5 * 3
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
onDoubleClicked: 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: framelessHelper.showMinimized()
|
||||
Component.onCompleted: framelessHelper.setHitTestVisible(minimizeButton, true)
|
||||
onClicked: FramelessUtils.showMinimized2(window)
|
||||
}
|
||||
|
||||
MaximizeButton {
|
||||
|
@ -88,18 +92,15 @@ Window {
|
|||
maximized: ((window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen))
|
||||
onClicked: {
|
||||
if (maximized) {
|
||||
window.showNormal()
|
||||
window.showNormal();
|
||||
} else {
|
||||
window.showMaximized()
|
||||
window.showMaximized();
|
||||
}
|
||||
}
|
||||
Component.onCompleted: framelessHelper.setHitTestVisible(maximizeButton, true)
|
||||
}
|
||||
|
||||
CloseButton {
|
||||
id: closeButton
|
||||
onClicked: window.close()
|
||||
Component.onCompleted: framelessHelper.setHitTestVisible(closeButton, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,41 +112,19 @@ Window {
|
|||
pointSize: 70
|
||||
bold: true
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: fullScreenButton
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: timeLabel.bottom
|
||||
topMargin: 15
|
||||
}
|
||||
property bool _full: window.visibility === Window.FullScreen
|
||||
text: _full ? qsTr("Exit FullScreen") : qsTr("Enter FullScreen")
|
||||
onClicked: {
|
||||
if (_full) {
|
||||
if (_win_prev_state == Window.Maximized) {
|
||||
window.showMaximized()
|
||||
} else if (_win_prev_state == Window.Windowed) {
|
||||
window.showNormal()
|
||||
}
|
||||
} else {
|
||||
_win_prev_state = window.visibility
|
||||
window.showFullScreen()
|
||||
}
|
||||
}
|
||||
color: FramelessUtils.darkModeEnabled ? "white" : "black"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: windowFrame
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
visible: !Utils.isWindows11OrGreater
|
||||
border {
|
||||
color: window.active ? Utils.activeFrameBorderColor : Utils.inactiveFrameBorderColor
|
||||
width: window._flh_margin
|
||||
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
|
||||
}
|
||||
|
||||
Component.onCompleted: framelessHelper.removeWindowFrame()
|
||||
Component.onCompleted: FramelessHelper.addWindow(window)
|
||||
}
|
|
@ -24,26 +24,37 @@
|
|||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
import org.wangwenx190.FramelessHelper 1.0
|
||||
|
||||
Button {
|
||||
id: button
|
||||
|
||||
implicitWidth: 45
|
||||
implicitHeight: 30
|
||||
implicitWidth: implicitHeight * 1.5
|
||||
|
||||
property bool maximized: false
|
||||
|
||||
ToolTip.visible: hovered && !down
|
||||
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
ToolTip.text: maximized ? qsTr("Restore") : qsTr("Maximize")
|
||||
ToolTip {
|
||||
visible: button.hovered && !button.down
|
||||
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
text: button.maximized ? qsTr("Restore") : qsTr("Maximize")
|
||||
}
|
||||
|
||||
contentItem: Image {
|
||||
anchors.fill: parent
|
||||
source: maximized ? "qrc:/images/button_restore_black.svg" : "qrc:/images/button_maximize_black.svg"
|
||||
contentItem: Item {
|
||||
implicitWidth: 16
|
||||
implicitHeight: implicitWidth
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
source: button.maximized ?
|
||||
(FramelessUtils.darkModeEnabled ? "qrc:/images/light/chrome-restore.svg" : "qrc:/images/dark/chrome-restore.svg") :
|
||||
(FramelessUtils.darkModeEnabled ? "qrc:/images/light/chrome-maximize.svg" : "qrc:/images/dark/chrome-maximize.svg")
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
visible: button.down || button.hovered
|
||||
color: button.down ? "#808080" : (button.hovered ? "#c7c7c7" : "transparent")
|
||||
visible: button.hovered
|
||||
color: "gray"
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,24 +24,33 @@
|
|||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
import org.wangwenx190.FramelessHelper 1.0
|
||||
|
||||
Button {
|
||||
id: button
|
||||
|
||||
implicitWidth: 45
|
||||
implicitHeight: 30
|
||||
implicitWidth: implicitHeight * 1.5
|
||||
|
||||
ToolTip.visible: hovered && !down
|
||||
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
ToolTip.text: qsTr("Minimize")
|
||||
ToolTip {
|
||||
visible: button.hovered && !button.down
|
||||
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
text: qsTr("Minimize")
|
||||
}
|
||||
|
||||
contentItem: Image {
|
||||
anchors.fill: parent
|
||||
source: "qrc:/images/button_minimize_black.svg"
|
||||
contentItem: Item {
|
||||
implicitWidth: 16
|
||||
implicitHeight: implicitWidth
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
source: FramelessUtils.darkModeEnabled ? "qrc:/images/light/chrome-minimize.svg" : "qrc:/images/dark/chrome-minimize.svg"
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
visible: button.down || button.hovered
|
||||
color: button.down ? "#808080" : (button.hovered ? "#c7c7c7" : "transparent")
|
||||
visible: button.hovered
|
||||
color: "gray"
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ add_executable(Widget WIN32 ${SOURCES})
|
|||
|
||||
target_link_libraries(Widget PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
wangwenx190::FramelessHelper
|
||||
FramelessHelper
|
||||
)
|
||||
|
||||
target_compile_definitions(Widget PRIVATE
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
static const QColor systemLightColor = QStringLiteral("#f0f0f0");
|
||||
static const QColor systemDarkColor = QColor::fromRgb(32, 32, 32);
|
||||
static const QColor systemDarkColor = QStringLiteral("#202020");
|
||||
|
||||
static const QString mainStyleSheet = QStringLiteral(R"(#MainWidget {
|
||||
background-color: %1;
|
||||
|
@ -132,7 +132,7 @@ void Widget::paintEvent(QPaintEvent *event)
|
|||
painter.save();
|
||||
QPen pen = {};
|
||||
pen.setColor(Utilities::getFrameBorderColor(isActiveWindow()));
|
||||
const int frameBorderThickness = Utilities::getFrameBorderThickness(winId(), false);
|
||||
const int frameBorderThickness = 1;
|
||||
pen.setWidth(frameBorderThickness);
|
||||
painter.setPen(pen);
|
||||
painter.drawLine(0, frameBorderThickness, width(), frameBorderThickness);
|
||||
|
@ -174,7 +174,7 @@ void Widget::initFramelessHelperOnce()
|
|||
|
||||
void Widget::setupUi()
|
||||
{
|
||||
const int titleBarHeight = /*Utilities::getTitleBarHeight(winId(), false)*/30;
|
||||
const int titleBarHeight = 30;
|
||||
const QSize systemButtonSize = {int(qRound(qreal(titleBarHeight) * 1.5)), titleBarHeight};
|
||||
const QSize systemIconSize = {16, 16};
|
||||
setObjectName(QStringLiteral("MainWidget"));
|
||||
|
@ -327,7 +327,7 @@ void Widget::resetContentsMargins()
|
|||
{
|
||||
#ifdef Q_OS_WIN
|
||||
if (Utilities::isWin10OrGreater()) {
|
||||
const int frameBorderThickness = Utilities::getFrameBorderThickness(winId(), false);
|
||||
const int frameBorderThickness = 1;
|
||||
setContentsMargins(0, frameBorderThickness, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -66,8 +66,7 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
|
|||
}
|
||||
const QEvent::Type type = event->type();
|
||||
// We are only interested in mouse events.
|
||||
if ((type != QEvent::MouseButtonDblClick) && (type != QEvent::MouseButtonPress)
|
||||
&& (type != QEvent::MouseMove)) {
|
||||
if ((type != QEvent::MouseButtonPress) && (type != QEvent::MouseMove)) {
|
||||
return false;
|
||||
}
|
||||
const auto window = qobject_cast<QWindow *>(object);
|
||||
|
|
|
@ -67,7 +67,7 @@ void FramelessHelperWin::addWindow(QWindow *window)
|
|||
qApp->installNativeEventFilter(g_helper()->instance.data());
|
||||
}
|
||||
const WId winId = window->winId();
|
||||
Utilities::fixupQtInternals(winId);
|
||||
//Utilities::fixupQtInternals(winId);
|
||||
Utilities::updateInternalWindowFrameMargins(window, true);
|
||||
Utilities::updateWindowFrameMargins(winId, false);
|
||||
const bool dark = Utilities::shouldAppsUseDarkMode();
|
||||
|
|
|
@ -23,85 +23,180 @@
|
|||
*/
|
||||
|
||||
#include "framelessquickhelper.h"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1))
|
||||
# include <QtGui/qpa/qplatformtheme.h>
|
||||
# include <QtGui/private/qguiapplication_p.h>
|
||||
#endif
|
||||
#include "framelesswindowsmanager.h"
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include "utilities.h"
|
||||
#ifdef Q_OS_WINDOWS
|
||||
#include "framelesshelper_windows.h"
|
||||
# include <QtCore/qt_windows.h>
|
||||
#endif
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent) : QQuickItem(parent)
|
||||
{
|
||||
}
|
||||
FramelessQuickHelper::FramelessQuickHelper(QObject *parent) : QObject(parent) {}
|
||||
|
||||
qreal FramelessQuickHelper::resizeBorderThickness() const
|
||||
{
|
||||
return FramelessWindowsManager::getResizeBorderThickness(window());
|
||||
}
|
||||
FramelessQuickHelper::~FramelessQuickHelper() = default;
|
||||
|
||||
void FramelessQuickHelper::setResizeBorderThickness(const qreal val)
|
||||
void FramelessQuickHelper::addWindow(QWindow *window)
|
||||
{
|
||||
FramelessWindowsManager::setResizeBorderThickness(window(), qRound(val));
|
||||
Q_EMIT resizeBorderThicknessChanged(val);
|
||||
}
|
||||
|
||||
qreal FramelessQuickHelper::titleBarHeight() const
|
||||
{
|
||||
return FramelessWindowsManager::getTitleBarHeight(window());
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::setTitleBarHeight(const qreal val)
|
||||
{
|
||||
FramelessWindowsManager::setTitleBarHeight(window(), qRound(val));
|
||||
Q_EMIT titleBarHeightChanged(val);
|
||||
}
|
||||
|
||||
bool FramelessQuickHelper::resizable() const
|
||||
{
|
||||
return FramelessWindowsManager::getResizable(window());
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::setResizable(const bool val)
|
||||
{
|
||||
FramelessWindowsManager::setResizable(window(), val);
|
||||
Q_EMIT resizableChanged(val);
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::removeWindowFrame()
|
||||
{
|
||||
FramelessWindowsManager::addWindow(window());
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::bringBackWindowFrame()
|
||||
{
|
||||
FramelessWindowsManager::removeWindow(window());
|
||||
}
|
||||
|
||||
bool FramelessQuickHelper::isWindowFrameless() const
|
||||
{
|
||||
return FramelessWindowsManager::isWindowFrameless(window());
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::setHitTestVisible(QQuickItem *item, const bool visible)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
if (!item) {
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
FramelessWindowsManager::setHitTestVisible(window(), item, visible);
|
||||
FramelessWindowsManager::addWindow(window);
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::showMinimized()
|
||||
void FramelessQuickHelper::removeWindow(QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
FramelessWindowsManager::removeWindow(window);
|
||||
}
|
||||
|
||||
FramelessQuickUtils::FramelessQuickUtils(QObject *parent) : QObject(parent)
|
||||
{
|
||||
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::themeChanged, this, [this](){
|
||||
Q_EMIT frameBorderActiveColorChanged();
|
||||
Q_EMIT frameBorderInactiveColorChanged();
|
||||
Q_EMIT darkModeEnabledChanged();
|
||||
Q_EMIT systemAccentColorChanged();
|
||||
Q_EMIT titleBarColorVisibleChanged();
|
||||
});
|
||||
}
|
||||
|
||||
FramelessQuickUtils::~FramelessQuickUtils() = default;
|
||||
|
||||
qreal FramelessQuickUtils::titleBarHeight()
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
|
||||
bool FramelessQuickUtils::frameBorderVisible()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
// Work-around a QtQuick bug: https://bugreports.qt.io/browse/QTBUG-69711
|
||||
// Don't use "SW_SHOWMINIMIZED" because it will activate the current
|
||||
// window instead of the next window in the Z order, that's not the
|
||||
// native behavior of Windows applications.
|
||||
ShowWindow(reinterpret_cast<HWND>(window()->winId()), SW_MINIMIZE);
|
||||
return (Utilities::isWin10OrGreater() && !Utilities::isWin11OrGreater());
|
||||
#else
|
||||
window()->showMinimized();
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
qreal FramelessQuickUtils::frameBorderThickness()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QColor FramelessQuickUtils::frameBorderActiveColor()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return Utilities::getFrameBorderColor(true);
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
QColor FramelessQuickUtils::frameBorderInactiveColor()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return Utilities::getFrameBorderColor(false);
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FramelessQuickUtils::darkModeEnabled()
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1))
|
||||
if (const QPlatformTheme * const theme = QGuiApplicationPrivate::platformTheme()) {
|
||||
return (theme->appearance() == QPlatformTheme::Appearance::Dark);
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
# ifdef Q_OS_WINDOWS
|
||||
return Utilities::shouldAppsUseDarkMode();
|
||||
# else
|
||||
return false;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
QColor FramelessQuickUtils::systemAccentColor()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return Utilities::getDwmColorizationColor();
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FramelessQuickUtils::titleBarColorVisible()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (!Utilities::isWin10OrGreater()) {
|
||||
return false;
|
||||
}
|
||||
const DwmColorizationArea area = Utilities::getDwmColorizationArea();
|
||||
return ((area == DwmColorizationArea::TitleBar_WindowBorder) || (area == DwmColorizationArea::All));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickUtils::showMinimized2(QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
// Work-around a QtQuick bug: https://bugreports.qt.io/browse/QTBUG-69711
|
||||
// Don't use "SW_SHOWMINIMIZED" because it will activate the current window
|
||||
// instead of the next window in the Z order, which is not the default behavior
|
||||
// of native Win32 applications.
|
||||
ShowWindow(reinterpret_cast<HWND>(window->winId()), SW_MINIMIZE);
|
||||
#else
|
||||
window->showMinimized();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickUtils::showSystemMenu(const QPointF &pos)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FramelessQuickUtils::startSystemMove2(QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
window->startSystemMove();
|
||||
#else
|
||||
# ifdef Q_OS_WINDOWS
|
||||
Utilities::startSystemMove(window);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickUtils::startSystemResize2(QWindow *window, const Qt::Edges edges)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
if (edges == Qt::Edges{}) {
|
||||
return;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
window->startSystemResize(edges);
|
||||
#else
|
||||
# ifdef Q_OS_WINDOWS
|
||||
Utilities::startSystemResize(window, edges);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -25,46 +25,72 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelper_global.h"
|
||||
#include <QtQuick/qquickitem.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtQml/qqmlregistration.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWindow;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class FRAMELESSHELPER_API FramelessQuickHelper : public QQuickItem
|
||||
class FRAMELESSHELPER_API FramelessQuickHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(FramelessQuickHelper)
|
||||
#ifdef QML_NAMED_ELEMENT
|
||||
QML_NAMED_ELEMENT(FramelessHelper)
|
||||
#endif
|
||||
Q_PROPERTY(qreal resizeBorderThickness READ resizeBorderThickness WRITE setResizeBorderThickness NOTIFY resizeBorderThicknessChanged)
|
||||
Q_PROPERTY(qreal titleBarHeight READ titleBarHeight WRITE setTitleBarHeight NOTIFY titleBarHeightChanged)
|
||||
Q_PROPERTY(bool resizable READ resizable WRITE setResizable NOTIFY resizableChanged)
|
||||
|
||||
public:
|
||||
explicit FramelessQuickHelper(QQuickItem *parent = nullptr);
|
||||
explicit FramelessQuickHelper(QObject *parent = nullptr);
|
||||
~FramelessQuickHelper() override;
|
||||
|
||||
Q_NODISCARD qreal resizeBorderThickness() const;
|
||||
void setResizeBorderThickness(const qreal val);
|
||||
Q_INVOKABLE static void addWindow(QWindow *window);
|
||||
Q_INVOKABLE static void removeWindow(QWindow *window);
|
||||
};
|
||||
|
||||
Q_NODISCARD qreal titleBarHeight() const;
|
||||
void setTitleBarHeight(const qreal val);
|
||||
class FRAMELESSHELPER_API FramelessQuickUtils : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(FramelessQuickUtils)
|
||||
#ifdef QML_NAMED_ELEMENT
|
||||
QML_NAMED_ELEMENT(FramelessUtils)
|
||||
#endif
|
||||
Q_PROPERTY(qreal titleBarHeight READ titleBarHeight CONSTANT FINAL)
|
||||
Q_PROPERTY(bool frameBorderVisible READ frameBorderVisible CONSTANT FINAL)
|
||||
Q_PROPERTY(qreal frameBorderThickness READ frameBorderThickness CONSTANT FINAL)
|
||||
Q_PROPERTY(QColor frameBorderActiveColor READ frameBorderActiveColor NOTIFY frameBorderActiveColorChanged FINAL)
|
||||
Q_PROPERTY(QColor frameBorderInactiveColor READ frameBorderInactiveColor NOTIFY frameBorderInactiveColorChanged FINAL)
|
||||
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_NODISCARD bool resizable() const;
|
||||
void setResizable(const bool val);
|
||||
public:
|
||||
explicit FramelessQuickUtils(QObject *parent = nullptr);
|
||||
~FramelessQuickUtils() override;
|
||||
|
||||
Q_NODISCARD Q_INVOKABLE bool isWindowFrameless() const;
|
||||
Q_NODISCARD static qreal titleBarHeight();
|
||||
Q_NODISCARD static bool frameBorderVisible();
|
||||
Q_NODISCARD static qreal frameBorderThickness();
|
||||
Q_NODISCARD static QColor frameBorderActiveColor();
|
||||
Q_NODISCARD static QColor frameBorderInactiveColor();
|
||||
Q_NODISCARD static bool darkModeEnabled();
|
||||
Q_NODISCARD static QColor systemAccentColor();
|
||||
Q_NODISCARD static bool titleBarColorVisible();
|
||||
|
||||
public Q_SLOTS:
|
||||
void removeWindowFrame();
|
||||
void bringBackWindowFrame();
|
||||
void setHitTestVisible(QQuickItem *item, const bool visible);
|
||||
void showMinimized();
|
||||
Q_INVOKABLE static void showMinimized2(QWindow *window);
|
||||
Q_INVOKABLE static void showSystemMenu(const QPointF &pos);
|
||||
Q_INVOKABLE static void startSystemMove2(QWindow *window);
|
||||
Q_INVOKABLE static void startSystemResize2(QWindow *window, const Qt::Edges edges);
|
||||
|
||||
Q_SIGNALS:
|
||||
void resizeBorderThicknessChanged(qreal);
|
||||
void titleBarHeightChanged(qreal);
|
||||
void resizableChanged(bool);
|
||||
void frameBorderActiveColorChanged();
|
||||
void frameBorderInactiveColorChanged();
|
||||
void darkModeEnabledChanged();
|
||||
void systemAccentColorChanged();
|
||||
void titleBarColorVisibleChanged();
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -158,20 +158,22 @@ void FramelessWindowsManager::addWindow(QWindow *window)
|
|||
g_managerPrivate()->qtFramelessHelpers.insert(uuid, qtFramelessHelper);
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
// Work-around Win32 multi-monitor artifacts.
|
||||
const QMetaObject::Connection workaroundConnection =
|
||||
if (!g_usePureQtImplementation) {
|
||||
// Work-around Win32 multi-monitor artifacts.
|
||||
const QMetaObject::Connection workaroundConnection =
|
||||
connect(window, &QWindow::screenChanged, window, [window](QScreen *screen){
|
||||
Q_UNUSED(screen);
|
||||
// Force a WM_NCCALCSIZE event to inform Windows about our custom window frame,
|
||||
// this is only necessary when the window is being moved cross monitors.
|
||||
Utilities::triggerFrameChange(window->winId());
|
||||
// For some reason the window is not repainted correctly when moving cross monitors,
|
||||
// we workaround this issue by force a re-paint and re-layout of the window by triggering
|
||||
// a resize event manually. Although the actual size does not change, the issue we
|
||||
// observed disappeared indeed, amazingly.
|
||||
window->resize(window->size());
|
||||
});
|
||||
g_managerPrivate()->win32WorkaroundConnections.insert(uuid, workaroundConnection);
|
||||
Q_UNUSED(screen);
|
||||
// Force a WM_NCCALCSIZE event to inform Windows about our custom window frame,
|
||||
// this is only necessary when the window is being moved cross monitors.
|
||||
Utilities::triggerFrameChange(window->winId());
|
||||
// For some reason the window is not repainted correctly when moving cross monitors,
|
||||
// we workaround this issue by force a re-paint and re-layout of the window by triggering
|
||||
// a resize event manually. Although the actual size does not change, the issue we
|
||||
// observed disappeared indeed, amazingly.
|
||||
window->resize(window->size());
|
||||
});
|
||||
g_managerPrivate()->win32WorkaroundConnections.insert(uuid, workaroundConnection);
|
||||
}
|
||||
#endif
|
||||
g_managerPrivate()->mutex.unlock();
|
||||
if (g_usePureQtImplementation) {
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
|
||||
Q_SIGNALS:
|
||||
void themeChanged();
|
||||
void systemMenuRequested(const QPointF &);
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
Loading…
Reference in New Issue