forked from github_mirror/framelesshelper
Improve the widget example
Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
parent
a5a5942d80
commit
d64b38a8db
|
@ -27,13 +27,54 @@
|
||||||
#include <QtWidgets/qlabel.h>
|
#include <QtWidgets/qlabel.h>
|
||||||
#include <QtCore/qdatetime.h>
|
#include <QtCore/qdatetime.h>
|
||||||
#include <QtWidgets/qpushbutton.h>
|
#include <QtWidgets/qpushbutton.h>
|
||||||
#include <QtGui/qguiapplication.h>
|
|
||||||
#include <QtGui/qpainter.h>
|
#include <QtGui/qpainter.h>
|
||||||
#include "../../utilities.h"
|
#include "../../utilities.h"
|
||||||
#include "../../framelesswindowsmanager.h"
|
#include "../../framelesswindowsmanager.h"
|
||||||
|
|
||||||
FRAMELESSHELPER_USE_NAMESPACE
|
FRAMELESSHELPER_USE_NAMESPACE
|
||||||
|
|
||||||
|
static const QColor systemLightColor = QStringLiteral("#f0f0f0");
|
||||||
|
static const QColor systemDarkColor = QColor::fromRgb(32, 32, 32);
|
||||||
|
|
||||||
|
static constexpr char mainStyleSheet[] = R"(
|
||||||
|
#MainWidget {
|
||||||
|
background-color: %1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#TitleBarWidget {
|
||||||
|
background-color: %2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#WindowTitleLabel {
|
||||||
|
color: %3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MinimizeButton, #MaximizeButton, #CloseButton {
|
||||||
|
border-style: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MinimizeButton:hover, #MaximizeButton:hover {
|
||||||
|
background-color: #c7c7c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
#MinimizeButton:pressed, #MaximizeButton:pressed {
|
||||||
|
background-color: #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
#CloseButton:hover {
|
||||||
|
background-color: #e81123;
|
||||||
|
}
|
||||||
|
|
||||||
|
#CloseButton:pressed {
|
||||||
|
background-color: #8c0a15;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ClockLabel {
|
||||||
|
color: %4;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
Widget::Widget(QWidget *parent) : QWidget(parent)
|
Widget::Widget(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_DontCreateNativeAncestors);
|
setAttribute(Qt::WA_DontCreateNativeAncestors);
|
||||||
|
@ -49,20 +90,28 @@ void Widget::showEvent(QShowEvent *event)
|
||||||
QWidget::showEvent(event);
|
QWidget::showEvent(event);
|
||||||
static bool inited = false;
|
static bool inited = false;
|
||||||
if (!inited) {
|
if (!inited) {
|
||||||
|
inited = true;
|
||||||
QWindow *win = windowHandle();
|
QWindow *win = windowHandle();
|
||||||
|
Q_ASSERT(win);
|
||||||
|
if (!win) {
|
||||||
|
qFatal("Failed to retrieve the window handle.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
FramelessWindowsManager::addWindow(win);
|
FramelessWindowsManager::addWindow(win);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_minimizeButton, true);
|
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_minimizeButton, true);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_maximizeButton, true);
|
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_maximizeButton, true);
|
||||||
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_closeButton, true);
|
FramelessWindowsManager::setHitTestVisibleInChrome(win, m_closeButton, true);
|
||||||
setContentsMargins(1, 1, 1, 1);
|
const int margin = Utilities::getWindowVisibleFrameBorderThickness(winId());
|
||||||
inited = true;
|
setContentsMargins(margin, margin, margin, margin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::timerEvent(QTimerEvent *event)
|
void Widget::timerEvent(QTimerEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::timerEvent(event);
|
QWidget::timerEvent(event);
|
||||||
m_label->setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss")));
|
if (m_clockLabel) {
|
||||||
|
m_clockLabel->setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::changeEvent(QEvent *event)
|
void Widget::changeEvent(QEvent *event)
|
||||||
|
@ -70,42 +119,45 @@ void Widget::changeEvent(QEvent *event)
|
||||||
QWidget::changeEvent(event);
|
QWidget::changeEvent(event);
|
||||||
bool shouldUpdate = false;
|
bool shouldUpdate = false;
|
||||||
if (event->type() == QEvent::WindowStateChange) {
|
if (event->type() == QEvent::WindowStateChange) {
|
||||||
if (isMaximized() || isFullScreen()) {
|
const int margin = ((isMaximized() || isFullScreen()) ? 0 : Utilities::getWindowVisibleFrameBorderThickness(winId()));
|
||||||
setContentsMargins(0, 0, 0, 0);
|
setContentsMargins(margin, margin, margin, margin);
|
||||||
m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_restore_black.svg")});
|
updateSystemButtonIcons();
|
||||||
} else if (!isMinimized()) {
|
updateTitleBarSize();
|
||||||
setContentsMargins(1, 1, 1, 1);
|
|
||||||
m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_maximize_black.svg")});
|
|
||||||
}
|
|
||||||
shouldUpdate = true;
|
shouldUpdate = true;
|
||||||
} else if (event->type() == QEvent::ActivationChange) {
|
} else if (event->type() == QEvent::ActivationChange) {
|
||||||
shouldUpdate = true;
|
shouldUpdate = true;
|
||||||
}
|
}
|
||||||
if (shouldUpdate) {
|
if (shouldUpdate) {
|
||||||
update();
|
updateStyleSheet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::paintEvent(QPaintEvent *event)
|
void Widget::paintEvent(QPaintEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::paintEvent(event);
|
QWidget::paintEvent(event);
|
||||||
if (windowState() == Qt::WindowNoState) {
|
if (!isMaximized() && !isFullScreen()) {
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
const int w = width();
|
painter.save();
|
||||||
const int h = height();
|
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||||
|
const auto w = static_cast<qreal>(width());
|
||||||
|
const auto h = static_cast<qreal>(height());
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
using BorderLines = QList<QLine>;
|
using BorderLines = QList<QLineF>;
|
||||||
#else
|
#else
|
||||||
using BorderLines = QVector<QLine>;
|
using BorderLines = QVector<QLineF>;
|
||||||
#endif
|
#endif
|
||||||
const BorderLines lines = {
|
const BorderLines lines = {
|
||||||
{0, 0, w, 0},
|
{0, 0, w, 0},
|
||||||
{w - 1, 0, w - 1, h},
|
{w, 0, w , h},
|
||||||
{w, h - 1, 0, h - 1},
|
{w, h, 0, h},
|
||||||
{0, h, 0, 0}
|
{0, h, 0, 0}
|
||||||
};
|
};
|
||||||
painter.save();
|
const ColorizationArea area = Utilities::getColorizationArea();
|
||||||
painter.setPen({isActiveWindow() ? Qt::black : Qt::darkGray, 1});
|
const bool colorizedBorder = ((area == ColorizationArea::TitleBar_WindowBorder)
|
||||||
|
|| (area == ColorizationArea::All));
|
||||||
|
const QColor borderColor = (isActiveWindow() ? (colorizedBorder ? Utilities::getColorizationColor() : Qt::black) : Qt::darkGray);
|
||||||
|
const auto borderThickness = static_cast<qreal>(Utilities::getWindowVisibleFrameBorderThickness(winId()));
|
||||||
|
painter.setPen({borderColor, qMax(borderThickness, devicePixelRatioF())});
|
||||||
painter.drawLines(lines);
|
painter.drawLines(lines);
|
||||||
painter.restore();
|
painter.restore();
|
||||||
}
|
}
|
||||||
|
@ -113,82 +165,163 @@ void Widget::paintEvent(QPaintEvent *event)
|
||||||
|
|
||||||
void Widget::setupUi()
|
void Widget::setupUi()
|
||||||
{
|
{
|
||||||
|
setObjectName(QStringLiteral("MainWidget"));
|
||||||
setWindowTitle(tr("Hello, World!"));
|
setWindowTitle(tr("Hello, World!"));
|
||||||
resize(800, 600);
|
resize(800, 600);
|
||||||
const QWindow *win = windowHandle();
|
m_titleBarWidget = new QWidget(this);
|
||||||
const int titleBarHeight = Utilities::getSystemMetric(win, SystemMetric::TitleBarHeight, false);
|
m_titleBarWidget->setObjectName(QStringLiteral("TitleBarWidget"));
|
||||||
const QSize systemButtonSize = {qRound(static_cast<qreal>(titleBarHeight) * 1.5), titleBarHeight};
|
m_titleBarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
m_minimizeButton = new QPushButton(this);
|
m_windowTitleLabel = new QLabel(m_titleBarWidget);
|
||||||
|
m_windowTitleLabel->setObjectName(QStringLiteral("WindowTitleLabel"));
|
||||||
|
m_windowTitleLabel->setFrameShape(QFrame::NoFrame);
|
||||||
|
QFont titleFont = font();
|
||||||
|
titleFont.setPointSize(11);
|
||||||
|
m_windowTitleLabel->setFont(titleFont);
|
||||||
|
m_windowTitleLabel->setText(windowTitle());
|
||||||
|
connect(this, &Widget::windowTitleChanged, m_windowTitleLabel, &QLabel::setText);
|
||||||
|
m_minimizeButton = new QPushButton(m_titleBarWidget);
|
||||||
m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton"));
|
m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton"));
|
||||||
m_minimizeButton->setFixedSize(systemButtonSize);
|
|
||||||
m_minimizeButton->setIcon(QIcon{QStringLiteral(":/images/button_minimize_black.svg")});
|
|
||||||
m_minimizeButton->setIconSize(systemButtonSize);
|
|
||||||
connect(m_minimizeButton, &QPushButton::clicked, this, &Widget::showMinimized);
|
connect(m_minimizeButton, &QPushButton::clicked, this, &Widget::showMinimized);
|
||||||
m_maximizeButton = new QPushButton(this);
|
m_maximizeButton = new QPushButton(m_titleBarWidget);
|
||||||
m_maximizeButton->setObjectName(QStringLiteral("MaximizeButton"));
|
m_maximizeButton->setObjectName(QStringLiteral("MaximizeButton"));
|
||||||
m_maximizeButton->setFixedSize(systemButtonSize);
|
|
||||||
m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_maximize_black.svg")});
|
|
||||||
m_maximizeButton->setIconSize(systemButtonSize);
|
|
||||||
connect(m_maximizeButton, &QPushButton::clicked, this, [this](){
|
connect(m_maximizeButton, &QPushButton::clicked, this, [this](){
|
||||||
if (isMaximized() || isFullScreen()) {
|
if (isMaximized() || isFullScreen()) {
|
||||||
showNormal();
|
showNormal();
|
||||||
m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_maximize_black.svg")});
|
|
||||||
} else {
|
} else {
|
||||||
showMaximized();
|
showMaximized();
|
||||||
m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_restore_black.svg")});
|
|
||||||
}
|
}
|
||||||
|
updateSystemButtonIcons();
|
||||||
});
|
});
|
||||||
m_closeButton = new QPushButton(this);
|
m_closeButton = new QPushButton(m_titleBarWidget);
|
||||||
m_closeButton->setObjectName(QStringLiteral("CloseButton"));
|
m_closeButton->setObjectName(QStringLiteral("CloseButton"));
|
||||||
m_closeButton->setFixedSize(systemButtonSize);
|
|
||||||
m_closeButton->setIcon(QIcon{QStringLiteral(":/images/button_close_black.svg")});
|
|
||||||
m_closeButton->setIconSize(systemButtonSize);
|
|
||||||
connect(m_closeButton, &QPushButton::clicked, this, &Widget::close);
|
connect(m_closeButton, &QPushButton::clicked, this, &Widget::close);
|
||||||
const auto systemButtonLayout = new QHBoxLayout;
|
updateSystemButtonIcons();
|
||||||
systemButtonLayout->setContentsMargins(0, 0, 0, 0);
|
updateTitleBarSize();
|
||||||
systemButtonLayout->setSpacing(0);
|
const auto titleBarLayout = new QHBoxLayout(m_titleBarWidget);
|
||||||
systemButtonLayout->addStretch();
|
titleBarLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
systemButtonLayout->addWidget(m_minimizeButton);
|
titleBarLayout->setSpacing(0);
|
||||||
systemButtonLayout->addWidget(m_maximizeButton);
|
titleBarLayout->addSpacerItem(new QSpacerItem(10, 10));
|
||||||
systemButtonLayout->addWidget(m_closeButton);
|
titleBarLayout->addWidget(m_windowTitleLabel);
|
||||||
m_label = new QLabel(this);
|
titleBarLayout->addStretch();
|
||||||
QFont font = QGuiApplication::font();
|
titleBarLayout->addWidget(m_minimizeButton);
|
||||||
font.setBold(true);
|
titleBarLayout->addWidget(m_maximizeButton);
|
||||||
font.setPointSize(70);
|
titleBarLayout->addWidget(m_closeButton);
|
||||||
m_label->setFont(font);
|
m_titleBarWidget->setLayout(titleBarLayout);
|
||||||
m_label->setFrameShape(QFrame::NoFrame);
|
m_clockLabel = new QLabel(this);
|
||||||
|
m_clockLabel->setObjectName(QStringLiteral("ClockLabel"));
|
||||||
|
m_clockLabel->setFrameShape(QFrame::NoFrame);
|
||||||
|
QFont clockFont = font();
|
||||||
|
clockFont.setBold(true);
|
||||||
|
clockFont.setPointSize(70);
|
||||||
|
m_clockLabel->setFont(clockFont);
|
||||||
const auto contentLayout = new QHBoxLayout;
|
const auto contentLayout = new QHBoxLayout;
|
||||||
|
contentLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
contentLayout->setSpacing(0);
|
||||||
contentLayout->addStretch();
|
contentLayout->addStretch();
|
||||||
contentLayout->addWidget(m_label);
|
contentLayout->addWidget(m_clockLabel);
|
||||||
contentLayout->addStretch();
|
contentLayout->addStretch();
|
||||||
const auto mainLayout = new QVBoxLayout(this);
|
const auto mainLayout = new QVBoxLayout(this);
|
||||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
mainLayout->setSpacing(0);
|
mainLayout->setSpacing(0);
|
||||||
mainLayout->addLayout(systemButtonLayout);
|
mainLayout->addWidget(m_titleBarWidget);
|
||||||
mainLayout->addStretch();
|
mainLayout->addStretch();
|
||||||
mainLayout->addLayout(contentLayout);
|
mainLayout->addLayout(contentLayout);
|
||||||
mainLayout->addStretch();
|
mainLayout->addStretch();
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
setStyleSheet(QStringLiteral(R"(
|
updateStyleSheet();
|
||||||
#MinimizeButton, #MaximizeButton, #CloseButton {
|
|
||||||
border-style: none;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#MinimizeButton:hover, #MaximizeButton:hover {
|
void Widget::updateStyleSheet()
|
||||||
background-color: #80c7c7c7;
|
{
|
||||||
|
const bool active = isActiveWindow();
|
||||||
|
const bool dark = Utilities::shouldAppsUseDarkMode();
|
||||||
|
const ColorizationArea area = Utilities::getColorizationArea();
|
||||||
|
const bool colorizedTitleBar = ((area == ColorizationArea::TitleBar_WindowBorder)
|
||||||
|
|| (area == ColorizationArea::All));
|
||||||
|
const QColor colorizationColor = Utilities::getColorizationColor();
|
||||||
|
const QColor mainWidgetBackgroundColor = (dark ? systemDarkColor : systemLightColor);
|
||||||
|
const QColor titleBarWidgetBackgroundColor = [active, colorizedTitleBar, &colorizationColor, dark]{
|
||||||
|
if (active) {
|
||||||
|
if (colorizedTitleBar) {
|
||||||
|
return colorizationColor;
|
||||||
|
} else {
|
||||||
|
if (dark) {
|
||||||
|
return QColor(Qt::black);
|
||||||
|
} else {
|
||||||
|
return QColor(Qt::white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dark) {
|
||||||
|
return systemDarkColor;
|
||||||
|
} else {
|
||||||
|
return QColor(Qt::white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
const QColor windowTitleLabelTextColor = (active ? (dark ? Qt::white : Qt::black) : Qt::darkGray);
|
||||||
|
const QColor clockLabelTextColor = (dark ? Qt::white : Qt::black);
|
||||||
|
setStyleSheet(QString::fromUtf8(mainStyleSheet)
|
||||||
|
.arg(mainWidgetBackgroundColor.name(),
|
||||||
|
titleBarWidgetBackgroundColor.name(),
|
||||||
|
windowTitleLabelTextColor.name(),
|
||||||
|
clockLabelTextColor.name()));
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
#MinimizeButton:pressed, #MaximizeButton:pressed {
|
void Widget::updateTitleBarSize()
|
||||||
background-color: #80808080;
|
{
|
||||||
|
const QWindow *win = windowHandle();
|
||||||
|
Q_ASSERT(win);
|
||||||
|
if (!win) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const int titleBarHeight = Utilities::getSystemMetric(win, SystemMetric::TitleBarHeight, false);
|
||||||
|
const QSize systemButtonSize = {qRound(static_cast<qreal>(titleBarHeight) * 1.5), titleBarHeight};
|
||||||
|
m_minimizeButton->setFixedSize(systemButtonSize);
|
||||||
|
m_minimizeButton->setIconSize(systemButtonSize);
|
||||||
|
m_maximizeButton->setFixedSize(systemButtonSize);
|
||||||
|
m_maximizeButton->setIconSize(systemButtonSize);
|
||||||
|
m_closeButton->setFixedSize(systemButtonSize);
|
||||||
|
m_closeButton->setIconSize(systemButtonSize);
|
||||||
|
m_titleBarWidget->setFixedHeight(titleBarHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
#CloseButton:hover {
|
void Widget::updateSystemButtonIcons()
|
||||||
background-color: #e81123;
|
{
|
||||||
|
Q_ASSERT(m_minimizeButton);
|
||||||
|
Q_ASSERT(m_maximizeButton);
|
||||||
|
Q_ASSERT(m_closeButton);
|
||||||
|
if (!m_minimizeButton || !m_maximizeButton || !m_closeButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QString suffix = (Utilities::shouldAppsUseDarkMode() ? QStringLiteral("white") : QStringLiteral("black"));
|
||||||
|
m_minimizeButton->setIcon(QIcon(QStringLiteral(":/images/button_minimize_%1.svg").arg(suffix)));
|
||||||
|
if (isMaximized() || isFullScreen()) {
|
||||||
|
m_maximizeButton->setIcon(QIcon(QStringLiteral(":/images/button_restore_%1.svg").arg(suffix)));
|
||||||
|
} else {
|
||||||
|
m_maximizeButton->setIcon(QIcon(QStringLiteral(":/images/button_maximize_%1.svg").arg(suffix)));
|
||||||
|
}
|
||||||
|
m_closeButton->setIcon(QIcon(QStringLiteral(":/images/button_close_%1.svg").arg(suffix)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#CloseButton:pressed {
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
background-color: #8c0a15;
|
bool Widget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
|
||||||
}
|
#else
|
||||||
)"));
|
bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (message) {
|
||||||
|
if (Utilities::isThemeChanged(message)) {
|
||||||
|
updateStyleSheet();
|
||||||
|
updateSystemButtonIcons();
|
||||||
|
}
|
||||||
|
QPointF pos = {};
|
||||||
|
if (Utilities::isSystemMenuRequested(message, &pos)) {
|
||||||
|
if (!Utilities::showSystemMenu(winId(), pos)) {
|
||||||
|
qWarning() << "Failed to display the system menu.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QWidget::nativeEvent(eventType, message, result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,13 +44,23 @@ protected:
|
||||||
void timerEvent(QTimerEvent *event) override;
|
void timerEvent(QTimerEvent *event) override;
|
||||||
void changeEvent(QEvent *event) override;
|
void changeEvent(QEvent *event) override;
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
|
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override;
|
||||||
|
#else
|
||||||
|
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUi();
|
void setupUi();
|
||||||
|
void updateStyleSheet();
|
||||||
|
void updateTitleBarSize();
|
||||||
|
void updateSystemButtonIcons();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *m_label = nullptr;
|
QWidget *m_titleBarWidget = nullptr;
|
||||||
|
QLabel *m_windowTitleLabel = nullptr;
|
||||||
QPushButton *m_minimizeButton = nullptr;
|
QPushButton *m_minimizeButton = nullptr;
|
||||||
QPushButton *m_maximizeButton = nullptr;
|
QPushButton *m_maximizeButton = nullptr;
|
||||||
QPushButton *m_closeButton = nullptr;
|
QPushButton *m_closeButton = nullptr;
|
||||||
|
QLabel *m_clockLabel = nullptr;
|
||||||
};
|
};
|
||||||
|
|
15
utilities.h
15
utilities.h
|
@ -38,6 +38,15 @@ namespace Utilities
|
||||||
[[nodiscard]] FRAMELESSHELPER_API bool isWindowFixedSize(const QWindow *window);
|
[[nodiscard]] FRAMELESSHELPER_API bool isWindowFixedSize(const QWindow *window);
|
||||||
[[nodiscard]] FRAMELESSHELPER_API bool isHitTestVisibleInChrome(const QWindow *window);
|
[[nodiscard]] FRAMELESSHELPER_API bool isHitTestVisibleInChrome(const QWindow *window);
|
||||||
[[nodiscard]] FRAMELESSHELPER_API QPointF mapOriginPointToWindow(const QObject *object);
|
[[nodiscard]] FRAMELESSHELPER_API QPointF mapOriginPointToWindow(const QObject *object);
|
||||||
|
[[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor();
|
||||||
|
[[nodiscard]] FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const WId winId);
|
||||||
|
[[nodiscard]] FRAMELESSHELPER_API bool shouldAppsUseDarkMode();
|
||||||
|
[[nodiscard]] FRAMELESSHELPER_API bool isHighContrastModeEnabled();
|
||||||
|
[[nodiscard]] FRAMELESSHELPER_API ColorizationArea getColorizationArea();
|
||||||
|
[[nodiscard]] FRAMELESSHELPER_API bool isWindowDarkFrameBorderEnabled(const WId winId);
|
||||||
|
[[nodiscard]] FRAMELESSHELPER_API bool isThemeChanged(const void *data);
|
||||||
|
[[nodiscard]] FRAMELESSHELPER_API bool isSystemMenuRequested(const void *data, QPointF *pos);
|
||||||
|
[[nodiscard]] FRAMELESSHELPER_API bool showSystemMenu(const WId winId, const QPointF &pos);
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
[[nodiscard]] FRAMELESSHELPER_API bool isWin8OrGreater();
|
[[nodiscard]] FRAMELESSHELPER_API bool isWin8OrGreater();
|
||||||
|
@ -48,12 +57,6 @@ FRAMELESSHELPER_API void triggerFrameChange(const WId winId);
|
||||||
FRAMELESSHELPER_API void updateFrameMargins(const WId winId, const bool reset);
|
FRAMELESSHELPER_API void updateFrameMargins(const WId winId, const bool reset);
|
||||||
FRAMELESSHELPER_API void updateQtFrameMargins(QWindow *window, const bool enable);
|
FRAMELESSHELPER_API void updateQtFrameMargins(QWindow *window, const bool enable);
|
||||||
[[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function, const HRESULT hr);
|
[[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function, const HRESULT hr);
|
||||||
[[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor();
|
|
||||||
[[nodiscard]] FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const QWindow *window);
|
|
||||||
[[nodiscard]] FRAMELESSHELPER_API bool shouldAppsUseDarkMode();
|
|
||||||
[[nodiscard]] FRAMELESSHELPER_API bool isHighContrastModeEnabled();
|
|
||||||
[[nodiscard]] FRAMELESSHELPER_API ColorizationArea getColorizationArea();
|
|
||||||
[[nodiscard]] FRAMELESSHELPER_API bool isWindowDarkFrameBorderEnabled(const WId winId);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,31 @@
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QMargins)
|
Q_DECLARE_METATYPE(QMargins)
|
||||||
|
|
||||||
|
#ifndef GET_X_LPARAM
|
||||||
|
// Only available since Windows 2000
|
||||||
|
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GET_Y_LPARAM
|
||||||
|
// Only available since Windows 2000
|
||||||
|
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IsMaximized
|
||||||
|
// Only available since Windows 2000
|
||||||
|
#define IsMaximized(window) (IsZoomed(window) != FALSE)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SM_CXPADDEDBORDER
|
#ifndef SM_CXPADDEDBORDER
|
||||||
// Only available since Windows Vista
|
// Only available since Windows Vista
|
||||||
#define SM_CXPADDEDBORDER (92)
|
#define SM_CXPADDEDBORDER (92)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef WM_DWMCOLORIZATIONCOLORCHANGED
|
||||||
|
// Only available since Windows Vista
|
||||||
|
#define WM_DWMCOLORIZATIONCOLORCHANGED (0x0320)
|
||||||
|
#endif
|
||||||
|
|
||||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||||
|
|
||||||
static constexpr char kDwmRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)";
|
static constexpr char kDwmRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)";
|
||||||
|
@ -310,16 +330,16 @@ QColor Utilities::getColorizationColor()
|
||||||
return QColor::fromRgba(color);
|
return QColor::fromRgba(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Utilities::getWindowVisibleFrameBorderThickness(const QWindow *window)
|
int Utilities::getWindowVisibleFrameBorderThickness(const WId winId)
|
||||||
{
|
{
|
||||||
Q_ASSERT(window);
|
Q_ASSERT(winId);
|
||||||
if (!window) {
|
if (!winId) {
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!isWin10OrGreater()) {
|
if (!isWin10OrGreater()) {
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
const auto hWnd = reinterpret_cast<HWND>(window->winId());
|
const auto hWnd = reinterpret_cast<HWND>(winId);
|
||||||
UINT value = 0;
|
UINT value = 0;
|
||||||
const HRESULT hr = DwmGetWindowAttribute(hWnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value));
|
const HRESULT hr = DwmGetWindowAttribute(hWnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value));
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
|
@ -329,9 +349,7 @@ int Utilities::getWindowVisibleFrameBorderThickness(const QWindow *window)
|
||||||
// late Windows 10 version, so querying it's value will always result in
|
// late Windows 10 version, so querying it's value will always result in
|
||||||
// a "parameter error" (code: 87) on systems before that value was introduced.
|
// a "parameter error" (code: 87) on systems before that value was introduced.
|
||||||
}
|
}
|
||||||
const bool max = (window->windowState() == Qt::WindowMaximized);
|
return 1;
|
||||||
const bool full = (window->windowState() == Qt::WindowFullScreen);
|
|
||||||
return ((max || full) ? 0 : qRound(1.0 * window->devicePixelRatio()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Utilities::shouldAppsUseDarkMode()
|
bool Utilities::shouldAppsUseDarkMode()
|
||||||
|
@ -443,4 +461,117 @@ bool Utilities::isWindowDarkFrameBorderEnabled(const WId winId)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Utilities::isThemeChanged(const void *data)
|
||||||
|
{
|
||||||
|
Q_ASSERT(data);
|
||||||
|
if (!data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto msg = static_cast<const MSG *>(data);
|
||||||
|
if (msg->message == WM_THEMECHANGED) {
|
||||||
|
return true;
|
||||||
|
} else if (msg->message == WM_DWMCOLORIZATIONCOLORCHANGED) {
|
||||||
|
return true;
|
||||||
|
} else if (msg->message == WM_SETTINGCHANGE) {
|
||||||
|
if ((msg->wParam == 0) && (_wcsicmp(reinterpret_cast<LPCWSTR>(msg->lParam), L"ImmersiveColorSet") == 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Utilities::isSystemMenuRequested(const void *data, QPointF *pos)
|
||||||
|
{
|
||||||
|
Q_ASSERT(data);
|
||||||
|
if (!data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto msg = static_cast<const MSG *>(data);
|
||||||
|
if (msg->message == WM_NCRBUTTONUP) {
|
||||||
|
if (msg->wParam == HTCAPTION) {
|
||||||
|
if (pos) {
|
||||||
|
const POINT nativePos = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
|
||||||
|
*pos = QPointF(static_cast<qreal>(nativePos.x), static_cast<qreal>(nativePos.y));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Utilities::showSystemMenu(const WId winId, const QPointF &pos)
|
||||||
|
{
|
||||||
|
Q_ASSERT(winId);
|
||||||
|
if (!winId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto hWnd = reinterpret_cast<HWND>(winId);
|
||||||
|
const HMENU menu = GetSystemMenu(hWnd, FALSE);
|
||||||
|
if (!menu) {
|
||||||
|
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
qWarning() << getSystemErrorMessage(QStringLiteral("GetSystemMenu"), hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Update the options based on window state.
|
||||||
|
MENUITEMINFOW mii;
|
||||||
|
SecureZeroMemory(&mii, sizeof(mii));
|
||||||
|
mii.cbSize = sizeof(mii);
|
||||||
|
mii.fMask = MIIM_STATE;
|
||||||
|
mii.fType = MFT_STRING;
|
||||||
|
const auto setState = [&mii, menu](const UINT item, const bool enabled) -> bool {
|
||||||
|
mii.fState = (enabled ? MF_ENABLED : MF_DISABLED);
|
||||||
|
return (SetMenuItemInfoW(menu, item, FALSE, &mii) != FALSE);
|
||||||
|
};
|
||||||
|
const bool max = IsMaximized(hWnd);
|
||||||
|
if (!setState(SC_RESTORE, max)) {
|
||||||
|
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!setState(SC_MOVE, !max)) {
|
||||||
|
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!setState(SC_SIZE, !max)) {
|
||||||
|
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!setState(SC_MINIMIZE, true)) {
|
||||||
|
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!setState(SC_MAXIMIZE, !max)) {
|
||||||
|
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!setState(SC_CLOSE, true)) {
|
||||||
|
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (SetMenuDefaultItem(menu, UINT_MAX, FALSE) == FALSE) {
|
||||||
|
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuDefaultItem"), hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const QPoint roundedPos = pos.toPoint();
|
||||||
|
UINT flags = TPM_RETURNCMD;
|
||||||
|
if (QGuiApplication::isRightToLeft()) {
|
||||||
|
flags |= TPM_LAYOUTRTL;
|
||||||
|
}
|
||||||
|
const auto ret = TrackPopupMenu(menu, flags, roundedPos.x(), roundedPos.y(), 0, hWnd, nullptr);
|
||||||
|
if (ret != 0) {
|
||||||
|
if (PostMessageW(hWnd, WM_SYSCOMMAND, ret, 0) == FALSE) {
|
||||||
|
const HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW"), hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
FRAMELESSHELPER_END_NAMESPACE
|
FRAMELESSHELPER_END_NAMESPACE
|
||||||
|
|
Loading…
Reference in New Issue