Skip to content

Commit 8f9ca6f

Browse files
committedMar 22, 2013
Merge pull request #475 from nyalldawson/blend_modes
Add support for blending (composition) modes, eg Overlay, Mutiply, etc (Close #5248)
2 parents 9afe76d + 647fbdb commit 8f9ca6f

10 files changed

+390
-4
lines changed
 

‎src/app/qgsrasterlayerproperties.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
243243
mMaximumOversamplingSpinBox->setValue( resampleFilter->maxOversampling() );
244244
}
245245

246+
//blend mode
247+
mBlendModeComboBox->setBlendMode( mRasterLayer->blendMode() );
248+
246249
//transparency band
247250
if ( provider )
248251
{
@@ -798,6 +801,8 @@ void QgsRasterLayerProperties::apply()
798801
resampleFilter->setMaxOversampling( mMaximumOversamplingSpinBox->value() );
799802
}
800803

804+
//set the blend mode for the layer
805+
mRasterLayer->setBlendMode(( QgsMapLayer::BlendMode ) mBlendModeComboBox->blendMode() );
801806

802807
//get the thumbnail for the layer
803808
pixmapThumbnail->setPixmap( mRasterLayer->previewAsPixmap( pixmapThumbnail->size() ) );

‎src/app/qgsvectorlayerproperties.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
192192
mLayerAbstractTextEdit->setPlainText( layer->abstract() );
193193
}
194194

195+
// Blend mode
196+
mBlendModeComboBox->setBlendMode( layer->blendMode() );
197+
195198
QSettings settings;
196199
restoreGeometry( settings.value( "/Windows/VectorLayerProperties/geometry" ).toByteArray() );
197200
int tabIndex = settings.value( "/Windows/VectorLayerProperties/row", 0 ).toInt();
@@ -528,6 +531,9 @@ void QgsVectorLayerProperties::apply()
528531
layer->setTitle( mLayerTitleLineEdit->text() );
529532
layer->setAbstract( mLayerAbstractTextEdit->toPlainText() );
530533

534+
// set the blend mode for the layer
535+
layer->setBlendMode(( QgsMapLayer::BlendMode ) mBlendModeComboBox->blendMode() );
536+
531537
// update symbology
532538
emit refreshLegend( layer->id(), QgsLegendItem::DontChange );
533539

‎src/core/qgsmaplayer.cpp

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ QgsMapLayer::QgsMapLayer( QgsMapLayer::LayerType type,
4949
mDataSource( source ),
5050
mLayerOrigName( lyrname ), // store the original name
5151
mID( "" ),
52-
mLayerType( type )
52+
mLayerType( type ),
53+
mBlendMode( QgsMapLayer::BlendNormal ) // Default to normal blending
5354
{
5455
mCRS = new QgsCoordinateReferenceSystem();
5556

@@ -133,6 +134,58 @@ QgsRectangle QgsMapLayer::extent()
133134
return mExtent;
134135
}
135136

137+
/** Write blend mode for layer */
138+
void QgsMapLayer::setBlendMode( const QgsMapLayer::BlendMode blendMode )
139+
{
140+
mBlendMode = blendMode;
141+
}
142+
143+
/** Read blend mode for layer */
144+
QgsMapLayer::BlendMode QgsMapLayer::blendMode() const
145+
{
146+
return mBlendMode;
147+
}
148+
149+
/** Returns a QPainter::CompositionMode corresponding to the current
150+
* blend mode for this layer
151+
*/
152+
QPainter::CompositionMode QgsMapLayer::getCompositionMode()
153+
{
154+
// Map QgsMapLayer::BlendNormal to QPainter::CompositionMode
155+
switch ( mBlendMode )
156+
{
157+
case QgsMapLayer::BlendNormal:
158+
return QPainter::CompositionMode_SourceOver;
159+
case QgsMapLayer::BlendLighten:
160+
return QPainter::CompositionMode_Lighten;
161+
case QgsMapLayer::BlendScreen:
162+
return QPainter::CompositionMode_Screen;
163+
case QgsMapLayer::BlendDodge:
164+
return QPainter::CompositionMode_ColorDodge;
165+
case QgsMapLayer::BlendAddition:
166+
return QPainter::CompositionMode_Plus;
167+
case QgsMapLayer::BlendDarken:
168+
return QPainter::CompositionMode_Darken;
169+
case QgsMapLayer::BlendMultiply:
170+
return QPainter::CompositionMode_Multiply;
171+
case QgsMapLayer::BlendBurn:
172+
return QPainter::CompositionMode_ColorBurn;
173+
case QgsMapLayer::BlendOverlay:
174+
return QPainter::CompositionMode_Overlay;
175+
case QgsMapLayer::BlendSoftLight:
176+
return QPainter::CompositionMode_SoftLight;
177+
case QgsMapLayer::BlendHardLight:
178+
return QPainter::CompositionMode_HardLight;
179+
case QgsMapLayer::BlendDifference:
180+
return QPainter::CompositionMode_Difference;
181+
case QgsMapLayer::BlendSubtract:
182+
return QPainter::CompositionMode_Exclusion;
183+
default:
184+
return QPainter::CompositionMode_SourceOver;
185+
}
186+
}
187+
188+
136189
bool QgsMapLayer::draw( QgsRenderContext& rendererContext )
137190
{
138191
Q_UNUSED( rendererContext );
@@ -358,6 +411,15 @@ bool QgsMapLayer::readXML( const QDomNode& layer_node )
358411
setTransparency( myElement.text().toInt() );
359412
}
360413

414+
//read blend mode
415+
QDomNode blendModeNode = layer_node.namedItem( "blendMode" );
416+
if ( ! blendModeNode.isNull() )
417+
{
418+
// set blend mode if it's specified in project
419+
QDomElement myElement = blendModeNode.toElement();
420+
setBlendMode(( QgsMapLayer::BlendMode )myElement.text().toInt() );
421+
}
422+
361423
readCustomProperties( layer_node );
362424

363425
return true;
@@ -473,6 +535,13 @@ bool QgsMapLayer::writeXML( QDomNode & layer_node, QDomDocument & document )
473535
QDomText transparencyLevelIntText = document.createTextNode( QString::number( getTransparency() ) );
474536
transparencyLevelIntElement.appendChild( transparencyLevelIntText );
475537
maplayer.appendChild( transparencyLevelIntElement );
538+
539+
// <blendMode>
540+
QDomElement blendModeElement = document.createElement( "blendMode" );
541+
QDomText blendModeText = document.createTextNode( QString::number( blendMode() ) );
542+
blendModeElement.appendChild( blendModeText );
543+
maplayer.appendChild( blendModeElement );
544+
476545
// now append layer node to map layer node
477546

478547
layer_node.appendChild( maplayer );

‎src/core/qgsmaplayer.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <QVariant>
2525
#include <QImage>
2626
#include <QDomNode>
27+
#include <QPainter>
2728

2829
#include "qgis.h"
2930
#include "qgserror.h"
@@ -52,6 +53,26 @@ class CORE_EXPORT QgsMapLayer : public QObject
5253
RasterLayer,
5354
PluginLayer // added in 1.5
5455
};
56+
57+
/** Blending modes enum defining the available composition modes that can
58+
* be used when rendering a layer
59+
*/
60+
enum BlendMode
61+
{
62+
BlendNormal,
63+
BlendLighten,
64+
BlendScreen,
65+
BlendDodge,
66+
BlendAddition,
67+
BlendDarken,
68+
BlendMultiply,
69+
BlendBurn,
70+
BlendOverlay,
71+
BlendSoftLight,
72+
BlendHardLight,
73+
BlendDifference,
74+
BlendSubtract
75+
};
5576

5677
/** Constructor
5778
* @param type Type of layer as defined in QgsMapLayer::LayerType enum
@@ -94,6 +115,15 @@ class CORE_EXPORT QgsMapLayer : public QObject
94115
void setAbstract( const QString& abstract ) { mAbstract = abstract; }
95116
const QString& abstract() const { return mAbstract; }
96117

118+
/* Set the blending mode used for rendering a layer */
119+
void setBlendMode( const QgsMapLayer::BlendMode blendMode );
120+
/* Returns the current blending mode for a layer */
121+
QgsMapLayer::BlendMode blendMode() const;
122+
/** Returns a QPainter::CompositionMode corresponding to the
123+
* current blending mode for the layer
124+
*/
125+
QPainter::CompositionMode getCompositionMode();
126+
97127
/**Synchronises with changes in the datasource
98128
@note added in version 1.6*/
99129
virtual void reload() {}
@@ -462,6 +492,9 @@ class CORE_EXPORT QgsMapLayer : public QObject
462492

463493
/** Type of the layer (eg. vector, raster) */
464494
QgsMapLayer::LayerType mLayerType;
495+
496+
/** Blend mode for the layer */
497+
QgsMapLayer::BlendMode mBlendMode;
465498

466499
/** Tag for embedding additional information */
467500
QString mTag;

‎src/core/qgsmaprenderer.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,18 @@ void QgsMapRenderer::render( QPainter* painter, double* forceWidthScale )
377377
continue;
378378
}
379379

380-
QgsDebugMsg( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 extent:%5" )
380+
QgsDebugMsg( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 extent:%5 blendmode:%6" )
381381
.arg( ml->name() )
382382
.arg( ml->minimumScale() )
383383
.arg( ml->maximumScale() )
384384
.arg( ml->hasScaleBasedVisibility() )
385385
.arg( ml->extent().toString() )
386+
.arg( ml->blendMode() )
386387
);
388+
389+
// Set the QPainter composition mode so that this layer is rendered using
390+
// the desired blending mode
391+
mypContextPainter->setCompositionMode(ml->getCompositionMode());
387392

388393
if ( !ml->hasScaleBasedVisibility() || ( ml->minimumScale() <= mScale && mScale < ml->maximumScale() ) || mOverview )
389394
{

‎src/gui/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ qgisinterface.cpp
4848
qgsannotationitem.cpp
4949
qgsattributeeditor.cpp
5050
qgslegendinterface.cpp
51+
qgsblendmodecombobox.cpp
5152
qgscharacterselectdialog.cpp
5253
qgscolorbutton.cpp
5354
qgscomposerview.cpp
@@ -153,6 +154,7 @@ attributetable/qgsattributetablememorymodel.h
153154
attributetable/qgsattributetabledelegate.h
154155

155156
qgsattributeeditor.h
157+
qgsblendmodecombobox.h
156158
qgscharacterselectdialog.h
157159
qgscomposerview.h
158160
qgsdetaileditemdelegate.h
@@ -227,6 +229,7 @@ qgsrubberband.h
227229
qgsvertexmarker.h
228230
qgsmaptip.h
229231
qgsscalecombobox.h
232+
qgsblendmodecombobox.h
230233
qgssearchquerybuilder.h
231234
qgsattributeeditor.h
232235
qgsfieldvalidator.h

‎src/gui/qgsblendmodecombobox.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/***************************************************************************
2+
qgsblendmodecombobox.cpp
3+
------------------------
4+
begin : March 21, 2013
5+
copyright : (C) 2013 by Nyall Dawson
6+
email : nyall.dawson@gmail.com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgis.h"
19+
#include "qgslogger.h"
20+
#include "qgsblendmodecombobox.h"
21+
22+
#include <QAbstractItemView>
23+
#include <QLocale>
24+
#include <QSettings>
25+
#include <QLineEdit>
26+
27+
QgsBlendModeComboBox::QgsBlendModeComboBox( QWidget* parent ) : QComboBox( parent )
28+
{
29+
updateModes();
30+
}
31+
32+
QgsBlendModeComboBox::~QgsBlendModeComboBox()
33+
{
34+
}
35+
36+
/* Returns a QStringList of the translated blend modes
37+
* "-" is used to indicate the position of a seperator in the list
38+
* This list is designed to emulate GIMP's layer modes, where
39+
* blending modes are grouped by their effect (lightening, darkening, etc)
40+
*/
41+
QStringList QgsBlendModeComboBox::blendModesList() const
42+
{
43+
return QStringList() << tr( "Normal" )
44+
<< "-"
45+
<< tr( "Lighten" )
46+
<< tr( "Screen" )
47+
<< tr( "Dodge" )
48+
<< tr( "Addition" )
49+
<< "-"
50+
<< tr( "Darken" )
51+
<< tr( "Multiply" )
52+
<< tr( "Burn" )
53+
<< "-"
54+
<< tr( "Overlay" )
55+
<< tr( "Soft light" )
56+
<< tr( "Hard light" )
57+
<< "-"
58+
<< tr( "Difference" )
59+
<< tr( "Subtract" );
60+
}
61+
62+
/* Populates the blend mode combo box, and sets up mapping for
63+
* blend modes to combo box indexes
64+
*/
65+
void QgsBlendModeComboBox::updateModes()
66+
{
67+
blockSignals( true );
68+
clear();
69+
70+
QStringList myBlendModesList = blendModesList();
71+
QStringList::const_iterator blendModeIt = myBlendModesList.constBegin();
72+
73+
mBlendModeToListIndex.resize( myBlendModesList.count() );
74+
mListIndexToBlendMode.resize( myBlendModesList.count() );
75+
76+
// Loop through blend modes
77+
int index = 0;
78+
int blendModeIndex = 0;
79+
for ( ; blendModeIt != myBlendModesList.constEnd(); ++blendModeIt )
80+
{
81+
if ( *blendModeIt == "-" )
82+
{
83+
// Add seperator
84+
insertSeparator( index );
85+
}
86+
else
87+
{
88+
// Not a seperator, so store indexes for translation
89+
// between blend modes and combo box item index
90+
addItem( *blendModeIt );
91+
mListIndexToBlendMode[ index ] = blendModeIndex;
92+
mBlendModeToListIndex[ blendModeIndex ] = index;
93+
blendModeIndex++;
94+
}
95+
index++;
96+
}
97+
98+
blockSignals( false );
99+
}
100+
101+
//! Function to read the selected blend mode as int
102+
int QgsBlendModeComboBox::blendMode()
103+
{
104+
return mListIndexToBlendMode[ currentIndex()];
105+
}
106+
107+
//! Function to set the selected blend mode from int
108+
void QgsBlendModeComboBox::setBlendMode( int blendMode )
109+
{
110+
setCurrentIndex( mBlendModeToListIndex[ blendMode ] );
111+
}
112+

‎src/gui/qgsblendmodecombobox.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/***************************************************************************
2+
qgsblendmodecombobox.h
3+
------------------------
4+
begin : March 21, 2013
5+
copyright : (C) 2013 by Nyall Dawson
6+
email : nyall.dawson@gmail.com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#ifndef QGSBLENDMODECOMBOBOX_H
19+
#define QGSBLENDMODECOMBOBOX_H
20+
21+
#include <QComboBox>
22+
23+
/** \ingroup gui
24+
* A combobox which lets the user select blend modes from a predefined list
25+
**/
26+
class GUI_EXPORT QgsBlendModeComboBox : public QComboBox
27+
{
28+
Q_OBJECT
29+
public:
30+
QgsBlendModeComboBox( QWidget* parent = 0 );
31+
virtual ~QgsBlendModeComboBox();
32+
33+
//! Function to read the selected blend mode as integer
34+
int blendMode();
35+
//! Function to set the selected blend mode from integer
36+
void setBlendMode( int blendMode );
37+
private:
38+
//! Returns a list of grouped blend modes (with seperators)
39+
QStringList blendModesList() const;
40+
41+
//! Used to map blend modes across to their corresponding
42+
// index within the combo box
43+
std::vector<int> mBlendModeToListIndex;
44+
std::vector<int> mListIndexToBlendMode;
45+
46+
public slots:
47+
void updateModes();
48+
49+
};
50+
51+
#endif // QGSBLENDMODECOMBOBOX_H

‎src/ui/qgsrasterlayerpropertiesbase.ui

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,52 @@ p, li { white-space: pre-wrap; }
869869
</layout>
870870
</widget>
871871
</item>
872+
<item>
873+
<layout class="QHBoxLayout" name="horizontalLayout_11">
874+
<property name="leftMargin">
875+
<number>0</number>
876+
</property>
877+
<property name="rightMargin">
878+
<number>0</number>
879+
</property>
880+
<property name="bottomMargin">
881+
<number>0</number>
882+
</property>
883+
<item>
884+
<widget class="QLabel" name="mBlendTypeLabel">
885+
<property name="text">
886+
<string>Composition blending mode</string>
887+
</property>
888+
<property name="margin">
889+
<number>0</number>
890+
</property>
891+
</widget>
892+
</item>
893+
<item>
894+
<widget class="QgsBlendModeComboBox" name="mBlendModeComboBox" native="true">
895+
<property name="minimumSize">
896+
<size>
897+
<width>0</width>
898+
<height>0</height>
899+
</size>
900+
</property>
901+
</widget>
902+
</item>
903+
<item>
904+
<spacer name="horizontalSpacer_6">
905+
<property name="orientation">
906+
<enum>Qt::Horizontal</enum>
907+
</property>
908+
<property name="sizeHint" stdset="0">
909+
<size>
910+
<width>40</width>
911+
<height>20</height>
912+
</size>
913+
</property>
914+
</spacer>
915+
</item>
916+
</layout>
917+
</item>
872918
<item>
873919
<widget class="QGroupBox" name="grpSRS">
874920
<property name="title">
@@ -1278,6 +1324,11 @@ p, li { white-space: pre-wrap; }
12781324
<header>qgscollapsiblegroupbox.h</header>
12791325
<container>1</container>
12801326
</customwidget>
1327+
<customwidget>
1328+
<class>QgsBlendModeComboBox</class>
1329+
<extends>QWidget</extends>
1330+
<header>qgsblendmodecombobox.h</header>
1331+
</customwidget>
12811332
</customwidgets>
12821333
<tabstops>
12831334
<tabstop>tabBar</tabstop>

‎src/ui/qgsvectorlayerpropertiesbase.ui

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ p, li { white-space: pre-wrap; }
530530
</layout>
531531
</widget>
532532
</item>
533-
<item row="3" column="0">
533+
<item row="4" column="0">
534534
<widget class="QGroupBox" name="grpSubset">
535535
<property name="title">
536536
<string>Subset</string>
@@ -578,7 +578,7 @@ p, li { white-space: pre-wrap; }
578578
</layout>
579579
</widget>
580580
</item>
581-
<item row="2" column="0">
581+
<item row="3" column="0">
582582
<widget class="QGroupBox" name="grpProviderOptions">
583583
<property name="title">
584584
<string>Provider-specific options</string>
@@ -600,6 +600,52 @@ p, li { white-space: pre-wrap; }
600600
</layout>
601601
</widget>
602602
</item>
603+
<item row="2" column="0">
604+
<layout class="QHBoxLayout" name="horizontalLayout_11">
605+
<property name="leftMargin">
606+
<number>9</number>
607+
</property>
608+
<property name="rightMargin">
609+
<number>9</number>
610+
</property>
611+
<property name="bottomMargin">
612+
<number>0</number>
613+
</property>
614+
<item>
615+
<widget class="QLabel" name="mBlendTypeLabel">
616+
<property name="text">
617+
<string>Composition blending mode</string>
618+
</property>
619+
<property name="margin">
620+
<number>0</number>
621+
</property>
622+
</widget>
623+
</item>
624+
<item>
625+
<widget class="QgsBlendModeComboBox" name="mBlendModeComboBox" native="true">
626+
<property name="minimumSize">
627+
<size>
628+
<width>0</width>
629+
<height>0</height>
630+
</size>
631+
</property>
632+
</widget>
633+
</item>
634+
<item>
635+
<spacer name="horizontalSpacer_4">
636+
<property name="orientation">
637+
<enum>Qt::Horizontal</enum>
638+
</property>
639+
<property name="sizeHint" stdset="0">
640+
<size>
641+
<width>40</width>
642+
<height>20</height>
643+
</size>
644+
</property>
645+
</spacer>
646+
</item>
647+
</layout>
648+
</item>
603649
</layout>
604650
</widget>
605651
</widget>
@@ -1008,6 +1054,11 @@ p, li { white-space: pre-wrap; }
10081054
<extends>QWidget</extends>
10091055
<header>qgsscalecombobox.h</header>
10101056
</customwidget>
1057+
<customwidget>
1058+
<class>QgsBlendModeComboBox</class>
1059+
<extends>QWidget</extends>
1060+
<header>qgsblendmodecombobox.h</header>
1061+
</customwidget>
10111062
</customwidgets>
10121063
<tabstops>
10131064
<tabstop>cbMinimumScale</tabstop>

0 commit comments

Comments
 (0)
Please sign in to comment.