diff --git a/src/lib/marble/MergedLayerDecorator.cpp b/src/lib/marble/MergedLayerDecorator.cpp index d2e454e3d..eb3d22e42 100644 --- a/src/lib/marble/MergedLayerDecorator.cpp +++ b/src/lib/marble/MergedLayerDecorator.cpp @@ -1,617 +1,618 @@ // Copyright 2008 David Roberts // Copyright 2009 Jens-Michael Hoffmann // Copyright 2011 Bernhard Beschow // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library. If not, see . #include "MergedLayerDecorator.h" #include "blendings/Blending.h" #include "blendings/BlendingFactory.h" #include "SunLocator.h" #include "MarbleMath.h" #include "MarbleDebug.h" #include "GeoDataGroundOverlay.h" #include "GeoSceneTextureTileDataset.h" #include "ImageF.h" #include "StackedTile.h" #include "TileLoaderHelper.h" #include "TextureTile.h" #include "TileLoader.h" #include "RenderState.h" #include "GeoDataCoordinates.h" #include #include +#include using namespace Marble; class Q_DECL_HIDDEN MergedLayerDecorator::Private { public: Private( TileLoader *tileLoader, const SunLocator *sunLocator ); static int maxDivisor( int maximum, int fullLength ); StackedTile *createTile( const QVector > &tiles ) const; void renderGroundOverlays( QImage *tileImage, const QVector > &tiles ) const; void paintSunShading( QImage *tileImage, const TileId &id ) const; void paintTileId( QImage *tileImage, const TileId &id ) const; void detectMaxTileLevel(); QVector findRelevantTextureLayers( const TileId &stackedTileId ) const; TileLoader *const m_tileLoader; const SunLocator *const m_sunLocator; BlendingFactory m_blendingFactory; QVector m_textureLayers; QList m_groundOverlays; int m_maxTileLevel; QString m_themeId; int m_levelZeroColumns; int m_levelZeroRows; bool m_showSunShading; bool m_showCityLights; bool m_showTileId; }; MergedLayerDecorator::Private::Private( TileLoader *tileLoader, const SunLocator *sunLocator ) : m_tileLoader( tileLoader ), m_sunLocator( sunLocator ), m_blendingFactory( sunLocator ), m_textureLayers(), m_maxTileLevel( 0 ), m_themeId(), m_levelZeroColumns( 0 ), m_levelZeroRows( 0 ), m_showSunShading( false ), m_showCityLights( false ), m_showTileId( false ) { } MergedLayerDecorator::MergedLayerDecorator( TileLoader * const tileLoader, const SunLocator* sunLocator ) : d( new Private( tileLoader, sunLocator ) ) { } MergedLayerDecorator::~MergedLayerDecorator() { delete d; } void MergedLayerDecorator::setTextureLayers( const QVector &textureLayers ) { if ( textureLayers.count() > 0 ) { const GeoSceneTileDataset *const firstTexture = textureLayers.at( 0 ); d->m_levelZeroColumns = firstTexture->levelZeroColumns(); d->m_levelZeroRows = firstTexture->levelZeroRows(); d->m_blendingFactory.setLevelZeroLayout( d->m_levelZeroColumns, d->m_levelZeroRows ); d->m_themeId = QLatin1String("maps/") + firstTexture->sourceDir(); } d->m_textureLayers = textureLayers; d->detectMaxTileLevel(); } void MergedLayerDecorator::updateGroundOverlays(const QList &groundOverlays ) { d->m_groundOverlays = groundOverlays; } int MergedLayerDecorator::textureLayersSize() const { return d->m_textureLayers.size(); } int MergedLayerDecorator::maximumTileLevel() const { return d->m_maxTileLevel; } int MergedLayerDecorator::tileColumnCount( int level ) const { Q_ASSERT( !d->m_textureLayers.isEmpty() ); const int levelZeroColumns = d->m_textureLayers.at( 0 )->levelZeroColumns(); return TileLoaderHelper::levelToColumn( levelZeroColumns, level ); } int MergedLayerDecorator::tileRowCount( int level ) const { Q_ASSERT( !d->m_textureLayers.isEmpty() ); const int levelZeroRows = d->m_textureLayers.at( 0 )->levelZeroRows(); return TileLoaderHelper::levelToRow( levelZeroRows, level ); } const GeoSceneAbstractTileProjection *MergedLayerDecorator::tileProjection() const { Q_ASSERT( !d->m_textureLayers.isEmpty() ); return d->m_textureLayers.at(0)->tileProjection(); } QSize MergedLayerDecorator::tileSize() const { Q_ASSERT( !d->m_textureLayers.isEmpty() ); return d->m_textureLayers.at( 0 )->tileSize(); } StackedTile *MergedLayerDecorator::Private::createTile( const QVector > &tiles ) const { Q_ASSERT( !tiles.isEmpty() ); const TileId firstId = tiles.first()->id(); const TileId id( 0, firstId.zoomLevel(), firstId.x(), firstId.y() ); // Image for blending all the texture tiles on it QImage resultImage; // if there are more than one active texture layers, we have to convert the // result tile into QImage::Format_ARGB32_Premultiplied to make blending possible const bool withConversion = tiles.count() > 1 || m_showSunShading || m_showTileId || !m_groundOverlays.isEmpty(); for ( const QSharedPointer &tile: tiles ) { // Image blending. If there are several images in the same tile (like clouds // or hillshading images over the map) blend them all into only one image const Blending *const blending = tile->blending(); if ( blending ) { mDebug() << Q_FUNC_INFO << "blending"; if ( resultImage.isNull() ) { resultImage = QImage( tile->image()->size(), QImage::Format_ARGB32_Premultiplied ); } blending->blend( &resultImage, tile.data() ); } else { mDebug() << Q_FUNC_INFO << "no blending defined => copying top over bottom image"; if ( withConversion ) { resultImage = tile->image()->convertToFormat( QImage::Format_ARGB32_Premultiplied ); } else { resultImage = tile->image()->copy(); } } } renderGroundOverlays( &resultImage, tiles ); if ( m_showSunShading && !m_showCityLights ) { paintSunShading( &resultImage, id ); } if ( m_showTileId ) { paintTileId( &resultImage, id ); } return new StackedTile( id, resultImage, tiles ); } void MergedLayerDecorator::Private::renderGroundOverlays( QImage *tileImage, const QVector > &tiles ) const { /* All tiles are covering the same area. Pick one. */ const TileId tileId = tiles.first()->id(); const GeoDataLatLonBox tileLatLonBox = findRelevantTextureLayers(tileId).first()->tileProjection()->geoCoordinates(tileId); /* Map the ground overlay to the image. */ for ( int i = 0; i < m_groundOverlays.size(); ++i ) { const GeoDataGroundOverlay* overlay = m_groundOverlays.at( i ); if ( !overlay->isGloballyVisible() ) { continue; } const GeoDataLatLonBox overlayLatLonBox = overlay->latLonBox(); if ( !tileLatLonBox.intersects( overlayLatLonBox.toCircumscribedRectangle() ) ) { continue; } const qreal pixelToLat = tileLatLonBox.height() / tileImage->height(); const qreal pixelToLon = tileLatLonBox.width() / tileImage->width(); const qreal latToPixel = overlay->icon().height() / overlayLatLonBox.height(); const qreal lonToPixel = overlay->icon().width() / overlayLatLonBox.width(); const qreal global_height = tileImage->height() * TileLoaderHelper::levelToRow( m_levelZeroRows, tileId.zoomLevel() ); const qreal pixel2Rad = M_PI / global_height; const qreal rad2Pixel = global_height / M_PI; qreal latPixelPosition = rad2Pixel/2 * gdInv(tileLatLonBox.north()); const bool isMercatorTileProjection = (m_textureLayers.at( 0 )->tileProjectionType() == GeoSceneAbstractTileProjection::Mercator); for ( int y = 0; y < tileImage->height(); ++y ) { QRgb *scanLine = ( QRgb* ) ( tileImage->scanLine( y ) ); const qreal lat = isMercatorTileProjection ? gd(2 * (latPixelPosition - y) * pixel2Rad ) : tileLatLonBox.north() - y * pixelToLat; for ( int x = 0; x < tileImage->width(); ++x, ++scanLine ) { qreal lon = GeoDataCoordinates::normalizeLon( tileLatLonBox.west() + x * pixelToLon ); GeoDataCoordinates coords(lon, lat); GeoDataCoordinates rotatedCoords(coords); if (overlay->latLonBox().rotation() != 0) { // Possible TODO: Make this faster by creating the axisMatrix beforehand // and just call Quaternion::rotateAroundAxis(const matrix &m) here. rotatedCoords = coords.rotateAround(overlayLatLonBox.center(), -overlay->latLonBox().rotation()); } // TODO: The rotated latLonBox is bigger. We need to take this into account. // (Currently the GroundOverlay sometimes gets clipped because of that) if ( overlay->latLonBox().contains( rotatedCoords ) ) { qreal px = GeoDataLatLonBox::width( rotatedCoords.longitude(), overlayLatLonBox.west() ) * lonToPixel; qreal py = (qreal)( overlay->icon().height() ) - ( GeoDataLatLonBox::height( rotatedCoords.latitude(), overlayLatLonBox.south() ) * latToPixel ) - 1; if ( px >= 0 && px < overlay->icon().width() && py >= 0 && py < overlay->icon().height() ) { int alpha = qAlpha( overlay->icon().pixel( px, py ) ); if ( alpha != 0 ) { QRgb result = ImageF::pixelF( overlay->icon(), px, py ); if (alpha == 255) { *scanLine = result; } else { *scanLine = qRgb( ( alpha * qRed(result) + (255 - alpha) * qRed(*scanLine) ) / 255, ( alpha * qGreen(result) + (255 - alpha) * qGreen(*scanLine) ) / 255, ( alpha * qBlue(result) + (255 - alpha) * qBlue(*scanLine) ) / 255 ); } } } } } } } } StackedTile *MergedLayerDecorator::loadTile( const TileId &stackedTileId ) { const QVector textureLayers = d->findRelevantTextureLayers( stackedTileId ); QVector > tiles; tiles.reserve(textureLayers.size()); for ( const GeoSceneTextureTileDataset *layer: textureLayers ) { const TileId tileId( layer->sourceDir(), stackedTileId.zoomLevel(), stackedTileId.x(), stackedTileId.y() ); mDebug() << Q_FUNC_INFO << layer->sourceDir() << tileId << layer->tileSize() << layer->fileFormat(); // Blending (how to merge the images into an only image) const Blending *blending = d->m_blendingFactory.findBlending( layer->blending() ); if ( blending == nullptr && !layer->blending().isEmpty() ) { mDebug() << Q_FUNC_INFO << "could not find blending" << layer->blending(); } const GeoSceneTextureTileDataset *const textureLayer = static_cast( layer ); const QImage tileImage = d->m_tileLoader->loadTileImage( textureLayer, tileId, DownloadBrowse ); QSharedPointer tile( new TextureTile( tileId, tileImage, blending ) ); tiles.append( tile ); } Q_ASSERT( !tiles.isEmpty() ); return d->createTile( tiles ); } RenderState MergedLayerDecorator::renderState( const TileId &stackedTileId ) const { QString const nameTemplate = "Tile %1/%2/%3"; RenderState state( nameTemplate.arg( stackedTileId.zoomLevel() ) .arg( stackedTileId.x() ) .arg( stackedTileId.y() ) ); const QVector textureLayers = d->findRelevantTextureLayers( stackedTileId ); for ( const GeoSceneTextureTileDataset *layer: textureLayers ) { const TileId tileId( layer->sourceDir(), stackedTileId.zoomLevel(), stackedTileId.x(), stackedTileId.y() ); RenderStatus tileStatus = Complete; switch ( TileLoader::tileStatus( layer, tileId ) ) { case TileLoader::Available: tileStatus = Complete; break; case TileLoader::Expired: tileStatus = WaitingForUpdate; break; case TileLoader::Missing: tileStatus = WaitingForData; break; } state.addChild( RenderState( layer->name(), tileStatus ) ); } return state; } bool MergedLayerDecorator::hasTextureLayer() const { return !d->m_textureLayers.isEmpty(); } StackedTile *MergedLayerDecorator::updateTile( const StackedTile &stackedTile, const TileId &tileId, const QImage &tileImage ) { Q_ASSERT( !tileImage.isNull() ); d->detectMaxTileLevel(); QVector > tiles = stackedTile.tiles(); for ( int i = 0; i < tiles.count(); ++ i) { if ( tiles[i]->id() == tileId ) { const Blending *blending = tiles[i]->blending(); tiles[i] = QSharedPointer( new TextureTile( tileId, tileImage, blending ) ); } } return d->createTile( tiles ); } void MergedLayerDecorator::downloadStackedTile( const TileId &id, DownloadUsage usage ) { const QVector textureLayers = d->findRelevantTextureLayers( id ); for ( const GeoSceneTextureTileDataset *textureLayer: textureLayers ) { if ( TileLoader::tileStatus( textureLayer, id ) != TileLoader::Available || usage == DownloadBrowse ) { d->m_tileLoader->downloadTile( textureLayer, id, usage ); } } } void MergedLayerDecorator::setShowSunShading( bool show ) { d->m_showSunShading = show; } bool MergedLayerDecorator::showSunShading() const { return d->m_showSunShading; } void MergedLayerDecorator::setShowCityLights( bool show ) { d->m_showCityLights = show; } bool MergedLayerDecorator::showCityLights() const { return d->m_showCityLights; } void MergedLayerDecorator::setShowTileId( bool visible ) { d->m_showTileId = visible; } void MergedLayerDecorator::Private::paintSunShading( QImage *tileImage, const TileId &id ) const { if ( tileImage->depth() != 32 ) return; // TODO add support for 8-bit maps? // add sun shading const qreal global_width = tileImage->width() * TileLoaderHelper::levelToColumn( m_levelZeroColumns, id.zoomLevel() ); const qreal global_height = tileImage->height() * TileLoaderHelper::levelToRow( m_levelZeroRows, id.zoomLevel() ); const qreal lon_scale = 2*M_PI / global_width; const qreal lat_scale = -M_PI / global_height; const int tileHeight = tileImage->height(); const int tileWidth = tileImage->width(); // First we determine the supporting point interval for the interpolation. const int n = maxDivisor( 30, tileWidth ); const int ipRight = n * (int)( tileWidth / n ); for ( int cur_y = 0; cur_y < tileHeight; ++cur_y ) { const qreal lat = lat_scale * ( id.y() * tileHeight + cur_y ) - 0.5*M_PI; const qreal a = sin( (lat+DEG2RAD * m_sunLocator->getLat() )/2.0 ); const qreal c = cos(lat)*cos( -DEG2RAD * m_sunLocator->getLat() ); QRgb* scanline = (QRgb*)tileImage->scanLine( cur_y ); qreal lastShade = -10.0; int cur_x = 0; while ( cur_x < tileWidth ) { const bool interpolate = ( cur_x != 0 && cur_x < ipRight && cur_x + n < tileWidth ); qreal shade = 0; if ( interpolate ) { const int check = cur_x + n; const qreal checklon = lon_scale * ( id.x() * tileWidth + check ); shade = m_sunLocator->shading( checklon, a, c ); // if the shading didn't change across the interpolation // interval move on and don't change anything. if ( shade == lastShade && shade == 1.0 ) { scanline += n; cur_x += n; continue; } if ( shade == lastShade && shade == 0.0 ) { for ( int t = 0; t < n; ++t ) { SunLocator::shadePixel(*scanline, shade); ++scanline; } cur_x += n; continue; } for ( int t = 0; t < n ; ++t ) { const qreal lon = lon_scale * ( id.x() * tileWidth + cur_x ); shade = m_sunLocator->shading( lon, a, c ); SunLocator::shadePixel(*scanline, shade); ++scanline; ++cur_x; } } else { // Make sure we don't exceed the image memory if ( cur_x < tileWidth ) { const qreal lon = lon_scale * ( id.x() * tileWidth + cur_x ); shade = m_sunLocator->shading( lon, a, c ); SunLocator::shadePixel(*scanline, shade); ++scanline; ++cur_x; } } lastShade = shade; } } } void MergedLayerDecorator::Private::paintTileId( QImage *tileImage, const TileId &id ) const { QString filename = QString( "%1_%2.jpg" ) .arg(id.x(), tileDigits, 10, QLatin1Char('0')) .arg(id.y(), tileDigits, 10, QLatin1Char('0')); QPainter painter( tileImage ); QColor foreground; QColor background; if ( ( (qreal)(id.x())/2 == id.x()/2 && (qreal)(id.y())/2 == id.y()/2 ) || ( (qreal)(id.x())/2 != id.x()/2 && (qreal)(id.y())/2 != id.y()/2 ) ) { foreground.setNamedColor( "#FFFFFF" ); background.setNamedColor( "#000000" ); } else { foreground.setNamedColor( "#000000" ); background.setNamedColor( "#FFFFFF" ); } int strokeWidth = 10; QPen testPen( foreground ); testPen.setWidth( strokeWidth ); testPen.setJoinStyle( Qt::MiterJoin ); painter.setPen( testPen ); painter.drawRect( strokeWidth / 2, strokeWidth / 2, tileImage->width() - strokeWidth, tileImage->height() - strokeWidth ); QFont testFont(QStringLiteral("Sans Serif"), 12); QFontMetrics testFm( testFont ); painter.setFont( testFont ); QPen outlinepen( foreground ); outlinepen.setWidthF( 6 ); painter.setPen( outlinepen ); painter.setBrush( background ); QPainterPath outlinepath; QPointF baseline1( ( tileImage->width() - testFm.boundingRect(filename).width() ) / 2, ( tileImage->height() * 0.25) ); outlinepath.addText( baseline1, testFont, QString( "level: %1" ).arg(id.zoomLevel()) ); QPointF baseline2( ( tileImage->width() - testFm.boundingRect(filename).width() ) / 2, tileImage->height() * 0.50 ); outlinepath.addText( baseline2, testFont, filename ); QPointF baseline3( ( tileImage->width() - testFm.boundingRect(filename).width() ) / 2, tileImage->height() * 0.75 ); outlinepath.addText( baseline3, testFont, m_themeId ); painter.drawPath( outlinepath ); painter.setPen( Qt::NoPen ); painter.drawPath( outlinepath ); } void MergedLayerDecorator::Private::detectMaxTileLevel() { if ( m_textureLayers.isEmpty() ) { m_maxTileLevel = -1; return; } m_maxTileLevel = TileLoader::maximumTileLevel( *m_textureLayers.at( 0 ) ); } QVector MergedLayerDecorator::Private::findRelevantTextureLayers( const TileId &stackedTileId ) const { QVector result; for ( const GeoSceneTextureTileDataset *candidate: m_textureLayers ) { Q_ASSERT( candidate ); // check, if layer provides tiles for the current level if ( !candidate->hasMaximumTileLevel() || candidate->maximumTileLevel() >= stackedTileId.zoomLevel() ) { //check if the tile intersects with texture bounds if (candidate->latLonBox().isNull()) { result.append(candidate); } else { const GeoDataLatLonBox bbox = candidate->tileProjection()->geoCoordinates(stackedTileId); if (candidate->latLonBox().intersects(bbox)) { result.append( candidate ); } } } } return result; } // TODO: This should likely go into a math class in the future ... int MergedLayerDecorator::Private::maxDivisor( int maximum, int fullLength ) { // Find the optimal interpolation interval n for the // current image canvas width int best = 2; int nEvalMin = fullLength; for ( int it = 1; it <= maximum; ++it ) { // The optimum is the interval which results in the least amount // supporting points taking into account the rest which can't // get used for interpolation. int nEval = fullLength / it + fullLength % it; if ( nEval < nEvalMin ) { nEvalMin = nEval; best = it; } } return best; } diff --git a/src/lib/marble/VisiblePlacemark.cpp b/src/lib/marble/VisiblePlacemark.cpp index cfe08af97..1a84006b7 100644 --- a/src/lib/marble/VisiblePlacemark.cpp +++ b/src/lib/marble/VisiblePlacemark.cpp @@ -1,285 +1,286 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2006-2007 Torsten Rahn // Copyright 2007 Inge Wallin // #include "VisiblePlacemark.h" #include "MarbleDebug.h" #include "RemoteIconLoader.h" #include "GeoDataPlacemark.h" #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include "GeoDataLabelStyle.h" #include "PlacemarkLayer.h" #include #include +#include #include #include using namespace Marble; VisiblePlacemark::VisiblePlacemark( const GeoDataPlacemark *placemark, const GeoDataCoordinates &coordinates, const GeoDataStyle::ConstPtr &style ) : m_placemark( placemark ), m_selected( false ), m_labelDirty(true), m_style(style), m_coordinates(coordinates) { const RemoteIconLoader *remoteLoader = style->iconStyle().remoteIconLoader(); QObject::connect( remoteLoader, SIGNAL(iconReady()), this, SLOT(setSymbolPixmap()) ); setSymbolPixmap(); } const GeoDataPlacemark* VisiblePlacemark::placemark() const { return m_placemark; } const QPixmap& VisiblePlacemark::symbolPixmap() const { if (!m_symbolId.isEmpty() && m_symbolPixmap.isNull()) { if ( !QPixmapCache::find( m_symbolId, &m_symbolPixmap ) ) { m_symbolPixmap = QPixmap::fromImage(m_style->iconStyle().scaledIcon()); QPixmapCache::insert( m_symbolId, m_symbolPixmap); } } return m_symbolPixmap; } const QString& VisiblePlacemark::symbolId() const { return m_symbolId; } bool VisiblePlacemark::selected() const { return m_selected; } void VisiblePlacemark::setSelected( bool selected ) { if (selected != m_selected) { m_selected = selected; m_labelDirty = true; } } const QPointF& VisiblePlacemark::symbolPosition() const { return m_symbolPosition; } const QPointF VisiblePlacemark::hotSpot() const { const QSize iconSize = m_style->iconStyle().scaledIcon().size(); GeoDataHotSpot::Units xunits; GeoDataHotSpot::Units yunits; QPointF pixelHotSpot = m_style->iconStyle().hotSpot( xunits, yunits ); switch ( xunits ) { case GeoDataHotSpot::Fraction: pixelHotSpot.setX( iconSize.width() * pixelHotSpot.x() ); break; case GeoDataHotSpot::Pixels: /* nothing to do */ break; case GeoDataHotSpot::InsetPixels: pixelHotSpot.setX( iconSize.width() - pixelHotSpot.x() ); break; } switch ( yunits ) { case GeoDataHotSpot::Fraction: pixelHotSpot.setY( iconSize.height() * ( 1.0 - pixelHotSpot.y() ) ); break; case GeoDataHotSpot::Pixels: /* nothing to do */ break; case GeoDataHotSpot::InsetPixels: pixelHotSpot.setY( iconSize.height() - pixelHotSpot.y() ); break; } return pixelHotSpot; } void VisiblePlacemark::setSymbolPosition( const QPointF& position ) { m_symbolPosition = position; } const QPixmap& VisiblePlacemark::labelPixmap() { if (m_labelDirty) { drawLabelPixmap(); } return m_labelPixmap; } void VisiblePlacemark::setSymbolPixmap() { if (m_style) { m_symbolId = m_style->iconStyle().iconPath() + QString::number(m_style->iconStyle().scale()); if (m_style->iconStyle().iconPath().isEmpty()) { m_symbolId.clear(); m_symbolPixmap = QPixmap::fromImage(m_style->iconStyle().scaledIcon()); } emit updateNeeded(); } else { mDebug() << "Style pointer is Null"; } } const QRectF& VisiblePlacemark::labelRect() const { return m_labelRect; } void VisiblePlacemark::setLabelRect( const QRectF& labelRect ) { m_labelRect = labelRect; } void VisiblePlacemark::setStyle(const GeoDataStyle::ConstPtr &style) { m_style = style; m_labelDirty = true; setSymbolPixmap(); } GeoDataStyle::ConstPtr VisiblePlacemark::style() const { return m_style; } QRectF VisiblePlacemark::symbolRect() const { return QRectF(m_symbolPosition, m_symbolPixmap.size()); } QRectF VisiblePlacemark::boundingBox() const { return m_labelRect.isEmpty() ? symbolRect() : m_labelRect.united(symbolRect()); } const GeoDataCoordinates &VisiblePlacemark::coordinates() const { return m_coordinates; } void VisiblePlacemark::drawLabelPixmap() { m_labelDirty = false; QString labelName = m_placemark->displayName(); if ( labelName.isEmpty() || m_style->labelStyle().color() == QColor(Qt::transparent) ) { m_labelPixmap = QPixmap(); return; } QFont labelFont = m_style->labelStyle().scaledFont(); QColor labelColor = m_style->labelStyle().color(); LabelStyle labelStyle = Normal; if ( m_selected ) { labelStyle = Selected; } else if ( m_style->labelStyle().glow() ) { labelStyle = Glow; } int textHeight = QFontMetrics( labelFont ).height(); int textWidth; if ( m_style->labelStyle().glow() ) { labelFont.setWeight( 75 ); // Needed to calculate the correct pixmap size; textWidth = ( QFontMetrics( labelFont ).width( labelName ) + qRound( 2 * s_labelOutlineWidth ) ); } else { textWidth = ( QFontMetrics( labelFont ).width( labelName ) ); } // Due to some XOrg bug this requires a workaround via // QImage in some cases (at least with Qt 4.2). if ( !PlacemarkLayer::m_useXWorkaround ) { m_labelPixmap = QPixmap( QSize( textWidth, textHeight ) ); m_labelPixmap.fill( Qt::transparent ); QPainter labelPainter( &m_labelPixmap ); drawLabelText( labelPainter, labelName, labelFont, labelStyle, labelColor ); } else { QImage image( QSize( textWidth, textHeight ), QImage::Format_ARGB32_Premultiplied ); image.fill( 0 ); QPainter labelPainter( &image ); drawLabelText( labelPainter, labelName, labelFont, labelStyle, labelColor ); labelPainter.end(); m_labelPixmap = QPixmap::fromImage( image ); } } void VisiblePlacemark::drawLabelText(QPainter &labelPainter, const QString &text, const QFont &labelFont, LabelStyle labelStyle, const QColor &color ) { QFont font = labelFont; QFontMetrics metrics = QFontMetrics( font ); int fontAscent = metrics.ascent(); switch ( labelStyle ) { case Selected: { labelPainter.setPen( color ); labelPainter.setFont( font ); QRect textRect( 0, 0, metrics.width( text ), metrics.height() ); labelPainter.fillRect( textRect, QApplication::palette().highlight() ); labelPainter.setPen( QPen( QApplication::palette().highlightedText(), 1 ) ); labelPainter.drawText( 0, fontAscent, text ); break; } case Glow: { font.setWeight( 75 ); fontAscent = QFontMetrics( font ).ascent(); QPen outlinepen( color == QColor( Qt::white ) ? Qt::black : Qt::white ); outlinepen.setWidthF( s_labelOutlineWidth ); QBrush outlinebrush( color ); QPainterPath outlinepath; const QPointF baseline( s_labelOutlineWidth / 2.0, fontAscent ); outlinepath.addText( baseline, font, text ); labelPainter.setRenderHint( QPainter::Antialiasing, true ); labelPainter.setPen( outlinepen ); labelPainter.setBrush( outlinebrush ); labelPainter.drawPath( outlinepath ); labelPainter.setPen( Qt::NoPen ); labelPainter.drawPath( outlinepath ); labelPainter.setRenderHint( QPainter::Antialiasing, false ); break; } default: { labelPainter.setPen( color ); labelPainter.setFont( font ); labelPainter.drawText( 0, fontAscent, text ); } } } #include "moc_VisiblePlacemark.cpp" diff --git a/src/lib/marble/graphicsview/FrameGraphicsItem.cpp b/src/lib/marble/graphicsview/FrameGraphicsItem.cpp index 8a90526fb..065f2452c 100644 --- a/src/lib/marble/graphicsview/FrameGraphicsItem.cpp +++ b/src/lib/marble/graphicsview/FrameGraphicsItem.cpp @@ -1,293 +1,294 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2009 Bastian Holst // // Self #include "FrameGraphicsItem.h" #include "FrameGraphicsItem_p.h" // Marble #include "MarbleDebug.h" // Qt #include #include +#include #include #include #include using namespace Marble; FrameGraphicsItem::FrameGraphicsItem( MarbleGraphicsItem *parent ) : ScreenGraphicsItem(new FrameGraphicsItemPrivate(this, parent)) { Q_D(FrameGraphicsItem); d->updateSize(); } FrameGraphicsItem::FrameGraphicsItem(FrameGraphicsItemPrivate *dd) : ScreenGraphicsItem(dd) { Q_D(FrameGraphicsItem); d->updateSize(); } FrameGraphicsItem::~FrameGraphicsItem() { } FrameGraphicsItem::FrameType FrameGraphicsItem::frame() const { Q_D(const FrameGraphicsItem); return d->m_frame; } void FrameGraphicsItem::setFrame( FrameType type ) { Q_D(FrameGraphicsItem); d->m_frame = type; setPadding( padding() ); } qreal FrameGraphicsItem::margin() const { Q_D(const FrameGraphicsItem); return d->m_margin; } void FrameGraphicsItem::setMargin( qreal margin ) { Q_D(FrameGraphicsItem); d->m_margin = margin; d->updateSize(); update(); } qreal FrameGraphicsItem::marginTop() const { Q_D(const FrameGraphicsItem); return d->m_marginTop; } void FrameGraphicsItem::setMarginTop( qreal marginTop ) { Q_D(FrameGraphicsItem); d->m_marginTop = marginTop; d->updateSize(); update(); } qreal FrameGraphicsItem::marginBottom() const { Q_D(const FrameGraphicsItem); return d->m_marginBottom; } void FrameGraphicsItem::setMarginBottom( qreal marginBottom ) { Q_D(FrameGraphicsItem); d->m_marginBottom = marginBottom; d->updateSize(); update(); } qreal FrameGraphicsItem::marginLeft() const { Q_D(const FrameGraphicsItem); return d->m_marginLeft; } void FrameGraphicsItem::setMarginLeft( qreal marginLeft ) { Q_D(FrameGraphicsItem); d->m_marginLeft = marginLeft; d->updateSize(); update(); } qreal FrameGraphicsItem::marginRight() const { Q_D(const FrameGraphicsItem); return d->m_marginRight; } void FrameGraphicsItem::setMarginRight( qreal marginRight ) { Q_D(FrameGraphicsItem); d->m_marginRight = marginRight; d->updateSize(); update(); } qreal FrameGraphicsItem::borderWidth() const { Q_D(const FrameGraphicsItem); return d->m_borderWidth; } void FrameGraphicsItem::setBorderWidth( qreal width ) { Q_D(FrameGraphicsItem); d->m_borderWidth = width; d->updateSize(); update(); } qreal FrameGraphicsItem::padding() const { Q_D(const FrameGraphicsItem); return d->m_padding; } void FrameGraphicsItem::setPadding( qreal width ) { Q_D(FrameGraphicsItem); if ( width >= 0 ) { d->m_padding = width; d->updateSize(); } } QBrush FrameGraphicsItem::borderBrush() const { Q_D(const FrameGraphicsItem); return d->m_borderBrush; } void FrameGraphicsItem::setBorderBrush( const QBrush &brush ) { Q_D(FrameGraphicsItem); d->m_borderBrush = brush; update(); } Qt::PenStyle FrameGraphicsItem::borderStyle () const { Q_D(const FrameGraphicsItem); return d->m_borderStyle; } void FrameGraphicsItem::setBorderStyle( Qt::PenStyle style ) { Q_D(FrameGraphicsItem); d->m_borderStyle = style; update(); } QBrush FrameGraphicsItem::background() const { Q_D(const FrameGraphicsItem); return d->m_backgroundBrush; } void FrameGraphicsItem::setBackground( const QBrush &background ) { Q_D(FrameGraphicsItem); d->m_backgroundBrush = background; update(); } QRectF FrameGraphicsItem::contentRect() const { Q_D(const FrameGraphicsItem); qreal marginTop = ( d->m_marginTop == 0.0 ) ? d->m_margin : d->m_marginTop; qreal marginLeft = ( d->m_marginLeft == 0.0 ) ? d->m_margin : d->m_marginLeft; QRectF contentRect = QRectF( marginLeft + d->m_padding, marginTop + d->m_padding, d->m_contentSize.width(), d->m_contentSize.height() ); return contentRect; } QSizeF FrameGraphicsItem::contentSize() const { Q_D(const FrameGraphicsItem); return d->m_contentSize; } QRectF FrameGraphicsItem::paintedRect() const { Q_D(const FrameGraphicsItem); qreal marginTop = ( d->m_marginTop == 0.0 ) ? d->m_margin : d->m_marginTop; qreal marginBottom = ( d->m_marginBottom == 0.0 ) ? d->m_margin : d->m_marginBottom; qreal marginLeft = ( d->m_marginLeft == 0.0 ) ? d->m_margin : d->m_marginLeft; qreal marginRight = ( d->m_marginRight == 0.0 ) ? d->m_margin : d->m_marginRight; QSizeF size = this->size(); QRectF paintedRect = QRectF( marginLeft, marginTop, size.width() - ( marginLeft + marginRight ), size.height() - ( marginTop + marginBottom ) ); return paintedRect; } void FrameGraphicsItem::setContentSize( const QSizeF& size ) { Q_D(FrameGraphicsItem); d->m_contentSize = size; d->updateSize(); } QPainterPath FrameGraphicsItem::backgroundShape() const { Q_D(const FrameGraphicsItem); QPainterPath path; if ( d->m_frame == RectFrame || d->m_frame == ShadowFrame ) { QRectF renderedRect = paintedRect(); path.addRect( QRectF( 0.0, 0.0, renderedRect.size().width(), renderedRect.size().height() ) ); } else if ( d->m_frame == RoundedRectFrame ) { QSizeF paintedSize = paintedRect().size(); path.addRoundedRect( QRectF( 0.0, 0.0, paintedSize.width() - 1, paintedSize.height() - 1 ), 6, 6 ); } return path; } void FrameGraphicsItem::paintBackground( QPainter *painter ) { Q_D(FrameGraphicsItem); painter->save(); painter->setPen( QPen( d->m_borderBrush, d->m_borderWidth, d->m_borderStyle ) ); painter->setBrush( d->m_backgroundBrush ); painter->drawPath( backgroundShape() ); painter->restore(); } void FrameGraphicsItem::paint( QPainter *painter ) { Q_D(FrameGraphicsItem); painter->save(); // Needs to be done here cause we don't want the margin translation if ( frame() == ShadowFrame ) { QPixmap shadow; if ( !QPixmapCache::find( "marble/frames/shadowframe.png", shadow ) ) { shadow = QPixmap(QStringLiteral(":/marble/frames/shadowframe.png")); QPixmapCache::insert( "marble/frames/shadowframe.png", shadow ); } qDrawBorderPixmap( painter, QRect( QPoint( 0, 0 ), size().toSize() ), QMargins( 10, 10, 10, 10 ), shadow ); } painter->translate( paintedRect().topLeft() ); paintBackground( painter ); painter->translate( d->m_padding, d->m_padding ); paintContent( painter ); painter->restore(); } void FrameGraphicsItem::paintContent( QPainter *painter ) { Q_UNUSED( painter ) } diff --git a/src/lib/marble/layers/GroundLayer.h b/src/lib/marble/layers/GroundLayer.h index b18b160cf..ad8d717b8 100644 --- a/src/lib/marble/layers/GroundLayer.h +++ b/src/lib/marble/layers/GroundLayer.h @@ -1,52 +1,53 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2012 Cezar Mocan // #ifndef MARBLE_GROUNDLAYER_H #define MARBLE_GROUNDLAYER_H #include "LayerInterface.h" #include +#include namespace Marble { class GroundLayer : public LayerInterface { public: GroundLayer(); ~GroundLayer() override; QStringList renderPosition() const override; bool render( GeoPainter *painter, ViewportParams *viewport, const QString& renderPos = QLatin1String("NONE"), GeoSceneLayer * layer = nullptr ) override; qreal zValue() const override; void setColor( const QColor &color ); QColor color() const; RenderState renderState() const override; QString runtimeTrace() const override { return QStringLiteral("GroundLayer"); } private: QColor m_color; // Gets the color specified via DGML's }; } #endif diff --git a/src/plugins/render/compass/CompassFloatItem.cpp b/src/plugins/render/compass/CompassFloatItem.cpp index 09e4c7655..9f222dcd9 100644 --- a/src/plugins/render/compass/CompassFloatItem.cpp +++ b/src/plugins/render/compass/CompassFloatItem.cpp @@ -1,258 +1,259 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2008 Torsten Rahn // Copyright 2010 Dennis Nienhüser // #include "CompassFloatItem.h" #include "ui_CompassConfigWidget.h" #include "MarbleDebug.h" #include "MarbleDirs.h" #include "ViewportParams.h" #include #include #include +#include #include #include namespace Marble { CompassFloatItem::CompassFloatItem() : AbstractFloatItem( nullptr ), m_svgobj( nullptr ), m_polarity( 0 ), m_themeIndex( 0 ), m_configDialog( nullptr ), m_uiConfigWidget( nullptr ) { } CompassFloatItem::CompassFloatItem( const MarbleModel *marbleModel ) : AbstractFloatItem( marbleModel, QPointF( -1.0, 10.0 ), QSizeF( 75.0, 75.0 ) ), m_isInitialized( false ), m_svgobj( nullptr ), m_compass(), m_polarity( 0 ), m_themeIndex( 0 ), m_configDialog( nullptr ), m_uiConfigWidget( nullptr ) { } CompassFloatItem::~CompassFloatItem () { delete m_svgobj; } QStringList CompassFloatItem::backendTypes() const { return QStringList(QStringLiteral("compass")); } QString CompassFloatItem::name() const { return tr( "Compass" ); } QString CompassFloatItem::guiString() const { return tr( "&Compass" ); } QString CompassFloatItem::nameId() const { return QStringLiteral("compass"); } QString CompassFloatItem::version() const { return QStringLiteral("1.0"); } QString CompassFloatItem::description() const { return tr( "This is a float item that provides a compass." ); } QString CompassFloatItem::copyrightYears() const { return QStringLiteral("2009, 2010"); } QVector CompassFloatItem::pluginAuthors() const { return QVector() << PluginAuthor(QStringLiteral("Dennis Nienhüser"), QStringLiteral("nienhueser@kde.org")) << PluginAuthor(QStringLiteral("Torsten Rahn"), QStringLiteral("tackat@kde.org")); } QIcon CompassFloatItem::icon() const { return QIcon(QStringLiteral(":/icons/compass.png")); } void CompassFloatItem::initialize() { readSettings(); m_isInitialized = true; } bool CompassFloatItem::isInitialized() const { return m_isInitialized; } QPainterPath CompassFloatItem::backgroundShape() const { QRectF contentRect = this->contentRect(); QPainterPath path; int fontheight = QFontMetrics( font() ).ascent(); int compassLength = static_cast( contentRect.height() ) - 5 - fontheight; path.addEllipse( QRectF( QPointF( marginLeft() + padding() + ( contentRect.width() - compassLength ) / 2, marginTop() + padding() + 5 + fontheight ), QSize( compassLength, compassLength ) ).toRect() ); return path; } void CompassFloatItem::setProjection( const ViewportParams *viewport ) { // figure out the polarity ... if ( m_polarity != viewport->polarity() ) { m_polarity = viewport->polarity(); update(); } AbstractFloatItem::setProjection( viewport ); } void CompassFloatItem::paintContent( QPainter *painter ) { painter->save(); QRectF compassRect( contentRect() ); const QString dirstr = (m_polarity == +1) ? tr("N") : (m_polarity == -1) ? tr("S") : /*else*/ QString(); int fontheight = QFontMetrics( font() ).ascent(); int fontwidth = QFontMetrics( font() ).boundingRect( dirstr ).width(); QPen outlinepen( background().color() ); outlinepen.setWidth( 2 ); QBrush outlinebrush( pen().color() ); QPainterPath outlinepath; const QPointF baseline( 0.5 * (qreal)( compassRect.width() - fontwidth ), (qreal)(fontheight) + 2.0 ); outlinepath.addText( baseline, font(), dirstr ); painter->setPen( outlinepen ); painter->setBrush( outlinebrush ); painter->drawPath( outlinepath ); painter->setPen( Qt::NoPen ); painter->drawPath( outlinepath ); int compassLength = static_cast( compassRect.height() ) - 5 - fontheight; QSize compassSize( compassLength, compassLength ); // Rerender compass pixmap if the size has changed if ( m_compass.isNull() || m_compass.size() != compassSize ) { m_compass = QPixmap( compassSize ); m_compass.fill( Qt::transparent ); QPainter mapPainter( &m_compass ); mapPainter.setViewport( m_compass.rect() ); m_svgobj->render( &mapPainter ); } painter->drawPixmap( QPoint( static_cast( compassRect.width() - compassLength ) / 2, fontheight + 5 ), m_compass ); painter->restore(); } QDialog *CompassFloatItem::configDialog() { if ( !m_configDialog ) { m_configDialog = new QDialog(); m_uiConfigWidget = new Ui::CompassConfigWidget; m_uiConfigWidget->setupUi( m_configDialog ); readSettings(); connect( m_uiConfigWidget->m_buttonBox, SIGNAL(accepted()), SLOT(writeSettings()) ); connect( m_uiConfigWidget->m_buttonBox, SIGNAL(rejected()), SLOT(readSettings()) ); QPushButton *applyButton = m_uiConfigWidget->m_buttonBox->button( QDialogButtonBox::Apply ); connect( applyButton, SIGNAL(clicked()), this, SLOT(writeSettings()) ); } return m_configDialog; } QHash CompassFloatItem::settings() const { QHash result = AbstractFloatItem::settings(); result.insert(QStringLiteral("theme"), m_themeIndex); return result; } void CompassFloatItem::setSettings( const QHash &settings ) { AbstractFloatItem::setSettings( settings ); m_themeIndex = settings.value(QStringLiteral("theme"), 0).toInt(); readSettings(); } void CompassFloatItem::readSettings() { if ( m_uiConfigWidget && m_themeIndex >= 0 && m_themeIndex < m_uiConfigWidget->m_themeList->count() ) { m_uiConfigWidget->m_themeList->setCurrentRow( m_themeIndex ); } QString theme = QStringLiteral(":/compass.svg"); switch( m_themeIndex ) { case 1: theme = QStringLiteral(":/compass-arrows.svg"); break; case 2: theme = QStringLiteral(":/compass-atom.svg"); break; case 3: theme = QStringLiteral(":/compass-magnet.svg"); break; } delete m_svgobj; m_svgobj = new QSvgRenderer( theme, this ); m_compass = QPixmap(); } void CompassFloatItem::writeSettings() { if ( m_uiConfigWidget ) { m_themeIndex = m_uiConfigWidget->m_themeList->currentRow(); } readSettings(); update(); emit settingsChanged( nameId() ); } } #include "moc_CompassFloatItem.cpp" diff --git a/src/plugins/render/elevationprofilefloatitem/ElevationProfileFloatItem.cpp b/src/plugins/render/elevationprofilefloatitem/ElevationProfileFloatItem.cpp index 154264e67..c63235958 100644 --- a/src/plugins/render/elevationprofilefloatitem/ElevationProfileFloatItem.cpp +++ b/src/plugins/render/elevationprofilefloatitem/ElevationProfileFloatItem.cpp @@ -1,729 +1,730 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2011-2012 Florian Eßer // Copyright 2012 Bernhard Beschow // Copyright 2013 Roman Karlstetter // #include "ElevationProfileFloatItem.h" #include "ElevationProfileContextMenu.h" #include "ui_ElevationProfileConfigWidget.h" #include "MarbleModel.h" #include "MarbleWidget.h" #include "GeoDataPlacemark.h" #include "GeoDataTreeModel.h" #include "ViewportParams.h" #include "MarbleColors.h" #include "MarbleDirs.h" #include "ElevationModel.h" #include "MarbleGraphicsGridLayout.h" #include "MarbleDebug.h" #include "routing/RoutingManager.h" #include "routing/RoutingModel.h" #include #include #include +#include #include #include #include namespace Marble { ElevationProfileFloatItem::ElevationProfileFloatItem( const MarbleModel *marbleModel ) : AbstractFloatItem( marbleModel, QPointF( 220, 10.5 ), QSizeF( 0.0, 50.0 ) ), m_activeDataSource(nullptr), m_routeDataSource( marbleModel ? marbleModel->routingManager()->routingModel() : nullptr, marbleModel ? marbleModel->elevationModel() : nullptr, this ), m_trackDataSource( marbleModel ? marbleModel->treeModel() : nullptr, this ), m_configDialog( nullptr ), ui_configWidget( nullptr ), m_leftGraphMargin( 0 ), m_eleGraphWidth( 0 ), m_viewportWidth( 0 ), m_shrinkFactorY( 1.2 ), m_fontHeight( 10 ), m_markerPlacemark( new GeoDataPlacemark ), m_documentIndex( -1 ), m_cursorPositionX( 0 ), m_isInitialized( false ), m_contextMenu( nullptr ), m_marbleWidget( nullptr ), m_firstVisiblePoint( 0 ), m_lastVisiblePoint( 0 ), m_zoomToViewport( false ) { setVisible( false ); bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; if ( smallScreen ) { setPosition( QPointF( 10.5, 10.5 ) ); } bool const highRes = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::HighResolution; m_eleGraphHeight = highRes ? 100 : 50; /// TODO make configurable setPadding( 1 ); m_markerDocument.setDocumentRole( UnknownDocument ); m_markerDocument.setName(QStringLiteral("Elevation Profile")); m_markerPlacemark->setName(QStringLiteral("Elevation Marker")); m_markerPlacemark->setVisible( false ); m_markerDocument.append( m_markerPlacemark ); m_contextMenu = new ElevationProfileContextMenu(this); connect( &m_trackDataSource, SIGNAL(sourceCountChanged()), m_contextMenu, SLOT(updateContextMenuEntries()) ); connect( &m_routeDataSource, SIGNAL(sourceCountChanged()), m_contextMenu, SLOT(updateContextMenuEntries()) ); } ElevationProfileFloatItem::~ElevationProfileFloatItem() { } QStringList ElevationProfileFloatItem::backendTypes() const { return QStringList(QStringLiteral("elevationprofile")); } qreal ElevationProfileFloatItem::zValue() const { return 3.0; } QString ElevationProfileFloatItem::name() const { return tr("Elevation Profile"); } QString ElevationProfileFloatItem::guiString() const { return tr("&Elevation Profile"); } QString ElevationProfileFloatItem::nameId() const { return QStringLiteral("elevationprofile"); } QString ElevationProfileFloatItem::version() const { return QStringLiteral("1.2"); // TODO: increase to 1.3 ? } QString ElevationProfileFloatItem::description() const { return tr( "A float item that shows the elevation profile of the current route." ); } QString ElevationProfileFloatItem::copyrightYears() const { return QStringLiteral("2011, 2012, 2013"); } QVector ElevationProfileFloatItem::pluginAuthors() const { return QVector() << PluginAuthor(QStringLiteral("Florian Eßer"),QStringLiteral("f.esser@rwth-aachen.de")) << PluginAuthor(QStringLiteral("Bernhard Beschow"), QStringLiteral("bbeschow@cs.tu-berlin.de")) << PluginAuthor(QStringLiteral("Roman Karlstetter"), QStringLiteral("roman.karlstetter@googlemail.com")); } QIcon ElevationProfileFloatItem::icon () const { return QIcon(QStringLiteral(":/icons/elevationprofile.png")); } void ElevationProfileFloatItem::initialize () { connect( marbleModel()->elevationModel(), SIGNAL(updateAvailable()), &m_routeDataSource, SLOT(requestUpdate()) ); connect( marbleModel()->routingManager()->routingModel(), SIGNAL(currentRouteChanged()), &m_routeDataSource, SLOT(requestUpdate()) ); connect( this, SIGNAL(dataUpdated()), SLOT(forceRepaint()) ); switchDataSource(&m_routeDataSource); m_fontHeight = QFontMetricsF( font() ).ascent() + 1; m_leftGraphMargin = QFontMetricsF( font() ).width( "0000 m" ); /// TODO make this dynamic according to actual need m_isInitialized = true; } bool ElevationProfileFloatItem::isInitialized () const { return m_isInitialized; } void ElevationProfileFloatItem::setProjection( const ViewportParams *viewport ) { if ( !( viewport->width() == m_viewportWidth && m_isInitialized ) ) { bool const highRes = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::HighResolution; int const widthRatio = highRes ? 2 : 3; setContentSize( QSizeF( viewport->width() / widthRatio, m_eleGraphHeight + m_fontHeight * 2.5 ) ); m_eleGraphWidth = contentSize().width() - m_leftGraphMargin; m_axisX.setLength( m_eleGraphWidth ); m_axisY.setLength( m_eleGraphHeight ); m_axisX.setTickCount( 3, m_eleGraphWidth / ( m_leftGraphMargin * 1.5 ) ); m_axisY.setTickCount( 2, m_eleGraphHeight / m_fontHeight ); m_viewportWidth = viewport->width(); bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; if ( !m_isInitialized && !smallScreen ) { setPosition( QPointF( (viewport->width() - contentSize().width()) / 2 , 10.5 ) ); } } update(); AbstractFloatItem::setProjection( viewport ); } void ElevationProfileFloatItem::paintContent( QPainter *painter ) { // do not try to draw if not initialized if(!isInitialized()) { return; } painter->save(); painter->setRenderHint( QPainter::Antialiasing, true ); painter->setFont( font() ); if ( ! ( m_activeDataSource->isDataAvailable() && m_eleData.size() > 0 ) ) { painter->setPen( QColor( Qt::black ) ); QString text = tr( "Create a route or load a track from file to view its elevation profile." ); painter->drawText( contentRect().toRect(), Qt::TextWordWrap | Qt::AlignCenter, text ); painter->restore(); return; } if ( m_zoomToViewport && ( m_lastVisiblePoint - m_firstVisiblePoint < 5 ) ) { painter->setPen( QColor( Qt::black ) ); QString text = tr( "Not enough points in the current viewport.\nTry to disable 'Zoom to viewport'." ); painter->drawText( contentRect().toRect(), Qt::TextWordWrap | Qt::AlignCenter, text ); painter->restore(); return; } QString intervalStr; int lastStringEnds; // draw viewport bounds if ( ! m_zoomToViewport && ( m_firstVisiblePoint > 0 || m_lastVisiblePoint < m_eleData.size() - 1 ) ) { QColor color( Qt::black ); color.setAlpha( 64 ); QRect rect; rect.setLeft( m_leftGraphMargin + m_eleData.value( m_firstVisiblePoint ).x() * m_eleGraphWidth / m_axisX.range() ); rect.setTop( 0 ); rect.setWidth( ( m_eleData.value( m_lastVisiblePoint ).x() - m_eleData.value( m_firstVisiblePoint ).x() ) * m_eleGraphWidth / m_axisX.range() ); rect.setHeight( m_eleGraphHeight ); painter->fillRect( rect, color ); } // draw X and Y axis painter->setPen( Oxygen::aluminumGray4 ); painter->drawLine( m_leftGraphMargin, m_eleGraphHeight, contentSize().width(), m_eleGraphHeight ); painter->drawLine( m_leftGraphMargin, m_eleGraphHeight, m_leftGraphMargin, 0 ); // draw Y grid and labels painter->setPen( QColor( Qt::black ) ); QPen dashedPen( Qt::DashLine ); dashedPen.setColor( Oxygen::aluminumGray4 ); QRect labelRect( 0, 0, m_leftGraphMargin - 1, m_fontHeight + 2 ); lastStringEnds = m_eleGraphHeight + m_fontHeight; // painter->drawText(m_leftGraphMargin + 1, m_fontHeight, QLatin1Char('[') + m_axisY.unit() + QLatin1Char(']')); for ( const AxisTick &tick: m_axisY.ticks() ) { const int posY = m_eleGraphHeight - tick.position; painter->setPen( dashedPen ); painter->drawLine( m_leftGraphMargin, posY, contentSize().width(), posY ); labelRect.moveCenter( QPoint( labelRect.center().x(), posY ) ); if ( labelRect.top() < 0 ) { // don't cut off uppermost label labelRect.moveTop( 0 ); } if ( labelRect.bottom() >= lastStringEnds ) { // Don't print overlapping labels continue; } lastStringEnds = labelRect.top(); painter->setPen( QColor( Qt::black ) ); intervalStr.setNum( tick.value * m_axisY.scale() ); painter->drawText( labelRect, Qt::AlignRight, intervalStr ); } // draw X grid and labels painter->setPen( QColor( Qt::black ) ); labelRect.moveTop( m_eleGraphHeight + 1 ); lastStringEnds = 0; for ( const AxisTick &tick: m_axisX.ticks() ) { const int posX = m_leftGraphMargin + tick.position; painter->setPen( dashedPen ); painter->drawLine( posX, 0, posX, m_eleGraphHeight ); intervalStr.setNum( tick.value * m_axisX.scale() ); if ( tick.position == m_axisX.ticks().last().position ) { intervalStr += QLatin1Char(' ') + m_axisX.unit(); } labelRect.setWidth( QFontMetricsF( font() ).width( intervalStr ) * 1.5 ); labelRect.moveCenter( QPoint( posX, labelRect.center().y() ) ); if ( labelRect.right() > m_leftGraphMargin + m_eleGraphWidth ) { // don't cut off rightmost label labelRect.moveRight( m_leftGraphMargin + m_eleGraphWidth ); } if ( labelRect.left() <= lastStringEnds ) { // Don't print overlapping labels continue; } lastStringEnds = labelRect.right(); painter->setPen( QColor( Qt::black ) ); painter->drawText( labelRect, Qt::AlignCenter, intervalStr ); } // display elevation gain/loss data painter->setPen( QColor( Qt::black ) ); intervalStr = tr( "Difference: %1 %2" ) .arg( QString::number( m_gain - m_loss, 'f', 0 ) ) .arg( m_axisY.unit() ); intervalStr += QString::fromUtf8( " (↗ %1 %3 ↘ %2 %3)" ) .arg( QString::number( m_gain, 'f', 0 ) ) .arg( QString::number( m_loss, 'f', 0 ) ) .arg( m_axisY.unit() ); painter->drawText( contentRect().toRect(), Qt::AlignBottom | Qt::AlignCenter, intervalStr ); // draw elevation profile painter->setPen( QColor( Qt::black ) ); bool const highRes = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::HighResolution; QPen pen = painter->pen(); pen.setWidth( highRes ? 2 : 1 ); painter->setPen( pen ); QLinearGradient fillGradient( 0, 0, 0, m_eleGraphHeight ); QColor startColor = Oxygen::forestGreen4; QColor endColor = Oxygen::hotOrange4; startColor.setAlpha( 200 ); endColor.setAlpha( 32 ); fillGradient.setColorAt( 0.0, startColor ); fillGradient.setColorAt( 1.0, endColor ); QBrush brush = QBrush( fillGradient ); painter->setBrush( brush ); QPoint oldPos; oldPos.setX( m_leftGraphMargin ); oldPos.setY( ( m_axisY.minValue() - m_axisY.minValue() ) * m_eleGraphHeight / ( m_axisY.range() / m_shrinkFactorY ) ); oldPos.setY( m_eleGraphHeight - oldPos.y() ); QPainterPath path; path.moveTo( oldPos.x(), m_eleGraphHeight ); path.lineTo( oldPos.x(), oldPos.y() ); const int start = m_zoomToViewport ? m_firstVisiblePoint : 0; const int end = m_zoomToViewport ? m_lastVisiblePoint : m_eleData.size() - 1; for ( int i = start; i <= end; ++i ) { QPoint newPos; if ( i == start ) { // make sure the plot always starts at the y-axis newPos.setX( 0 ); } else { newPos.setX( ( m_eleData.value(i).x() - m_axisX.minValue() ) * m_eleGraphWidth / m_axisX.range() ); } newPos.rx() += m_leftGraphMargin; if ( newPos.x() != oldPos.x() || newPos.y() != oldPos.y() ) { newPos.setY( ( m_eleData.value(i).y() - m_axisY.minValue() ) * m_eleGraphHeight / ( m_axisY.range() * m_shrinkFactorY ) ); newPos.setY( m_eleGraphHeight - newPos.y() ); path.lineTo( newPos.x(), newPos.y() ); oldPos = newPos; } } path.lineTo( oldPos.x(), m_eleGraphHeight ); // fill painter->setPen( QPen( Qt::NoPen ) ); painter->drawPath( path ); // contour // "remove" the first and last path element first, they are only used to fill down to the bottom painter->setBrush( QBrush( Qt::NoBrush ) ); path.setElementPositionAt( 0, path.elementAt( 1 ).x, path.elementAt( 1 ).y ); path.setElementPositionAt( path.elementCount()-1, path.elementAt( path.elementCount()-2 ).x, path.elementAt( path.elementCount()-2 ).y ); painter->setPen( pen ); painter->drawPath( path ); pen.setWidth( 1 ); painter->setPen( pen ); // draw interactive cursor const GeoDataCoordinates currentPoint = m_markerPlacemark->coordinate(); if ( currentPoint.isValid() ) { painter->setPen( QColor( Qt::white ) ); painter->drawLine( m_leftGraphMargin + m_cursorPositionX, 0, m_leftGraphMargin + m_cursorPositionX, m_eleGraphHeight ); qreal xpos = m_axisX.minValue() + ( m_cursorPositionX / m_eleGraphWidth ) * m_axisX.range(); qreal ypos = m_eleGraphHeight - ( ( currentPoint.altitude() - m_axisY.minValue() ) / ( qMax( 1.0, m_axisY.range() ) * m_shrinkFactorY ) ) * m_eleGraphHeight; painter->drawLine( m_leftGraphMargin + m_cursorPositionX - 5, ypos, m_leftGraphMargin + m_cursorPositionX + 5, ypos ); intervalStr.setNum( xpos * m_axisX.scale(), 'f', 2 ); intervalStr += QLatin1Char(' ') + m_axisX.unit(); int currentStringBegin = m_leftGraphMargin + m_cursorPositionX - QFontMetricsF( font() ).width( intervalStr ) / 2; painter->drawText( currentStringBegin, contentSize().height() - 1.5 * m_fontHeight, intervalStr ); intervalStr.setNum( currentPoint.altitude(), 'f', 1 ); intervalStr += QLatin1Char(' ') + m_axisY.unit(); if ( m_cursorPositionX + QFontMetricsF( font() ).width( intervalStr ) + m_leftGraphMargin < m_eleGraphWidth ) { currentStringBegin = ( m_leftGraphMargin + m_cursorPositionX + 5 + 2 ); } else { currentStringBegin = m_leftGraphMargin + m_cursorPositionX - 5 - QFontMetricsF( font() ).width( intervalStr ) * 1.5; } // Make sure the text still fits into the window while ( ypos < m_fontHeight ) { ypos++; } painter->drawText( currentStringBegin, ypos + m_fontHeight / 2, intervalStr ); } painter->restore(); } QDialog *ElevationProfileFloatItem::configDialog() //FIXME TODO Make a config dialog? /// TODO what is this comment? { if ( !m_configDialog ) { // Initializing configuration dialog m_configDialog = new QDialog(); ui_configWidget = new Ui::ElevationProfileConfigWidget; ui_configWidget->setupUi( m_configDialog ); readSettings(); connect( ui_configWidget->m_buttonBox, SIGNAL(accepted()), SLOT(writeSettings()) ); connect( ui_configWidget->m_buttonBox, SIGNAL(rejected()), SLOT(readSettings()) ); QPushButton *applyButton = ui_configWidget->m_buttonBox->button( QDialogButtonBox::Apply ); connect( applyButton, SIGNAL(clicked()), this, SLOT(writeSettings()) ); } return m_configDialog; } void ElevationProfileFloatItem::contextMenuEvent( QWidget *w, QContextMenuEvent *e ) { Q_ASSERT( m_contextMenu ); m_contextMenu->getMenu()->exec( w->mapToGlobal( e->pos() ) ); } bool ElevationProfileFloatItem::eventFilter( QObject *object, QEvent *e ) { if ( !enabled() || !visible() ) { return false; } MarbleWidget *widget = dynamic_cast( object ); if ( !widget ) { return AbstractFloatItem::eventFilter(object,e); } if ( widget && !m_marbleWidget ) { m_marbleWidget = widget; connect( this, SIGNAL(dataUpdated()), this, SLOT(updateVisiblePoints()) ); connect( m_marbleWidget, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)), this, SLOT(updateVisiblePoints()) ); connect( this, SIGNAL(settingsChanged(QString)), this, SLOT(updateVisiblePoints()) ); } if ( e->type() == QEvent::MouseButtonDblClick || e->type() == QEvent::MouseMove ) { GeoDataTreeModel *const treeModel = const_cast( marbleModel() )->treeModel(); QMouseEvent *event = static_cast( e ); QRectF plotRect = QRectF ( m_leftGraphMargin, 0, m_eleGraphWidth, contentSize().height() ); plotRect.translate( positivePosition() ); plotRect.translate( padding(), padding() ); // for antialiasing: increase size by 1 px to each side plotRect.translate(-1, -1); plotRect.setSize(plotRect.size() + QSize(2, 2) ); const bool cursorAboveFloatItem = plotRect.contains(event->pos()); if ( cursorAboveFloatItem ) { const int start = m_zoomToViewport ? m_firstVisiblePoint : 0; const int end = m_zoomToViewport ? m_lastVisiblePoint : m_eleData.size(); // Double click triggers recentering the map at the specified position if ( e->type() == QEvent::MouseButtonDblClick ) { const QPointF mousePosition = event->pos() - plotRect.topLeft(); const int xPos = mousePosition.x(); for ( int i = start; i < end; ++i) { const int plotPos = ( m_eleData.value(i).x() - m_axisX.minValue() ) * m_eleGraphWidth / m_axisX.range(); if ( plotPos >= xPos ) { widget->centerOn( m_points[i], true ); break; } } return true; } if ( e->type() == QEvent::MouseMove && !(event->buttons() & Qt::LeftButton) ) { // Cross hair cursor when moving above the float item // and mark the position on the graph widget->setCursor(QCursor(Qt::CrossCursor)); if ( m_cursorPositionX != event->pos().x() - plotRect.left() ) { m_cursorPositionX = event->pos().x() - plotRect.left(); const qreal xpos = m_axisX.minValue() + ( m_cursorPositionX / m_eleGraphWidth ) * m_axisX.range(); GeoDataCoordinates currentPoint; // invalid coordinates for ( int i = start; i < end; ++i) { if ( m_eleData.value(i).x() >= xpos ) { currentPoint = m_points[i]; currentPoint.setAltitude( m_eleData.value(i).y() ); break; } } m_markerPlacemark->setCoordinate( currentPoint ); if ( m_documentIndex < 0 ) { m_documentIndex = treeModel->addDocument( &m_markerDocument ); } emit repaintNeeded(); } return true; } } else { if ( m_documentIndex >= 0 ) { m_markerPlacemark->setCoordinate( GeoDataCoordinates() ); // set to invalid treeModel->removeDocument( &m_markerDocument ); m_documentIndex = -1; emit repaintNeeded(); } } } return AbstractFloatItem::eventFilter(object,e); } void ElevationProfileFloatItem::handleDataUpdate(const GeoDataLineString &points, const QVector &eleData) { m_eleData = eleData; m_points = points; calculateStatistics( m_eleData ); if ( m_eleData.length() >= 2 ) { m_axisX.setRange( m_eleData.first().x(), m_eleData.last().x() ); m_axisY.setRange( qMin( m_minElevation, qreal( 0.0 ) ), m_maxElevation ); } emit dataUpdated(); } void ElevationProfileFloatItem::updateVisiblePoints() { if ( ! m_activeDataSource->isDataAvailable() || m_points.size() < 2 ) { return; } // find the longest visible route section on screen QList > routeSegments; QList currentRouteSegment; for ( int i = 0; i < m_eleData.count(); i++ ) { qreal lon = m_points[i].longitude(GeoDataCoordinates::Degree); qreal lat = m_points[i].latitude (GeoDataCoordinates::Degree); qreal x = 0; qreal y = 0; if ( m_marbleWidget->screenCoordinates(lon, lat, x, y) ) { // on screen --> add point to list currentRouteSegment.append(i); } else { // off screen --> start new list if ( !currentRouteSegment.isEmpty() ) { routeSegments.append( currentRouteSegment ); currentRouteSegment.clear(); } } } routeSegments.append( currentRouteSegment ); // in case the route ends on screen int maxLenght = 0; for ( const QList ¤tRouteSegment: routeSegments ) { if ( currentRouteSegment.size() > maxLenght ) { maxLenght = currentRouteSegment.size() ; m_firstVisiblePoint = currentRouteSegment.first(); m_lastVisiblePoint = currentRouteSegment.last(); } } if ( m_firstVisiblePoint < 0 ) { m_firstVisiblePoint = 0; } if ( m_lastVisiblePoint < 0 || m_lastVisiblePoint >= m_eleData.count() ) { m_lastVisiblePoint = m_eleData.count() - 1; } // include setting range to statistics and test for m_zoomToViewport in calculateStatistics(); if ( m_zoomToViewport ) { calculateStatistics( m_eleData ); m_axisX.setRange( m_eleData.value( m_firstVisiblePoint ).x(), m_eleData.value( m_lastVisiblePoint ).x() ); m_axisY.setRange( m_minElevation, m_maxElevation ); } return; } void ElevationProfileFloatItem::calculateStatistics(const QVector &eleData) { // This basically calculates the important peaks of the moving average filtered elevation and // calculates the elevation data based on this points. // This is done by always placing the averaging window in a way that it starts or ends at an // original data point. This should ensure that all minima/maxima of the moving average // filtered data are covered. const qreal averageDistance = 200.0; m_maxElevation = 0.0; m_minElevation = invalidElevationData; m_gain = 0.0; m_loss = 0.0; const int start = m_zoomToViewport ? m_firstVisiblePoint : 0; const int end = m_zoomToViewport ? m_lastVisiblePoint + 1 : eleData.size(); if( start < end ) { qreal lastX = eleData.value( start ).x(); qreal lastY = eleData.value( start ).y(); qreal nextX = eleData.value( start + 1 ).x(); qreal nextY = eleData.value( start + 1 ).y(); m_maxElevation = qMax( lastY, nextY ); m_minElevation = qMin( lastY, nextY ); int averageStart = start; if(lastX + averageDistance < eleData.value( start + 2 ).x()) ++averageStart; for ( int index = start + 2; index <= end; ++index ) { qreal indexX = index < end ? eleData.value( index ).x() : eleData.value( end - 1 ).x() + averageDistance; qreal indexY = eleData.value( qMin( index, end - 1 ) ).y(); m_maxElevation = qMax( m_maxElevation, indexY ); m_minElevation = qMin( m_minElevation, indexY ); // Low-pass filtering (moving average) of the elevation profile to calculate gain and loss values // not always the best method, see for example // http://www.ikg.uni-hannover.de/fileadmin/ikg/staff/thesis/finished/documents/StudArb_Schulze.pdf // (German), chapter 4.2 // Average over the part ending with the previous point. // Do complete recalculation to avoid accumulation of floating point artifacts. nextY = 0; qreal averageX = nextX - averageDistance; for( int averageIndex = averageStart; averageIndex < index; ++averageIndex ) { qreal nextAverageX = eleData.value( averageIndex ).x(); qreal ratio = ( nextAverageX - averageX ) / averageDistance; // Weighting of original data based on covered distance nextY += eleData.value( qMax( averageIndex - 1, 0 ) ).y() * ratio; averageX = nextAverageX; } while( averageStart < index ) { // This handles the part ending with the previous point on the first iteration and the parts starting with averageStart afterwards if ( nextY > lastY ) { m_gain += nextY - lastY; } else { m_loss += lastY - nextY; } // Here we split the data into parts that average over the same data points // As soon as the end of the averaging window reaches the current point we reached the end of the current part lastX = nextX; lastY = nextY; nextX = eleData.value( averageStart ).x() + averageDistance; if( nextX >= indexX ) { break; } // We don't need to recalculate the average completely, just remove the reached point qreal ratio = (nextX - lastX) / averageDistance; nextY += ( eleData.value( index - 1 ).y() - eleData.value( qMax( averageStart - 1, 0 ) ).y() ) * ratio; ++averageStart; } // This is for the next part already, the end of the averaging window is at the following point nextX = indexX; } // Also include the last point nextY = eleData.value( end - 1 ).y(); if ( nextY > lastY ) { m_gain += nextY - lastY; } else { m_loss += lastY - nextY; } } } void ElevationProfileFloatItem::forceRepaint() { // We add one pixel as antialiasing could result into painting on these pixels to. QRectF floatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ), size() + QSize( 2, 2 ) ); update(); emit repaintNeeded( floatItemRect.toRect() ); } void ElevationProfileFloatItem::readSettings() { if ( !m_configDialog ) return; if ( m_zoomToViewport ) { ui_configWidget->m_zoomToViewportCheckBox->setCheckState( Qt::Checked ); } else { ui_configWidget->m_zoomToViewportCheckBox->setCheckState( Qt::Unchecked ); } } void ElevationProfileFloatItem::writeSettings() { if ( ui_configWidget->m_zoomToViewportCheckBox->checkState() == Qt::Checked ) { m_zoomToViewport = true; } else { m_zoomToViewport = false; } emit settingsChanged( nameId() ); } void ElevationProfileFloatItem::toggleZoomToViewport() { m_zoomToViewport = ! m_zoomToViewport; calculateStatistics( m_eleData ); if ( ! m_zoomToViewport ) { m_axisX.setRange( m_eleData.first().x(), m_eleData.last().x() ); m_axisY.setRange( qMin( m_minElevation, qreal( 0.0 ) ), m_maxElevation ); } readSettings(); emit settingsChanged( nameId() ); } void ElevationProfileFloatItem::switchToRouteDataSource() { switchDataSource(&m_routeDataSource); } void ElevationProfileFloatItem::switchToTrackDataSource(int index) { m_trackDataSource.setSourceIndex(index); switchDataSource(&m_trackDataSource); } void ElevationProfileFloatItem::switchDataSource(ElevationProfileDataSource* source) { if (m_activeDataSource) { disconnect(m_activeDataSource, SIGNAL(dataUpdated(GeoDataLineString,QVector)),nullptr,nullptr); } m_activeDataSource = source; connect(m_activeDataSource, SIGNAL(dataUpdated(GeoDataLineString,QVector)), this, SLOT(handleDataUpdate(GeoDataLineString,QVector))); m_activeDataSource->requestUpdate(); } } #include "moc_ElevationProfileFloatItem.cpp" diff --git a/src/plugins/render/foursquare/FoursquareItem.cpp b/src/plugins/render/foursquare/FoursquareItem.cpp index d9e1f57d8..0bf68face 100644 --- a/src/plugins/render/foursquare/FoursquareItem.cpp +++ b/src/plugins/render/foursquare/FoursquareItem.cpp @@ -1,172 +1,173 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2012 Utku Aydın // #include "FoursquareItem.h" #include "GeoPainter.h" #include "ViewportParams.h" #include +#include namespace Marble { QFont FoursquareItem::s_font = QFont( QStringLiteral( "Sans Serif" ), 8 ); FoursquareItem::FoursquareItem(QObject* parent) : AbstractDataPluginItem( parent ), m_usersCount( 0 ) { setSize( QSize( 0, 0 ) ); } FoursquareItem::~FoursquareItem() { } bool FoursquareItem::initialized() const { // Find something logical for this return true; } bool FoursquareItem::operator<( const AbstractDataPluginItem *other ) const { const FoursquareItem* item = dynamic_cast( other ); return item && this->usersCount() > item->usersCount(); } QString FoursquareItem::name() const { return m_name; } void FoursquareItem::setName(const QString& name) { if( name != m_name ) { m_name = name; QFontMetrics const fontMetrics( s_font ); setSize( QSizeF( fontMetrics.width( m_name ) + 10, fontMetrics.height() + 10 ) ); emit nameChanged(); } } QString FoursquareItem::category() const { return m_category; } void FoursquareItem::setCategory(const QString& category) { if( category != m_category ) { m_category = category; emit categoryChanged(); } } QString FoursquareItem::address() const { return m_address; } void FoursquareItem::setAddress(const QString& address) { if( address != m_address ) { m_address = address; emit addressChanged(); } } QString FoursquareItem::city() const { return m_city; } void FoursquareItem::setCity(const QString& city) { if( city != m_city ) { m_city = city; emit cityChanged(); } } QString FoursquareItem::country() const { return m_country; } void FoursquareItem::setCountry(const QString& country) { if( country != m_country ) { m_country = country; emit countryChanged(); } } int FoursquareItem::usersCount() const { return m_usersCount; } void FoursquareItem::setUsersCount(const int count) { if( count != m_usersCount ) { m_usersCount = count; emit usersCountChanged(); } } QString FoursquareItem::categoryIconUrl() const { return m_categoryIconUrl; } void FoursquareItem::setCategoryIconUrl(const QString& url) { if( url != m_categoryIconUrl ) { m_categoryIconUrl = url; emit categoryIconUrlChanged(); } } QString FoursquareItem::categoryLargeIconUrl() const { return m_categoryLargeIconUrl; } void FoursquareItem::setCategoryLargeIconUrl(const QString& url) { if( url != m_categoryLargeIconUrl ) { m_categoryLargeIconUrl = url; emit categoryLargeIconUrlChanged(); } } void FoursquareItem::paint( QPainter* painter ) { // Save the old painter state. painter->save(); painter->setPen( QPen( QColor( Qt::white ) ) ); painter->setFont( s_font ); // Draw the text into the given rect. QRect rect = QRect( QPoint( 0, 0 ), size().toSize() ); QRect boundingRect = QRect( QPoint( rect.top(), rect.left() ), QSize( rect.width(), rect.height() ) ); QPainterPath painterPath; painterPath.addRoundedRect( boundingRect, 5, 5 ); painter->setClipPath( painterPath ); painter->drawPath( painterPath ); painter->fillPath( painterPath, QBrush( QColor( "#39AC39" ) ) ); painter->drawText( rect.adjusted( 5, 5, -5, -5 ), 0, m_name ); painter->restore(); } } #include "moc_FoursquareItem.cpp" diff --git a/src/plugins/render/license/License.cpp b/src/plugins/render/license/License.cpp index 6faaa3e08..45682c3b8 100644 --- a/src/plugins/render/license/License.cpp +++ b/src/plugins/render/license/License.cpp @@ -1,246 +1,247 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2012 Dennis Nienhüser // Copyright 2012 Illya Kovalevskyy // #include "License.h" #include "MarbleWidget.h" #include "MarbleModel.h" #include "MarbleAboutDialog.h" #include "WidgetGraphicsItem.h" #include "MarbleGraphicsGridLayout.h" #include "ViewportParams.h" #include "GeoSceneDocument.h" #include "GeoSceneHead.h" #include "GeoSceneLicense.h" #include #include #include +#include #include #include #include namespace Marble { class OutlinedStyle : public QCommonStyle { public: void drawItemText( QPainter *painter, const QRect &rect, int alignment, const QPalette &palette, bool enabled, const QString& text, QPalette::ColorRole textRole ) const override { Q_UNUSED( alignment ); Q_UNUSED( enabled ); if ( text.isEmpty() ) { return; } QPen savedPen; if ( textRole != QPalette::NoRole ) { savedPen = painter->pen(); painter->setPen( QPen( palette.brush( textRole ), savedPen.widthF() ) ); } QPainterPath path; QFontMetricsF metrics( painter->font() ); QPointF point( rect.x() + 7.0, rect.y() + metrics.ascent() ); path.addText( point, painter->font(), text ); QPen pen( Qt::white ); pen.setWidth( 3 ); painter->setPen( pen ); painter->setBrush( QBrush( Qt::black ) ); painter->setRenderHint( QPainter::Antialiasing, true ); painter->drawPath( path ); painter->setPen( Qt::NoPen ); painter->drawPath( path ); if ( textRole != QPalette::NoRole ) { painter->setPen( savedPen ); } } }; License::License( const MarbleModel *marbleModel ) : AbstractFloatItem( marbleModel, QPointF( -10.0, -5.0 ), QSizeF( 150.0, 20.0 ) ), m_widgetItem( nullptr ), m_label( nullptr ), m_showFullLicense( false ), m_contextMenu( nullptr ) { setEnabled( true ); setVisible( true ); setBackground( QBrush( QColor( Qt::transparent ) ) ); setFrame( NoFrame ); } License::~License() { } QStringList License::backendTypes() const { return QStringList(QStringLiteral("License")); } QString License::name() const { return tr( "License" ); } QString License::guiString() const { return tr( "&License" ); } QString License::nameId() const { return QStringLiteral("license"); } QString License::version() const { return QStringLiteral("1.0"); } QString License::description() const { return tr( "This is a float item that provides copyright information." ); } QString License::copyrightYears() const { return QStringLiteral("2012"); } QVector License::pluginAuthors() const { return QVector() << PluginAuthor(QStringLiteral("Dennis Nienhüser"), QStringLiteral("nienhueser@kde.org")) << PluginAuthor(QStringLiteral("Illya Kovalevskyy"), QStringLiteral("illya.kovalevskyy@gmail.com")); } QIcon License::icon () const { return QIcon(QStringLiteral(":/icons/license.png")); } void License::initialize () { delete m_widgetItem; m_widgetItem = new WidgetGraphicsItem( this ); m_label = new QLabel; auto style = new OutlinedStyle; style->setParent(this); m_label->setStyle( style ); m_label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ); m_widgetItem->setWidget( m_label ); MarbleGraphicsGridLayout *layout = new MarbleGraphicsGridLayout( 1, 1 ); layout->addItem( m_widgetItem, 0, 0 ); setLayout( layout ); setPadding( 0 ); updateLicenseText(); connect( marbleModel(), SIGNAL(themeChanged(QString)), this, SLOT(updateLicenseText()) ); } void License::updateLicenseText() { const GeoSceneDocument *const mapTheme = marbleModel()->mapTheme(); if ( !mapTheme ) return; const GeoSceneHead *const head = mapTheme->head(); if ( !head ) return; const GeoSceneLicense *license = marbleModel()->mapTheme()->head()->license(); m_label->setText( m_showFullLicense ? license->license() : license->shortLicense() ); m_label->setToolTip( license->license() ); if( license->attribution() == GeoSceneLicense::Always ) { setUserCheckable( false ); } else if( license->attribution() == GeoSceneLicense::Never ) { setVisible( false ); setUserCheckable( false ); } else if( license->attribution() == GeoSceneLicense::OptIn ) { setUserCheckable( true ); setVisible( false ); } else { setUserCheckable( true ); setVisible( true ); } QSizeF const magic( 6,0 ); m_widgetItem->setSize( m_label->sizeHint()+magic ); setSize( m_label->sizeHint()+magic ); update(); emit repaintNeeded(); } void License::toggleLicenseSize() { m_showFullLicense = !m_showFullLicense; updateLicenseText(); } void License::showAboutDialog() { QPointer aboutDialog = new MarbleAboutDialog; aboutDialog->setInitialTab( MarbleAboutDialog::Data ); aboutDialog->exec(); delete aboutDialog; } bool License::isInitialized () const { return m_widgetItem; } bool License::eventFilter( QObject *object, QEvent *event ) { if ( !enabled() || !visible() ) return false; MarbleWidget *widget = dynamic_cast( object ); if ( !widget ) { return AbstractFloatItem::eventFilter( object,event ); } if( event->type() == QEvent::MouseMove ) { QMouseEvent *mouseEvent = static_cast( event ); QRectF floatItemRect = QRectF( positivePosition(), size() ); if ( floatItemRect.contains( mouseEvent->pos() ) ) { widget->setCursor( QCursor( Qt::ArrowCursor ) ); return true; } } return AbstractFloatItem::eventFilter( object, event ); } void License::contextMenuEvent( QWidget *w, QContextMenuEvent *e ) { if ( !m_contextMenu ) { m_contextMenu = contextMenu(); QAction *toggleAction = m_contextMenu->addAction( tr("&Full License"), this, SLOT(toggleLicenseSize()) ); toggleAction->setCheckable( true ); toggleAction->setChecked( m_showFullLicense ); m_contextMenu->addAction( tr("&Show Details"), this, SLOT(showAboutDialog()) ); } Q_ASSERT( m_contextMenu ); m_contextMenu->exec( w->mapToGlobal( e->pos() ) ); } } #include "moc_License.cpp" diff --git a/src/plugins/render/notes/NotesItem.cpp b/src/plugins/render/notes/NotesItem.cpp index 9d0961fcd..0c9fe992b 100644 --- a/src/plugins/render/notes/NotesItem.cpp +++ b/src/plugins/render/notes/NotesItem.cpp @@ -1,142 +1,143 @@ // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2017 Spencer Brown // #include "NotesItem.h" #include "MarbleDirs.h" #include +#include #include using namespace Marble; const QFont NotesItem::s_font = QFont(QStringLiteral("Sans Serif"), 10); const int NotesItem::s_labelOutlineWidth = 5; NotesItem::NotesItem(QObject *parent) : AbstractDataPluginItem(parent), m_pixmap_open(QPixmap(MarbleDirs::path("bitmaps/notes_open.png"))), m_pixmap_closed(QPixmap(MarbleDirs::path("bitmaps/notes_closed.png"))) { setSize(m_pixmap_open.size()); setAlignment(Qt::AlignHCenter | Qt::AlignTop); setCacheMode(ItemCoordinateCache); } NotesItem::~NotesItem() { } bool NotesItem::initialized() const { return !id().isEmpty(); } bool NotesItem::operator<(const AbstractDataPluginItem *other) const { return this->id() < other->id(); } void NotesItem::paint(QPainter *painter) { painter->save(); painter->setFont(s_font); const int fontAscent = painter->fontMetrics().ascent(); QPen outlinepen(Qt::white); outlinepen.setWidthF(s_labelOutlineWidth); QBrush outlinebrush(Qt::black); const QPointF baseline(s_labelOutlineWidth / 2.0, fontAscent); QPainterPath outlinepath; outlinepath.addText(baseline, painter->font(), m_labelText); painter->setRenderHint(QPainter::Antialiasing, true); painter->setPen(outlinepen); painter->setBrush(outlinebrush); painter->drawPath(outlinepath); painter->setPen(Qt::NoPen); painter->drawPath(outlinepath); painter->setRenderHint(QPainter::Antialiasing, false); int const y = qMax(0, int(size().width() - m_pixmap_open.width()) / 2); //The two pixmaps have the same dimensions, so all the logic for one works for the other QPixmap const & pixmap = m_noteStatus == "closed" ? m_pixmap_closed : m_pixmap_open; painter->drawPixmap(y, 2 + painter->fontMetrics().height(), pixmap); painter->restore(); } void NotesItem::setDateCreated(const QDateTime& dateCreated) { m_dateCreated = dateCreated; } void NotesItem::setDateClosed(const QDateTime& dateClosed) { m_dateClosed = dateClosed; } void NotesItem::setNoteStatus(const QString& noteStatus) { m_noteStatus = noteStatus; } void NotesItem::addComment(const Comment& comment) { m_commentsList.push_back(comment); std::sort(m_commentsList.begin(), m_commentsList.end(), [](const Comment & a, const Comment & b) { return a.date() > b.date(); }); QStringList toolTip; for (auto const &entry: m_commentsList) { QString const date = entry.date().toString(Qt::SystemLocaleShortDate); QString const user = entry.user().isEmpty() ? tr("anonymous", "The author name is not known") : entry.user(); toolTip << QStringLiteral("%1\n--%2, %3").arg(entry.text().trimmed()).arg(user).arg(date); } setToolTip(toolTip.join(QStringLiteral("\n\n"))); QFontMetrics fontmet(s_font); m_labelText = fontmet.elidedText(m_commentsList.front().text(), Qt::ElideRight, 125); auto const width = qMax(fontmet.width(m_labelText), m_pixmap_open.width()); setSize(QSizeF(width, fontmet.height() + 2 + m_pixmap_open.height())); } Comment::Comment() : m_uid(0) { } Comment::Comment(const QDateTime &date, const QString &text, const QString &user, int uid) : m_date(date) , m_text(text) , m_user(user) { m_uid = uid; } QDateTime Comment::date() const { return m_date; } QString Comment::text() const { return m_text; } QString Comment::user() const { return m_user; } int Comment::uid() const { return m_uid; } #include "moc_NotesItem.cpp" diff --git a/src/plugins/render/postalcode/PostalCodeItem.cpp b/src/plugins/render/postalcode/PostalCodeItem.cpp index 772c0b269..0ff7957d2 100644 --- a/src/plugins/render/postalcode/PostalCodeItem.cpp +++ b/src/plugins/render/postalcode/PostalCodeItem.cpp @@ -1,85 +1,86 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2011 Valery Kharitonov // // Self #include "PostalCodeItem.h" // Marble #include "ViewportParams.h" // Qt #include #include +#include using namespace Marble; const QFont PostalCodeItem::s_font = QFont( QStringLiteral( "Sans Serif" ), 10, QFont::Bold ); const int PostalCodeItem::s_labelOutlineWidth = 5; PostalCodeItem::PostalCodeItem( QObject *parent ) : AbstractDataPluginItem( parent ) { setSize( QSize( 0, 0 ) ); setCacheMode( ItemCoordinateCache ); } PostalCodeItem::~PostalCodeItem() { } bool PostalCodeItem::initialized() const { return !m_text.isEmpty(); } bool PostalCodeItem::operator<( const AbstractDataPluginItem *other ) const { return this->id() < other->id(); } QString PostalCodeItem::text() const { return m_text; } void PostalCodeItem::setText( const QString& text ) { QFontMetrics metrics( s_font ); setSize( metrics.size( 0, text ) + QSize( 10, 10 ) ); m_text = text; } void PostalCodeItem::paint( QPainter *painter ) { painter->save(); const int fontAscent = QFontMetrics( s_font ).ascent(); QPen outlinepen( Qt::white ); outlinepen.setWidthF( s_labelOutlineWidth ); QBrush outlinebrush( Qt::black ); const QPointF baseline( s_labelOutlineWidth / 2.0, fontAscent ); QPainterPath outlinepath; outlinepath.addText( baseline, s_font, m_text ); painter->setRenderHint( QPainter::Antialiasing, true ); painter->setPen( outlinepen ); painter->setBrush( outlinebrush ); painter->drawPath( outlinepath ); painter->setPen( Qt::NoPen ); painter->drawPath( outlinepath ); painter->setRenderHint( QPainter::Antialiasing, false ); painter->restore(); } #include "moc_PostalCodeItem.cpp" diff --git a/src/plugins/render/progress/ProgressFloatItem.cpp b/src/plugins/render/progress/ProgressFloatItem.cpp index a4658577c..6e2452c5f 100644 --- a/src/plugins/render/progress/ProgressFloatItem.cpp +++ b/src/plugins/render/progress/ProgressFloatItem.cpp @@ -1,291 +1,292 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2010 Dennis Nienhüser // Copyright 2010,2011 Bernhard Beschow // #include "ProgressFloatItem.h" #include "MarbleDebug.h" #include "MarbleDirs.h" #include "MarbleModel.h" #include "MarbleWidget.h" #include "ViewportParams.h" #include "HttpDownloadManager.h" #include #include #include #include +#include namespace Marble { ProgressFloatItem::ProgressFloatItem( const MarbleModel *marbleModel ) : AbstractFloatItem( marbleModel, QPointF( -10.5, -150.5 ), QSizeF( 40.0, 40.0 ) ), m_isInitialized( false ), m_totalJobs( 0 ), m_completedJobs ( 0 ), m_completed( 1 ), m_progressHideTimer(), m_progressShowTimer(), m_active( false ), m_fontSize( 0 ), m_repaintTimer() { // This timer is responsible to activate the automatic display with a small delay m_progressShowTimer.setInterval( 250 ); m_progressShowTimer.setSingleShot( true ); connect( &m_progressShowTimer, SIGNAL(timeout()), this, SLOT(show()) ); // This timer is responsible to hide the automatic display when downloads are finished m_progressHideTimer.setInterval( 750 ); m_progressHideTimer.setSingleShot( true ); connect( &m_progressHideTimer, SIGNAL(timeout()), this, SLOT(hideProgress()) ); // Repaint timer m_repaintTimer.setSingleShot( true ); m_repaintTimer.setInterval( 1000 ); connect( &m_repaintTimer, SIGNAL(timeout()), this, SIGNAL(repaintNeeded()) ); // Plugin is enabled by default setEnabled( true ); // Plugin is visible by default on devices with small screens only setVisible( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ); } ProgressFloatItem::~ProgressFloatItem () { // nothing to do } QStringList ProgressFloatItem::backendTypes() const { return QStringList(QStringLiteral("progress")); } QString ProgressFloatItem::name() const { return tr( "Download Progress Indicator" ); } QString ProgressFloatItem::guiString() const { return tr( "&Download Progress" ); } QString ProgressFloatItem::nameId() const { return QStringLiteral("progress"); } QString ProgressFloatItem::version() const { return QStringLiteral("1.0"); } QString ProgressFloatItem::description() const { return tr( "Shows a pie chart download progress indicator" ); } QString ProgressFloatItem::copyrightYears() const { return QStringLiteral("2010, 2011"); } QVector ProgressFloatItem::pluginAuthors() const { return QVector() << PluginAuthor(QStringLiteral("Dennis Nienhüser"), QStringLiteral("nienhueser@kde.org")) << PluginAuthor(QStringLiteral("Bernhard Beschow"), QStringLiteral("bbeschow@cs.tu-berlin.de")); } QIcon ProgressFloatItem::icon() const { return m_icon; } void ProgressFloatItem::initialize() { const HttpDownloadManager* manager = marbleModel()->downloadManager(); Q_ASSERT( manager ); connect( manager, SIGNAL(progressChanged(int,int)), this, SLOT(handleProgress(int,int)) , Qt::UniqueConnection ); connect( manager, SIGNAL(jobRemoved()), this, SLOT(removeProgressItem()), Qt::UniqueConnection ); // Calculate font size QFont myFont = font(); const QString text = "100%"; int fontSize = myFont.pointSize(); while( QFontMetrics( myFont ).boundingRect( text ).width() < contentRect().width() - 2 ) { ++fontSize; myFont.setPointSize( fontSize ); } m_fontSize = fontSize - 1; // The icon resembles the pie chart QImage canvas( 16, 16, QImage::Format_ARGB32 ); canvas.fill( Qt::transparent ); QPainter painter( &canvas ); painter.setRenderHint( QPainter::Antialiasing, true ); painter.setPen( QColor ( Qt::black ) ); painter.drawEllipse( 1, 1, 14, 14 ); painter.setPen( Qt::NoPen ); painter.setBrush( QBrush( QColor( Qt::darkGray ) ) ); painter.drawPie( 2, 2, 12, 12, 1440, -1325 ); // 23 percent of a full circle m_icon = QIcon( QPixmap::fromImage( canvas ) ); m_isInitialized = true; } bool ProgressFloatItem::isInitialized() const { return m_isInitialized; } QPainterPath ProgressFloatItem::backgroundShape() const { QPainterPath path; if ( active() ) { // Circular shape if active, invisible otherwise QRectF rect = contentRect(); qreal width = rect.width(); qreal height = rect.height(); path.addEllipse( marginLeft() + 2 * padding(), marginTop() + 2 * padding(), width, height ); } return path; } void ProgressFloatItem::paintContent( QPainter *painter ) { // Stop repaint timer if it is already running m_repaintTimer.stop(); if ( !active() ) { return; } painter->save(); // Paint progress pie int startAngle = 90 * 16; // 12 o' clock int spanAngle = -ceil ( 360 * 16 * m_completed ); QRectF rect( contentRect() ); rect.adjust( 1, 1, -1, -1 ); painter->setBrush( QColor( Qt::white ) ); painter->setPen( Qt::NoPen ); painter->drawPie( rect, startAngle, spanAngle ); // Paint progress label QFont myFont = font(); myFont.setPointSize( m_fontSize ); const QString done = QString::number((int) (m_completed * 100)) + QLatin1Char('%'); int fontWidth = QFontMetrics( myFont ).boundingRect( done ).width(); QPointF baseline( padding() + 0.5 * ( rect.width() - fontWidth ), 0.75 * rect.height() ); QPainterPath path; path.addText( baseline, myFont, done ); painter->setFont( myFont ); painter->setBrush( QBrush() ); painter->setPen( QPen() ); painter->drawPath( path ); painter->restore(); } void ProgressFloatItem::removeProgressItem() { m_jobMutex.lock(); ++m_completedJobs; m_jobMutex.unlock(); if ( enabled() ) { if ( !active() && !m_progressShowTimer.isActive() ) { m_progressShowTimer.start(); m_progressHideTimer.stop(); } else if ( active() ) { update(); scheduleRepaint(); } } } void ProgressFloatItem::handleProgress( int current, int queued ) { m_jobMutex.lock(); if ( current < 1 ) { m_totalJobs = 0; m_completedJobs = 0; } else { m_totalJobs = qMax( m_totalJobs, queued + current ); } m_jobMutex.unlock(); if ( enabled() ) { if ( !active() && !m_progressShowTimer.isActive() && m_totalJobs > 0 ) { m_progressShowTimer.start(); m_progressHideTimer.stop(); } else if ( active() ) { if ( m_totalJobs < 1 || m_completedJobs == m_totalJobs ) { m_progressShowTimer.stop(); m_progressHideTimer.start(); } update(); scheduleRepaint(); } m_completed = 1.0; if ( m_totalJobs && m_completedJobs <= m_totalJobs ) { m_completed = (qreal) m_completedJobs / (qreal) m_totalJobs; } } } void ProgressFloatItem::hideProgress() { if ( enabled() ) { setActive( false ); update(); emit repaintNeeded( QRegion() ); } } bool ProgressFloatItem::active() const { return m_active; } void ProgressFloatItem::setActive( bool active ) { m_active = active; update(); } void ProgressFloatItem::show() { setActive( true ); update(); emit repaintNeeded( QRegion() ); } void ProgressFloatItem::scheduleRepaint() { if ( !m_repaintTimer.isActive() ) { m_repaintTimer.start(); } } } #include "moc_ProgressFloatItem.cpp" diff --git a/src/plugins/render/stars/StarsPlugin.cpp b/src/plugins/render/stars/StarsPlugin.cpp index ba1d2e349..5c83b8088 100644 --- a/src/plugins/render/stars/StarsPlugin.cpp +++ b/src/plugins/render/stars/StarsPlugin.cpp @@ -1,1489 +1,1490 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2008 Torsten Rahn // Copyright 2011-2013 Bernhard Beschow // #include "StarsPlugin.h" #include "ui_StarsConfigWidget.h" #include #include #include #include #include #include #include +#include #include #include "MarbleClock.h" #include "MarbleColors.h" #include "MarbleDebug.h" #include "MarbleDirs.h" #include "MarbleModel.h" #include "MarbleWidget.h" #include "AbstractFloatItem.h" #include "GeoPainter.h" #include "Planet.h" #include "PlanetFactory.h" #include "SunLocator.h" #include "ViewportParams.h" #include "src/lib/astro/solarsystem.h" namespace Marble { StarsPlugin::StarsPlugin( const MarbleModel *marbleModel ) : RenderPlugin( marbleModel ), m_nameIndex( 0 ), m_configDialog( nullptr ), ui_configWidget( nullptr ), m_renderStars( true ), m_renderConstellationLines( true ), m_renderConstellationLabels( true ), m_renderDsos( true ), m_renderDsoLabels( true ), m_renderSun( true ), m_renderMoon( true ), m_renderEcliptic( true ), m_renderCelestialEquator( true ), m_renderCelestialPole( true ), m_starsLoaded( false ), m_starPixmapsCreated( false ), m_constellationsLoaded( false ), m_dsosLoaded( false ), m_zoomSunMoon( true ), m_viewSolarSystemLabel( true ), m_magnitudeLimit( 100 ), m_zoomCoefficient( 4 ), m_constellationBrush( Marble::Oxygen::aluminumGray5 ), m_constellationLabelBrush( Marble::Oxygen::aluminumGray5 ), m_dsoLabelBrush( Marble::Oxygen::aluminumGray5 ), m_eclipticBrush( Marble::Oxygen::aluminumGray5 ), m_celestialEquatorBrush( Marble::Oxygen::aluminumGray5 ), m_celestialPoleBrush( Marble::Oxygen::aluminumGray5 ), m_contextMenu(nullptr), m_constellationsAction(nullptr), m_sunMoonAction(nullptr), m_planetsAction(nullptr), m_dsoAction(nullptr), m_doRender( false ) { bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; if (smallScreen) m_magnitudeLimit = 5; prepareNames(); } StarsPlugin::~StarsPlugin() { delete m_contextMenu; } QStringList StarsPlugin::backendTypes() const { return QStringList(QStringLiteral("stars")); } QString StarsPlugin::renderPolicy() const { return QStringLiteral("SPECIFIED_ALWAYS"); } QStringList StarsPlugin::renderPosition() const { return QStringList(QStringLiteral("STARS")); } RenderPlugin::RenderType StarsPlugin::renderType() const { return RenderPlugin::ThemeRenderType; } QString StarsPlugin::name() const { return tr( "Stars" ); } QString StarsPlugin::guiString() const { return tr( "&Stars" ); } QString StarsPlugin::nameId() const { return QStringLiteral("stars"); } QString StarsPlugin::version() const { return QStringLiteral("1.2"); } QString StarsPlugin::description() const { return tr( "A plugin that shows the Starry Sky and the Sun." ); } QString StarsPlugin::copyrightYears() const { return QStringLiteral("2008-2012"); } QVector StarsPlugin::pluginAuthors() const { return QVector() << PluginAuthor(QStringLiteral("Torsten Rahn"), QStringLiteral("tackat@kde.org")) << PluginAuthor(QStringLiteral("Rene Kuettner"), QStringLiteral("rene@bitkanal.net")) << PluginAuthor(QStringLiteral("Timothy Lanzi"), QStringLiteral("trlanzi@gmail.com")); } QIcon StarsPlugin::icon() const { return QIcon(QStringLiteral(":/icons/stars.png")); } void StarsPlugin::initialize() { } bool StarsPlugin::isInitialized() const { return true; } QDialog *StarsPlugin::configDialog() { if (!m_configDialog) { // Initializing configuration dialog m_configDialog = new QDialog; ui_configWidget = new Ui::StarsConfigWidget; ui_configWidget->setupUi( m_configDialog ); readSettings(); connect( ui_configWidget->m_buttonBox, SIGNAL(accepted()), SLOT(writeSettings()) ); connect( ui_configWidget->m_buttonBox, SIGNAL(rejected()), SLOT(readSettings()) ); connect( ui_configWidget->m_constellationColorButton, SIGNAL(clicked()), this, SLOT(constellationGetColor()) ); connect( ui_configWidget->m_constellationLabelColorButton, SIGNAL(clicked()), this, SLOT(constellationLabelGetColor()) ); connect( ui_configWidget->m_dsoLabelColorButton, SIGNAL(clicked()), this, SLOT(dsoLabelGetColor()) ); connect( ui_configWidget->m_eclipticColorButton, SIGNAL(clicked()), this, SLOT(eclipticGetColor()) ); connect( ui_configWidget->m_celestialEquatorColorButton, SIGNAL(clicked()), this, SLOT(celestialEquatorGetColor()) ); connect( ui_configWidget->m_celestialPoleColorButton, SIGNAL(clicked()), this, SLOT(celestialPoleGetColor()) ); } return m_configDialog; } QHash StarsPlugin::settings() const { QHash settings = RenderPlugin::settings(); settings.insert(QStringLiteral("nameIndex"), m_nameIndex); settings.insert(QStringLiteral("renderStars"), m_renderStars); settings.insert(QStringLiteral("renderConstellationLines"), m_renderConstellationLines); settings.insert(QStringLiteral("renderConstellationLabels"), m_renderConstellationLabels); settings.insert(QStringLiteral("renderDsos"), m_renderDsos); settings.insert(QStringLiteral("renderDsoLabels"), m_renderDsoLabels); settings.insert(QStringLiteral("renderSun"), m_renderSun); settings.insert(QStringLiteral("renderMoon"), m_renderMoon); QStringList planetState; for (const QString &key: m_renderPlanet.keys()) planetState += key + QLatin1Char(':') + QString::number((int)m_renderPlanet[key]); settings.insert(QStringLiteral("renderPlanet"), planetState.join(QLatin1Char('|'))); settings.insert(QStringLiteral("renderEcliptic"), m_renderEcliptic); settings.insert(QStringLiteral("renderCelestialEquator"), m_renderCelestialEquator); settings.insert(QStringLiteral("renderCelestialPole"), m_renderCelestialPole); settings.insert(QStringLiteral("zoomSunMoon"), m_zoomSunMoon); settings.insert(QStringLiteral("viewSolarSystemLabel"), m_viewSolarSystemLabel); settings.insert(QStringLiteral("magnitudeLimit"), m_magnitudeLimit); settings.insert(QStringLiteral("constellationBrush"), m_constellationBrush.color().rgb()); settings.insert(QStringLiteral("constellationLabelBrush"), m_constellationLabelBrush.color().rgb()); settings.insert(QStringLiteral("dsoLabelBrush"), m_dsoLabelBrush.color().rgb()); settings.insert(QStringLiteral("eclipticBrush"), m_eclipticBrush.color().rgb()); settings.insert(QStringLiteral("celestialEaquatorBrush"), m_celestialEquatorBrush.color().rgb()); settings.insert(QStringLiteral("celestialPoleBrush"), m_celestialPoleBrush.color().rgb()); return settings; } void StarsPlugin::setSettings( const QHash &settings ) { RenderPlugin::setSettings( settings ); m_nameIndex = readSetting(settings, QStringLiteral("nameIndex"), 0); m_renderStars = readSetting(settings, QStringLiteral("renderStars"), true); m_renderConstellationLines = readSetting(settings, QStringLiteral("renderConstellationLines"), true); m_renderConstellationLabels = readSetting(settings, QStringLiteral("renderConstellationLabels"), true); m_renderDsos = readSetting(settings, QStringLiteral("renderDsos"), true); m_renderDsoLabels = readSetting(settings, QStringLiteral("renderDsoLabels"), true); m_renderSun = readSetting(settings, QStringLiteral("renderSun"), true); m_renderMoon = readSetting(settings, QStringLiteral("renderMoon"), true); m_renderPlanet.clear(); const QString renderPlanet = readSetting(settings, QStringLiteral("renderPlanet"), QString()); const QStringList renderStates = renderPlanet.split(QLatin1Char('|')); for(const QString &state: renderStates) { const QStringList stateList = state.split(QLatin1Char(':')); if (stateList.size() == 2) m_renderPlanet[stateList[0]] = (bool)stateList[1].toInt(); } m_renderEcliptic = readSetting(settings, QStringLiteral("renderEcliptic"), true); m_renderCelestialEquator = readSetting(settings, QStringLiteral("renderCelestialEquator"), true); m_renderCelestialPole = readSetting(settings, QStringLiteral("renderCelestialPole"), true); m_zoomSunMoon = readSetting(settings, QStringLiteral("zoomSunMoon"), true); m_viewSolarSystemLabel = readSetting(settings, QStringLiteral("viewSolarSystemLabel"), true); m_magnitudeLimit = readSetting(settings, QStringLiteral("magnitudeLimit"), 100); QColor const defaultColor = Marble::Oxygen::aluminumGray5; m_constellationBrush = QColor(readSetting(settings, QStringLiteral("constellationBrush"), defaultColor.rgb())); m_constellationLabelBrush = QColor(readSetting(settings, QStringLiteral("constellationLabelBrush"), defaultColor.rgb())); m_dsoLabelBrush = QColor(readSetting(settings, QStringLiteral("dsoLabelBrush"), defaultColor.rgb())); m_eclipticBrush = QColor(readSetting(settings, QStringLiteral("eclipticBrush"), defaultColor.rgb())); m_celestialEquatorBrush = QColor(readSetting(settings, QStringLiteral("celestialEquatorBrush"), defaultColor.rgb())); m_celestialPoleBrush = QColor(readSetting(settings, QStringLiteral("celestialPoleBrush"), defaultColor.rgb())); } QPixmap StarsPlugin::starPixmap(qreal mag, int colorId) const { if ( mag < -1 ) { return m_pixN1Stars.at(colorId); } else if ( mag < 0 ) { return m_pixP0Stars.at(colorId); } else if ( mag < 1 ) { return m_pixP1Stars.at(colorId); } else if ( mag < 2 ) { return m_pixP2Stars.at(colorId); } else if ( mag < 3 ) { return m_pixP3Stars.at(colorId); } else if ( mag < 4 ) { return m_pixP4Stars.at(colorId); } else if ( mag < 5 ) { return m_pixP5Stars.at(colorId); } else if ( mag < 6 ) { return m_pixP6Stars.at(colorId); } else { return m_pixP7Stars.at(colorId); } return QPixmap(); } void StarsPlugin::prepareNames() { QFile names(MarbleDirs::path(QStringLiteral("stars/names.csv"))); if ( !names.open( QIODevice::ReadOnly ) ) { return; } QTextStream in( &names ); while ( !in.atEnd() ) { QString line = in.readLine(); const QStringList list = line.split(QLatin1Char(';')); if ( list.size() == 3 ) { m_nativeHash[ list.at( 0 ) ] = QCoreApplication::translate( "StarNames", list.at( 1 ).toUtf8().constData() ); m_abbrHash[ list.at( 0 ) ] = list.at( 2 ); } } names.close(); } QString StarsPlugin::assembledConstellation(const QString &name) { switch (m_nameIndex) { case 0: return name; case 1: return m_nativeHash[name]; case 2: return m_abbrHash[name]; default: return name; } } void StarsPlugin::readSettings() { if ( !m_configDialog ) { return; } ui_configWidget->constellationNamesComboBox->setCurrentIndex(m_nameIndex); Qt::CheckState const constellationLineState = m_renderConstellationLines ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_viewConstellationLinesCheckbox->setCheckState( constellationLineState ); Qt::CheckState const constellationLabelState = m_renderConstellationLabels ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_viewConstellationLabelsCheckbox->setCheckState( constellationLabelState ); Qt::CheckState const dsoState = m_renderDsos ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_viewDsosCheckbox->setCheckState( dsoState ); Qt::CheckState const dsoLabelState = m_renderDsoLabels ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_viewDsoLabelCheckbox->setCheckState( dsoLabelState ); Qt::CheckState const sunState = m_renderSun ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_solarSystemListWidget->item( 0 )->setCheckState( sunState ); Qt::CheckState const moonState = m_renderMoon ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_solarSystemListWidget->item( 1 )->setCheckState( moonState ); Qt::CheckState const mercuryState = m_renderPlanet["mercury"] ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_solarSystemListWidget->item( 2 )->setCheckState(mercuryState); Qt::CheckState const venusState = m_renderPlanet["venus"] ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_solarSystemListWidget->item( 3 )->setCheckState(venusState); Qt::CheckState const marsState = m_renderPlanet["mars"] ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_solarSystemListWidget->item( 5 )->setCheckState(marsState); Qt::CheckState const jupiterState = m_renderPlanet["jupiter"] ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_solarSystemListWidget->item( 6 )->setCheckState(jupiterState); Qt::CheckState const saturnState = m_renderPlanet["saturn"] ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_solarSystemListWidget->item( 7 )->setCheckState(saturnState); Qt::CheckState const uranusState = m_renderPlanet["uranus"] ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_solarSystemListWidget->item( 8 )->setCheckState(uranusState); Qt::CheckState const neptuneState = m_renderPlanet["neptune"] ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_solarSystemListWidget->item( 9 )->setCheckState(neptuneState); Qt::CheckState const eclipticState = m_renderEcliptic ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_viewEclipticCheckbox->setCheckState( eclipticState ); Qt::CheckState const celestialEquatorState = m_renderCelestialEquator ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_viewCelestialEquatorCheckbox->setCheckState( celestialEquatorState ); Qt::CheckState const celestialPoleState = m_renderCelestialPole ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_viewCelestialPoleCheckbox->setCheckState( celestialPoleState ); Qt::CheckState const zoomSunMoonState = m_zoomSunMoon ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_zoomSunMoonCheckbox->setCheckState( zoomSunMoonState ); Qt::CheckState const viewSolarSystemLabelState = m_viewSolarSystemLabel ? Qt::Checked : Qt::Unchecked; ui_configWidget->m_viewSolarSystemLabelCheckbox->setCheckState( viewSolarSystemLabelState ); int magState = m_magnitudeLimit; if ( magState < ui_configWidget->m_magnitudeSlider->minimum() ) { magState = ui_configWidget->m_magnitudeSlider->minimum(); } else if ( magState > ui_configWidget->m_magnitudeSlider->maximum() ) { magState = ui_configWidget->m_magnitudeSlider->maximum(); } ui_configWidget->m_magnitudeSlider->setValue(magState); QPalette constellationPalette; constellationPalette.setColor( QPalette::Button, m_constellationBrush.color() ); ui_configWidget->m_constellationColorButton->setPalette( constellationPalette ); QPalette constellationLabelPalette; constellationLabelPalette.setColor( QPalette::Button, m_constellationLabelBrush.color() ); ui_configWidget->m_constellationLabelColorButton->setPalette( constellationLabelPalette ); QPalette dsoLabelPalette; dsoLabelPalette.setColor( QPalette::Button, m_dsoLabelBrush.color() ); ui_configWidget->m_dsoLabelColorButton->setPalette( dsoLabelPalette ); QPalette eclipticPalette; eclipticPalette.setColor( QPalette::Button, m_eclipticBrush.color() ); ui_configWidget->m_eclipticColorButton->setPalette( eclipticPalette ); QPalette celestialEquatorPalette; celestialEquatorPalette.setColor( QPalette::Button, m_celestialEquatorBrush.color() ); ui_configWidget->m_celestialEquatorColorButton->setPalette( celestialEquatorPalette ); QPalette celestialPolePalette; celestialPolePalette.setColor( QPalette::Button, m_celestialPoleBrush.color() ); ui_configWidget->m_celestialPoleColorButton->setPalette( celestialPolePalette ); } void StarsPlugin::writeSettings() { m_nameIndex = ui_configWidget->constellationNamesComboBox->currentIndex(); m_renderConstellationLines = ui_configWidget->m_viewConstellationLinesCheckbox->checkState() == Qt::Checked; m_renderConstellationLabels = ui_configWidget->m_viewConstellationLabelsCheckbox->checkState() == Qt::Checked; m_renderDsos = ui_configWidget->m_viewDsosCheckbox->checkState() == Qt::Checked; m_renderDsoLabels = ui_configWidget->m_viewDsoLabelCheckbox->checkState() == Qt::Checked; m_renderSun = ui_configWidget->m_solarSystemListWidget->item( 0 )->checkState() == Qt::Checked; m_renderMoon = ui_configWidget->m_solarSystemListWidget->item( 1 )->checkState() == Qt::Checked; m_renderPlanet["mercury"] = ui_configWidget->m_solarSystemListWidget->item( 2 )->checkState() == Qt::Checked; m_renderPlanet["venus"] = ui_configWidget->m_solarSystemListWidget->item( 3 )->checkState() == Qt::Checked; m_renderPlanet["mars"] = ui_configWidget->m_solarSystemListWidget->item( 5 )->checkState() == Qt::Checked; m_renderPlanet["jupiter"] = ui_configWidget->m_solarSystemListWidget->item( 6 )->checkState() == Qt::Checked; m_renderPlanet["saturn"] = ui_configWidget->m_solarSystemListWidget->item( 7 )->checkState() == Qt::Checked; m_renderPlanet["uranus"] = ui_configWidget->m_solarSystemListWidget->item( 8 )->checkState() == Qt::Checked; m_renderPlanet["neptune"] = ui_configWidget->m_solarSystemListWidget->item( 9 )->checkState() == Qt::Checked; m_renderEcliptic = ui_configWidget->m_viewEclipticCheckbox->checkState() == Qt::Checked; m_renderCelestialEquator = ui_configWidget->m_viewCelestialEquatorCheckbox->checkState() == Qt::Checked; m_renderCelestialPole = ui_configWidget->m_viewCelestialPoleCheckbox->checkState() == Qt::Checked; m_zoomSunMoon = ui_configWidget->m_zoomSunMoonCheckbox->checkState() == Qt::Checked; m_viewSolarSystemLabel = ui_configWidget->m_viewSolarSystemLabelCheckbox->checkState() == Qt::Checked; m_magnitudeLimit = ui_configWidget->m_magnitudeSlider->value(); m_constellationBrush = QBrush( ui_configWidget->m_constellationColorButton->palette().color( QPalette::Button) ); m_constellationLabelBrush = QBrush( ui_configWidget->m_constellationLabelColorButton->palette().color( QPalette::Button) ); m_dsoLabelBrush = QBrush( ui_configWidget->m_dsoLabelColorButton->palette().color( QPalette::Button) ); m_eclipticBrush = QBrush( ui_configWidget->m_eclipticColorButton->palette().color( QPalette::Button) ); m_celestialEquatorBrush = QBrush( ui_configWidget->m_celestialEquatorColorButton->palette().color( QPalette::Button) ); m_celestialPoleBrush = QBrush( ui_configWidget->m_celestialPoleColorButton->palette().color( QPalette::Button) ); emit settingsChanged( nameId() ); } void StarsPlugin::constellationGetColor() { const QColor c = QColorDialog::getColor( m_constellationBrush.color(), nullptr, tr("Please choose the color for the constellation lines.") ); if ( c.isValid() ) { QPalette palette = ui_configWidget->m_constellationColorButton->palette(); palette.setColor( QPalette::Button, c ); ui_configWidget->m_constellationColorButton->setPalette( palette ); } } void StarsPlugin::constellationLabelGetColor() { const QColor c = QColorDialog::getColor( m_constellationLabelBrush.color(), nullptr, tr("Please choose the color for the constellation labels.") ); if ( c.isValid() ) { QPalette palette = ui_configWidget->m_constellationLabelColorButton->palette(); palette.setColor( QPalette::Button, c ); ui_configWidget->m_constellationLabelColorButton->setPalette( palette ); } } void StarsPlugin::dsoLabelGetColor() { const QColor c = QColorDialog::getColor( m_dsoLabelBrush.color(), nullptr, tr("Please choose the color for the dso labels.") ); if ( c.isValid() ) { QPalette palette = ui_configWidget->m_dsoLabelColorButton->palette(); palette.setColor( QPalette::Button, c ); ui_configWidget->m_dsoLabelColorButton->setPalette( palette ); } } void StarsPlugin::eclipticGetColor() { const QColor c = QColorDialog::getColor( m_eclipticBrush.color(), nullptr, tr("Please choose the color for the ecliptic.") ); if ( c.isValid() ) { QPalette palette = ui_configWidget->m_eclipticColorButton->palette(); palette.setColor( QPalette::Button, c ); ui_configWidget->m_eclipticColorButton->setPalette( palette ); } } void StarsPlugin::celestialEquatorGetColor() { const QColor c = QColorDialog::getColor( m_celestialEquatorBrush.color(), nullptr, tr("Please choose the color for the celestial equator.") ); if ( c.isValid() ) { QPalette palette = ui_configWidget->m_celestialEquatorColorButton->palette(); palette.setColor( QPalette::Button, c ); ui_configWidget->m_celestialEquatorColorButton->setPalette( palette ); } } void StarsPlugin::celestialPoleGetColor() { const QColor c = QColorDialog::getColor( m_celestialPoleBrush.color(), nullptr, tr("Please choose the color for the celestial equator.") ); if ( c.isValid() ) { QPalette palette = ui_configWidget->m_celestialPoleColorButton->palette(); palette.setColor( QPalette::Button, c ); ui_configWidget->m_celestialPoleColorButton->setPalette( palette ); } } void StarsPlugin::loadStars() { //mDebug() << Q_FUNC_INFO; // Load star data m_stars.clear(); QFile starFile(MarbleDirs::path(QStringLiteral("stars/stars.dat"))); starFile.open( QIODevice::ReadOnly ); QDataStream in( &starFile ); // Read and check the header quint32 magic; in >> magic; if ( magic != 0x73746172 ) { return; } // Read the version qint32 version; in >> version; if ( version > 004 ) { mDebug() << "stars.dat: file too new."; return; } if ( version == 003 ) { mDebug() << "stars.dat: file version no longer supported."; return; } int maxid = 0; int id = 0; int starIndex = 0; double ra; double de; double mag; int colorId = 2; mDebug() << "Star Catalog Version " << version; while ( !in.atEnd() ) { if ( version >= 2 ) { in >> id; } if ( id > maxid ) { maxid = id; } in >> ra; in >> de; in >> mag; if ( version >= 4 ) { in >> colorId; } StarPoint star( id, ( qreal )( ra ), ( qreal )( de ), ( qreal )( mag ), colorId ); // Create entry in stars database m_stars << star; // Create key,value pair in idHash table to map from star id to // index in star database vector m_idHash[id] = starIndex; // Increment Index for use in hash ++starIndex; } // load the Sun pixmap // TODO: adjust pixmap size according to distance m_pixmapSun.load(MarbleDirs::path(QStringLiteral("svg/sun.png"))); m_pixmapMoon.load(MarbleDirs::path(QStringLiteral("svg/moon.png"))); m_starsLoaded = true; } void StarsPlugin::createStarPixmaps() { // Load star pixmaps QVector pixBigStars; pixBigStars.clear(); pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_blue.png")))); pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_bluewhite.png")))); pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_white.png")))); pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_yellow.png")))); pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_orange.png")))); pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_red.png")))); pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_garnetred.png")))); QVector pixSmallStars; pixSmallStars.clear(); pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_blue.png")))); pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_bluewhite.png")))); pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_white.png")))); pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_yellow.png")))); pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_orange.png")))); pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_red.png")))); pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_garnetred.png")))); // Pre-Scale Star Pixmaps m_pixN1Stars.clear(); for ( int p=0; p < pixBigStars.size(); ++p) { int width = 1.0*pixBigStars.at(p).width(); m_pixN1Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation)); } m_pixP0Stars.clear(); for ( int p=0; p < pixBigStars.size(); ++p) { int width = 0.90*pixBigStars.at(p).width(); m_pixP0Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation)); } m_pixP1Stars.clear(); for ( int p=0; p < pixBigStars.size(); ++p) { int width = 0.80*pixBigStars.at(p).width(); m_pixP1Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation)); } m_pixP2Stars.clear(); for ( int p=0; p < pixBigStars.size(); ++p) { int width = 0.70*pixBigStars.at(p).width(); m_pixP2Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation)); } m_pixP3Stars.clear(); for ( int p=0; p < pixSmallStars.size(); ++p) { int width = 14; m_pixP3Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation)); } m_pixP4Stars.clear(); for ( int p=0; p < pixSmallStars.size(); ++p) { int width = 10; m_pixP4Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation)); } m_pixP5Stars.clear(); for ( int p=0; p < pixSmallStars.size(); ++p) { int width = 6; m_pixP5Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation)); } m_pixP6Stars.clear(); for ( int p=0; p < pixSmallStars.size(); ++p) { int width = 4; m_pixP6Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation)); } m_pixP7Stars.clear(); for ( int p=0; p < pixSmallStars.size(); ++p) { int width = 1; m_pixP7Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation)); } m_starPixmapsCreated = true; } void StarsPlugin::loadConstellations() { // Load star data m_constellations.clear(); QFile constellationFile(MarbleDirs::path(QStringLiteral("stars/constellations.dat"))); constellationFile.open( QIODevice::ReadOnly ); QTextStream in( &constellationFile ); QString line; QString indexList; while ( !in.atEnd() ) { line = in.readLine(); // Check for null line at end of file if ( line.isNull() ) { continue; } // Ignore Comment lines in header and // between constellation entries if (line.startsWith(QLatin1Char('#'))) { continue; } indexList = in.readLine(); // Make sure we have a valid label and indexList if ( indexList.isNull() ) { break; } Constellation constellation( this, line, indexList ); m_constellations << constellation; } m_constellationsLoaded = true; } void StarsPlugin::loadDsos() { // Load star data m_dsos.clear(); QFile dsoFile(MarbleDirs::path(QStringLiteral("stars/dso.dat"))); dsoFile.open( QIODevice::ReadOnly ); QTextStream in( &dsoFile ); QString line; while ( !in.atEnd() ) { line = in.readLine(); // Check for null line at end of file if ( line.isNull() ) { continue; } // Ignore Comment lines in header and // between dso entries if (line.startsWith(QLatin1Char('#'))) { continue; } QStringList entries = line.split( QLatin1Char( ',' ) ); QString id = entries.at( 0 ); double raH = entries.at( 1 ).toDouble(); double raM = entries.at( 2 ).toDouble(); double raS = entries.at( 3 ).toDouble(); double decD = entries.at( 4 ).toDouble(); double decM = entries.at( 5 ).toDouble(); double decS = entries.at( 6 ).toDouble(); double raRad = ( raH+raM/60.0+raS/3600.0 )*15.0*M_PI/180.0; double decRad; if ( decD >= 0.0 ) { decRad = ( decD+decM/60.0+decS/3600.0 )*M_PI/180.0; } else { decRad = ( decD-decM/60.0-decS/3600.0 )*M_PI/180.0; } DsoPoint dso( id, ( qreal )( raRad ), ( qreal )( decRad ) ); // Create entry in stars database m_dsos << dso; } m_dsoImage.load(MarbleDirs::path(QStringLiteral("stars/deepsky.png"))); m_dsosLoaded = true; } bool StarsPlugin::render( GeoPainter *painter, ViewportParams *viewport, const QString& renderPos, GeoSceneLayer * layer ) { Q_UNUSED( renderPos ) Q_UNUSED( layer ) QString planetId = marbleModel()->planetId(); const bool doRender = !viewport->mapCoversViewport() && ( (viewport->projection() == Spherical || viewport->projection() == VerticalPerspective) && planetId == QLatin1String("earth")); // So far displaying stars is only supported on earth. if ( doRender != m_doRender ) { if ( doRender ) { connect( marbleModel()->clock(), SIGNAL(timeChanged()), this, SLOT(requestRepaint()) ); } else { disconnect( marbleModel()->clock(), SIGNAL(timeChanged()), this, SLOT(requestRepaint()) ); } m_doRender = doRender; } painter->save(); SolarSystem sys; QDateTime dateTime = marbleModel()->clock()->dateTime(); sys.setCurrentMJD( dateTime.date().year(), dateTime.date().month(), dateTime.date().day(), dateTime.time().hour(), dateTime.time().minute(), (double)dateTime.time().second()); QString const pname = planetId.at(0).toUpper() + planetId.right(planetId.size() - 1); QByteArray name = pname.toLatin1(); sys.setCentralBody( name.data() ); Vec3 skyVector = sys.getPlanetocentric (0.0, 0.0); qreal skyRotationAngle = -atan2(skyVector[1], skyVector[0]); const qreal centerLon = viewport->centerLongitude(); const qreal centerLat = viewport->centerLatitude(); const qreal skyRadius = 0.6 * sqrt( ( qreal )viewport->width() * viewport->width() + viewport->height() * viewport->height() ); if ( doRender ) { if (!m_starPixmapsCreated) { createStarPixmaps(); m_starPixmapsCreated = true; } // Delayed initialization: // Load the star database only if the sky is actually being painted... if ( !m_starsLoaded ) { loadStars(); m_starsLoaded = true; } if ( !m_constellationsLoaded ) { loadConstellations(); m_constellationsLoaded = true; } if ( !m_dsosLoaded ) { loadDsos(); m_dsosLoaded = true; } const qreal earthRadius = viewport->radius(); // List of Pens used to draw the sky QPen polesPen( m_celestialPoleBrush, 2, Qt::SolidLine ); QPen constellationPenSolid( m_constellationBrush, 1, Qt::SolidLine ); QPen constellationPenDash( m_constellationBrush, 1, Qt::DashLine ); QPen constellationLabelPen( m_constellationLabelBrush, 1, Qt::SolidLine ); QPen eclipticPen( m_eclipticBrush, 1, Qt::DotLine ); QPen equatorPen( m_celestialEquatorBrush, 1, Qt::DotLine ); QPen dsoLabelPen (m_dsoLabelBrush, 1, Qt::SolidLine); const Quaternion skyAxis = Quaternion::fromEuler( -centerLat , centerLon + skyRotationAngle, 0.0 ); matrix skyAxisMatrix; skyAxis.inverse().toMatrix( skyAxisMatrix ); if ( m_renderCelestialPole ) { polesPen.setWidth( 2 ); painter->setPen( polesPen ); Quaternion qpos1; qpos1 = Quaternion::fromSpherical( 0, 90 * DEG2RAD ); qpos1.rotateAroundAxis( skyAxisMatrix ); if ( qpos1.v[Q_Z] < 0 ) { const int x1 = ( int )( viewport->width() / 2 + skyRadius * qpos1.v[Q_X] ); const int y1 = ( int )( viewport->height() / 2 - skyRadius * qpos1.v[Q_Y] ); painter->drawLine( x1, y1, x1+10, y1 ); painter->drawLine( x1+5, y1-5, x1+5, y1+5 ); painter->drawText( x1+8, y1+12, "NP" ); } Quaternion qpos2; qpos2 = Quaternion::fromSpherical( 0, -90 * DEG2RAD ); qpos2.rotateAroundAxis( skyAxisMatrix ); if ( qpos2.v[Q_Z] < 0 ) { const int x1 = ( int )( viewport->width() / 2 + skyRadius * qpos2.v[Q_X] ); const int y1 = ( int )( viewport->height() / 2 - skyRadius * qpos2.v[Q_Y] ); painter->drawLine( x1, y1, x1+10, y1 ); painter->drawLine( x1+5, y1-5, x1+5, y1+5 ); painter->drawText( x1+8, y1+12, "SP" ); } } if( m_renderEcliptic ) { const Quaternion eclipticAxis = Quaternion::fromEuler( 0.0, 0.0, -marbleModel()->planet()->epsilon() ); matrix eclipticAxisMatrix; (eclipticAxis * skyAxis).inverse().toMatrix( eclipticAxisMatrix ); painter->setPen(eclipticPen); int previousX = -1; int previousY = -1; for ( int i = 0; i <= 36; ++i) { Quaternion qpos; qpos = Quaternion::fromSpherical( i * 10 * DEG2RAD, 0 ); qpos.rotateAroundAxis( eclipticAxisMatrix ); int x = ( int )( viewport->width() / 2 + skyRadius * qpos.v[Q_X] ); int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] ); if ( qpos.v[Q_Z] < 0 && previousX >= 0 ) painter->drawLine(previousX, previousY, x, y); previousX = x; previousY = y; } } if( m_renderCelestialEquator ) { painter->setPen(equatorPen); int previousX = -1; int previousY = -1; for ( int i = 0; i <= 36; ++i) { Quaternion qpos; qpos = Quaternion::fromSpherical( i * 10 * DEG2RAD, 0 ); qpos.rotateAroundAxis( skyAxisMatrix ); int x = ( int )( viewport->width() / 2 + skyRadius * qpos.v[Q_X] ); int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] ); if ( qpos.v[Q_Z] < 0 && previousX > 0 ) painter->drawLine(previousX, previousY, x, y); previousX = x; previousY = y; } } if ( m_renderDsos ) { painter->setPen(dsoLabelPen); // Render Deep Space Objects for ( int d = 0; d < m_dsos.size(); ++d ) { Quaternion qpos = m_dsos.at( d ).quaternion(); qpos.rotateAroundAxis( skyAxisMatrix ); if ( qpos.v[Q_Z] > 0 ) { continue; } qreal earthCenteredX = qpos.v[Q_X] * skyRadius; qreal earthCenteredY = qpos.v[Q_Y] * skyRadius; // Don't draw high placemarks (e.g. satellites) that aren't visible. if ( qpos.v[Q_Z] < 0 && ( ( earthCenteredX * earthCenteredX + earthCenteredY * earthCenteredY ) < earthRadius * earthRadius ) ) { continue; } // Let (x, y) be the position on the screen of the placemark.. const int x = ( int )( viewport->width() / 2 + skyRadius * qpos.v[Q_X] ); const int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] ); // Skip placemarks that are outside the screen area if ( x < 0 || x >= viewport->width() || y < 0 || y >= viewport->height() ) { continue; } // Hard Code DSO Size for now qreal size = 20; // Center Image on x,y location painter->drawImage( QRectF( x-size/2, y-size/2, size, size ),m_dsoImage ); if (m_renderDsoLabels) { painter->drawText( x+8, y+12, m_dsos.at( d ).id() ); } } } if ( m_renderConstellationLines || m_renderConstellationLabels ) { // Render Constellations for ( int c = 0; c < m_constellations.size(); ++c ) { int xMean = 0; int yMean = 0; int endptCount = 0; painter->setPen( constellationPenSolid ); for ( int s = 0; s < ( m_constellations.at( c ).size() - 1 ); ++s ) { int starId1 = m_constellations.at( c ).at( s ); int starId2 = m_constellations.at( c ).at( s + 1 ); if ( starId1 == -1 || starId2 == -1 ) { // starId == -1 means we don't draw this segment continue; } else if ( starId1 == -2 || starId2 == -2 ) { painter->setPen( constellationPenDash ); } else if ( starId1 == -3 || starId2 == -3 ) { painter->setPen( constellationPenSolid ); } int idx1 = m_idHash.value( starId1,-1 ); int idx2 = m_idHash.value( starId2,-1 ); if ( idx1 < 0 ) { mDebug() << "unknown star, " << starId1 << ", in constellation " << m_constellations.at( c ).name(); continue; } if ( idx2 < 0 ) { mDebug() << "unknown star, " << starId1 << ", in constellation " << m_constellations.at( c ).name(); continue; } // Fetch quaternion from star s in constellation c Quaternion q1 = m_stars.at( idx1 ).quaternion(); // Fetch quaternion from star s+1 in constellation c Quaternion q2 = m_stars.at( idx2 ).quaternion(); q1.rotateAroundAxis( skyAxisMatrix ); q2.rotateAroundAxis( skyAxisMatrix ); if ( q1.v[Q_Z] > 0 || q2.v[Q_Z] > 0 ) { continue; } // Let (x, y) be the position on the screen of the placemark.. int x1 = ( int )( viewport->width() / 2 + skyRadius * q1.v[Q_X] ); int y1 = ( int )( viewport->height() / 2 - skyRadius * q1.v[Q_Y] ); int x2 = ( int )( viewport->width() / 2 + skyRadius * q2.v[Q_X] ); int y2 = ( int )( viewport->height() / 2 - skyRadius * q2.v[Q_Y] ); xMean = xMean + x1 + x2; yMean = yMean + y1 + y2; endptCount = endptCount + 2; if ( m_renderConstellationLines ) { painter->drawLine( x1, y1, x2, y2 ); } } // Skip constellation labels that are outside the screen area if ( endptCount > 0 ) { xMean = xMean / endptCount; yMean = yMean / endptCount; } if ( endptCount < 1 || xMean < 0 || xMean >= viewport->width() || yMean < 0 || yMean >= viewport->height() ) continue; painter->setPen( constellationLabelPen ); if ( m_renderConstellationLabels ) { painter->drawText( xMean, yMean, m_constellations.at( c ).name() ); } } } // Render Stars for ( int s = 0; s < m_stars.size(); ++s ) { Quaternion qpos = m_stars.at(s).quaternion(); qpos.rotateAroundAxis( skyAxisMatrix ); if ( qpos.v[Q_Z] > 0 ) { continue; } qreal earthCenteredX = qpos.v[Q_X] * skyRadius; qreal earthCenteredY = qpos.v[Q_Y] * skyRadius; // Don't draw high placemarks (e.g. satellites) that aren't visible. if ( qpos.v[Q_Z] < 0 && ( ( earthCenteredX * earthCenteredX + earthCenteredY * earthCenteredY ) < earthRadius * earthRadius ) ) { continue; } // Let (x, y) be the position on the screen of the placemark.. const int x = ( int )( viewport->width() / 2 + skyRadius * qpos.v[Q_X] ); const int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] ); // Skip placemarks that are outside the screen area if ( x < 0 || x >= viewport->width() || y < 0 || y >= viewport->height() ) continue; // Show star if it is brighter than magnitude threshold if ( m_stars.at(s).magnitude() < m_magnitudeLimit ) { // colorId is used to select which pixmap in vector to display int colorId = m_stars.at(s).colorId(); QPixmap s_pixmap = starPixmap(m_stars.at(s).magnitude(), colorId); int sizeX = s_pixmap.width(); int sizeY = s_pixmap.height(); painter->drawPixmap( x-sizeX/2, y-sizeY/2 ,s_pixmap ); } } if ( m_renderSun ) { // sun double ra = 0.0; double decl = 0.0; sys.getSun( ra, decl ); ra = 15.0 * sys.DmsDegF( ra ); decl = sys.DmsDegF( decl ); Quaternion qpos = Quaternion::fromSpherical( ra * DEG2RAD, decl * DEG2RAD ); qpos.rotateAroundAxis( skyAxisMatrix ); if ( qpos.v[Q_Z] <= 0 ) { QPixmap glow(MarbleDirs::path(QStringLiteral("svg/glow.png"))); qreal deltaX = glow.width() / 2.; qreal deltaY = glow.height() / 2.; int x = (int)(viewport->width() / 2 + skyRadius * qpos.v[Q_X]); int y = (int)(viewport->height() / 2 - skyRadius * qpos.v[Q_Y]); bool glowDrawn = false; if (!(x < -glow.width() || x >= viewport->width() || y < -glow.height() || y >= viewport->height())) { painter->drawPixmap( x - deltaX, y - deltaY, glow ); glowDrawn = true; } if (glowDrawn) { double diameter = 0.0, mag = 0.0; sys.getPhysSun(diameter, mag); const int coefficient = m_zoomSunMoon ? m_zoomCoefficient : 1; const qreal size = skyRadius * qSin(diameter) * coefficient; const qreal factor = size/m_pixmapSun.width(); QPixmap sun = m_pixmapSun.transformed(QTransform().scale(factor, factor), Qt::SmoothTransformation); deltaX = sun.width() / 2.; deltaY = sun.height() / 2.; x = (int)(viewport->width() / 2 + skyRadius * qpos.v[Q_X]); y = (int)(viewport->height() / 2 - skyRadius * qpos.v[Q_Y]); painter->drawPixmap( x - deltaX, y - deltaY, sun ); } // It's labels' time! if (m_viewSolarSystemLabel) painter->drawText(x+deltaX*1.5, y+deltaY*1.5, tr("Sun")); } } if ( m_renderMoon && marbleModel()->planetId() == QLatin1String("earth")) { // moon double ra=0.0; double decl=0.0; sys.getMoon(ra, decl); ra = 15.0 * sys.DmsDegF(ra); decl = sys.DmsDegF(decl); Quaternion qpos = Quaternion::fromSpherical( ra * DEG2RAD, decl * DEG2RAD ); qpos.rotateAroundAxis( skyAxisMatrix ); if ( qpos.v[Q_Z] <= 0 ) { // If zoom Sun and Moon is enabled size is multiplied by zoomCoefficient. const int coefficient = m_zoomSunMoon ? m_zoomCoefficient : 1; QPixmap moon = m_pixmapMoon.copy(); const qreal size = skyRadius * qSin(sys.getDiamMoon()) * coefficient; qreal deltaX = size / 2.; qreal deltaY = size / 2.; const int x = (int)(viewport->width() / 2 + skyRadius * qpos.v[Q_X]); const int y = (int)(viewport->height() / 2 - skyRadius * qpos.v[Q_Y]); if (!(x < -size || x >= viewport->width() || y < -size || y >= viewport->height())) { // Moon phases double phase = 0.0, ildisk = 0.0, amag = 0.0; sys.getLunarPhase(phase, ildisk, amag); QPainterPath path; QRectF fullMoonRect = moon.rect(); if (ildisk < 0.05) { // small enough, so it's not visible path.addEllipse(fullMoonRect); } else if (ildisk < 0.95) { // makes sense to do smth QRectF halfEllipseRect; qreal ellipseWidth = 2 * qAbs(ildisk-0.5) * moon.width(); halfEllipseRect.setX((fullMoonRect.width() - ellipseWidth) * 0.5); halfEllipseRect.setWidth(ellipseWidth); halfEllipseRect.setHeight(moon.height()); if (phase < 0.5) { if (ildisk < 0.5) { path.moveTo(fullMoonRect.width()/2, moon.height()); path.arcTo(fullMoonRect, -90, -180); path.arcTo(halfEllipseRect, 90, -180); } else { path.moveTo(fullMoonRect.width()/2, 0); path.arcTo(fullMoonRect, 90, 180); path.arcTo(halfEllipseRect, -90, -180); } } else { if (ildisk < 0.5) { path.moveTo(fullMoonRect.width()/2, moon.height()); path.arcTo(fullMoonRect, -90, 180); path.arcTo(halfEllipseRect, 90, 180); } else { path.moveTo(fullMoonRect.width()/2, 0); path.arcTo(fullMoonRect, 90, -180); path.arcTo(halfEllipseRect, -90, 180); } } path.closeSubpath(); } QPainter overlay; overlay.begin(&moon); overlay.setPen(Qt::NoPen); overlay.setBrush(QBrush(QColor(0, 0, 0, 180))); overlay.setRenderHint(QPainter::Antialiasing, true); overlay.drawPath(path); overlay.end(); qreal angle = marbleModel()->planet()->epsilon() * qCos(ra * DEG2RAD) * RAD2DEG; if (viewport->polarity() < 0) angle += 180; QTransform form; const qreal factor = size / moon.size().width(); moon = moon.transformed(form.rotate(angle).scale(factor, factor), Qt::SmoothTransformation); painter->drawPixmap( x - deltaX, y - deltaY, moon ); // It's labels' time! if (m_viewSolarSystemLabel) painter->drawText(x+deltaX, y+deltaY, PlanetFactory::localizedName("moon")); } } } for(const QString &planet: m_renderPlanet.keys()) { if (m_renderPlanet[planet]) renderPlanet(planet, painter, sys, viewport, skyRadius, skyAxisMatrix); } } painter->restore(); return true; } void StarsPlugin::renderPlanet(const QString &planetId, GeoPainter *painter, SolarSystem &sys, ViewportParams *viewport, qreal skyRadius, matrix &skyAxisMatrix) const { double ra(.0), decl(.0), diam(.0), mag(.0), phase(.0); int color=0; // venus, mars, jupiter, uranus, neptune, saturn if (planetId == QLatin1String("venus")) { sys.getVenus(ra, decl); sys.getPhysVenus(diam, mag, phase); color = 2; } else if (planetId == QLatin1String("mars")) { sys.getMars(ra, decl); sys.getPhysMars(diam, mag, phase); color = 5; } else if (planetId == QLatin1String("jupiter")) { sys.getJupiter(ra, decl); sys.getPhysJupiter(diam, mag, phase); color = 2; } else if (planetId == QLatin1String("mercury")) { sys.getMercury(ra, decl); sys.getPhysMercury(diam, mag, phase); color = 3; } else if (planetId == QLatin1String("saturn")) { sys.getSaturn(ra, decl); sys.getPhysSaturn(diam, mag, phase); color = 3; } else if (planetId == QLatin1String("uranus")) { sys.getUranus(ra, decl); sys.getPhysUranus(diam, mag, phase); color = 0; } else if (planetId == QLatin1String("neptune")) { sys.getNeptune(ra, decl); sys.getPhysNeptune(diam, mag, phase); color = 0; } else { return; } ra = 15.0 * sys.DmsDegF(ra); decl = sys.DmsDegF(decl); Quaternion qpos = Quaternion::fromSpherical( ra * DEG2RAD, decl * DEG2RAD ); qpos.rotateAroundAxis( skyAxisMatrix ); if ( qpos.v[Q_Z] <= 0 ) { QPixmap planetPixmap = starPixmap(mag, color); qreal deltaX = planetPixmap.width() / 2.; qreal deltaY = planetPixmap.height() / 2.; const int x = (int)(viewport->width() / 2 + skyRadius * qpos.v[Q_X]); const int y = (int)(viewport->height() / 2 - skyRadius * qpos.v[Q_Y]); if (!(x < 0 || x >= viewport->width() || y < 0 || y >= viewport->height())) { painter->drawPixmap( x - deltaX, y - deltaY, planetPixmap ); } // It's labels' time! if (m_viewSolarSystemLabel) painter->drawText(x+deltaX, y+deltaY, PlanetFactory::localizedName(planetId)); } } void StarsPlugin::requestRepaint() { emit repaintNeeded( QRegion() ); } void StarsPlugin::toggleSunMoon(bool on) { m_renderSun = on; m_renderMoon = on; if (on) { m_viewSolarSystemLabel = true; } const Qt::CheckState state = on ? Qt::Checked : Qt::Unchecked; if ( m_configDialog ) { ui_configWidget->m_solarSystemListWidget->item( 0 )->setCheckState( state ); ui_configWidget->m_solarSystemListWidget->item( 1 )->setCheckState( state ); ui_configWidget->m_viewSolarSystemLabelCheckbox->setChecked(m_viewSolarSystemLabel); } emit settingsChanged( nameId() ); requestRepaint(); } void StarsPlugin::toggleDsos(bool on) { m_renderDsos = on; // only enable labels if set to true if (on) { m_renderDsoLabels = true; } const Qt::CheckState state = on ? Qt::Checked : Qt::Unchecked; if ( m_configDialog ) { ui_configWidget->m_viewDsosCheckbox->setChecked(state); ui_configWidget->m_viewDsoLabelCheckbox->setChecked(state); } emit settingsChanged( nameId() ); requestRepaint(); } void StarsPlugin::toggleConstellations(bool on) { m_renderConstellationLines = on; m_renderConstellationLabels = on; const Qt::CheckState state = on ? Qt::Checked : Qt::Unchecked; if ( m_configDialog ) { ui_configWidget->m_viewConstellationLinesCheckbox->setChecked( state ); ui_configWidget->m_viewConstellationLabelsCheckbox->setChecked( state ); } emit settingsChanged( nameId() ); requestRepaint(); } void StarsPlugin::togglePlanets(bool on) { m_renderPlanet["venus"] = on; m_renderPlanet["mars"] = on; m_renderPlanet["jupiter"] = on; m_renderPlanet["mercury"] = on; m_renderPlanet["saturn"] = on; m_renderPlanet["uranus"] = on; m_renderPlanet["neptune"] = on; const Qt::CheckState state = on ? Qt::Checked : Qt::Unchecked; if ( m_configDialog ) { // Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune ui_configWidget->m_solarSystemListWidget->item(2)->setCheckState(state); ui_configWidget->m_solarSystemListWidget->item(3)->setCheckState(state); ui_configWidget->m_solarSystemListWidget->item(5)->setCheckState(state); ui_configWidget->m_solarSystemListWidget->item(6)->setCheckState(state); ui_configWidget->m_solarSystemListWidget->item(7)->setCheckState(state); ui_configWidget->m_solarSystemListWidget->item(8)->setCheckState(state); ui_configWidget->m_solarSystemListWidget->item(9)->setCheckState(state); } emit settingsChanged( nameId() ); requestRepaint(); } void StarsPlugin::executeConfigDialog() { QDialog *dialog = configDialog(); Q_ASSERT( dialog ); dialog->exec(); } bool StarsPlugin::eventFilter( QObject *object, QEvent *e ) { if ( !enabled() || !visible() ) { return false; } if( e->type() == QEvent::ContextMenu ) { MarbleWidget *widget = dynamic_cast( object ); QContextMenuEvent *menuEvent = dynamic_cast ( e ); if( widget && menuEvent ) { qreal mouseLon, mouseLat; const bool aboveMap = widget->geoCoordinates( menuEvent->x(), menuEvent->y(), mouseLon, mouseLat, GeoDataCoordinates::Radian ); if ( aboveMap ) { return false; } for ( AbstractFloatItem *floatItem: widget->floatItems() ) { if ( floatItem->enabled() && floatItem->visible() && floatItem->contains( menuEvent->pos() ) ) { return false; } } if (!m_contextMenu) { m_contextMenu = new QMenu; m_constellationsAction = m_contextMenu->addAction(tr("Show &Constellations"), this, SLOT(toggleConstellations(bool))); m_constellationsAction->setCheckable(true); m_sunMoonAction = m_contextMenu->addAction(tr("Show &Sun and Moon"), this, SLOT(toggleSunMoon(bool))); m_sunMoonAction->setCheckable(true); m_planetsAction = m_contextMenu->addAction(tr("Show &Planets"), this, SLOT(togglePlanets(bool))); m_planetsAction->setCheckable(true); m_dsoAction = m_contextMenu->addAction(tr("Show &Deep Sky Objects"), this, SLOT(toggleDsos(bool)) ); m_dsoAction->setCheckable(true); m_contextMenu->addSeparator(); m_contextMenu->addAction(tr("&Configure..."), this, SLOT(executeConfigDialog())); } // update action states m_constellationsAction->setChecked(m_renderConstellationLines || m_renderConstellationLabels); m_sunMoonAction->setChecked(m_renderSun || m_renderMoon); m_dsoAction->setChecked(m_renderDsos); const bool isAnyPlanetRendered = m_renderPlanet["venus"] || m_renderPlanet["mars"] || m_renderPlanet["jupiter"] || m_renderPlanet["mercury"] || m_renderPlanet["saturn"] || m_renderPlanet["uranus"] || m_renderPlanet["neptune"]; m_planetsAction->setChecked(isAnyPlanetRendered); m_contextMenu->exec(widget->mapToGlobal(menuEvent->pos())); return true; } return false; } else { return RenderPlugin::eventFilter( object, e ); } } } #include "moc_StarsPlugin.cpp"