2024-02-17 22:51:19 +00:00
|
|
|
/*
|
|
|
|
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "breezemdiwindowshadow.h"
|
|
|
|
|
|
|
|
#include "breezeboxshadowrenderer.h"
|
|
|
|
#include "breezemetrics.h"
|
|
|
|
#include "breezeshadowhelper.h"
|
|
|
|
#include "breezestyleconfigdata.h"
|
|
|
|
|
|
|
|
#include <QMdiArea>
|
|
|
|
#include <QMdiSubWindow>
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QTextStream>
|
|
|
|
|
|
|
|
namespace Breeze
|
|
|
|
{
|
|
|
|
//____________________________________________________________________
|
|
|
|
MdiWindowShadow::MdiWindowShadow(QWidget *parent, const TileSet &shadowTiles)
|
|
|
|
: QWidget(parent)
|
|
|
|
, _shadowTiles(shadowTiles)
|
|
|
|
{
|
|
|
|
setAttribute(Qt::WA_OpaquePaintEvent, false);
|
|
|
|
setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
|
|
|
setFocusPolicy(Qt::NoFocus);
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________
|
|
|
|
void MdiWindowShadow::updateGeometry()
|
|
|
|
{
|
|
|
|
if (!_widget) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// metrics
|
|
|
|
const CompositeShadowParams params = ShadowHelper::lookupShadowParams(StyleConfigData::shadowSize());
|
|
|
|
if (params.isNone()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QSize boxSize =
|
|
|
|
BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius).expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius));
|
|
|
|
|
|
|
|
const QSize shadowSize = BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow1.radius, params.shadow1.offset)
|
|
|
|
.expandedTo(BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow2.radius, params.shadow2.offset));
|
|
|
|
|
|
|
|
const QRect shadowRect(QPoint(0, 0), shadowSize);
|
|
|
|
|
|
|
|
QRect boxRect(QPoint(0, 0), boxSize);
|
|
|
|
boxRect.moveCenter(shadowRect.center());
|
|
|
|
|
|
|
|
const int topSize(boxRect.top() - shadowRect.top() - Metrics::Shadow_Overlap - params.offset.y());
|
|
|
|
const int bottomSize(shadowRect.bottom() - boxRect.bottom() - Metrics::Shadow_Overlap + params.offset.y());
|
|
|
|
const int leftSize(boxRect.left() - shadowRect.left() - Metrics::Shadow_Overlap - params.offset.x());
|
|
|
|
const int rightSize(shadowRect.right() - boxRect.right() - Metrics::Shadow_Overlap + params.offset.x());
|
|
|
|
|
|
|
|
// get tileSet rect
|
|
|
|
auto hole = _widget->frameGeometry();
|
|
|
|
_shadowTilesRect = hole.adjusted(-leftSize, -topSize, rightSize, bottomSize);
|
|
|
|
|
|
|
|
// get parent MDI area's viewport
|
|
|
|
auto parent(parentWidget());
|
|
|
|
if (parent && !qobject_cast<QMdiArea *>(parent) && qobject_cast<QMdiArea *>(parent->parentWidget())) {
|
|
|
|
parent = parent->parentWidget();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qobject_cast<QAbstractScrollArea *>(parent)) {
|
|
|
|
parent = qobject_cast<QAbstractScrollArea *>(parent)->viewport();
|
|
|
|
}
|
|
|
|
|
|
|
|
// set geometry
|
|
|
|
QRect geometry(_shadowTilesRect);
|
|
|
|
if (parent) {
|
|
|
|
geometry &= parent->rect();
|
|
|
|
hole &= parent->rect();
|
|
|
|
}
|
|
|
|
|
|
|
|
// update geometry and mask
|
|
|
|
const QRegion mask = QRegion(geometry) - hole.adjusted(2, 2, -2, -2);
|
|
|
|
if (mask.isEmpty()) {
|
|
|
|
hide();
|
|
|
|
} else {
|
|
|
|
setGeometry(geometry);
|
|
|
|
setMask(mask.translated(-geometry.topLeft()));
|
|
|
|
show();
|
|
|
|
}
|
|
|
|
|
|
|
|
// translate rendering rect
|
|
|
|
_shadowTilesRect.translate(-geometry.topLeft());
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________
|
|
|
|
void MdiWindowShadow::updateZOrder()
|
|
|
|
{
|
|
|
|
stackUnder(_widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________
|
|
|
|
void MdiWindowShadow::paintEvent(QPaintEvent *event)
|
|
|
|
{
|
|
|
|
if (!_shadowTiles.isValid()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QPainter painter(this);
|
|
|
|
painter.setRenderHints(QPainter::Antialiasing);
|
|
|
|
painter.setClipRegion(event->region());
|
|
|
|
_shadowTiles.render(_shadowTilesRect, &painter);
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________
|
|
|
|
MdiWindowShadowFactory::MdiWindowShadowFactory(QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________________________
|
|
|
|
bool MdiWindowShadowFactory::registerWidget(QWidget *widget)
|
|
|
|
{
|
|
|
|
// check widget type
|
|
|
|
auto subwindow(qobject_cast<QMdiSubWindow *>(widget));
|
|
|
|
if (!subwindow) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (subwindow->widget() && subwindow->widget()->inherits("KMainWindow")) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure widget is not already registered
|
|
|
|
if (isRegistered(widget)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// store in set
|
|
|
|
_registeredWidgets.insert(widget);
|
|
|
|
|
|
|
|
// create shadow immediately if widget is already visible
|
|
|
|
if (widget->isVisible()) {
|
|
|
|
installShadow(widget);
|
|
|
|
updateShadowGeometry(widget);
|
|
|
|
updateShadowZOrder(widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
widget->installEventFilter(this);
|
|
|
|
|
|
|
|
// catch object destruction
|
|
|
|
connect(widget, &QObject::destroyed, this, &MdiWindowShadowFactory::widgetDestroyed);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________________________
|
|
|
|
void MdiWindowShadowFactory::unregisterWidget(QWidget *widget)
|
|
|
|
{
|
|
|
|
if (!isRegistered(widget)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
widget->removeEventFilter(this);
|
|
|
|
_registeredWidgets.remove(widget);
|
|
|
|
removeShadow(widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________________________
|
|
|
|
bool MdiWindowShadowFactory::eventFilter(QObject *object, QEvent *event)
|
|
|
|
{
|
|
|
|
switch (event->type()) {
|
|
|
|
// TODO: possibly implement ZOrderChange event, to make sure that
|
|
|
|
// the shadow is always painted on top
|
|
|
|
case QEvent::ZOrderChange:
|
|
|
|
updateShadowZOrder(object);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEvent::Hide:
|
|
|
|
hideShadows(object);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEvent::Show:
|
|
|
|
installShadow(object);
|
|
|
|
updateShadowGeometry(object);
|
|
|
|
updateShadowZOrder(object);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEvent::Move:
|
|
|
|
case QEvent::Resize:
|
|
|
|
updateShadowGeometry(object);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return QObject::eventFilter(object, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________________________
|
|
|
|
MdiWindowShadow *MdiWindowShadowFactory::findShadow(QObject *object) const
|
|
|
|
{
|
|
|
|
// check object,
|
|
|
|
if (!object->parent()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find existing window shadows
|
2024-08-09 01:20:25 +00:00
|
|
|
const auto children = object->parent()->children();
|
|
|
|
for (QObject *child : children) {
|
2024-02-17 22:51:19 +00:00
|
|
|
if (MdiWindowShadow *shadow = qobject_cast<MdiWindowShadow *>(child)) {
|
|
|
|
if (shadow->widget() == object) {
|
|
|
|
return shadow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________________________
|
|
|
|
void MdiWindowShadowFactory::installShadow(QObject *object)
|
|
|
|
{
|
|
|
|
// cast
|
|
|
|
auto widget(static_cast<QWidget *>(object));
|
|
|
|
if (!widget->parentWidget()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure shadow is not already installed
|
|
|
|
if (findShadow(object)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!_shadowHelper) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create new shadow
|
|
|
|
auto windowShadow(new MdiWindowShadow(widget->parentWidget(), _shadowHelper->shadowTiles(widget)));
|
|
|
|
windowShadow->setWidget(widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________________________
|
|
|
|
void MdiWindowShadowFactory::removeShadow(QObject *object)
|
|
|
|
{
|
|
|
|
if (MdiWindowShadow *windowShadow = findShadow(object)) {
|
|
|
|
windowShadow->hide();
|
|
|
|
windowShadow->deleteLater();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________________________
|
|
|
|
void MdiWindowShadowFactory::widgetDestroyed(QObject *object)
|
|
|
|
{
|
|
|
|
_registeredWidgets.remove(object);
|
|
|
|
removeShadow(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|