/* * MIT License * * Copyright (C) 2020 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. */ #include "widget.h" #include "../../framelesshelper.h" #include #include #include #include #include #include #include #include Q_GLOBAL_STATIC(FramelessHelper, framelessHelper) ContentsWidget::ContentsWidget(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_StyledBackground); } void ContentsWidget::setShouldDrawWindowBorder(const bool val) { m_bShouldDrawWindowBorder = val; update(); } bool ContentsWidget::getShouldDrawWindowBorder() const { return m_bShouldDrawWindowBorder; } void ContentsWidget::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); if (m_bShouldDrawWindowBorder) { QPainter painter(this); painter.save(); painter.setPen({window()->isActiveWindow() ? Qt::black : Qt::darkGray, 1.5}); painter.drawLine(0, 0, width(), 0); painter.drawLine(0, height(), width(), height()); painter.drawLine(0, 0, 0, height()); painter.drawLine(width(), 0, width(), height()); painter.restore(); } } Widget::Widget(QWidget *parent) : QWidget(parent) { titleBarHeight = framelessHelper()->getTitleBarHeight(); createWinId(); setupUi(); initBackgroundWindow(); installEventFilter(this); } bool Widget::isNormal() const { return (!isMinimized() && !isMaximized() && !isFullScreen()); } void Widget::setupUi() { contentsWidget = new ContentsWidget(this); contentsWidget->setObjectName(QString::fromUtf8("contentsWidget")); contentsWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); const QSize systemButtonSize = {qRound(titleBarHeight * 1.5), titleBarHeight}; const QSize systemIconSize = {17, 17}; titleBarWidget = new QWidget(contentsWidget); titleBarWidget->setObjectName(QString::fromUtf8("titleBarWidget")); titleBarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); titleBarWidget->setFixedHeight(titleBarHeight); windowIconButton = new QPushButton(this); windowIconButton->setObjectName(QString::fromUtf8("windowIconButton")); windowIconButton->setFixedSize(systemIconSize); windowIconButton->setIconSize(systemIconSize); connect(this, &Widget::windowIconChanged, windowIconButton, &QPushButton::setIcon); windowTitleLabel = new QLabel(this); QFont f = font(); f.setPointSizeF(8.63); windowTitleLabel->setFont(f); connect(this, &Widget::windowTitleChanged, windowTitleLabel, &QLabel::setText); minimizeButton = new QPushButton(this); minimizeButton->setObjectName(QString::fromUtf8("minimizeButton")); minimizeButton->setFixedSize(systemButtonSize); minimizeButton->setIconSize(systemButtonSize); minimizeButton->setIcon(QIcon(QString::fromUtf8(":/images/button_minimize_black.svg"))); connect(minimizeButton, &QPushButton::clicked, this, &Widget::showMinimized); maximizeButton = new QPushButton(this); maximizeButton->setObjectName(QString::fromUtf8("maximizeButton")); maximizeButton->setFixedSize(systemButtonSize); maximizeButton->setIconSize(systemButtonSize); maximizeButton->setIcon(QIcon(QString::fromUtf8(":/images/button_maximize_black.svg"))); connect(maximizeButton, &QPushButton::clicked, this, [this]() { if (isMaximized()) { showNormal(); } else { showMaximized(); } }); closeButton = new QPushButton(this); closeButton->setObjectName(QString::fromUtf8("closeButton")); closeButton->setFixedSize(systemButtonSize); closeButton->setIconSize(systemButtonSize); closeButton->setIcon(QIcon(QString::fromUtf8(":/images/button_close_black.svg"))); connect(closeButton, &QPushButton::clicked, this, &Widget::close); const auto titleBarWidgetLayout = new QHBoxLayout(titleBarWidget); titleBarWidgetLayout->setSpacing(0); titleBarWidgetLayout->setContentsMargins(0, 0, 0, 0); titleBarWidgetLayout->addSpacerItem( new QSpacerItem(7, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)); titleBarWidgetLayout->addWidget(windowIconButton); titleBarWidgetLayout->addSpacerItem( new QSpacerItem(3, 20, QSizePolicy::Fixed, QSizePolicy::Fixed)); titleBarWidgetLayout->addWidget(windowTitleLabel); titleBarWidgetLayout->addStretch(); titleBarWidgetLayout->addWidget(minimizeButton); titleBarWidgetLayout->addWidget(maximizeButton); titleBarWidgetLayout->addWidget(closeButton); titleBarWidget->setLayout(titleBarWidgetLayout); const auto contentsWidgetLayout = new QVBoxLayout(contentsWidget); contentsWidgetLayout->setSpacing(0); contentsWidgetLayout->setContentsMargins(1, 1, 1, 0); contentsWidgetLayout->addWidget(titleBarWidget); contentsWidgetLayout->addStretch(); contentsWidget->setLayout(contentsWidgetLayout); const auto backgroundWindowLayout = new QVBoxLayout(this); backgroundWindowLayout->setSpacing(0); backgroundWindowLayout->addWidget(contentsWidget); setLayout(backgroundWindowLayout); setStyleSheet(QString::fromUtf8(R"( #contentsWidget { background-color: #f0f0f0; } #titleBarWidget { background-color: white; } #windowIconButton, #minimizeButton, #maximizeButton, #closeButton { border-style: none; background-color: transparent; } #minimizeButton:hover, #maximizeButton:hover { background-color: #80c7c7c7; } #minimizeButton:pressed, #maximizeButton:pressed { background-color: #80808080; } #closeButton:hover { background-color: #e81123; } #closeButton:pressed { background-color: #8c0a15; } )")); } void Widget::initBackgroundWindow() { QWindow *win = windowHandle(); framelessHelper()->removeWindowFrame(win); framelessHelper()->addIgnoreObject(win, windowIconButton); framelessHelper()->addIgnoreObject(win, minimizeButton); framelessHelper()->addIgnoreObject(win, maximizeButton); framelessHelper()->addIgnoreObject(win, closeButton); framelessHelper()->setTitleBarHeight(titleBarHeight + framelessHelper()->getBorderHeight()); //setAttribute(Qt::WA_Hover); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_TranslucentBackground); shadowEffect = new QGraphicsDropShadowEffect(this); shadowEffect->setOffset(0, 0); contentsWidget->setGraphicsEffect(shadowEffect); setFrameShadowEnabled(); setFrameShadowActive(); } void Widget::setFrameShadowEnabled(const bool enable) { if (enable) { const int bw = framelessHelper()->getBorderWidth(); const int bh = framelessHelper()->getBorderHeight(); layout()->setContentsMargins(bw, bh, bw, bh); shadowEffect->setEnabled(true); } else { shadowEffect->setEnabled(false); layout()->setContentsMargins(0, 0, 0, 0); } } void Widget::setFrameShadowActive(const bool active) { if (active) { shadowEffect->setColor({0, 0, 0, 80}); shadowEffect->setBlurRadius(25); } else { shadowEffect->setColor({0, 0, 0, 60}); shadowEffect->setBlurRadius(20); } } bool Widget::eventFilter(QObject *object, QEvent *event) { Q_ASSERT(object); Q_ASSERT(event); if (object == this) { switch (event->type()) { case QEvent::WindowStateChange: { const bool normal = isNormal(); contentsWidget->setShouldDrawWindowBorder(normal); setFrameShadowEnabled(normal); framelessHelper()->setTitleBarHeight( titleBarHeight + (normal ? framelessHelper()->getBorderHeight() : 0)); const QString maxIconPath = QString::fromUtf8(":/images/button_maximize_black.svg"); const QString restoreIconPath = QString::fromUtf8(":/images/button_restore_black.svg"); maximizeButton->setIcon(QIcon(normal ? maxIconPath : restoreIconPath)); } break; case QEvent::WindowActivate: { if (isNormal()) { setFrameShadowActive(); } } break; case QEvent::WindowDeactivate: { if (isNormal()) { setFrameShadowActive(false); } } break; default: break; } } return QWidget::eventFilter(object, event); }