diff --git a/python/core/composer/qgscomposermap.sip b/python/core/composer/qgscomposermap.sip index b57ed7a7f90..b646d22e604 100644 --- a/python/core/composer/qgscomposermap.sip +++ b/python/core/composer/qgscomposermap.sip @@ -208,6 +208,11 @@ class QgsComposerMap : QgsComposerItem @note this function was added in version 1.4*/ void setGridAnnotationFont( const QFont& f ); QFont gridAnnotationFont() const; + + /**Sets font color for grid annotations + @note this function was added in version 2.0*/ + void setAnnotationFontColor( const QColor& c ); + QColor annotationFontColor() const; /**Sets coordinate precision for grid annotations @note this function was added in version 1.4*/ @@ -242,6 +247,13 @@ class QgsComposerMap : QgsComposerItem @note: this function was added in version 1.9*/ void setGridFrameWidth( double w ); double gridFrameWidth() const; + + /** Returns the grid's blending mode + @note added in version 2.0*/ + const QPainter::CompositionMode gridBlendMode() const; + /** Sets the grid's blending mode + @note added in version 2.0*/ + void setGridBlendMode( const QPainter::CompositionMode blendMode ); /**In case of annotations, the bounding rectangle can be larger than the map item rectangle @note this function was added in version 1.4*/ diff --git a/python/core/qgsvectorlayer.sip b/python/core/qgsvectorlayer.sip index 110a7d0705f..193a9bdd048 100644 --- a/python/core/qgsvectorlayer.sip +++ b/python/core/qgsvectorlayer.sip @@ -755,7 +755,25 @@ class QgsVectorLayer : QgsMapLayer @note this method was added in version 1.1 */ QgsVectorOverlay* findOverlayByType( const QString& typeName ); - + + /* Set the blending mode used for rendering each feature + * @note added in 2.0 + */ + void setFeatureBlendMode( const QPainter::CompositionMode blendMode ); + /* Returns the current blending mode for features + * @note added in 2.0 + */ + const QPainter::CompositionMode featureBlendMode() const; + + /* Set the transparency for the vector layer + * @note added in 2.0 + */ + void setLayerTransparency( const int layerTransparency ); + /* Returns the current transparency for the vector layer + * @note added in 2.0 + */ + const int layerTransparency() const; + //! Buffer with uncommitted editing operations. Only valid after editing has been turned on. QgsVectorLayerEditBuffer* editBuffer(); diff --git a/src/app/composer/qgscomposer.cpp b/src/app/composer/qgscomposer.cpp index 1557db15267..dc982b00bad 100644 --- a/src/app/composer/qgscomposer.cpp +++ b/src/app/composer/qgscomposer.cpp @@ -632,9 +632,9 @@ void QgsComposer::on_mActionExportAsPDF_triggered() showWMSPrintingWarning(); } - if ( containsBlendModes() ) + if ( containsAdvancedEffects() ) { - showBlendModePrintingWarning(); + showAdvancedEffectsWarning(); } // If we are not printing as raster, temporarily disable advanced effects @@ -828,9 +828,9 @@ void QgsComposer::on_mActionPrint_triggered() showWMSPrintingWarning(); } - if ( containsBlendModes() ) + if ( containsAdvancedEffects() ) { - showBlendModePrintingWarning(); + showAdvancedEffectsWarning(); } // If we are not printing as raster, temporarily disable advanced effects @@ -2056,9 +2056,9 @@ bool QgsComposer::containsWMSLayer() const return false; } -bool QgsComposer::containsBlendModes() const +bool QgsComposer::containsAdvancedEffects() const { - // Check if composer contains any blend modes + // Check if composer contains any blend modes or flattened layers for transparency QMap::const_iterator item_it = mItemWidgetMap.constBegin(); QgsComposerItem* currentItem = 0; QgsComposerMap* currentMap = 0; @@ -2071,11 +2071,11 @@ bool QgsComposer::containsBlendModes() const { return true; } - // If item is a composer map, check if it contains any blended layers + // If item is a composer map, check if it contains any advanced effects currentMap = dynamic_cast( currentItem ); if ( currentMap ) { - if ( currentMap->containsBlendModes() ) + if ( currentMap->containsAdvancedEffects() ) { return true; } @@ -2087,6 +2087,14 @@ bool QgsComposer::containsBlendModes() const return true; } } + if ( currentMap->gridEnabled() ) + { + // map contains an grid, check its blend mode + if ( currentMap->gridBlendMode() != QPainter::CompositionMode_SourceOver ) + { + return true; + } + } } } return false; @@ -2111,13 +2119,13 @@ void QgsComposer::showWMSPrintingWarning() } } -void QgsComposer::showBlendModePrintingWarning() +void QgsComposer::showAdvancedEffectsWarning() { if ( ! mComposition->printAsRaster() ) { QgsMessageViewer* m = new QgsMessageViewer( this, QgisGui::ModalDialogFlags, false ); - m->setWindowTitle( tr( "Project contains blend modes" ) ); - m->setMessage( tr( "Blend modes are enabled in this project, which cannot be printed as vectors. Printing as a raster is recommended." ), QgsMessageOutput::MessageText ); + m->setWindowTitle( tr( "Project contains composition effects" ) ); + m->setMessage( tr( "Advanced composition effects such as blend modes or vector layer transparency are enabled in this project, which cannot be printed as vectors. Printing as a raster is recommended." ), QgsMessageOutput::MessageText ); m->setCheckBoxText( tr( "Print as raster" ) ); m->setCheckBoxState( Qt::Checked ); m->setCheckBoxVisible( true ); diff --git a/src/app/composer/qgscomposer.h b/src/app/composer/qgscomposer.h index db7b8868ac1..8a5d0695300 100644 --- a/src/app/composer/qgscomposer.h +++ b/src/app/composer/qgscomposer.h @@ -309,14 +309,14 @@ class QgsComposer: public QMainWindow, private Ui::QgsComposerBase //! True if a composer map contains a WMS layer bool containsWMSLayer() const; - //! True if a composer contains blend modes - bool containsBlendModes() const; + //! True if a composer contains advanced effects, such as blend modes + bool containsAdvancedEffects() const; //! Displays a warning because of possible min/max size in WMS void showWMSPrintingWarning(); //! Displays a warning because of incompatibility between blend modes and QPrinter - void showBlendModePrintingWarning(); + void showAdvancedEffectsWarning(); //! Changes elements that are not suitable for this project void cleanupAfterTemplateRead(); diff --git a/src/app/composer/qgscomposermapwidget.cpp b/src/app/composer/qgscomposermapwidget.cpp index 47e2e471d02..0c0ab7c82bd 100644 --- a/src/app/composer/qgscomposermapwidget.cpp +++ b/src/app/composer/qgscomposermapwidget.cpp @@ -343,6 +343,9 @@ void QgsComposerMapWidget::updateGuiElements() mFrameStyleComboBox->setCurrentIndex( mFrameStyleComboBox->findText( tr( "No frame" ) ) ); } + //grid blend mode + mGridBlendComboBox->setBlendMode( mComposerMap->gridBlendMode() ); + //grid annotation format QgsComposerMap::GridAnnotationFormat gf = mComposerMap->gridAnnotationFormat(); mAnnotationFormatComboBox->setCurrentIndex(( int )gf ); @@ -359,6 +362,10 @@ void QgsComposerMapWidget::updateGuiElements() initAnnotationDirectionBox( mAnnotationDirectionComboBoxTop, mComposerMap->gridAnnotationDirection( QgsComposerMap::Top ) ); initAnnotationDirectionBox( mAnnotationDirectionComboBoxBottom, mComposerMap->gridAnnotationDirection( QgsComposerMap::Bottom ) ); + mAnnotationFontColorButton->setColor( mComposerMap->annotationFontColor() ); + mAnnotationFontColorButton->setColorDialogTitle( tr( "Select font color" ) ); + mAnnotationFontColorButton->setColorDialogOptions( QColorDialog::ShowAlphaChannel ); + mDistanceToMapFrameSpinBox->setValue( mComposerMap->annotationFrameDistance() ); if ( mComposerMap->showGridAnnotation() ) @@ -423,6 +430,7 @@ void QgsComposerMapWidget::blockAllSignals( bool b ) mSetToMapCanvasExtentButton->blockSignals( b ); mUpdatePreviewButton->blockSignals( b ); mGridLineStyleButton->blockSignals( b ); + mGridBlendComboBox->blockSignals( b ); mDrawAnnotationCheckableGroupBox->blockSignals( b ); mAnnotationFontButton->blockSignals( b ); mAnnotationFormatComboBox->blockSignals( b ); @@ -436,6 +444,7 @@ void QgsComposerMapWidget::blockAllSignals( bool b ) mAnnotationDirectionComboBoxTop->blockSignals( b ); mAnnotationDirectionComboBoxBottom->blockSignals( b ); mCoordinatePrecisionSpinBox->blockSignals( b ); + mAnnotationFontColorButton->blockSignals( b ); mDrawCanvasItemsCheckBox->blockSignals( b ); mFrameStyleComboBox->blockSignals( b ); mFrameWidthSpinBox->blockSignals( b ); @@ -705,6 +714,16 @@ void QgsComposerMapWidget::on_mCrossWidthSpinBox_valueChanged( double d ) mComposerMap->endCommand(); } +void QgsComposerMapWidget::on_mGridBlendComboBox_currentIndexChanged( int index ) +{ + Q_UNUSED( index ); + if ( mComposerMap ) + { + mComposerMap->setGridBlendMode( mGridBlendComboBox->blendMode() ); + } + +} + void QgsComposerMapWidget::on_mAnnotationFontButton_clicked() { if ( !mComposerMap ) @@ -729,6 +748,18 @@ void QgsComposerMapWidget::on_mAnnotationFontButton_clicked() } } +void QgsComposerMapWidget::on_mAnnotationFontColorButton_colorChanged( const QColor& newFontColor ) +{ + if ( !mComposerMap ) + { + return; + } + mComposerMap->beginCommand( tr( "Label font changed" ) ); + mComposerMap->setAnnotationFontColor( newFontColor ); + mComposerMap->update(); + mComposerMap->endCommand(); +} + void QgsComposerMapWidget::on_mDistanceToMapFrameSpinBox_valueChanged( double d ) { if ( !mComposerMap ) diff --git a/src/app/composer/qgscomposermapwidget.h b/src/app/composer/qgscomposermapwidget.h index abe4f2fa213..d424d1e1829 100644 --- a/src/app/composer/qgscomposermapwidget.h +++ b/src/app/composer/qgscomposermapwidget.h @@ -60,7 +60,9 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase void on_mGridLineStyleButton_clicked(); void on_mGridTypeComboBox_currentIndexChanged( const QString& text ); void on_mCrossWidthSpinBox_valueChanged( double d ); + void on_mGridBlendComboBox_currentIndexChanged( int index ); void on_mAnnotationFontButton_clicked(); + void on_mAnnotationFontColorButton_colorChanged( const QColor& newFontColor ); void on_mDistanceToMapFrameSpinBox_valueChanged( double d ); void on_mAnnotationFormatComboBox_currentIndexChanged( int index ); diff --git a/src/core/composer/qgscomposermap.cpp b/src/core/composer/qgscomposermap.cpp index 0551b0c0802..8b5ac1a2ef3 100644 --- a/src/core/composer/qgscomposermap.cpp +++ b/src/core/composer/qgscomposermap.cpp @@ -42,10 +42,12 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height ) : QgsComposerItem( x, y, width, height, composition ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 ), mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mGridEnabled( false ), mGridStyle( Solid ), - mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), - mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame ), mTopGridAnnotationPosition( OutsideMapFrame ), - mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ), mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), - mTopGridAnnotationDirection( Horizontal ), mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ), + mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) ), + mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), mGridBlendMode( QPainter::CompositionMode_SourceOver ), + mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame ), + mTopGridAnnotationPosition( OutsideMapFrame ), mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ), + mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), mTopGridAnnotationDirection( Horizontal ), + mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ), mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true ) { mComposition = composition; @@ -85,10 +87,12 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int w QgsComposerMap::QgsComposerMap( QgsComposition *composition ) : QgsComposerItem( 0, 0, 10, 10, composition ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 ), mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mGridEnabled( false ), mGridStyle( Solid ), - mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), - mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame ), mTopGridAnnotationPosition( OutsideMapFrame ), - mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ), mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), - mTopGridAnnotationDirection( Horizontal ), mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ), mCrossLength( 3 ), + mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) ), + mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), mGridBlendMode( QPainter::CompositionMode_SourceOver ), + mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame ), + mTopGridAnnotationPosition( OutsideMapFrame ), mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ), + mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), mTopGridAnnotationDirection( Horizontal ), + mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ), mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true ) { mOverviewFrameMapSymbol = 0; @@ -631,8 +635,9 @@ bool QgsComposerMap::containsWMSLayer() const return false; } -bool QgsComposerMap::containsBlendModes() const +bool QgsComposerMap::containsAdvancedEffects() const { + // check if map contains advanced effects like blend modes, or flattened layers for transparency if ( !mMapRenderer ) { return false; @@ -655,10 +660,19 @@ bool QgsComposerMap::containsBlendModes() const { return true; } - // if vector layer and has labels, check label blend modes + // if vector layer, check labels and feature blend mode QgsVectorLayer* currentVectorLayer = qobject_cast( currentLayer ); if ( currentVectorLayer ) { + if ( currentVectorLayer->layerTransparency() != 0 ) + { + return true; + } + if ( currentVectorLayer->featureBlendMode() != QPainter::CompositionMode_SourceOver ) + { + return true; + } + // check label blend modes if ( lbl->willUseLayer( currentVectorLayer ) ) { // Check all label blending properties @@ -782,6 +796,7 @@ bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const gridElem.setAttribute( "crossLength", QString::number( mCrossLength ) ); gridElem.setAttribute( "gridFrameStyle", mGridFrameStyle ); gridElem.setAttribute( "gridFrameWidth", QString::number( mGridFrameWidth ) ); + gridElem.setAttribute( "gridBlendMode", QgsMapRenderer::getBlendModeEnum( mGridBlendMode ) ); QDomElement gridLineStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridLineSymbol, doc ); gridElem.appendChild( gridLineStyleElem ); @@ -800,6 +815,12 @@ bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const annotationElem.setAttribute( "frameDistance", QString::number( mAnnotationFrameDistance ) ); annotationElem.setAttribute( "font", mGridAnnotationFont.toString() ); annotationElem.setAttribute( "precision", mGridAnnotationPrecision ); + //annotation font color + QDomElement annotationFontColorElem = doc.createElement( "fontColor" ); + annotationFontColorElem.setAttribute( "red", mGridAnnotationFontColor.red() ); + annotationFontColorElem.setAttribute( "green", mGridAnnotationFontColor.green() ); + annotationFontColorElem.setAttribute( "blue", mGridAnnotationFontColor.blue() ); + annotationElem.appendChild( annotationFontColorElem ); gridElem.appendChild( annotationElem ); composerMapElem.appendChild( gridElem ); @@ -928,6 +949,7 @@ bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& d mCrossLength = gridElem.attribute( "crossLength", "3" ).toDouble(); mGridFrameStyle = ( QgsComposerMap::GridFrameStyle )gridElem.attribute( "gridFrameStyle", "0" ).toInt(); mGridFrameWidth = gridElem.attribute( "gridFrameWidth", "2.0" ).toDouble(); + setGridBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) gridElem.attribute( "gridBlendMode", "0" ).toUInt() ) ); QDomElement gridSymbolElem = gridElem.firstChildElement( "symbol" ); delete mGridLineSymbol; @@ -961,6 +983,22 @@ bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& d mBottomGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "bottomDirection", "0" ).toInt() ); mAnnotationFrameDistance = annotationElem.attribute( "frameDistance", "0" ).toDouble(); mGridAnnotationFont.fromString( annotationElem.attribute( "font", "" ) ); + + //annotation font color + QDomNodeList annotationFontColorList = annotationElem.elementsByTagName( "fontColor" ); + if ( annotationFontColorList.size() > 0 ) + { + QDomElement fontColorElem = annotationFontColorList.at( 0 ).toElement(); + int red = fontColorElem.attribute( "red", "0" ).toInt(); + int green = fontColorElem.attribute( "green", "0" ).toInt(); + int blue = fontColorElem.attribute( "blue", "0" ).toInt(); + mGridAnnotationFontColor = QColor( red, green, blue ); + } + else + { + mGridAnnotationFontColor = QColor( 0, 0, 0 ); + } + mGridAnnotationPrecision = annotationElem.attribute( "precision", "3" ).toInt(); } } @@ -1025,6 +1063,10 @@ void QgsComposerMap::drawGrid( QPainter* p ) QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() ); p->setClipRect( thisPaintRect ); + // set the blend mode for drawing grid lines + p->save(); + p->setCompositionMode( mGridBlendMode ); + //simpler approach: draw vertical lines first, then horizontal ones if ( mGridStyle == QgsComposerMap::Solid ) { @@ -1085,6 +1127,8 @@ void QgsComposerMap::drawGrid( QPainter* p ) drawGridLine( QLineF( hIt->second.p2(), crossEnd1 ), p ); } } + // reset composition mode + p->restore(); p->setClipRect( thisPaintRect , Qt::NoClip ); @@ -1097,6 +1141,7 @@ void QgsComposerMap::drawGrid( QPainter* p ) { drawCoordinateAnnotations( p, horizontalLines, verticalLines ); } + } void QgsComposerMap::drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) @@ -1377,7 +1422,7 @@ void QgsComposerMap::drawAnnotation( QPainter* p, const QPointF& pos, int rotati p->save(); p->translate( pos ); p->rotate( rotation ); - p->setPen( QColor( 0, 0, 0 ) ); + p->setPen( QPen( QColor( mGridAnnotationFontColor ) ) ); drawText( p, 0, 0, annotationText, mGridAnnotationFont ); p->restore(); } @@ -1587,6 +1632,12 @@ QPen QgsComposerMap::gridPen() const return p; } +void QgsComposerMap::setGridBlendMode( QPainter::CompositionMode blendMode ) +{ + mGridBlendMode = blendMode; + update(); +} + QRectF QgsComposerMap::boundingRect() const { return mCurrentRectangle; diff --git a/src/core/composer/qgscomposermap.h b/src/core/composer/qgscomposermap.h index 0974c165c9b..473850833c2 100644 --- a/src/core/composer/qgscomposermap.h +++ b/src/core/composer/qgscomposermap.h @@ -183,8 +183,8 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem /**True if composer map renders a WMS layer*/ bool containsWMSLayer() const; - /**True if composer map contains layers with blend modes*/ - bool containsBlendModes() const; + /**True if composer map contains layers with blend modes or flattened layers for vectors */ + bool containsAdvancedEffects() const; /** stores state in Dom node * @param elem is Dom element corresponding to 'Composer' tag @@ -246,6 +246,13 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem void setGridAnnotationFont( const QFont& f ) { mGridAnnotationFont = f; } QFont gridAnnotationFont() const { return mGridAnnotationFont; } + /**Sets font color for grid annotations + @note: this function was added in version 2.0*/ + void setAnnotationFontColor( const QColor& c ) {mGridAnnotationFontColor = c;} + /**Get font color for grid annotations + @note: this function was added in version 2.0*/ + QColor annotationFontColor() const {return mGridAnnotationFontColor;} + /**Sets coordinate precision for grid annotations @note this function was added in version 1.4*/ void setGridAnnotationPrecision( int p ) {mGridAnnotationPrecision = p;} @@ -328,6 +335,11 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem void setGridLineSymbol( QgsLineSymbolV2* symbol ); QgsLineSymbolV2* gridLineSymbol() { return mGridLineSymbol; } + /** Returns the grid's blending mode */ + QPainter::CompositionMode gridBlendMode() const {return mGridBlendMode;} + /** Sets the grid's blending mode*/ + void setGridBlendMode( QPainter::CompositionMode blendMode ); + /**Sets mId to a number not yet used in the composition. mId is kept if it is not in use. Usually, this function is called before adding the composer map to the composition*/ void assignFreeId(); @@ -417,10 +429,14 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem double mGridOffsetY; /**Font for grid line annotation*/ QFont mGridAnnotationFont; + /**Font color for grid line annotation*/ + QColor mGridAnnotationFontColor; /**Digits after the dot*/ int mGridAnnotationPrecision; /**True if coordinate values should be drawn*/ bool mShowGridAnnotation; + /**Blend mode for grid*/ + QPainter::CompositionMode mGridBlendMode; /**Annotation position for left map side (inside / outside / not shown)*/ GridAnnotationPosition mLeftGridAnnotationPosition; diff --git a/src/core/qgsmaprenderer.cpp b/src/core/qgsmaprenderer.cpp index 683a4cddf97..f55e8b16834 100644 --- a/src/core/qgsmaprenderer.cpp +++ b/src/core/qgsmaprenderer.cpp @@ -518,20 +518,30 @@ void QgsMapRenderer::render( QPainter* painter, double* forceWidthScale ) // before compositing this on the map. This effectively flattens the layer and prevents // blending occuring between objects on the layer // (this is not required for raster layers or when layer caching is enabled, since that has the same effect) - if (( mRenderContext.useAdvancedEffects() ) && ( ml->blendMode() != QPainter::CompositionMode_SourceOver ) && - ( ml->type() != QgsMapLayer::RasterLayer ) && - ( split || !mySettings.value( "/qgis/enable_render_caching", false ).toBool() ) ) + bool flattenedLayer = false; + if (( mRenderContext.useAdvancedEffects() ) && ( ml->type() == QgsMapLayer::VectorLayer ) ) { - mypFlattenedImage = new QImage( mRenderContext.painter()->device()->width(), - mRenderContext.painter()->device()->height(), QImage::Format_ARGB32 ); - mypFlattenedImage->fill( 0 ); - QPainter * mypPainter = new QPainter( mypFlattenedImage ); - if ( mySettings.value( "/qgis/enable_anti_aliasing", true ).toBool() ) + QgsVectorLayer* vl = qobject_cast( ml ); + if (( vl->blendMode() != QPainter::CompositionMode_SourceOver && ( split || !mySettings.value( "/qgis/enable_render_caching", false ).toBool() ) ) + || ( vl->featureBlendMode() != QPainter::CompositionMode_SourceOver ) + || ( vl->layerTransparency() != 0 ) ) + { - mypPainter->setRenderHint( QPainter::Antialiasing ); + flattenedLayer = true; + mypFlattenedImage = new QImage( mRenderContext.painter()->device()->width(), + mRenderContext.painter()->device()->height(), QImage::Format_ARGB32 ); + mypFlattenedImage->fill( 0 ); + QPainter * mypPainter = new QPainter( mypFlattenedImage ); + if ( mySettings.value( "/qgis/enable_anti_aliasing", true ).toBool() ) + { + mypPainter->setRenderHint( QPainter::Antialiasing ); + } + mypPainter->scale( rasterScaleFactor, rasterScaleFactor ); + mRenderContext.setPainter( mypPainter ); + + // set the painter to the feature blend mode + mypPainter->setCompositionMode( vl->featureBlendMode() ); } - mypPainter->scale( rasterScaleFactor, rasterScaleFactor ); - mRenderContext.setPainter( mypPainter ); } if ( scaleRaster ) @@ -584,10 +594,19 @@ void QgsMapRenderer::render( QPainter* painter, double* forceWidthScale ) } // If we flattened this layer for alternate blend modes, composite it now - if (( mRenderContext.useAdvancedEffects() ) && ( ml->blendMode() != QPainter::CompositionMode_SourceOver ) && - ( ml->type() != QgsMapLayer::RasterLayer ) && - ( split || !mySettings.value( "/qgis/enable_render_caching", false ).toBool() ) ) + if ( flattenedLayer ) { + QgsVectorLayer* vl = qobject_cast( ml ); + if ( vl->layerTransparency() != 0 ) + { + // a layer transparency has been set, so update the alpha for the flattened layer + // by combining it with the layer transparency + QColor transparentFillColor = QColor( 0, 0, 0, 255 - ( 255 * vl->layerTransparency() / 100 ) ); + // use destination in composition mode to merge source's alpha with destination + mRenderContext.painter()->setCompositionMode( QPainter::CompositionMode_DestinationIn ); + mRenderContext.painter()->fillRect( mypFlattenedImage->rect(), transparentFillColor ); + } + delete mRenderContext.painter(); mRenderContext.setPainter( mypContextPainter ); mypContextPainter->save(); diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index dd1da602372..9bbaee13902 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -122,6 +122,8 @@ QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath, , mRendererV2( NULL ) , mLabel( 0 ) , mLabelOn( false ) + , mFeatureBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal feature blending + , mLayerTransparency( 0 ) , mVertexMarkerOnlyForSelection( false ) , mCache( new QgsGeometryCache( this ) ) , mEditBuffer( 0 ) @@ -1759,6 +1761,22 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage setBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) e.text().toInt() ) ); } + // get and set the feature blend mode if it exists + QDomNode featureBlendModeNode = node.namedItem( "featureBlendMode" ); + if ( !featureBlendModeNode.isNull() ) + { + QDomElement e = featureBlendModeNode.toElement(); + setFeatureBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) e.text().toInt() ) ); + } + + // get and set the layer transparency if it exists + QDomNode layerTransparencyNode = node.namedItem( "layerTransparency" ); + if ( !layerTransparencyNode.isNull() ) + { + QDomElement e = layerTransparencyNode.toElement(); + setLayerTransparency( e.text().toInt() ); + } + // use scale dependent visibility flag QDomElement e = node.toElement(); mLabel->setScaleBasedVisibility( e.attribute( "scaleBasedLabelVisibilityFlag", "0" ) == "1" ); @@ -2084,6 +2102,18 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& blendModeElem.appendChild( blendModeText ); node.appendChild( blendModeElem ); + // add the feature blend mode field + QDomElement featureBlendModeElem = doc.createElement( "featureBlendMode" ); + QDomText featureBlendModeText = doc.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( featureBlendMode() ) ) ); + featureBlendModeElem.appendChild( featureBlendModeText ); + node.appendChild( featureBlendModeElem ); + + // add the layer transparency + QDomElement layerTransparencyElem = doc.createElement( "layerTransparency" ); + QDomText layerTransparencyText = doc.createTextNode( QString::number( layerTransparency() ) ); + layerTransparencyElem.appendChild( layerTransparencyText ); + node.appendChild( layerTransparencyElem ); + // add the display field QDomElement dField = doc.createElement( "displayfield" ); QDomText dFieldText = doc.createTextNode( displayField() ); @@ -3340,6 +3370,30 @@ QVariant QgsVectorLayer::maximumValue( int index ) return QVariant(); } +/** Write blend mode for features */ +void QgsVectorLayer::setFeatureBlendMode( const QPainter::CompositionMode featureBlendMode ) +{ + mFeatureBlendMode = featureBlendMode; +} + +/** Read blend mode for layer */ +QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const +{ + return mFeatureBlendMode; +} + +/** Write transparency for layer */ +void QgsVectorLayer::setLayerTransparency( int layerTransparency ) +{ + mLayerTransparency = layerTransparency; +} + +/** Read transparency for layer */ +int QgsVectorLayer::layerTransparency() const +{ + return mLayerTransparency; +} + void QgsVectorLayer::stopRendererV2( QgsRenderContext& rendererContext, QgsSingleSymbolRendererV2* selRenderer ) { mRendererV2->stopRender( rendererContext ); diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index e29991d8419..d9048a30b94 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -1226,6 +1226,24 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer @note added in 1.7*/ QVariant maximumValue( int index ); + /* Set the blending mode used for rendering each feature + * @note added in 2.0 + */ + void setFeatureBlendMode( const QPainter::CompositionMode blendMode ); + /* Returns the current blending mode for features + * @note added in 2.0 + */ + QPainter::CompositionMode featureBlendMode() const; + + /* Set the transparency for the vector layer + * @note added in 2.0 + */ + void setLayerTransparency( int layerTransparency ); + /* Returns the current transparency for the vector layer + * @note added in 2.0 + */ + int layerTransparency() const; + public slots: /** * Select feature by its ID @@ -1480,6 +1498,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer /** Display labels */ bool mLabelOn; + /** Blend mode for features */ + QPainter::CompositionMode mFeatureBlendMode; + + /** Layer transparency */ + int mLayerTransparency; + /**The current type of editing marker*/ QgsVectorLayer::VertexMarkerType mCurrentVertexMarkerType; diff --git a/src/gui/symbology-ng/qgsrendererv2propertiesdialog.cpp b/src/gui/symbology-ng/qgsrendererv2propertiesdialog.cpp index ca7b1c11dcf..501f883b85e 100644 --- a/src/gui/symbology-ng/qgsrendererv2propertiesdialog.cpp +++ b/src/gui/symbology-ng/qgsrendererv2propertiesdialog.cpp @@ -89,6 +89,17 @@ QgsRendererV2PropertiesDialog::QgsRendererV2PropertiesDialog( QgsVectorLayer* la // Blend mode mBlendModeComboBox->setBlendMode( mLayer->blendMode() ); + // Feature blend mode + mFeatureBlendComboBox->setBlendMode( mLayer->featureBlendMode() ); + + // Layer transparency + mLayerTransparencySlider->setValue( mLayer->layerTransparency() ); + mLayerTransparencySpnBx->setValue( mLayer->layerTransparency() ); + + // connect layer transparency slider and spin box + connect( mLayerTransparencySlider, SIGNAL( valueChanged( int ) ), mLayerTransparencySpnBx, SLOT( setValue( int ) ) ); + connect( mLayerTransparencySpnBx, SIGNAL( valueChanged( int ) ), mLayerTransparencySlider, SLOT( setValue( int ) ) ); + QPixmap pix; QgsRendererV2Registry* reg = QgsRendererV2Registry::instance(); QStringList renderers = reg->renderersList(); @@ -173,8 +184,12 @@ void QgsRendererV2PropertiesDialog::apply() mLayer->setRendererV2( renderer->clone() ); } - // set the blend mode for the layer + // set the blend modes for the layer mLayer->setBlendMode( mBlendModeComboBox->blendMode() ); + mLayer->setFeatureBlendMode( mFeatureBlendComboBox->blendMode() ); + + // set transparency for the layer + mLayer->setLayerTransparency( mLayerTransparencySlider->value() ); } void QgsRendererV2PropertiesDialog::onOK() diff --git a/src/ui/qgscomposermapwidgetbase.ui b/src/ui/qgscomposermapwidgetbase.ui index f86ecc5f55d..479cf10ab65 100644 --- a/src/ui/qgscomposermapwidgetbase.ui +++ b/src/ui/qgscomposermapwidgetbase.ui @@ -56,7 +56,7 @@ 0 -202 440 - 1310 + 1380 @@ -448,6 +448,16 @@ + + + + + + + Blend mode + + + @@ -583,7 +593,7 @@ - + Distance to map frame @@ -596,10 +606,10 @@ - + - + Coordinate precision @@ -612,9 +622,16 @@ - + + + + + Font color... + + + @@ -702,6 +719,11 @@ QComboBox
qgsblendmodecombobox.h
+ + QgsColorButton + QPushButton +
qgscolorbutton.h
+
diff --git a/src/ui/qgsrendererv2propsdialogbase.ui b/src/ui/qgsrendererv2propsdialogbase.ui index a59769f0cb4..761ab242481 100644 --- a/src/ui/qgsrendererv2propsdialogbase.ui +++ b/src/ui/qgsrendererv2propsdialogbase.ui @@ -14,6 +14,69 @@ Renderer settings + + + + Layer rendering + + + false + + + true + + + + + + + + 100 + + + Qt::Horizontal + + + + + + + 100 + + + + + + + + + Layer transparency + + + + + + + + + + Feature blending mode + + + + + + + Layer blending mode + + + + + + + + + @@ -32,16 +95,6 @@ - - - - Blending mode - - - - - - @@ -89,6 +142,12 @@ QComboBox
qgsblendmodecombobox.h
+ + QgsCollapsibleGroupBox + QGroupBox +
qgscollapsiblegroupbox.h
+ 1 +
cboRenderers diff --git a/tests/src/core/testqgsblendmodes.cpp b/tests/src/core/testqgsblendmodes.cpp index 2d3d16ea062..0fc62fdf28c 100644 --- a/tests/src/core/testqgsblendmodes.cpp +++ b/tests/src/core/testqgsblendmodes.cpp @@ -45,12 +45,15 @@ class TestQgsBlendModes: public QObject void cleanup() {};// will be called after every testfunction. void vectorBlending(); + void featureBlending(); + void vectorLayerTransparency(); void rasterBlending(); private: bool imageCheck( QString theType ); //as above QgsMapRenderer * mpMapRenderer; QgsMapLayer * mpPointsLayer; QgsMapLayer * mpPolysLayer; + QgsVectorLayer * mpLinesLayer; QgsRasterLayer* mRasterLayer1; QgsRasterLayer* mRasterLayer2; QString mTestDataDir; @@ -85,6 +88,14 @@ void TestQgsBlendModes::initTestCase() QgsMapLayerRegistry::instance()->addMapLayers( QList() << mpPolysLayer ); + //create a line layer that will be used in tests + QString myLinesFileName = mTestDataDir + "lines.shp"; + QFileInfo myLineFileInfo( myLinesFileName ); + mpLinesLayer = new QgsVectorLayer( myLineFileInfo.filePath(), + myLineFileInfo.completeBaseName(), "ogr" ); + QgsMapLayerRegistry::instance()->addMapLayers( + QList() << mpLinesLayer ); + //create two raster layers QFileInfo rasterFileInfo( mTestDataDir + "landsat.tif" ); mRasterLayer1 = new QgsRasterLayer( rasterFileInfo.filePath(), @@ -121,6 +132,35 @@ void TestQgsBlendModes::vectorBlending() QVERIFY( imageCheck( "vector_blendmodes" ) ); } +void TestQgsBlendModes::featureBlending() +{ + //Add two vector layers + QStringList myLayers; + myLayers << mpLinesLayer->id(); + myLayers << mpPolysLayer->id(); + mpMapRenderer->setLayerSet( myLayers ); + + //Set feature blending modes for point layer + mpLinesLayer->setFeatureBlendMode( QPainter::CompositionMode_Plus ); + mpMapRenderer->setExtent( mpPointsLayer->extent() ); + QVERIFY( imageCheck( "vector_featureblendmodes" ) ); +} + +void TestQgsBlendModes::vectorLayerTransparency() +{ + //Add two vector layers + QStringList myLayers; + myLayers << mpLinesLayer->id(); + myLayers << mpPolysLayer->id(); + mpMapRenderer->setLayerSet( myLayers ); + mpLinesLayer->setFeatureBlendMode( QPainter::CompositionMode_SourceOver ); + + //Set feature blending modes for point layer + mpLinesLayer->setLayerTransparency( 50 ); + mpMapRenderer->setExtent( mpPointsLayer->extent() ); + QVERIFY( imageCheck( "vector_layertransparency" ) ); +} + void TestQgsBlendModes::rasterBlending() { //Add two raster layers to map renderer diff --git a/tests/src/core/testqgscomposermap.cpp b/tests/src/core/testqgscomposermap.cpp index 948340ba6f4..a21fa481be1 100644 --- a/tests/src/core/testqgscomposermap.cpp +++ b/tests/src/core/testqgscomposermap.cpp @@ -107,6 +107,7 @@ void TestQgsComposerMap::grid() mComposerMap->setGridIntervalY( 2000 ); mComposerMap->setShowGridAnnotation( true ); mComposerMap->setGridPenWidth( 0.5 ); + mComposerMap->setGridPenColor( QColor( 0, 255, 0 ) ); mComposerMap->setGridAnnotationPrecision( 0 ); mComposerMap->setGridAnnotationPosition( QgsComposerMap::Disabled, QgsComposerMap::Left ); mComposerMap->setGridAnnotationPosition( QgsComposerMap::OutsideMapFrame, QgsComposerMap::Right ); @@ -114,6 +115,8 @@ void TestQgsComposerMap::grid() mComposerMap->setGridAnnotationPosition( QgsComposerMap::OutsideMapFrame, QgsComposerMap::Bottom ); mComposerMap->setGridAnnotationDirection( QgsComposerMap::Horizontal, QgsComposerMap::Right ); mComposerMap->setGridAnnotationDirection( QgsComposerMap::Horizontal, QgsComposerMap::Bottom ); + mComposerMap->setAnnotationFontColor( QColor( 255, 0, 0, 150 ) ); + mComposerMap->setGridBlendMode( QPainter::CompositionMode_Overlay ); QgsCompositionChecker checker( "Composer map grid", mComposition, QString( QString( TEST_DATA_DIR ) + QDir::separator() + "control_images" + QDir::separator() + "expected_composermap" + QDir::separator() + "composermap_landsat_grid.png" ) ); bool testResult = checker.testComposition(); @@ -200,6 +203,10 @@ void TestQgsComposerMap::uniqueId() void TestQgsComposerMap::zebraStyle() { + mComposerMap->setGridPenColor( QColor( 0, 0, 0 ) ); + mComposerMap->setAnnotationFontColor( QColor( 0, 0, 0, 0 ) ); + mComposerMap->setGridBlendMode( QPainter::CompositionMode_SourceOver ); + mComposerMap->setGridFrameStyle( QgsComposerMap::Zebra ); mComposerMap->setGridEnabled( true ); diff --git a/tests/src/python/test_qgsblendmodes.py b/tests/src/python/test_qgsblendmodes.py index 12eb082ea8e..d835cc4e86b 100644 --- a/tests/src/python/test_qgsblendmodes.py +++ b/tests/src/python/test_qgsblendmodes.py @@ -67,6 +67,11 @@ class TestQgsBlendModes(TestCase): self.mPolygonLayer = QgsVectorLayer(myShpFile, 'Polygons', 'ogr') self.mMapRegistry.addMapLayer(self.mPolygonLayer) + # create line layer + myShpFile = os.path.join(TEST_DATA_DIR, 'lines.shp') + self.mLineLayer = QgsVectorLayer(myShpFile, 'Lines', 'ogr') + self.mMapRegistry.addMapLayer(self.mLineLayer) + # create two raster layers myRasterFile = os.path.join(TEST_DATA_DIR, 'landsat.tif') self.mRasterLayer1 = QgsRasterLayer(myRasterFile, "raster1") @@ -108,6 +113,50 @@ class TestQgsBlendModes(TestCase): myMessage = ('vector blending failed') assert myResult, myMessage + def testVectorFeatureBlending(self): + """Test that feature blend modes work for vector layers.""" + + #Add vector layers to map + myLayers = QStringList() + myLayers.append(self.mLineLayer.id()) + myLayers.append(self.mPolygonLayer.id()) + self.mMapRenderer.setLayerSet(myLayers) + self.mMapRenderer.setExtent(self.mPointLayer.extent()) + self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_Multiply) + + #Set feature blending for line layer + self.mLineLayer.setFeatureBlendMode(QPainter.CompositionMode_Plus) + + checker = QgsRenderChecker() + checker.setControlName("expected_vector_featureblendmodes") + checker.setMapRenderer(self.mMapRenderer) + + myResult = checker.runTest("vector_featureblendmodes"); + myMessage = ('vector feature blending failed') + assert myResult, myMessage + + def testVectorLayerTransparency(self): + """Test that layer transparency works for vector layers.""" + + #Add vector layers to map + myLayers = QStringList() + myLayers.append(self.mLineLayer.id()) + myLayers.append(self.mPolygonLayer.id()) + self.mMapRenderer.setLayerSet(myLayers) + self.mMapRenderer.setExtent(self.mPointLayer.extent()) + self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_Multiply) + + #Set feature blending for line layer + self.mLineLayer.setLayerTransparency( 50 ) + + checker = QgsRenderChecker() + checker.setControlName("expected_vector_layertransparency") + checker.setMapRenderer(self.mMapRenderer) + + myResult = checker.runTest("vector_layertransparency"); + myMessage = ('vector layer transparency failed') + assert myResult, myMessage + def testRasterBlending(self): """Test that blend modes work for raster layers.""" #Add raster layers to map diff --git a/tests/src/python/test_qgscomposermap.py b/tests/src/python/test_qgscomposermap.py index e940325b9da..95a279794c5 100644 --- a/tests/src/python/test_qgscomposermap.py +++ b/tests/src/python/test_qgscomposermap.py @@ -16,7 +16,8 @@ import os from PyQt4.QtCore import (QStringList, QFileInfo) from PyQt4.QtXml import QDomDocument -from PyQt4.QtGui import QPainter +from PyQt4.QtGui import (QPainter, + QColor) from qgis.core import (QgsComposerMap, QgsRectangle, @@ -76,6 +77,7 @@ class TestQgsComposerMap(TestCase): self.mComposerMap.setGridIntervalY(2000) self.mComposerMap.setShowGridAnnotation(True) self.mComposerMap.setGridPenWidth(0.5) + self.mComposerMap.setGridPenColor(QColor(0,255,0)) self.mComposerMap.setGridAnnotationPrecision(0) self.mComposerMap.setGridAnnotationPosition(QgsComposerMap.Disabled, QgsComposerMap.Left) @@ -91,6 +93,8 @@ class TestQgsComposerMap(TestCase): QgsComposerMap.Right) self.mComposerMap.setGridAnnotationDirection(QgsComposerMap.Horizontal, QgsComposerMap.Bottom) + self.mComposerMap.setAnnotationFontColor(QColor(255,0,0,150)) + self.mComposerMap.setGridBlendMode(QPainter.CompositionMode_Overlay) checker = QgsCompositionChecker() myPath = os.path.join(TEST_DATA_DIR, 'control_images', diff --git a/tests/testdata/control_images/expected_composermap/composermap_landsat_grid.png b/tests/testdata/control_images/expected_composermap/composermap_landsat_grid.png index 0f0b46dab54..d0050ac5afa 100644 Binary files a/tests/testdata/control_images/expected_composermap/composermap_landsat_grid.png and b/tests/testdata/control_images/expected_composermap/composermap_landsat_grid.png differ diff --git a/tests/testdata/control_images/expected_vector_featureblendmodes/expected_vector_featureblendmodes.png b/tests/testdata/control_images/expected_vector_featureblendmodes/expected_vector_featureblendmodes.png new file mode 100644 index 00000000000..becc271e44b Binary files /dev/null and b/tests/testdata/control_images/expected_vector_featureblendmodes/expected_vector_featureblendmodes.png differ diff --git a/tests/testdata/control_images/expected_vector_layertransparency/expected_vector_layertransparency.png b/tests/testdata/control_images/expected_vector_layertransparency/expected_vector_layertransparency.png new file mode 100644 index 00000000000..b7a4ca71c89 Binary files /dev/null and b/tests/testdata/control_images/expected_vector_layertransparency/expected_vector_layertransparency.png differ