File indexing completed on 2024-04-14 03:48:11

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
0005 //
0006 
0007 #include "VisiblePlacemark.h"
0008 
0009 #include "MarbleDebug.h"
0010 #include "RemoteIconLoader.h"
0011 
0012 #include "GeoDataPlacemark.h"
0013 #include "GeoDataStyle.h"
0014 #include "GeoDataIconStyle.h"
0015 #include "GeoDataLabelStyle.h"
0016 #include "PlacemarkLayer.h"
0017 
0018 #include <QApplication>
0019 #include <QPainter>
0020 #include <QPainterPath>
0021 #include <QPalette>
0022 #include <QPixmapCache>
0023 
0024 using namespace Marble;
0025 
0026 VisiblePlacemark::VisiblePlacemark( const GeoDataPlacemark *placemark, const GeoDataCoordinates &coordinates, const GeoDataStyle::ConstPtr &style )
0027     : m_placemark( placemark ),
0028       m_selected( false ),
0029       m_labelDirty(true),
0030       m_style(style),
0031       m_coordinates(coordinates)
0032 {
0033     const RemoteIconLoader *remoteLoader = style->iconStyle().remoteIconLoader();
0034     QObject::connect( remoteLoader, SIGNAL(iconReady()),
0035                      this, SLOT(setSymbolPixmap()) );
0036 
0037     setSymbolPixmap();
0038 }
0039 
0040 const GeoDataPlacemark* VisiblePlacemark::placemark() const
0041 {
0042     return m_placemark;
0043 }
0044 
0045 const QPixmap& VisiblePlacemark::symbolPixmap() const
0046 {
0047     if (!m_symbolId.isEmpty() && m_symbolPixmap.isNull()) {
0048         if ( !QPixmapCache::find( m_symbolId, &m_symbolPixmap ) ) {
0049             m_symbolPixmap = QPixmap::fromImage(m_style->iconStyle().scaledIcon());
0050             QPixmapCache::insert( m_symbolId, m_symbolPixmap);
0051         }
0052     }
0053     return m_symbolPixmap;
0054 }
0055 
0056 const QString& VisiblePlacemark::symbolId() const
0057 {
0058     return m_symbolId;
0059 }
0060 
0061 bool VisiblePlacemark::selected() const
0062 {
0063     return m_selected;
0064 }
0065 
0066 void VisiblePlacemark::setSelected( bool selected )
0067 {
0068     if (selected != m_selected) {
0069         m_selected = selected;
0070         m_labelDirty = true;
0071     }
0072 }
0073 
0074 const QPointF& VisiblePlacemark::symbolPosition() const
0075 {
0076     return m_symbolPosition;
0077 }
0078 
0079 const QPointF VisiblePlacemark::hotSpot() const
0080 {
0081     const QSize iconSize = m_style->iconStyle().scaledIcon().size();
0082 
0083     GeoDataHotSpot::Units xunits;
0084     GeoDataHotSpot::Units yunits;
0085     QPointF pixelHotSpot = m_style->iconStyle().hotSpot( xunits, yunits );
0086 
0087     switch ( xunits ) {
0088     case GeoDataHotSpot::Fraction:
0089         pixelHotSpot.setX( iconSize.width() * pixelHotSpot.x() );
0090         break;
0091     case GeoDataHotSpot::Pixels:
0092         /* nothing to do */
0093         break;
0094     case GeoDataHotSpot::InsetPixels:
0095         pixelHotSpot.setX( iconSize.width() - pixelHotSpot.x() );
0096         break;
0097     }
0098 
0099     switch ( yunits ) {
0100     case GeoDataHotSpot::Fraction:
0101         pixelHotSpot.setY( iconSize.height() * ( 1.0 - pixelHotSpot.y() ) );
0102         break;
0103     case GeoDataHotSpot::Pixels:
0104         /* nothing to do */
0105         break;
0106     case GeoDataHotSpot::InsetPixels:
0107         pixelHotSpot.setY( iconSize.height() - pixelHotSpot.y() );
0108         break;
0109     }
0110 
0111     return pixelHotSpot;
0112 }
0113 
0114 void VisiblePlacemark::setSymbolPosition( const QPointF& position )
0115 {
0116     m_symbolPosition = position;
0117 }
0118 
0119 const QPixmap& VisiblePlacemark::labelPixmap()
0120 {
0121     if (m_labelDirty) {
0122         drawLabelPixmap();
0123     }
0124 
0125     return m_labelPixmap;
0126 }
0127 
0128 void VisiblePlacemark::setSymbolPixmap()
0129 {
0130     if (m_style) {
0131         m_symbolId = m_style->iconStyle().iconPath() + QString::number(m_style->iconStyle().scale());
0132         if (m_style->iconStyle().iconPath().isEmpty()) {
0133             m_symbolId.clear();
0134             m_symbolPixmap = QPixmap::fromImage(m_style->iconStyle().scaledIcon());
0135         }
0136         emit updateNeeded();
0137     }
0138     else {
0139         mDebug() << "Style pointer is Null";
0140     }
0141 }
0142 
0143 const QRectF& VisiblePlacemark::labelRect() const
0144 {
0145     return m_labelRect;
0146 }
0147 
0148 void VisiblePlacemark::setLabelRect( const QRectF& labelRect )
0149 {
0150     m_labelRect = labelRect;
0151 }
0152 
0153 void VisiblePlacemark::setStyle(const GeoDataStyle::ConstPtr &style)
0154 {
0155     m_style = style;
0156     m_labelDirty = true;
0157     setSymbolPixmap();
0158 }
0159 
0160 GeoDataStyle::ConstPtr VisiblePlacemark::style() const
0161 {
0162     return m_style;
0163 }
0164 
0165 QRectF VisiblePlacemark::symbolRect() const
0166 {
0167     return QRectF(m_symbolPosition, m_symbolPixmap.size());
0168 }
0169 
0170 QRectF VisiblePlacemark::boundingBox() const
0171 {
0172     return m_labelRect.isEmpty() ? symbolRect() : m_labelRect.united(symbolRect());
0173 }
0174 
0175 const GeoDataCoordinates &VisiblePlacemark::coordinates() const
0176 {
0177     return m_coordinates;
0178 }
0179 
0180 void VisiblePlacemark::drawLabelPixmap()
0181 {
0182     m_labelDirty = false;
0183     QString labelName = m_placemark->displayName();
0184     if ( labelName.isEmpty() || m_style->labelStyle().color() == QColor(Qt::transparent) ) {
0185         m_labelPixmap = QPixmap();
0186         return;
0187     }
0188 
0189     QFont  labelFont  = m_style->labelStyle().scaledFont();
0190     QColor labelColor = m_style->labelStyle().color();
0191 
0192     LabelStyle labelStyle = Normal;
0193     if ( m_selected ) {
0194         labelStyle = Selected;
0195     } else if ( m_style->labelStyle().glow() ) {
0196         labelStyle = Glow;
0197     }
0198 
0199     int textHeight = QFontMetrics( labelFont ).height();
0200 
0201     int textWidth;
0202     if ( m_style->labelStyle().glow() ) {
0203         labelFont.setWeight( 75 ); // Needed to calculate the correct pixmap size;
0204         textWidth = ( QFontMetrics( labelFont ).horizontalAdvance( labelName )
0205             + qRound( 2 * s_labelOutlineWidth ) );
0206     } else {
0207         textWidth = ( QFontMetrics( labelFont ).horizontalAdvance( labelName ) );
0208     }
0209 
0210     m_labelPixmap = QPixmap( QSize( textWidth, textHeight ) );
0211     m_labelPixmap.fill( Qt::transparent );
0212 
0213     QPainter labelPainter( &m_labelPixmap );
0214 
0215     drawLabelText( labelPainter, labelName, labelFont, labelStyle, labelColor );
0216 }
0217 
0218 void VisiblePlacemark::drawLabelText(QPainter &labelPainter, const QString &text,
0219                                             const QFont &labelFont, LabelStyle labelStyle, const QColor &color )
0220 {
0221     QFont font = labelFont;
0222     QFontMetrics metrics = QFontMetrics( font );
0223     int fontAscent = metrics.ascent();
0224 
0225     switch ( labelStyle ) {
0226     case Selected: {
0227         labelPainter.setPen( color );
0228         labelPainter.setFont( font );
0229         QRect textRect( 0, 0, metrics.horizontalAdvance( text ), metrics.height() );
0230         labelPainter.fillRect( textRect, QApplication::palette().highlight() );
0231         labelPainter.setPen( QPen( QApplication::palette().highlightedText(), 1 ) );
0232         labelPainter.drawText( 0, fontAscent, text );
0233         break;
0234     }
0235     case Glow: {
0236         font.setWeight( 75 );
0237         fontAscent = QFontMetrics( font ).ascent();
0238 
0239         QPen outlinepen( (color.red() + color.green() + color.blue())/3 < 160 ? Qt::white : Qt::black);
0240         outlinepen.setWidthF( s_labelOutlineWidth );
0241         QBrush  outlinebrush( color );
0242 
0243         QPainterPath outlinepath;
0244 
0245         const QPointF  baseline( s_labelOutlineWidth / 2.0, fontAscent );
0246         outlinepath.addText( baseline, font, text );
0247         labelPainter.setRenderHint( QPainter::Antialiasing, true );
0248         labelPainter.setPen( outlinepen );
0249         labelPainter.setBrush( outlinebrush );
0250         labelPainter.drawPath( outlinepath );
0251         labelPainter.setPen( Qt::NoPen );
0252         labelPainter.drawPath( outlinepath );
0253         labelPainter.setRenderHint( QPainter::Antialiasing, false );
0254         break;
0255     }
0256     default: {
0257         labelPainter.setPen( color );
0258         labelPainter.setFont( font );
0259         labelPainter.drawText( 0, fontAscent, text );
0260     }
0261     }
0262 }
0263 
0264 #include "moc_VisiblePlacemark.cpp"