/***********************************************************************
*
* Copyright (C) 2014-2019 wereturtle
* Copyright(c) 2009 by Gabriel M. Beddingfield
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
***********************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "HudWindow.h"
#include "ColorHelper.h"
QT_BEGIN_NAMESPACE
extern void qt_blurImage
(
QPainter *p,
QImage& blurImage,
qreal radius,
bool quality,
bool alphaOnly,
int transposed = 0
);
QT_END_NAMESPACE
HudWindow::HudWindow(QWidget *parent)
: QWidget(parent)
{
this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
this->setAttribute(Qt::WA_TranslucentBackground);
this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
this->setMouseTracking(true);
desktopCompositingEnabled = true;
hudWindowShape = HudWindowShapeRounded;
// Set up the close button.
closeButton = new QPushButton(this);
closeButton->setFocusPolicy(Qt::NoFocus);
closeButton->setStyleSheet(
"QPushButton { margin: 1; padding: 0; border: 0; width: 16px; "
"height: 16px; background: transparent; "
"image: url(:/resources/images/close.svg) } "
"QPushButton:hover:!pressed { image: url(:/resources/images/close-hover.svg) } "
"QPushButton:pressed { image: url(:/resources/images/close-pressed.svg) }");
closeButtonColorEffect = new QGraphicsColorizeEffect();
closeButtonColorEffect->setColor(QColor(Qt::white));
closeButtonColorEffect->setStrength(1.0);
closeButton->setGraphicsEffect(closeButtonColorEffect);
closeButton->installEventFilter(this);
closeButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
connect(closeButton, SIGNAL(clicked()), this, SIGNAL(closed()));
// Set up initial window title (blank).
windowTitleLabel = new QLabel("");
windowTitleLabel->setObjectName("windowTitle");
windowTitleLabel->setStyleSheet("border: 0; font-size: 10pt");
windowTitleLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
// Set up the size grip.
QWidget* sizeGripContainer = new QWidget();
QGridLayout* sizeGripLayout = new QGridLayout();
sizeGripContainer->setLayout(sizeGripLayout);
sizeGrip = new QSizeGrip(this);
sizeGrip->setStyleSheet(
"width: 16px; height 16px; "
"image: url(:/resources/images/size-grip.svg)");
sizeGripColorEffect = new QGraphicsColorizeEffect();
sizeGripColorEffect->setColor(QColor(Qt::white));
sizeGripColorEffect->setStrength(1.0);
sizeGrip->setGraphicsEffect(sizeGripColorEffect);
sizeGrip->setVisible(true);
sizeGripLayout->addWidget(sizeGrip, 0, 0, 1, 1);
sizeGripLayout->setMargin(3);
// Set up the layout for this window.
QWidget* titleBar = new QWidget();
titleBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
titleBarLayout = new QGridLayout();
titleBar->setLayout(titleBarLayout);
titleBar->setStyleSheet("margin: 0; border: 0; padding: 0");
titleBarLayout->setMargin(1);
titleBarLayout->addWidget
(
windowTitleLabel,
0,
1,
1,
2,
Qt::AlignCenter | Qt::AlignTop
);
// Put the close button on the left if the OS is Mac OS X so that it
// meshes with the window manager. Otherwise, keep it on the right-hand
// side. Note that at the moment it seems detecting the window manager's
// settings for which sides the window frame's buttons are displayed
// is not possible. Thus, defaulting to the right-hand side for all other
// systems other than OS X seems to be the safest course of action for now.
//
#ifdef Q_OS_MAC
this->setButtonLayout(HudWindowButtonLayoutLeft);
#else
this->setButtonLayout(HudWindowButtonLayoutRight);
#endif
layout = new QGridLayout();
layout->setMargin(11);
layout->addWidget(titleBar, 0, 0, 1, 1, Qt::AlignTop);
Qt::Alignment sizeGripAlignment = Qt::AlignRight;
// The size grip is invisible on the left side when the application's
// layout is for a right-to-left language. Instead, place it on the right
// side of the HUD window (i.e., specify an alignment of AlignLeft, which
// will be flipped to be the opposite in the right-to-left layout). At
// least this way it will still be visible.
//
if (QApplication::isRightToLeft())
{
sizeGripAlignment = Qt::AlignLeft;
}
layout->addWidget(sizeGripContainer, 2, 0, 1, 1, sizeGripAlignment);
layout->setRowStretch(0, 0);
layout->setRowStretch(1, 1);
layout->setRowStretch(2, 0);
this->setLayout(layout);
setForegroundColor(QColor(Qt::white));
setBackgroundColor(QColor(0, 0, 0, 200));
isTitleBarBeingDragged = false;
}
HudWindow::~HudWindow()
{
}
void HudWindow::keyPressEvent(QKeyEvent* e)
{
int key = e->key();
switch (key)
{
case Qt::Key_Escape:
this->hide();
emit closed();
break;
default:
break;
}
QWidget::keyPressEvent(e);
}
void HudWindow::setCentralWidget(QWidget* widget)
{
layout->addWidget(widget, 1, 0, 1, 1);
widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
}
void HudWindow::setWindowTitle(const QString& title)
{
windowTitleLabel->setText(title);
}
QColor HudWindow::getForegroundColor()
{
return foregroundColor;
}
void HudWindow::setForegroundColor(const QColor& color)
{
foregroundColor = color;
QString styleSheet = "";
QTextStream stream(&styleSheet);
stream = 0x050600
pixmap.setDevicePixelRatio(dpr);
#endif
QPainter painter(this);
painter.drawPixmap(0, 0, pixmap);
painter.end();
}
}
void HudWindow::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event);
predrawDropShadow();
}
void HudWindow::moveEvent(QMoveEvent *event)
{
// Need to redraw the background image in case the window has moved
// onto a different screen where the device pixel ratio is different.
//
Q_UNUSED(event);
predrawDropShadow();
}
void HudWindow::mousePressEvent(QMouseEvent* event)
{
if (event->button() & Qt::LeftButton)
{
isTitleBarBeingDragged = true;
mouseDragStartingPoint = event->globalPos() - frameGeometry().topLeft();
this->setCursor(Qt::SizeAllCursor);
event->accept();
}
else
{
event->ignore();
}
}
void HudWindow::mouseReleaseEvent(QMouseEvent* event)
{
if (isTitleBarBeingDragged)
{
isTitleBarBeingDragged = false;
setCursor(Qt::ArrowCursor);
}
// Ignore the event in case the parent widget wants to change the
// cursor icon to something else.
//
event->ignore();
}
void HudWindow::mouseMoveEvent(QMouseEvent* event)
{
if (isTitleBarBeingDragged)
{
move(event->globalPos() - mouseDragStartingPoint);
event->accept();
}
else
{
event->ignore();
}
}
void HudWindow::predrawDropShadow()
{
if (desktopCompositingEnabled)
{
// devicePixelRatio
qreal dpr = 1.0;
#if QT_VERSION >= 0x050600
dpr = devicePixelRatioF();
#endif
int w = rect().width() * dpr;
int h = rect().height() * dpr;
// Pre-draw the window drop shadow. It only needs to be drawn upon
// resizing or moving the window. We do this because applying a blur
// effect to the drop shadow is computationally expensive.
//
QImage unblurredImage
(
w,
h,
QImage::Format_ARGB32_Premultiplied
);
unblurredImage.fill(Qt::transparent);
QPainter painter(&unblurredImage);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(Qt::NoPen));
painter.setBrush(QBrush(QColor(0, 0, 0, 200)));
QRect r = rect().adjusted(10, 12, -10, -8);
if (HudWindowShapeRounded == hudWindowShape)
{
painter.drawRoundedRect(r, 5.0, 5.0);
}
else
{
painter.drawRect(r);
}
painter.end();
// Now we need to blur the shadow onto its final destination image,
// dropShadowImg, which will be drawn on the next paintEvent().
//
dropShadowImg = QPixmap(w, h);
dropShadowImg.fill(Qt::transparent);
#if QT_VERSION >= 0x050600
dropShadowImg.setDevicePixelRatio(dpr);
#endif
painter.begin(&dropShadowImg);
painter.setRenderHint(QPainter::Antialiasing);
// Note that the blur only applies to the alpha channel.
qt_blurImage(&painter, unblurredImage, 18, true, true);
painter.end();
}
}