File indexing completed on 2025-01-05 03:59:17
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2009-2010 Bastian Holst <bastianholst@gmx.de> 0004 // 0005 0006 #include "MarbleGraphicsItem.h" 0007 #include "MarbleGraphicsItem_p.h" 0008 0009 // Qt 0010 #include <QList> 0011 #include <QPainter> 0012 #include <QPixmap> 0013 #include <QMouseEvent> 0014 0015 // Marble 0016 #include "ViewportParams.h" 0017 0018 #include "digikam_debug.h" 0019 0020 using namespace Marble; 0021 0022 MarbleGraphicsItem::MarbleGraphicsItem(MarbleGraphicsItemPrivate *dd) 0023 : d_ptr(dd) 0024 { 0025 } 0026 0027 MarbleGraphicsItem::~MarbleGraphicsItem() 0028 { 0029 delete d_ptr; 0030 } 0031 0032 bool MarbleGraphicsItem::paintEvent( QPainter *painter, const ViewportParams *viewport ) 0033 { 0034 Q_D(MarbleGraphicsItem); 0035 0036 if (!d->m_visibility) { 0037 return true; 0038 } 0039 0040 if (d->m_repaintNeeded) { 0041 d->updateChildPositions(); 0042 d->m_pixmap = QPixmap(); 0043 d->m_repaintNeeded = false; 0044 } 0045 0046 setProjection( viewport ); 0047 0048 if (d->positions().size() == 0) { 0049 return true; 0050 } 0051 0052 // At the moment, as GraphicsItems can't be zoomed or rotated ItemCoordinateCache 0053 // and DeviceCoordianteCache is exactly the same 0054 if ( ItemCoordinateCache == cacheMode() 0055 || DeviceCoordinateCache == cacheMode() ) 0056 { 0057 const qreal scale = painter->device()->devicePixelRatio(); 0058 0059 const QSize neededPixmapSize = scale * size().toSize() + QSize( 1, 1 ); // adding a pixel for rounding errors 0060 0061 if (d->m_pixmap.size() != neededPixmapSize || 0062 d->m_pixmap.devicePixelRatio() != scale) { 0063 0064 0065 if ( size().isValid() && !size().isNull() ) { 0066 d->m_pixmap = QPixmap(neededPixmapSize); 0067 d->m_pixmap.setDevicePixelRatio(scale); 0068 } 0069 else { 0070 qCDebug(DIGIKAM_MARBLE_LOG) << "Warning: Invalid pixmap size suggested: " << d->m_size; 0071 } 0072 0073 d->m_pixmap.fill(Qt::transparent); 0074 QPainter pixmapPainter(&d->m_pixmap); 0075 // We paint in best quality here, as we only have to paint once. 0076 pixmapPainter.setRenderHint( QPainter::Antialiasing, true ); 0077 // The cache image will get a 0.5 pixel bounding to save antialiasing effects. 0078 pixmapPainter.translate( 0.5, 0.5 ); 0079 paint( &pixmapPainter ); 0080 0081 // Paint children 0082 for (MarbleGraphicsItem *item: d->m_children) { 0083 item->paintEvent( &pixmapPainter, viewport ); 0084 } 0085 } 0086 0087 for (const QPointF& position: d->positions()) { 0088 painter->drawPixmap(position, d->m_pixmap); 0089 } 0090 } 0091 else { 0092 for (const QPointF& position: d->positions()) { 0093 painter->save(); 0094 0095 painter->translate( position ); 0096 paint( painter ); 0097 0098 // Paint children 0099 for (MarbleGraphicsItem *item: d->m_children) { 0100 item->paintEvent( painter, viewport ); 0101 } 0102 0103 painter->restore(); 0104 } 0105 } 0106 0107 return true; 0108 } 0109 0110 bool MarbleGraphicsItem::contains( const QPointF& point ) const 0111 { 0112 Q_D(const MarbleGraphicsItem); 0113 for (const QRectF& rect: d->boundingRects()) { 0114 if( rect.contains( point ) ) 0115 return true; 0116 } 0117 return false; 0118 } 0119 0120 QVector<QRectF> MarbleGraphicsItemPrivate::boundingRects() const 0121 { 0122 const QVector<QPointF> positions = this->positions(); 0123 0124 QVector<QRectF> list; 0125 list.reserve(positions.count()); 0126 0127 for (const QPointF &point: positions) { 0128 QRectF rect( point, m_size ); 0129 if( rect.x() < 0 ) 0130 rect.setLeft( 0 ); 0131 if( rect.y() < 0 ) 0132 rect.setTop( 0 ); 0133 0134 list.append( rect ); 0135 } 0136 0137 return list; 0138 } 0139 0140 QSizeF MarbleGraphicsItem::size() const 0141 { 0142 Q_D(const MarbleGraphicsItem); 0143 return d->m_size; 0144 } 0145 0146 AbstractMarbleGraphicsLayout *MarbleGraphicsItem::layout() const 0147 { 0148 Q_D(const MarbleGraphicsItem); 0149 return d->m_layout; 0150 } 0151 0152 void MarbleGraphicsItem::setLayout( AbstractMarbleGraphicsLayout *layout ) 0153 { 0154 Q_D(MarbleGraphicsItem); 0155 // Deleting the old layout 0156 delete d->m_layout; 0157 d->m_layout = layout; 0158 update(); 0159 } 0160 0161 MarbleGraphicsItem::CacheMode MarbleGraphicsItem::cacheMode() const 0162 { 0163 Q_D(const MarbleGraphicsItem); 0164 return d->m_cacheMode; 0165 } 0166 0167 void MarbleGraphicsItem::setCacheMode( CacheMode mode ) 0168 { 0169 Q_D(MarbleGraphicsItem); 0170 d->m_cacheMode = mode; 0171 if (d->m_cacheMode == NoCache) { 0172 d->m_repaintNeeded = true; 0173 } 0174 } 0175 0176 void MarbleGraphicsItem::update() 0177 { 0178 Q_D(MarbleGraphicsItem); 0179 d->m_repaintNeeded = true; 0180 0181 // Update the parent. 0182 if (d->m_parent) { 0183 d->m_parent->update(); 0184 } 0185 } 0186 0187 bool MarbleGraphicsItem::visible() const 0188 { 0189 Q_D(const MarbleGraphicsItem); 0190 return d->m_visibility; 0191 } 0192 0193 void MarbleGraphicsItem::setVisible( bool visible ) 0194 { 0195 Q_D(MarbleGraphicsItem); 0196 d->m_visibility = visible; 0197 } 0198 0199 void MarbleGraphicsItem::hide() 0200 { 0201 setVisible( false ); 0202 } 0203 0204 void MarbleGraphicsItem::show() 0205 { 0206 setVisible( true ); 0207 } 0208 0209 void MarbleGraphicsItem::setSize( const QSizeF& size ) 0210 { 0211 Q_D(MarbleGraphicsItem); 0212 if (d->m_size != size) { 0213 d->m_size = size; 0214 update(); 0215 } 0216 } 0217 0218 QSizeF MarbleGraphicsItem::contentSize() const 0219 { 0220 return size(); 0221 } 0222 0223 void MarbleGraphicsItem::setContentSize( const QSizeF& size ) 0224 { 0225 setSize( size ); 0226 } 0227 0228 QRectF MarbleGraphicsItem::contentRect() const 0229 { 0230 return QRectF( QPointF( 0, 0 ), contentSize() ); 0231 } 0232 0233 void MarbleGraphicsItem::paint( QPainter *painter ) 0234 { 0235 Q_UNUSED( painter ); 0236 } 0237 0238 bool MarbleGraphicsItem::eventFilter( QObject *object, QEvent *e ) 0239 { 0240 if ( ! ( e->type() == QEvent::MouseButtonDblClick 0241 || e->type() == QEvent::MouseMove 0242 || e->type() == QEvent::MouseButtonPress 0243 || e->type() == QEvent::MouseButtonRelease ) ) 0244 { 0245 return false; 0246 } 0247 0248 Q_D(const MarbleGraphicsItem); 0249 QMouseEvent *event = static_cast<QMouseEvent*> (e); 0250 0251 if (!d->m_children.isEmpty()) { 0252 const QVector<QPointF> absolutePositions = d->absolutePositions(); 0253 0254 for( const QPointF& absolutePosition: absolutePositions ) { 0255 QPoint shiftedPos = event->pos() - absolutePosition.toPoint(); 0256 0257 if ( QRect( QPoint( 0, 0 ), size().toSize() ).contains( shiftedPos ) ) { 0258 for (MarbleGraphicsItem *child: d->m_children) { 0259 const QVector<QRectF> childRects = child->d_func()->boundingRects(); 0260 0261 for( const QRectF& childRect: childRects ) { 0262 if( childRect.toRect().contains( shiftedPos ) ) { 0263 if( child->eventFilter( object, e ) ) { 0264 return true; 0265 } 0266 } 0267 } 0268 } 0269 } 0270 } 0271 } 0272 0273 return false; 0274 } 0275 0276 void MarbleGraphicsItem::setProjection( const ViewportParams *viewport ) 0277 { 0278 Q_D(MarbleGraphicsItem); 0279 d->setProjection(viewport); 0280 }