Skip to content

Commit e26b6b5

Browse files
committed
[FEATURE] Identify highlight options.
- optional highlight color, line/outline buffer and minimum width - fixed symbol sizes (thanks to Martin Dobias)
1 parent 3b7b2b4 commit e26b6b5

File tree

5 files changed

+336
-117
lines changed

5 files changed

+336
-117
lines changed

src/app/qgsidentifyresultsdialog.cpp

+18-12
Original file line numberDiff line numberDiff line change
@@ -1253,24 +1253,30 @@ void QgsIdentifyResultsDialog::highlightFeature( QTreeWidgetItem *item )
12531253
if ( !featItem->feature().geometry() || featItem->feature().geometry()->wkbType() == QGis::WKBUnknown )
12541254
return;
12551255

1256+
QgsHighlight *highlight = 0;
12561257
if ( vlayer )
12571258
{
1258-
QgsHighlight *h = new QgsHighlight( mCanvas, featItem->feature(), vlayer );
1259-
h->setColor( Qt::red );
1260-
h->show();
1261-
mHighlights.insert( featItem, h );
1259+
highlight = new QgsHighlight( mCanvas, featItem->feature(), vlayer );
12621260
}
12631261
else
12641262
{
1265-
QgsHighlight *h = new QgsHighlight( mCanvas, featItem->feature().geometry(), layer );
1266-
if ( h )
1267-
{
1268-
h->setWidth( 2 );
1269-
h->setColor( Qt::red );
1270-
h->show();
1271-
mHighlights.insert( featItem, h );
1272-
}
1263+
highlight = new QgsHighlight( mCanvas, featItem->feature().geometry(), layer );
1264+
highlight->setWidth( 2 );
12731265
}
1266+
1267+
QSettings settings;
1268+
QColor color = QColor( settings.value( "/Map/identify/highlight/color", "#ff0000" ).toString() );
1269+
int alpha = settings.value( "/Map/identify/highlight/colorAlpha", "128" ).toInt();
1270+
double buffer = settings.value( "/Map/highlight/buffer", "0.5" ).toDouble();
1271+
double minWidth = settings.value( "/Map/highlight/minWidth", "1." ).toDouble();
1272+
1273+
highlight->setColor( color ); // sets also fill with default alpha
1274+
color.setAlpha( alpha );
1275+
highlight->setFillColor( color ); // sets fill with alpha
1276+
highlight->setBuffer( buffer );
1277+
highlight->setMinWidth( minWidth );
1278+
highlight->show();
1279+
mHighlights.insert( featItem, highlight );
12741280
}
12751281

12761282
void QgsIdentifyResultsDialog::zoomToFeature()

src/app/qgsoptions.cpp

+22-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "qgis.h"
2222
#include "qgisapp.h"
2323
#include "qgisappstylesheet.h"
24+
#include "qgshighlight.h"
2425
#include "qgslegend.h"
2526
#include "qgsmapcanvas.h"
2627
#include "qgsmaprenderer.h"
@@ -104,7 +105,9 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
104105
cmbIdentifyMode->addItem( tr( "Top down" ), 2 );
105106
cmbIdentifyMode->addItem( tr( "Layer selection" ), 3 );
106107

107-
// read the current browser and set it
108+
mIdentifyHighlightColorButton->setColorDialogTitle( tr( "Identify highlight color" ) );
109+
mIdentifyHighlightColorButton->setColorDialogOptions( QColorDialog::ShowAlphaChannel );
110+
108111
QSettings settings;
109112

110113
int identifyMode = settings.value( "/Map/identifyMode", 0 ).toInt();
@@ -116,6 +119,14 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
116119
identifyValue = QGis::DEFAULT_IDENTIFY_RADIUS;
117120
spinBoxIdentifyValue->setMinimum( 0.01 );
118121
spinBoxIdentifyValue->setValue( identifyValue );
122+
QColor highlightColor = QColor( settings.value( "/Map/identify/highlight/color", "#ff0000" ).toString() );
123+
int highlightAlpha = settings.value( "/Map/identify/highlight/colorAlpha", "63" ).toInt();
124+
highlightColor.setAlpha( highlightAlpha );
125+
mIdentifyHighlightColorButton->setColor( highlightColor );
126+
double highlightBuffer = settings.value( "/Map/highlight/buffer", "0.5" ).toDouble();
127+
mIdentifyHighlightBufferSpinBox->setValue( highlightBuffer );
128+
double highlightMinWidth = settings.value( "/Map/highlight/minWidth", "1." ).toDouble();
129+
mIdentifyHighlightMinWidthSpinBox->setValue( highlightMinWidth );
119130

120131
// custom environment variables
121132
bool useCustomVars = settings.value( "qgis/customEnvVarsUse", QVariant( false ) ).toBool();
@@ -1035,6 +1046,11 @@ void QgsOptions::saveOptions()
10351046
settings.setValue( "/Map/identifyMode", cmbIdentifyMode->itemData( cmbIdentifyMode->currentIndex() ).toInt() );
10361047
settings.setValue( "/Map/identifyAutoFeatureForm", cbxAutoFeatureForm->isChecked() );
10371048
settings.setValue( "/Map/identifyRadius", spinBoxIdentifyValue->value() );
1049+
settings.setValue( "/Map/identify/highlight/color", mIdentifyHighlightColorButton->color().name() );
1050+
settings.setValue( "/Map/identify/highlight/colorAlpha", mIdentifyHighlightColorButton->color().alpha() );
1051+
settings.setValue( "/Map/highlight/buffer", mIdentifyHighlightBufferSpinBox->value() );
1052+
settings.setValue( "/Map/highlight/minWidth", mIdentifyHighlightMinWidthSpinBox->value() );
1053+
10381054
bool showLegendClassifiers = settings.value( "/qgis/showLegendClassifiers", false ).toBool();
10391055
settings.setValue( "/qgis/showLegendClassifiers", cbxLegendClassifiers->isChecked() );
10401056
bool legendLayersBold = settings.value( "/qgis/legendLayersBold", true ).toBool();
@@ -1533,11 +1549,11 @@ QStringList QgsOptions::i18nList()
15331549

15341550
void QgsOptions::on_mRestoreDefaultWindowStateBtn_clicked()
15351551
{
1536-
// richard
1537-
QSettings mySettings;
1538-
if ( QMessageBox::warning( this, tr( "Restore UI defaults" ), tr( "Are you sure to reset the UI to default (needs restart)?" ), QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )
1539-
return;
1540-
mySettings.setValue( "/qgis/restoreDefaultWindowState", true );
1552+
// richard
1553+
QSettings mySettings;
1554+
if ( QMessageBox::warning( this, tr( "Restore UI defaults" ), tr( "Are you sure to reset the UI to default (needs restart)?" ), QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )
1555+
return;
1556+
mySettings.setValue( "/qgis/restoreDefaultWindowState", true );
15411557
}
15421558

15431559
void QgsOptions::on_mCustomVariablesChkBx_toggled( bool chkd )

src/gui/qgshighlight.cpp

+86-34
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,35 @@
2121
#include "qgslinesymbollayerv2.h"
2222

2323
#include "qgscoordinatetransform.h"
24+
#include "qgsfillsymbollayerv2.h"
2425
#include "qgsgeometry.h"
2526
#include "qgshighlight.h"
27+
#include "qgslinesymbollayerv2.h"
28+
#include "qgslinesymbollayerv2.h"
2629
#include "qgsmapcanvas.h"
2730
#include "qgsmaplayer.h"
2831
#include "qgsmaprenderer.h"
32+
#include "qgsmarkersymbollayerv2.h"
2933
#include "qgsrendercontext.h"
3034
#include "qgssymbollayerv2.h"
3135
#include "qgssymbolv2.h"
3236
#include "qgsvectorlayer.h"
3337

38+
/* Few notes about highligting (RB):
39+
- The highlight fill must always be partially transparent because above highlighted layer
40+
may be another layer which must remain partially visible.
41+
- Because single highlight color does not work well with layers using similar layer color
42+
there were considered various possibilities but no optimal solution was found.
43+
What does not work:
44+
- lighter/darker color: it would work more or less for fully opaque highlight, but
45+
overlaying transparent lighter color over original has small visual efect.
46+
- complemetary color: mixing transparent (128) complement color with original color
47+
results in grey for all colors
48+
- contrast line style/ fill pattern: impression is not highligh but just different style
49+
- line buffer with contrast (or 2 contrast) color: the same as with patterns, no highlight impression
50+
- fill with highlight or contrast color but opaque and using pattern
51+
(e.g. Qt::Dense7Pattern): again no highlight impression
52+
*/
3453
/*!
3554
\class QgsHighlight
3655
\brief The QgsHighlight class provides a transparent overlay widget
@@ -39,7 +58,8 @@
3958
QgsHighlight::QgsHighlight( QgsMapCanvas* mapCanvas, QgsGeometry *geom, QgsMapLayer *layer )
4059
: QgsMapCanvasItem( mapCanvas )
4160
, mLayer( layer )
42-
, mRenderer( 0 )
61+
, mBuffer( 0 )
62+
, mMinWidth( 0 )
4363
{
4464
mGeometry = geom ? new QgsGeometry( *geom ) : 0;
4565
init();
@@ -48,7 +68,8 @@ QgsHighlight::QgsHighlight( QgsMapCanvas* mapCanvas, QgsGeometry *geom, QgsMapLa
4868
QgsHighlight::QgsHighlight( QgsMapCanvas* mapCanvas, QgsGeometry *geom, QgsVectorLayer *layer )
4969
: QgsMapCanvasItem( mapCanvas )
5070
, mLayer( static_cast<QgsMapLayer *>( layer ) )
51-
, mRenderer( 0 )
71+
, mBuffer( 0 )
72+
, mMinWidth( 0 )
5273
{
5374
mGeometry = geom ? new QgsGeometry( *geom ) : 0;
5475
init();
@@ -59,7 +80,8 @@ QgsHighlight::QgsHighlight( QgsMapCanvas* mapCanvas, const QgsFeature& feature,
5980
, mGeometry( 0 )
6081
, mLayer( static_cast<QgsMapLayer *>( layer ) )
6182
, mFeature( feature )
62-
, mRenderer( 0 )
83+
, mBuffer( 0 )
84+
, mMinWidth( 0 )
6385
{
6486
init();
6587
}
@@ -90,7 +112,6 @@ void QgsHighlight::init()
90112
QgsHighlight::~QgsHighlight()
91113
{
92114
delete mGeometry;
93-
delete mRenderer;
94115
}
95116

96117
/*!
@@ -102,25 +123,34 @@ void QgsHighlight::setColor( const QColor & color )
102123
QColor fillColor( color.red(), color.green(), color.blue(), 63 );
103124
mBrush.setColor( fillColor );
104125
mBrush.setStyle( Qt::SolidPattern );
126+
}
105127

106-
delete mRenderer;
107-
mRenderer = 0;
128+
void QgsHighlight::setFillColor( const QColor & fillColor )
129+
{
130+
mBrush.setColor( fillColor );
131+
mBrush.setStyle( Qt::SolidPattern );
132+
}
133+
134+
QgsFeatureRendererV2 * QgsHighlight::getRenderer( const QgsRenderContext & context )
135+
{
136+
QgsFeatureRendererV2 *renderer = 0;
108137
QgsVectorLayer *layer = vectorLayer();
109138
if ( layer && layer->rendererV2() )
110139
{
111-
mRenderer = layer->rendererV2()->clone();
140+
renderer = layer->rendererV2()->clone();
112141
}
113-
if ( mRenderer )
142+
if ( renderer )
114143
{
115-
foreach ( QgsSymbolV2* symbol, mRenderer->symbols() )
144+
foreach ( QgsSymbolV2* symbol, renderer->symbols() )
116145
{
117146
if ( !symbol ) continue;
118-
setSymbolColor( symbol, color );
147+
setSymbol( symbol, context, mPen.color() );
119148
}
120149
}
150+
return renderer;
121151
}
122152

123-
void QgsHighlight::setSymbolColor( QgsSymbolV2* symbol, const QColor & color )
153+
void QgsHighlight::setSymbol( QgsSymbolV2* symbol, const QgsRenderContext & context, const QColor & color )
124154
{
125155
if ( !symbol ) return;
126156

@@ -146,20 +176,49 @@ void QgsHighlight::setSymbolColor( QgsSymbolV2* symbol, const QColor & color )
146176

147177
if ( symbolLayer->subSymbol() )
148178
{
149-
setSymbolColor( symbolLayer->subSymbol(), color );
179+
setSymbol( symbolLayer->subSymbol(), context, color );
150180
}
151181
else
152182
{
153183
symbolLayer->setColor( color ); // line symbology layers
154184
symbolLayer->setOutlineColor( color ); // marker and fill symbology layers
155185
symbolLayer->setFillColor( mTemporaryFillColor ); // marker and fill symbology layers
156186

187+
// Data defined widths overwrite what we set here (widths do not work with data defined)
188+
QgsSimpleMarkerSymbolLayerV2 * simpleMarker = dynamic_cast<QgsSimpleMarkerSymbolLayerV2*>( symbolLayer );
189+
if ( simpleMarker )
190+
{
191+
simpleMarker->setOutlineWidth( getSymbolWidth( context, simpleMarker->outlineWidth(), simpleMarker->outlineWidthUnit() ) );
192+
}
193+
QgsSimpleLineSymbolLayerV2 * simpleLine = dynamic_cast<QgsSimpleLineSymbolLayerV2*>( symbolLayer );
194+
if ( simpleLine )
195+
{
196+
simpleLine->setWidth( getSymbolWidth( context, simpleLine->width(), simpleLine->widthUnit() ) );
197+
}
198+
QgsSimpleFillSymbolLayerV2 * simpleFill = dynamic_cast<QgsSimpleFillSymbolLayerV2*>( symbolLayer );
199+
if ( simpleFill )
200+
{
201+
simpleFill->setBorderWidth( getSymbolWidth( context, simpleFill->borderWidth(), simpleFill->outputUnit() ) );
202+
}
157203
symbolLayer->removeDataDefinedProperty( "color" );
158204
symbolLayer->removeDataDefinedProperty( "color_border" );
159205
}
160206
}
161207
}
162208

209+
double QgsHighlight::getSymbolWidth( const QgsRenderContext & context, double width, QgsSymbolV2::OutputUnit unit )
210+
{
211+
// if necessary scale mm to map units
212+
double scale = 1.;
213+
if ( unit == QgsSymbolV2::MapUnit )
214+
{
215+
scale = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, QgsSymbolV2::MM ) / QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, QgsSymbolV2::MapUnit );
216+
}
217+
return qMax( width + 2*mBuffer*scale, mMinWidth*scale );
218+
219+
220+
}
221+
163222
/*!
164223
Set the outline width.
165224
*/
@@ -299,50 +358,41 @@ void QgsHighlight::paint( QPainter* p )
299358
return;
300359
}
301360
}
302-
else if ( mFeature.geometry() && mRenderer )
361+
else if ( mFeature.geometry() )
303362
{
304363
QgsVectorLayer *layer = vectorLayer();
305-
if ( layer )
306-
{
307-
QgsRenderContext context = *( mMapCanvas->mapRenderer()->rendererContext() );
364+
QgsMapSettings mapSettings = mMapCanvas->mapSettings();
365+
QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
308366

309-
// The context is local rectangle of QgsHighlight we previously set.
310-
// Because QgsMapCanvasItem::setRect() adds 1 pixel on border we cannot simply
311-
// use boundingRect().height() for QgsMapToPixel height.
367+
QgsFeatureRendererV2 *renderer = getRenderer( context );
368+
if ( layer && renderer )
369+
{
312370
QgsRectangle extent = mMapCanvas->extent();
313371
if ( extent != rect() ) // catches also canvas resize as it is causing extent change
314372
{
315373
updateRect();
316374
return; // it will be repainted after updateRect()
317375
}
318376

319-
320-
QPointF ll = toCanvasCoordinates( QgsPoint( extent.xMinimum(), extent.yMinimum() ) );
321-
QPointF ur = toCanvasCoordinates( QgsPoint( extent.xMaximum(), extent.yMaximum() ) );
322-
double height = ll.y() - ur.y();
323-
double width = ur.x() - ll.x();
324-
325377
// Because lower level outlines must be covered by upper level fill color
326378
// we render first with temporary opaque color, which is then replaced
327379
// by final transparent fill color.
328-
QImage image = QImage(( int )width, ( int )height, QImage::Format_ARGB32 );
380+
//QImage image = QImage(( int )width, ( int )height, QImage::Format_ARGB32 );
381+
QSize imageSize( mMapCanvas->mapSettings().outputSize() );
382+
QImage image = QImage( imageSize.width(), imageSize.height(), QImage::Format_ARGB32 );
329383
image.fill( 0 );
330384
QPainter *imagePainter = new QPainter( &image );
331385
imagePainter->setRenderHint( QPainter::Antialiasing, true );
332386

333-
QgsMapToPixel mapToPixel = QgsMapToPixel( mMapCanvas->mapUnitsPerPixel(),
334-
height, extent.yMinimum(), extent.xMinimum() );
335-
context.setMapToPixel( mapToPixel );
336-
context.setExtent( extent );
337-
context.setCoordinateTransform( 0 ); // we reprojected geometry in init()
338387
context.setPainter( imagePainter );
339388

340-
mRenderer->startRender( context, layer );
341-
mRenderer->renderFeature( mFeature, context );
342-
mRenderer->stopRender( context );
389+
renderer->startRender( context, layer->pendingFields() );
390+
renderer->renderFeature( mFeature, context );
391+
renderer->stopRender( context );
343392

344393
imagePainter->end();
345394

395+
// overwrite temporary fill color
346396
QRgb temporaryRgb = mTemporaryFillColor.rgba();
347397
QColor color = QColor( mBrush.color() );
348398
color.setAlpha( 63 );
@@ -363,6 +413,7 @@ void QgsHighlight::paint( QPainter* p )
363413
p->drawImage( 0, 0, image );
364414

365415
delete imagePainter;
416+
delete renderer;
366417
}
367418
}
368419
}
@@ -404,3 +455,4 @@ QgsVectorLayer * QgsHighlight::vectorLayer()
404455
{
405456
return dynamic_cast<QgsVectorLayer *>( mLayer );
406457
}
458+

0 commit comments

Comments
 (0)