Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgslayoutitemmarker.cpp 3 : : --------------------- 4 : : begin : April 2020 5 : : copyright : (C) 2020 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : /*************************************************************************** 9 : : * * 10 : : * This program is free software; you can redistribute it and/or modify * 11 : : * it under the terms of the GNU General Public License as published by * 12 : : * the Free Software Foundation; either version 2 of the License, or * 13 : : * (at your option) any later version. * 14 : : * * 15 : : ***************************************************************************/ 16 : : 17 : : #include "qgslayoutitemmarker.h" 18 : : #include "qgslayout.h" 19 : : #include "qgslayoututils.h" 20 : : #include "qgssymbollayerutils.h" 21 : : #include "qgslayoutmodel.h" 22 : : #include "qgsstyleentityvisitor.h" 23 : : #include "qgslayoutitemmap.h" 24 : : 25 : : #include <QPainter> 26 : : 27 : 0 : QgsLayoutItemMarker::QgsLayoutItemMarker( QgsLayout *layout ) 28 : 0 : : QgsLayoutItem( layout ) 29 : 0 : , mNorthArrowHandler( new QgsLayoutNorthArrowHandler( this ) ) 30 : 0 : { 31 : 0 : setBackgroundEnabled( false ); 32 : 0 : setFrameEnabled( false ); 33 : 0 : setReferencePoint( QgsLayoutItem::Middle ); 34 : 0 : QVariantMap properties; 35 : 0 : properties.insert( QStringLiteral( "size" ), QStringLiteral( "4" ) ); 36 : 0 : mShapeStyleSymbol.reset( QgsMarkerSymbol::createSimple( properties ) ); 37 : 0 : refreshSymbol(); 38 : : 39 : 0 : connect( this, &QgsLayoutItemMarker::sizePositionChanged, this, [ = ] 40 : : { 41 : 0 : updateBoundingRect(); 42 : 0 : update(); 43 : 0 : } ); 44 : : 45 : 0 : connect( mNorthArrowHandler, &QgsLayoutNorthArrowHandler::arrowRotationChanged, this, &QgsLayoutItemMarker::northArrowRotationChanged ); 46 : 0 : } 47 : : 48 : 0 : QgsLayoutItemMarker::~QgsLayoutItemMarker() = default; 49 : : 50 : 0 : QgsLayoutItemMarker *QgsLayoutItemMarker::create( QgsLayout *layout ) 51 : : { 52 : 0 : return new QgsLayoutItemMarker( layout ); 53 : 0 : } 54 : : 55 : 0 : int QgsLayoutItemMarker::type() const 56 : : { 57 : 0 : return QgsLayoutItemRegistry::LayoutMarker; 58 : : } 59 : : 60 : 0 : QIcon QgsLayoutItemMarker::icon() const 61 : : { 62 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemMarker.svg" ) ); 63 : 0 : } 64 : : 65 : 0 : void QgsLayoutItemMarker::refreshSymbol() 66 : : { 67 : 0 : if ( auto *lLayout = layout() ) 68 : : { 69 : 0 : QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( lLayout, nullptr, lLayout->renderContext().dpi() ); 70 : : 71 : 0 : std::unique_ptr< QgsMarkerSymbol > sym( mShapeStyleSymbol->clone() ); 72 : 0 : sym->setAngle( sym->angle() + mNorthArrowRotation ); 73 : 0 : sym->startRender( rc ); 74 : 0 : QRectF bounds = sym->bounds( QPointF( 0, 0 ), rc ); 75 : 0 : sym->stopRender( rc ); 76 : 0 : mPoint = QPointF( -bounds.left() * 25.4 / lLayout->renderContext().dpi(), 77 : 0 : -bounds.top() * 25.4 / lLayout->renderContext().dpi() ); 78 : 0 : bounds.translate( mPoint ); 79 : : 80 : 0 : QgsLayoutSize newSizeMm = QgsLayoutSize( bounds.size() * 25.4 / lLayout->renderContext().dpi(), QgsUnitTypes::LayoutMillimeters ); 81 : 0 : mFixedSize = mLayout->renderContext().measurementConverter().convert( newSizeMm, sizeWithUnits().units() ); 82 : : 83 : 0 : attemptResize( mFixedSize ); 84 : 0 : } 85 : : 86 : 0 : updateBoundingRect(); 87 : : 88 : 0 : update(); 89 : 0 : emit frameChanged(); 90 : 0 : } 91 : : 92 : 0 : void QgsLayoutItemMarker::updateBoundingRect() 93 : : { 94 : 0 : QRectF rectangle = rect(); 95 : : 96 : : // add a bit, to account for antialiasing on stroke and miter effects on stroke 97 : 0 : rectangle.adjust( -5, -5, 5, 5 ); 98 : 0 : if ( rectangle != mCurrentRectangle ) 99 : : { 100 : 0 : prepareGeometryChange(); 101 : 0 : mCurrentRectangle = rectangle; 102 : 0 : } 103 : 0 : } 104 : : 105 : 0 : void QgsLayoutItemMarker::northArrowRotationChanged( double rotation ) 106 : : { 107 : 0 : mNorthArrowRotation = rotation; 108 : 0 : refreshSymbol(); 109 : 0 : } 110 : : 111 : 0 : void QgsLayoutItemMarker::setSymbol( QgsMarkerSymbol *symbol ) 112 : : { 113 : 0 : if ( !symbol ) 114 : 0 : return; 115 : : 116 : 0 : mShapeStyleSymbol.reset( symbol ); 117 : 0 : refreshSymbol(); 118 : 0 : } 119 : : 120 : 0 : QgsMarkerSymbol *QgsLayoutItemMarker::symbol() 121 : : { 122 : 0 : return mShapeStyleSymbol.get(); 123 : : } 124 : : 125 : 0 : void QgsLayoutItemMarker::setLinkedMap( QgsLayoutItemMap *map ) 126 : : { 127 : 0 : mNorthArrowHandler->setLinkedMap( map ); 128 : 0 : } 129 : : 130 : 0 : QgsLayoutItemMap *QgsLayoutItemMarker::linkedMap() const 131 : : { 132 : 0 : return mNorthArrowHandler->linkedMap(); 133 : : } 134 : : 135 : 0 : QgsLayoutNorthArrowHandler::NorthMode QgsLayoutItemMarker::northMode() const 136 : : { 137 : 0 : return mNorthArrowHandler->northMode(); 138 : : 139 : : } 140 : : 141 : 0 : void QgsLayoutItemMarker::setNorthMode( QgsLayoutNorthArrowHandler::NorthMode mode ) 142 : : { 143 : 0 : mNorthArrowHandler->setNorthMode( mode ); 144 : : 145 : 0 : } 146 : : 147 : 0 : double QgsLayoutItemMarker::northOffset() const 148 : : { 149 : 0 : return mNorthArrowHandler->northOffset(); 150 : : } 151 : : 152 : 0 : void QgsLayoutItemMarker::setNorthOffset( double offset ) 153 : : { 154 : 0 : mNorthArrowHandler->setNorthOffset( offset ); 155 : 0 : } 156 : : 157 : 0 : QRectF QgsLayoutItemMarker::boundingRect() const 158 : : { 159 : 0 : return mCurrentRectangle; 160 : : } 161 : 0 : 162 : 0 : QgsLayoutSize QgsLayoutItemMarker::fixedSize() const 163 : : { 164 : 0 : return mFixedSize; 165 : : } 166 : : 167 : 0 : bool QgsLayoutItemMarker::accept( QgsStyleEntityVisitorInterface *visitor ) const 168 : : { 169 : 0 : if ( mShapeStyleSymbol ) 170 : : { 171 : 0 : QgsStyleSymbolEntity entity( mShapeStyleSymbol.get() ); 172 : 0 : if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) ) 173 : 0 : return false; 174 : 0 : } 175 : : 176 : 0 : return true; 177 : 0 : } 178 : : 179 : 0 : void QgsLayoutItemMarker::draw( QgsLayoutItemRenderContext &context ) 180 : : { 181 : 0 : QPainter *painter = context.renderContext().painter(); 182 : 0 : painter->setPen( Qt::NoPen ); 183 : 0 : painter->setBrush( Qt::NoBrush ); 184 : : 185 : 0 : double scale = context.renderContext().convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters ); 186 : : 187 : 0 : QPointF shapePoint = mPoint * scale; 188 : : 189 : 0 : std::unique_ptr< QgsMarkerSymbol > sym( mShapeStyleSymbol->clone() ); 190 : 0 : sym->setAngle( sym->angle() + mNorthArrowRotation ); 191 : 0 : sym->startRender( context.renderContext() ); 192 : 0 : sym->renderPoint( shapePoint, nullptr, context.renderContext() ); 193 : 0 : sym->stopRender( context.renderContext() ); 194 : 0 : } 195 : : 196 : 0 : bool QgsLayoutItemMarker::writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const 197 : : { 198 : 0 : QDomElement shapeStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mShapeStyleSymbol.get(), document, context ); 199 : 0 : element.appendChild( shapeStyleElem ); 200 : : 201 : : //rotation 202 : 0 : element.setAttribute( QStringLiteral( "arrowRotation" ), QString::number( mNorthArrowRotation ) ); 203 : 0 : if ( !mNorthArrowHandler->linkedMap() ) 204 : : { 205 : 0 : element.setAttribute( QStringLiteral( "mapUuid" ), QString() ); 206 : 0 : } 207 : : else 208 : : { 209 : 0 : element.setAttribute( QStringLiteral( "mapUuid" ), mNorthArrowHandler->linkedMap()->uuid() ); 210 : : } 211 : 0 : element.setAttribute( QStringLiteral( "northMode" ), mNorthArrowHandler->northMode() ); 212 : 0 : element.setAttribute( QStringLiteral( "northOffset" ), mNorthArrowHandler->northOffset() ); 213 : : 214 : : return true; 215 : 0 : } 216 : : 217 : 0 : bool QgsLayoutItemMarker::readPropertiesFromElement( const QDomElement &element, const QDomDocument &, const QgsReadWriteContext &context ) 218 : : { 219 : 0 : QDomElement shapeStyleSymbolElem = element.firstChildElement( QStringLiteral( "symbol" ) ); 220 : 0 : if ( !shapeStyleSymbolElem.isNull() ) 221 : : { 222 : 0 : mShapeStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( shapeStyleSymbolElem, context ) ); 223 : 0 : } 224 : : 225 : : //picture rotation 226 : 0 : if ( !qgsDoubleNear( element.attribute( QStringLiteral( "arrowRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) ) 227 : : { 228 : 0 : mNorthArrowRotation = element.attribute( QStringLiteral( "arrowRotation" ), QStringLiteral( "0" ) ).toDouble(); 229 : 0 : } 230 : : 231 : : //rotation map 232 : 0 : mNorthArrowHandler->setNorthMode( static_cast< QgsLayoutNorthArrowHandler::NorthMode >( element.attribute( QStringLiteral( "northMode" ), QStringLiteral( "0" ) ).toInt() ) ); 233 : 0 : mNorthArrowHandler->setNorthOffset( element.attribute( QStringLiteral( "northOffset" ), QStringLiteral( "0" ) ).toDouble() ); 234 : : 235 : 0 : mNorthArrowHandler->setLinkedMap( nullptr ); 236 : 0 : mRotationMapUuid = element.attribute( QStringLiteral( "mapUuid" ) ); 237 : : 238 : 0 : refreshSymbol(); 239 : : 240 : : return true; 241 : 0 : } 242 : : 243 : 0 : void QgsLayoutItemMarker::finalizeRestoreFromXml() 244 : : { 245 : 0 : if ( !mLayout || mRotationMapUuid.isEmpty() ) 246 : : { 247 : 0 : mNorthArrowHandler->setLinkedMap( nullptr ); 248 : 0 : } 249 : : else 250 : : { 251 : 0 : mNorthArrowHandler->setLinkedMap( qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mRotationMapUuid, true ) ) ); 252 : : } 253 : 0 : emit changed(); 254 : 0 : }