/* * SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "breezemdiwindowshadow.h" #include "breezemetrics.h" #include "breezeboxshadowrenderer.h" #include "breezeshadowhelper.h" #include "breezestyleconfigdata.h" #include #include #include #include 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(parent) && qobject_cast(parent->parentWidget())) { parent = parent->parentWidget(); } if( qobject_cast( parent ) ) { parent = qobject_cast( 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( 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 auto children = object->parent()->children(); foreach( QObject *child, children ) { if( MdiWindowShadow* shadow = qobject_cast(child) ) { if( shadow->widget() == object ) return shadow; } } return nullptr; } //____________________________________________________________________________________ void MdiWindowShadowFactory::installShadow( QObject* object ) { // cast auto widget( static_cast( 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() ) ); 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 ); } }