Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-03-11 21:57:24 +08:00
parent 0ce352ff22
commit 01ad24aae1
20 changed files with 131 additions and 97 deletions

View File

@ -1,12 +1,12 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>images/button_minimize_black.svg</file> <file>images/dark/chrome-close.svg</file>
<file>images/button_minimize_white.svg</file> <file>images/dark/chrome-maximize.svg</file>
<file>images/button_maximize_black.svg</file> <file>images/dark/chrome-minimize.svg</file>
<file>images/button_maximize_white.svg</file> <file>images/dark/chrome-restore.svg</file>
<file>images/button_restore_black.svg</file> <file>images/light/chrome-close.svg</file>
<file>images/button_restore_white.svg</file> <file>images/light/chrome-maximize.svg</file>
<file>images/button_close_black.svg</file> <file>images/light/chrome-minimize.svg</file>
<file>images/button_close_white.svg</file> <file>images/light/chrome-restore.svg</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -1,5 +0,0 @@
All the SVG images in this folder are created by me, using Inkscape. No images are downloaded from the Internet, not even one pixel.
Since I copied the screenshot (when the scale factor is 1.0) pixel by pixel, they should be exactly the same with the real system buttons, in theory.
Anyone can use them freely.

View File

@ -1,6 +0,0 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="#000" stroke-width=".17639">
<path d="m6.1295 3.6601 3.2632 3.2632z"/>
<path d="m9.3927 3.6601-3.2632 3.2632z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 264 B

View File

@ -1,6 +0,0 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="#fff" stroke-width=".17639">
<path d="m6.1295 3.6601 3.2632 3.2632z"/>
<path d="m9.3927 3.6601-3.2632 3.2632z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 264 B

View File

@ -1,3 +0,0 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<rect x="6.1736" y="3.7042" width="3.175" height="3.175" fill="none" stroke="#000" stroke-width=".35278"/>
</svg>

Before

Width:  |  Height:  |  Size: 225 B

View File

@ -1,3 +0,0 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<rect x="6.1736" y="3.7042" width="3.175" height="3.175" fill="none" stroke="#fff" stroke-width=".35278"/>
</svg>

Before

Width:  |  Height:  |  Size: 225 B

View File

@ -1,3 +0,0 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<path d="m6.35 5.4681h3.5278z" fill="none" stroke="#000" stroke-width=".35278"/>
</svg>

Before

Width:  |  Height:  |  Size: 199 B

View File

@ -1,3 +0,0 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<path d="m6.35 5.4681h3.5278z" fill="none" stroke="#fff" stroke-width=".35278"/>
</svg>

Before

Width:  |  Height:  |  Size: 199 B

View File

@ -1,11 +0,0 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="#000">
<rect x="6.1736" y="4.4097" width="2.4694" height="2.4694" stroke-width=".35278"/>
<g stroke-width=".35278">
<path d="m6.8792 4.2333v-0.70556z"/>
<path d="m7.0556 3.7042h2.4694z"/>
<path d="m9.3486 3.8806v2.4694z"/>
<path d="m9.1722 6.1736h-0.35278z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 430 B

View File

@ -1,11 +0,0 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="#fff">
<rect x="6.1736" y="4.4097" width="2.4694" height="2.4694" stroke-width=".35278"/>
<g stroke-width=".35278">
<path d="m6.8792 4.2333v-0.70556z"/>
<path d="m7.0556 3.7042h2.4694z"/>
<path d="m9.3486 3.8806v2.4694z"/>
<path d="m9.1722 6.1736h-0.35278z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 430 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.11641 7.99992L2.55835 12.558L3.44223 13.4419L8.00029 8.88381L12.5583 13.4419L13.4422 12.558L8.88417 7.99992L13.4422 3.44187L12.5583 2.55798L8.00029 7.11604L3.44223 2.55798L2.55835 3.44187L7.11641 7.99992Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 378 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.00024 3V13H13.0002V3H3.00024ZM12.0002 12H4.00024V4H12.0002V12Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 196 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.0002 7.99994V8.99994H3.00024V7.99994H14.0002Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 180 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.00024 5V14H12.0002V5H3.00024ZM11.0002 13H4.00024V6H11.0002V13Z" fill="#424242"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.00024 5H6.00024V4H13.0002V11H12.0002V12H14.0002V5V3H12.0002H5.00024V5Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 337 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.1161 7.99992L2.55804 12.558L3.44193 13.4419L7.99999 8.88381L12.558 13.4419L13.4419 12.558L8.88387 7.99992L13.4419 3.44187L12.558 2.55798L7.99999 7.11604L3.44193 2.55798L2.55804 3.44187L7.1161 7.99992Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 374 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 3V13H13V3H3ZM12 12H4V4H12V12Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 163 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 7.99994V8.99994H3V7.99994H14Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 164 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 5V14H12V5H3ZM11 13H4V6H11V13Z" fill="#C5C5C5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 5H6V4H13V11H12V12H14V5V3H12H5V5Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 266 B

View File

@ -29,14 +29,14 @@
#include <QtWidgets/qlabel.h> #include <QtWidgets/qlabel.h>
#include <QtWidgets/qpushbutton.h> #include <QtWidgets/qpushbutton.h>
#include <framelesswindowsmanager.h> #include <framelesswindowsmanager.h>
#include <utilities.h>
FRAMELESSHELPER_USE_NAMESPACE FRAMELESSHELPER_USE_NAMESPACE
static const QColor systemLightColor = QStringLiteral("#f0f0f0"); static const QColor systemLightColor = QStringLiteral("#f0f0f0");
static const QColor systemDarkColor = QColor::fromRgb(32, 32, 32); static const QColor systemDarkColor = QColor::fromRgb(32, 32, 32);
static constexpr const char mainStyleSheet[] = R"( static const QString mainStyleSheet = QStringLiteral(R"(#MainWidget {
#MainWidget {
background-color: %1; background-color: %1;
} }
@ -72,14 +72,14 @@ static constexpr const char mainStyleSheet[] = R"(
#ClockLabel { #ClockLabel {
color: %4; color: %4;
} }
)"; )");
Widget::Widget(QWidget *parent) : QWidget(parent) Widget::Widget(QWidget *parent) : QWidget(parent)
{ {
setAttribute(Qt::WA_DontCreateNativeAncestors); setAttribute(Qt::WA_DontCreateNativeAncestors);
createWinId(); createWinId();
//setupUi(); setupUi();
//startTimer(500); startTimer(500);
} }
Widget::~Widget() = default; Widget::~Widget() = default;
@ -87,11 +87,7 @@ Widget::~Widget() = default;
void Widget::showEvent(QShowEvent *event) void Widget::showEvent(QShowEvent *event)
{ {
QWidget::showEvent(event); QWidget::showEvent(event);
static bool inited = false; initOnce();
if (!inited) {
inited = true;
FramelessWindowsManager::addWindow(windowHandle());
}
} }
void Widget::timerEvent(QTimerEvent *event) void Widget::timerEvent(QTimerEvent *event)
@ -105,17 +101,18 @@ void Widget::timerEvent(QTimerEvent *event)
void Widget::changeEvent(QEvent *event) void Widget::changeEvent(QEvent *event)
{ {
QWidget::changeEvent(event); QWidget::changeEvent(event);
#if 0
bool shouldUpdate = false; bool shouldUpdate = false;
if (event->type() == QEvent::WindowStateChange) { if (event->type() == QEvent::WindowStateChange) {
#ifdef Q_OS_WIN
if (Utilities::isWin10OrGreater()) {
if (isMaximized() || isFullScreen()) { if (isMaximized() || isFullScreen()) {
setContentsMargins(0, 0, 0, 0); setContentsMargins(0, 0, 0, 0);
} else if (!isMinimized()) { } else if (!isMinimized()) {
const auto margin = static_cast<int>(qRound(frameBorderThickness())); resetContentsMargins();
setContentsMargins(margin, margin, margin, margin);
} }
}
#endif
updateSystemButtonIcons(); updateSystemButtonIcons();
updateTitleBarSize();
shouldUpdate = true; shouldUpdate = true;
} else if (event->type() == QEvent::ActivationChange) { } else if (event->type() == QEvent::ActivationChange) {
shouldUpdate = true; shouldUpdate = true;
@ -123,23 +120,48 @@ void Widget::changeEvent(QEvent *event)
if (shouldUpdate) { if (shouldUpdate) {
updateStyleSheet(); updateStyleSheet();
} }
#endif
} }
void Widget::paintEvent(QPaintEvent *event) void Widget::paintEvent(QPaintEvent *event)
{ {
QWidget::paintEvent(event); QWidget::paintEvent(event);
#ifdef Q_OS_WIN
if ((windowState() == Qt::WindowNoState) && Utilities::isWin10OrGreater() && !Utilities::isWin11OrGreater()) {
QPainter painter(this);
painter.save();
QPen pen = {};
pen.setColor(Utilities::getFrameBorderColor(isActiveWindow()));
const int frameBorderThickness = Utilities::getFrameBorderThickness(winId(), false);
pen.setWidth(frameBorderThickness);
painter.setPen(pen);
painter.drawLine(0, frameBorderThickness, width(), frameBorderThickness);
painter.restore();
}
#endif
}
void Widget::initOnce()
{
if (m_inited) {
return;
}
m_inited = true;
resetContentsMargins();
FramelessWindowsManager::addWindow(windowHandle());
} }
void Widget::setupUi() void Widget::setupUi()
{ {
#if 0 const int titleBarHeight = /*Utilities::getTitleBarHeight(winId(), false)*/30;
const QSize systemButtonSize = {int(qRound(qreal(titleBarHeight) * 1.5)), titleBarHeight};
const QSize systemIconSize = {16, 16};
setObjectName(QStringLiteral("MainWidget")); setObjectName(QStringLiteral("MainWidget"));
setWindowTitle(tr("Hello, World!")); setWindowTitle(tr("Hello, World!"));
resize(800, 600); resize(800, 600);
m_titleBarWidget = new QWidget(this); m_titleBarWidget = new QWidget(this);
m_titleBarWidget->setObjectName(QStringLiteral("TitleBarWidget")); m_titleBarWidget->setObjectName(QStringLiteral("TitleBarWidget"));
m_titleBarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); m_titleBarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_titleBarWidget->setFixedHeight(titleBarHeight);
m_windowTitleLabel = new QLabel(m_titleBarWidget); m_windowTitleLabel = new QLabel(m_titleBarWidget);
m_windowTitleLabel->setObjectName(QStringLiteral("WindowTitleLabel")); m_windowTitleLabel->setObjectName(QStringLiteral("WindowTitleLabel"));
m_windowTitleLabel->setFrameShape(QFrame::NoFrame); m_windowTitleLabel->setFrameShape(QFrame::NoFrame);
@ -150,19 +172,30 @@ void Widget::setupUi()
connect(this, &Widget::windowTitleChanged, m_windowTitleLabel, &QLabel::setText); connect(this, &Widget::windowTitleChanged, m_windowTitleLabel, &QLabel::setText);
m_minimizeButton = new QPushButton(m_titleBarWidget); m_minimizeButton = new QPushButton(m_titleBarWidget);
m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton")); m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton"));
m_minimizeButton->setFixedSize(systemButtonSize);
m_minimizeButton->setIconSize(systemIconSize);
m_minimizeButton->setToolTip(tr("Minimize"));
connect(m_minimizeButton, &QPushButton::clicked, this, &Widget::showMinimized); connect(m_minimizeButton, &QPushButton::clicked, this, &Widget::showMinimized);
m_maximizeButton = new QPushButton(m_titleBarWidget); m_maximizeButton = new QPushButton(m_titleBarWidget);
m_maximizeButton->setObjectName(QStringLiteral("MaximizeButton")); m_maximizeButton->setObjectName(QStringLiteral("MaximizeButton"));
m_maximizeButton->setFixedSize(systemButtonSize);
m_maximizeButton->setIconSize(systemIconSize);
m_maximizeButton->setToolTip(tr("Maximize"));
connect(m_maximizeButton, &QPushButton::clicked, this, [this](){ connect(m_maximizeButton, &QPushButton::clicked, this, [this](){
if (isMaximized() || isFullScreen()) { if (isMaximized() || isFullScreen()) {
showNormal(); showNormal();
m_maximizeButton->setToolTip(tr("Maximize"));
} else { } else {
showMaximized(); showMaximized();
m_maximizeButton->setToolTip(tr("Restore"));
} }
updateSystemButtonIcons(); updateSystemButtonIcons();
}); });
m_closeButton = new QPushButton(m_titleBarWidget); m_closeButton = new QPushButton(m_titleBarWidget);
m_closeButton->setObjectName(QStringLiteral("CloseButton")); m_closeButton->setObjectName(QStringLiteral("CloseButton"));
m_closeButton->setFixedSize(systemButtonSize);
m_closeButton->setIconSize(systemIconSize);
m_closeButton->setToolTip(tr("Close"));
connect(m_closeButton, &QPushButton::clicked, this, &Widget::close); connect(m_closeButton, &QPushButton::clicked, this, &Widget::close);
updateSystemButtonIcons(); updateSystemButtonIcons();
const auto titleBarLayout = new QHBoxLayout(m_titleBarWidget); const auto titleBarLayout = new QHBoxLayout(m_titleBarWidget);
@ -197,38 +230,66 @@ void Widget::setupUi()
mainLayout->addStretch(); mainLayout->addStretch();
setLayout(mainLayout); setLayout(mainLayout);
updateStyleSheet(); updateStyleSheet();
#endif
} }
void Widget::updateStyleSheet() void Widget::updateStyleSheet()
{ {
const bool active = isActiveWindow();
const bool dark = Utilities::shouldAppsUseDarkMode();
const DwmColorizationArea area = Utilities::getDwmColorizationArea();
const bool colorizedTitleBar = ((area == DwmColorizationArea::TitleBar_WindowBorder) || (area == DwmColorizationArea::All));
const QColor colorizationColor = Utilities::getDwmColorizationColor();
const QColor mainWidgetBackgroundColor = (dark ? systemDarkColor : systemLightColor);
const QColor titleBarWidgetBackgroundColor = [active, colorizedTitleBar, &colorizationColor, dark]() -> QColor {
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(mainStyleSheet.arg(mainWidgetBackgroundColor.name(), titleBarWidgetBackgroundColor.name(),
windowTitleLabelTextColor.name(), clockLabelTextColor.name()));
update();
} }
void Widget::updateSystemButtonIcons() void Widget::updateSystemButtonIcons()
{ {
#if 0
Q_ASSERT(m_minimizeButton); Q_ASSERT(m_minimizeButton);
Q_ASSERT(m_maximizeButton); Q_ASSERT(m_maximizeButton);
Q_ASSERT(m_closeButton); Q_ASSERT(m_closeButton);
if (!m_minimizeButton || !m_maximizeButton || !m_closeButton) { if (!m_minimizeButton || !m_maximizeButton || !m_closeButton) {
return; return;
} }
const QString suffix = (Utilities::shouldAppsUseDarkMode() ? QStringLiteral("white") : QStringLiteral("black")); const QString prefix = (Utilities::shouldAppsUseDarkMode() ? QStringLiteral("light") : QStringLiteral("dark"));
m_minimizeButton->setIcon(QIcon(QStringLiteral(":/images/button_minimize_%1.svg").arg(suffix))); m_minimizeButton->setIcon(QIcon(QStringLiteral(":/images/%1/chrome-minimize.svg").arg(prefix)));
if (isMaximized() || isFullScreen()) { if (isMaximized() || isFullScreen()) {
m_maximizeButton->setIcon(QIcon(QStringLiteral(":/images/button_restore_%1.svg").arg(suffix))); m_maximizeButton->setIcon(QIcon(QStringLiteral(":/images/%1/chrome-restore.svg").arg(prefix)));
} else { } else {
m_maximizeButton->setIcon(QIcon(QStringLiteral(":/images/button_maximize_%1.svg").arg(suffix))); m_maximizeButton->setIcon(QIcon(QStringLiteral(":/images/%1/chrome-maximize.svg").arg(prefix)));
} }
m_closeButton->setIcon(QIcon(QStringLiteral(":/images/button_close_%1.svg").arg(suffix))); m_closeButton->setIcon(QIcon(QStringLiteral(":/images/%1/chrome-close.svg").arg(prefix)));
#endif
} }
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) void Widget::resetContentsMargins()
bool Widget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
#else
bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *result)
#endif
{ {
return QWidget::nativeEvent(eventType, message, result); #ifdef Q_OS_WIN
if (Utilities::isWin10OrGreater()) {
const int frameBorderThickness = Utilities::getFrameBorderThickness(winId(), false);
setContentsMargins(0, frameBorderThickness, 0, 0);
}
#endif
} }

View File

@ -44,18 +44,16 @@ 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 initOnce();
void setupUi(); void setupUi();
void updateStyleSheet(); void updateStyleSheet();
void updateSystemButtonIcons(); void updateSystemButtonIcons();
void resetContentsMargins();
private: private:
bool m_inited = false;
QWidget *m_titleBarWidget = nullptr; QWidget *m_titleBarWidget = nullptr;
QLabel *m_windowTitleLabel = nullptr; QLabel *m_windowTitleLabel = nullptr;
QPushButton *m_minimizeButton = nullptr; QPushButton *m_minimizeButton = nullptr;