mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE] add expressions at the symbollist level
Size and Rotation can be defined by an expression for all symbols composing a marker. Width can be defined by an expression for all symbols composing a line. For markers, a legend is generated for varying sizes. This allows multivariate analysis legend in the case of classified/graduated colors. The offset is now set along with size to maintain the relative position of symbols composing a marker. An asistant, with preview, is accessible through the data defined button to help the user define the size expression. Three methods are available: Frannery, Area and Radius. Added a widget for use in categorized/classified symbology gui to set the expression if needed. The assistant is also available from it.
This commit is contained in:
parent
c38ff519e2
commit
1e46196937
@ -172,6 +172,7 @@
|
||||
%Include symbology-ng/characterwidget.sip
|
||||
%Include symbology-ng/qgsdashspacedialog.sip
|
||||
%Include symbology-ng/qgsdatadefinedsymboldialog.sip
|
||||
%Include symbology-ng/qgssizescalewidget.sip
|
||||
%Include symbology-ng/qgsstylev2exportimportdialog.sip
|
||||
%Include symbology-ng/qgssvgselectorwidget.sip
|
||||
%Include symbology-ng/qgsgraduatedhistogramwidget.sip
|
||||
|
@ -11,7 +11,7 @@ class QgsDataDefinedAssistant: QDialog
|
||||
#include <qgsdatadefinedbutton.h>
|
||||
%End
|
||||
public:
|
||||
virtual QgsDataDefined* dataDefined() const = 0 /Factory/;
|
||||
virtual QgsDataDefined dataDefined() const = 0;
|
||||
};
|
||||
|
||||
/** \ingroup gui
|
||||
|
11
python/gui/symbology-ng/qgssizescalewidget.sip
Normal file
11
python/gui/symbology-ng/qgssizescalewidget.sip
Normal file
@ -0,0 +1,11 @@
|
||||
class QgsSizeScaleWidget : QgsDataDefinedAssistant
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <qgssizescalewidget.h>
|
||||
%End
|
||||
public:
|
||||
QgsSizeScaleWidget( const QgsVectorLayer * layer, const QgsMarkerSymbolV2 * symbol );
|
||||
|
||||
QgsDataDefined dataDefined() const;
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ class QgsSymbolsListWidget : QWidget
|
||||
#include <qgssymbolslistwidget.h>
|
||||
%End
|
||||
public:
|
||||
QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* style, QMenu* menu, QWidget* parent /TransferThis/ = 0 );
|
||||
QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* style, QMenu* menu, QWidget* parent /TransferThis/ = 0, const QgsVectorLayer * layer = 0 );
|
||||
|
||||
public slots:
|
||||
void setSymbolFromStyle( const QModelIndex & index );
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "qgspointdisplacementrenderer.h"
|
||||
#include "qgsinvertedpolygonrenderer.h"
|
||||
#include "qgspainteffect.h"
|
||||
#include "qgsscaleexpression.h"
|
||||
#include "qgsdatadefined.h"
|
||||
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
@ -695,6 +697,56 @@ QgsLegendSymbolList QgsCategorizedSymbolRendererV2::legendSymbolItems( double sc
|
||||
return lst;
|
||||
}
|
||||
|
||||
QgsLegendSymbolListV2 QgsCategorizedSymbolRendererV2::legendSymbolItemsV2() const
|
||||
{
|
||||
QgsLegendSymbolListV2 lst;
|
||||
if ( mSourceSymbol.data() && mSourceSymbol->type() == QgsSymbolV2::Marker )
|
||||
{
|
||||
// check that all symbols that have the same size expression
|
||||
QgsDataDefined ddSize;
|
||||
foreach ( QgsRendererCategoryV2 category, mCategories )
|
||||
{
|
||||
const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( category.symbol() );
|
||||
if ( !ddSize.hasDefaultValues() && symbol->dataDefinedSize() != ddSize )
|
||||
{
|
||||
// no common size expression
|
||||
return QgsFeatureRendererV2::legendSymbolItemsV2();
|
||||
}
|
||||
else
|
||||
{
|
||||
ddSize = symbol->dataDefinedSize();
|
||||
}
|
||||
}
|
||||
|
||||
if ( !ddSize.isActive() || !ddSize.useExpression() )
|
||||
{
|
||||
return QgsFeatureRendererV2::legendSymbolItemsV2();
|
||||
}
|
||||
|
||||
QgsScaleExpression exp( ddSize.expressionString() );
|
||||
if ( exp.type() != QgsScaleExpression::Unknown )
|
||||
{
|
||||
QgsLegendSymbolItemV2 title( NULL, exp.baseExpression(), "" );
|
||||
lst << title;
|
||||
foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( exp.minValue(), exp.maxValue(), 4 ) )
|
||||
{
|
||||
QgsLegendSymbolItemV2 si( mSourceSymbol.data(), QString::number( v ), "" );
|
||||
QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
|
||||
s->setColor( QColor( 0, 0, 0 ) );
|
||||
s->setDataDefinedSize( QgsDataDefined() );
|
||||
s->setSize( exp.size( v ) );
|
||||
lst << si;
|
||||
}
|
||||
// now list the categorized symbols
|
||||
const QgsLegendSymbolListV2 list2 = QgsFeatureRendererV2::legendSymbolItemsV2() ;
|
||||
foreach ( QgsLegendSymbolItemV2 item, list2 )
|
||||
lst << item;
|
||||
return lst;
|
||||
}
|
||||
}
|
||||
|
||||
return QgsFeatureRendererV2::legendSymbolItemsV2();
|
||||
}
|
||||
|
||||
QgsSymbolV2* QgsCategorizedSymbolRendererV2::sourceSymbol()
|
||||
{
|
||||
|
@ -139,6 +139,9 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2
|
||||
//! @note not available in python bindings
|
||||
virtual QgsLegendSymbolList legendSymbolItems( double scaleDenominator = -1, QString rule = QString() ) override;
|
||||
|
||||
//! @note added in 2.10
|
||||
QgsLegendSymbolListV2 legendSymbolItemsV2() const override;
|
||||
|
||||
QgsSymbolV2* sourceSymbol();
|
||||
void setSourceSymbol( QgsSymbolV2* sym );
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "qgspointdisplacementrenderer.h"
|
||||
#include "qgsinvertedpolygonrenderer.h"
|
||||
#include "qgspainteffect.h"
|
||||
#include "qgsscaleexpression.h"
|
||||
#include "qgsdatadefined.h"
|
||||
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
@ -1151,6 +1153,57 @@ QgsLegendSymbologyList QgsGraduatedSymbolRendererV2::legendSymbologyItems( QSize
|
||||
return lst;
|
||||
}
|
||||
|
||||
QgsLegendSymbolListV2 QgsGraduatedSymbolRendererV2::legendSymbolItemsV2() const
|
||||
{
|
||||
QgsLegendSymbolListV2 list;
|
||||
if ( mSourceSymbol.data() && mSourceSymbol->type() == QgsSymbolV2::Marker )
|
||||
{
|
||||
// check that all symbols that have the same size expression
|
||||
QgsDataDefined ddSize;
|
||||
foreach ( QgsRendererRangeV2 range, mRanges )
|
||||
{
|
||||
const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( range.symbol() );
|
||||
if ( !ddSize.hasDefaultValues() && symbol->dataDefinedSize() != ddSize )
|
||||
{
|
||||
// no common size expression
|
||||
return QgsFeatureRendererV2::legendSymbolItemsV2();
|
||||
}
|
||||
else
|
||||
{
|
||||
ddSize = symbol->dataDefinedSize();
|
||||
}
|
||||
}
|
||||
|
||||
if ( !ddSize.isActive() || !ddSize.useExpression() )
|
||||
{
|
||||
return QgsFeatureRendererV2::legendSymbolItemsV2();
|
||||
}
|
||||
|
||||
QgsScaleExpression exp( ddSize.expressionString() );
|
||||
if ( exp.type() != QgsScaleExpression::Unknown )
|
||||
{
|
||||
QgsLegendSymbolItemV2 title( NULL, exp.baseExpression(), "" );
|
||||
list << title;
|
||||
foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( exp.minValue(), exp.maxValue(), 4 ) )
|
||||
{
|
||||
QgsLegendSymbolItemV2 si( mSourceSymbol.data(), QString::number( v ), "" );
|
||||
QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
|
||||
s->setColor( QColor( 0, 0, 0 ) );
|
||||
s->setDataDefinedSize( QgsDataDefined() );
|
||||
s->setSize( exp.size( v ) );
|
||||
list << si;
|
||||
}
|
||||
// now list the graduated symbols
|
||||
const QgsLegendSymbolListV2 list2 = QgsFeatureRendererV2::legendSymbolItemsV2() ;
|
||||
foreach ( QgsLegendSymbolItemV2 item, list2 )
|
||||
list << item;
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
return QgsFeatureRendererV2::legendSymbolItemsV2();
|
||||
}
|
||||
|
||||
QgsLegendSymbolList QgsGraduatedSymbolRendererV2::legendSymbolItems( double scaleDenominator, QString rule )
|
||||
{
|
||||
Q_UNUSED( scaleDenominator );
|
||||
|
@ -239,6 +239,10 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
|
||||
//! @note not available in python bindings
|
||||
virtual QgsLegendSymbolList legendSymbolItems( double scaleDenominator = -1, QString rule = QString() ) override;
|
||||
|
||||
//! @note added in 2.10
|
||||
QgsLegendSymbolListV2 legendSymbolItemsV2() const override;
|
||||
|
||||
|
||||
QgsSymbolV2* sourceSymbol();
|
||||
void setSourceSymbol( QgsSymbolV2* sym );
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "qgspointdisplacementrenderer.h"
|
||||
#include "qgsinvertedpolygonrenderer.h"
|
||||
#include "qgspainteffect.h"
|
||||
#include "qgsscaleexpression.h"
|
||||
#include "qgsdatadefined.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
@ -384,6 +386,30 @@ QgsLegendSymbolList QgsSingleSymbolRendererV2::legendSymbolItems( double scaleDe
|
||||
QgsLegendSymbolListV2 QgsSingleSymbolRendererV2::legendSymbolItemsV2() const
|
||||
{
|
||||
QgsLegendSymbolListV2 lst;
|
||||
if ( mSymbol->type() == QgsSymbolV2::Marker )
|
||||
{
|
||||
const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( mSymbol.data() );
|
||||
QgsDataDefined sizeDD = symbol->dataDefinedSize();
|
||||
if ( sizeDD.isActive() && sizeDD.useExpression() )
|
||||
{
|
||||
QgsScaleExpression scaleExp( sizeDD.expressionString() );
|
||||
if ( scaleExp.type() != QgsScaleExpression::Unknown )
|
||||
{
|
||||
QgsLegendSymbolItemV2 title( NULL, scaleExp.baseExpression(), 0 );
|
||||
lst << title;
|
||||
foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( scaleExp.minValue(), scaleExp.maxValue(), 4 ) )
|
||||
{
|
||||
QgsLegendSymbolItemV2 si( mSymbol.data(), QString::number( v ), 0 );
|
||||
QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
|
||||
s->setDataDefinedSize( 0 );
|
||||
s->setSize( scaleExp.size( v ) );
|
||||
lst << si;
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lst << QgsLegendSymbolItemV2( mSymbol.data(), QString(), 0 );
|
||||
return lst;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
#endif
|
||||
|
||||
#define DEG2RAD(x) ((x)*M_PI/180)
|
||||
#define DEFAULT_SCALE_METHOD QgsSymbolV2::ScaleArea
|
||||
#define DEFAULT_SCALE_METHOD QgsSymbolV2::ScaleDiameter
|
||||
|
||||
#include <QColor>
|
||||
#include <QMap>
|
||||
@ -330,7 +330,7 @@ class CORE_EXPORT QgsMarkerSymbolLayerV2 : public QgsSymbolLayerV2
|
||||
QgsSymbolV2::ScaleMethod scaleMethod() const { return mScaleMethod; }
|
||||
|
||||
void setOffset( QPointF offset ) { mOffset = offset; }
|
||||
QPointF offset() { return mOffset; }
|
||||
QPointF offset() const { return mOffset; }
|
||||
|
||||
virtual void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const override;
|
||||
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "qgspainteffect.h"
|
||||
#include "qgseffectstack.h"
|
||||
|
||||
#include "qgsdatadefined.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
@ -35,6 +37,42 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
inline
|
||||
QgsDataDefined* rotateWholeSymbol( double additionalRotation, const QgsDataDefined& dd )
|
||||
{
|
||||
QgsDataDefined* rotatedDD = new QgsDataDefined( dd );
|
||||
rotatedDD->setUseExpression( true );
|
||||
QString exprString = dd.useExpression() ? dd.expressionString() : dd.field();
|
||||
rotatedDD->setExpressionString( QString::number( additionalRotation ) + " + (" + exprString + ")" );
|
||||
return rotatedDD;
|
||||
}
|
||||
|
||||
inline
|
||||
QgsDataDefined* scaleWholeSymbol( double scaleFactor, const QgsDataDefined& dd )
|
||||
{
|
||||
QgsDataDefined* scaledDD = new QgsDataDefined( dd );
|
||||
scaledDD->setUseExpression( true );
|
||||
QString exprString = dd.useExpression() ? dd.expressionString() : dd.field();
|
||||
scaledDD->setExpressionString( QString::number( scaleFactor ) + "*(" + exprString + ")" );
|
||||
return scaledDD;
|
||||
}
|
||||
|
||||
inline
|
||||
QgsDataDefined* scaleWholeSymbol( double scaleFactorX, double scaleFactorY, const QgsDataDefined& dd )
|
||||
{
|
||||
QgsDataDefined* scaledDD = new QgsDataDefined( dd );
|
||||
scaledDD->setUseExpression( true );
|
||||
QString exprString = dd.useExpression() ? dd.expressionString() : dd.field();
|
||||
scaledDD->setExpressionString(
|
||||
( scaleFactorX ? "tostring(" + QString::number( scaleFactorX ) + "*(" + exprString + "))" : "'0'" ) +
|
||||
"|| ',' || " +
|
||||
( scaleFactorY ? "tostring(" + QString::number( scaleFactorY ) + "*(" + exprString + "))" : "'0'" ));
|
||||
return scaledDD;
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
|
||||
QgsSymbolV2::QgsSymbolV2( SymbolType type, QgsSymbolLayerV2List layers )
|
||||
: mType( type )
|
||||
, mLayers( layers )
|
||||
@ -500,7 +538,6 @@ QgsFillSymbolV2* QgsFillSymbolV2::createSimple( const QgsStringMap& properties )
|
||||
|
||||
///////////////////
|
||||
|
||||
|
||||
QgsMarkerSymbolV2::QgsMarkerSymbolV2( QgsSymbolLayerV2List layers )
|
||||
: QgsSymbolV2( Marker, layers )
|
||||
{
|
||||
@ -519,8 +556,7 @@ void QgsMarkerSymbolV2::setAngle( double ang )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double QgsMarkerSymbolV2::angle()
|
||||
double QgsMarkerSymbolV2::angle() const
|
||||
{
|
||||
QgsSymbolLayerV2List::const_iterator it = mLayers.begin();
|
||||
|
||||
@ -541,6 +577,74 @@ void QgsMarkerSymbolV2::setLineAngle( double lineAng )
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMarkerSymbolV2::setDataDefinedAngle( const QgsDataDefined& dd )
|
||||
{
|
||||
const double symbolRotation = angle();
|
||||
|
||||
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
{
|
||||
QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2 *>( *it );
|
||||
if ( dd.hasDefaultValues() )
|
||||
{
|
||||
layer->removeDataDefinedProperty( "angle" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( qgsDoubleNear( layer->angle(), symbolRotation ) )
|
||||
{
|
||||
layer->setDataDefinedProperty( "angle", new QgsDataDefined( dd ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDataDefined* rotatedDD = rotateWholeSymbol( layer->angle() - symbolRotation, dd );
|
||||
layer->setDataDefinedProperty( "angle", rotatedDD );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsDataDefined QgsMarkerSymbolV2::dataDefinedAngle() const
|
||||
{
|
||||
const double symbolRotation = angle();
|
||||
QgsDataDefined* symbolDD = 0;
|
||||
|
||||
// find the base of the "en masse" pattern
|
||||
for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
{
|
||||
const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
|
||||
if ( layer->angle() == symbolRotation && layer->getDataDefinedProperty( "angle" ) )
|
||||
{
|
||||
symbolDD = layer->getDataDefinedProperty( "angle" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !symbolDD )
|
||||
return QgsDataDefined();
|
||||
|
||||
// check that all layer's angle expressions match the "en masse" pattern
|
||||
for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
{
|
||||
const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
|
||||
|
||||
QgsDataDefined* layerAngleDD = layer->getDataDefinedProperty( "angle" );
|
||||
|
||||
if ( qgsDoubleNear( layer->angle(), symbolRotation ) )
|
||||
{
|
||||
if ( *layerAngleDD != *symbolDD )
|
||||
return QgsDataDefined();
|
||||
}
|
||||
else
|
||||
{
|
||||
QScopedPointer< QgsDataDefined > rotatedDD( rotateWholeSymbol( layer->angle() - symbolRotation, *symbolDD ) );
|
||||
if ( *layerAngleDD != *( rotatedDD.data() ) )
|
||||
return QgsDataDefined();
|
||||
}
|
||||
}
|
||||
return QgsDataDefined( *symbolDD );
|
||||
}
|
||||
|
||||
|
||||
void QgsMarkerSymbolV2::setSize( double s )
|
||||
{
|
||||
double origSize = size();
|
||||
@ -550,16 +654,19 @@ void QgsMarkerSymbolV2::setSize( double s )
|
||||
QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2*>( *it );
|
||||
if ( layer->size() == origSize )
|
||||
layer->setSize( s );
|
||||
else
|
||||
else if ( origSize != 0 )
|
||||
{
|
||||
// proportionally scale size
|
||||
if ( origSize != 0 )
|
||||
layer->setSize( layer->size() * s / origSize );
|
||||
layer->setSize( layer->size() * s / origSize );
|
||||
}
|
||||
// also scale offset to maintain relative position
|
||||
if ( origSize != 0 && ( layer->offset().x() || layer->offset().y() ) )
|
||||
layer->setOffset( QPointF( layer->offset().x() * s / origSize,
|
||||
layer->offset().y() * s / origSize ) );
|
||||
}
|
||||
}
|
||||
|
||||
double QgsMarkerSymbolV2::size()
|
||||
double QgsMarkerSymbolV2::size() const
|
||||
{
|
||||
// return size of the largest symbol
|
||||
double maxSize = 0;
|
||||
@ -573,6 +680,91 @@ double QgsMarkerSymbolV2::size()
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
void QgsMarkerSymbolV2::setDataDefinedSize( const QgsDataDefined &dd )
|
||||
{
|
||||
const double symbolSize = size();
|
||||
|
||||
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
{
|
||||
QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2 *>( *it );
|
||||
|
||||
if ( dd.hasDefaultValues() )
|
||||
{
|
||||
layer->removeDataDefinedProperty( "size" );
|
||||
layer->removeDataDefinedProperty( "offset" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( symbolSize == 0 || qgsDoubleNear( layer->size(), symbolSize ) )
|
||||
{
|
||||
layer->setDataDefinedProperty( "size", new QgsDataDefined( dd ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
layer->setDataDefinedProperty( "size", scaleWholeSymbol( layer->size() / symbolSize, dd ) );
|
||||
}
|
||||
|
||||
if ( layer->offset().x() || layer->offset().y() )
|
||||
{
|
||||
layer->setDataDefinedProperty( "offset", scaleWholeSymbol(
|
||||
layer->offset().x() / symbolSize,
|
||||
layer->offset().y() / symbolSize, dd ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsDataDefined QgsMarkerSymbolV2::dataDefinedSize() const
|
||||
{
|
||||
const double symbolSize = size();
|
||||
|
||||
QgsDataDefined* symbolDD = 0;
|
||||
|
||||
// find the base of the "en masse" pattern
|
||||
for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
{
|
||||
const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
|
||||
if ( layer->size() == symbolSize && layer->getDataDefinedProperty( "size" ) )
|
||||
{
|
||||
symbolDD = layer->getDataDefinedProperty( "size" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !symbolDD )
|
||||
return QgsDataDefined();
|
||||
|
||||
// check that all layers size expressions match the "en masse" pattern
|
||||
for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
{
|
||||
const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
|
||||
|
||||
QgsDataDefined* layerSizeDD = layer->getDataDefinedProperty( "size" );
|
||||
QgsDataDefined* layerOffsetDD = layer->getDataDefinedProperty( "offset" );
|
||||
|
||||
if ( qgsDoubleNear( layer->size(), symbolSize ) )
|
||||
{
|
||||
if ( !layerSizeDD || *layerSizeDD != *symbolDD )
|
||||
return QgsDataDefined();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( symbolSize == 0 )
|
||||
return QgsDataDefined();
|
||||
|
||||
QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( layer->size() / symbolSize, *symbolDD ) );
|
||||
if ( !layerSizeDD || *layerSizeDD != *( scaledDD.data() ) )
|
||||
return QgsDataDefined();
|
||||
}
|
||||
|
||||
|
||||
QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( layer->offset().x() / symbolSize, layer->offset().y() / symbolSize, *symbolDD ) );
|
||||
if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
|
||||
return QgsDataDefined();
|
||||
}
|
||||
|
||||
return QgsDataDefined( *symbolDD );
|
||||
}
|
||||
|
||||
void QgsMarkerSymbolV2::setScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod )
|
||||
{
|
||||
@ -668,16 +860,18 @@ void QgsLineSymbolV2::setWidth( double w )
|
||||
{
|
||||
layer->setWidth( w );
|
||||
}
|
||||
else
|
||||
else if ( origWidth != 0 )
|
||||
{
|
||||
// proportionally scale the width
|
||||
if ( origWidth != 0 )
|
||||
layer->setWidth( layer->width() * w / origWidth );
|
||||
layer->setWidth( layer->width() * w / origWidth );
|
||||
}
|
||||
// also scale offset to maintain relative position
|
||||
if ( origWidth != 0 && layer->offset() )
|
||||
layer->setOffset( layer->offset() * w / origWidth );
|
||||
}
|
||||
}
|
||||
|
||||
double QgsLineSymbolV2::width()
|
||||
double QgsLineSymbolV2::width() const
|
||||
{
|
||||
double maxWidth = 0;
|
||||
for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
@ -690,6 +884,89 @@ double QgsLineSymbolV2::width()
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
void QgsLineSymbolV2::setDataDefinedWidth( const QgsDataDefined& dd )
|
||||
{
|
||||
const double symbolWidth = width();
|
||||
|
||||
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
{
|
||||
QgsLineSymbolLayerV2* layer = static_cast<QgsLineSymbolLayerV2*>( *it );
|
||||
|
||||
if ( dd.hasDefaultValues() )
|
||||
{
|
||||
layer->removeDataDefinedProperty( "width" );
|
||||
layer->removeDataDefinedProperty( "offset" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( symbolWidth == 0 || qgsDoubleNear( layer->width(), symbolWidth ) )
|
||||
{
|
||||
layer->setDataDefinedProperty( "width", new QgsDataDefined( dd ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
layer->setDataDefinedProperty( "width", scaleWholeSymbol( layer->width() / symbolWidth, dd ) );
|
||||
}
|
||||
|
||||
if ( layer->offset() )
|
||||
{
|
||||
layer->setDataDefinedProperty( "offset", scaleWholeSymbol( layer->offset() / symbolWidth, dd ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsDataDefined QgsLineSymbolV2::dataDefinedWidth() const
|
||||
{
|
||||
const double symbolWidth = width();
|
||||
|
||||
QgsDataDefined* symbolDD = 0;
|
||||
|
||||
// find the base of the "en masse" pattern
|
||||
for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
{
|
||||
const QgsLineSymbolLayerV2* layer = static_cast<const QgsLineSymbolLayerV2*>( *it );
|
||||
if ( layer->width() == symbolWidth && layer->getDataDefinedProperty( "width" ) )
|
||||
{
|
||||
symbolDD = layer->getDataDefinedProperty( "width" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !symbolDD )
|
||||
return QgsDataDefined();
|
||||
|
||||
// check that all layers width expressions match the "en masse" pattern
|
||||
for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
|
||||
{
|
||||
const QgsLineSymbolLayerV2* layer = static_cast<const QgsLineSymbolLayerV2*>( *it );
|
||||
|
||||
QgsDataDefined* layerWidthDD = layer->getDataDefinedProperty( "width" );
|
||||
QgsDataDefined* layerOffsetDD = layer->getDataDefinedProperty( "offset" );
|
||||
|
||||
if ( qgsDoubleNear( layer->width(), symbolWidth ) )
|
||||
{
|
||||
if ( !layerWidthDD || *layerWidthDD != *symbolDD )
|
||||
return QgsDataDefined();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( symbolWidth == 0 )
|
||||
return QgsDataDefined();
|
||||
|
||||
QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( layer->width() / symbolWidth, *symbolDD ) );
|
||||
if ( !layerWidthDD || *layerWidthDD != *( scaledDD.data() ) )
|
||||
return QgsDataDefined();
|
||||
}
|
||||
|
||||
QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( layer->offset() / symbolWidth, *symbolDD ) );
|
||||
if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
|
||||
return QgsDataDefined();
|
||||
}
|
||||
|
||||
return QgsDataDefined( *symbolDD );
|
||||
}
|
||||
|
||||
void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, const QgsFeature* f, QgsRenderContext& context, int layer, bool selected )
|
||||
{
|
||||
//save old painter
|
||||
|
@ -41,6 +41,7 @@ class QgsPaintEffect;
|
||||
class QgsMarkerSymbolLayerV2;
|
||||
class QgsLineSymbolLayerV2;
|
||||
class QgsFillSymbolLayerV2;
|
||||
class QgsDataDefined;
|
||||
|
||||
typedef QList<QgsSymbolLayerV2*> QgsSymbolLayerV2List;
|
||||
|
||||
@ -183,6 +184,7 @@ class CORE_EXPORT QgsSymbolV2
|
||||
|
||||
QSet<QString> usedAttributes() const;
|
||||
|
||||
//! @note the layer will be NULL after stopRender
|
||||
void setLayer( const QgsVectorLayer* layer ) { mLayer = layer; }
|
||||
const QgsVectorLayer* layer() const { return mLayer; }
|
||||
|
||||
@ -280,7 +282,22 @@ class CORE_EXPORT QgsMarkerSymbolV2 : public QgsSymbolV2
|
||||
QgsMarkerSymbolV2( QgsSymbolLayerV2List layers = QgsSymbolLayerV2List() );
|
||||
|
||||
void setAngle( double angle );
|
||||
double angle();
|
||||
double angle() const;
|
||||
|
||||
/** Set data defined angle for whole symbol (including all symbol layers).
|
||||
* @param dd data defined angle
|
||||
* @note added in QGIS 2.9
|
||||
* @see dataDefinedAngle
|
||||
*/
|
||||
void setDataDefinedAngle( const QgsDataDefined& dd );
|
||||
|
||||
/** Returns data defined angle for whole symbol (including all symbol layers).
|
||||
* @returns data defined angle, or empty data defined if angle is not set
|
||||
* at the marker level
|
||||
* @note added in QGIS 2.9
|
||||
* @see setDataDefinedAngle
|
||||
*/
|
||||
QgsDataDefined dataDefinedAngle() const;
|
||||
|
||||
/** Sets the line angle modification for the symbol's angle. This angle is added to
|
||||
* the marker's rotation and data defined rotation before rendering the symbol, and
|
||||
@ -291,7 +308,22 @@ class CORE_EXPORT QgsMarkerSymbolV2 : public QgsSymbolV2
|
||||
void setLineAngle( double lineAngle );
|
||||
|
||||
void setSize( double size );
|
||||
double size();
|
||||
double size() const;
|
||||
|
||||
/** Set data defined size for whole symbol (including all symbol layers).
|
||||
* @param dd data defined size
|
||||
* @note added in QGIS 2.9
|
||||
* @see dataDefinedSize
|
||||
*/
|
||||
void setDataDefinedSize( const QgsDataDefined& dd );
|
||||
|
||||
/** Returns data defined size for whole symbol (including all symbol layers).
|
||||
* @returns data defined size, or empty data defined if size is not set
|
||||
* at the marker level
|
||||
* @note added in QGIS 2.9
|
||||
* @see setDataDefinedSize
|
||||
*/
|
||||
QgsDataDefined dataDefinedSize() const;
|
||||
|
||||
void setScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod );
|
||||
ScaleMethod scaleMethod();
|
||||
@ -319,7 +351,22 @@ class CORE_EXPORT QgsLineSymbolV2 : public QgsSymbolV2
|
||||
QgsLineSymbolV2( QgsSymbolLayerV2List layers = QgsSymbolLayerV2List() );
|
||||
|
||||
void setWidth( double width );
|
||||
double width();
|
||||
double width() const;
|
||||
|
||||
/** Set data defined width for whole symbol (including all symbol layers).
|
||||
* @param dd data defined width
|
||||
* @note added in QGIS 2.9
|
||||
* @see dataDefinedWidth
|
||||
*/
|
||||
void setDataDefinedWidth( const QgsDataDefined& dd );
|
||||
|
||||
/** Returns data defined size for whole symbol (including all symbol layers).
|
||||
* @returns data defined size, or empty data defined if size is not set
|
||||
* at the line level
|
||||
* @note added in QGIS 2.9
|
||||
* @see setDataDefinedWidth
|
||||
*/
|
||||
QgsDataDefined dataDefinedWidth() const;
|
||||
|
||||
void renderPolyline( const QPolygonF& points, const QgsFeature* f, QgsRenderContext& context, int layer = -1, bool selected = false );
|
||||
|
||||
|
@ -41,6 +41,7 @@ symbology-ng/qgssymbolslistwidget.cpp
|
||||
symbology-ng/qgssvgselectorwidget.cpp
|
||||
symbology-ng/qgslayerpropertieswidget.cpp
|
||||
symbology-ng/qgssmartgroupeditordialog.cpp
|
||||
symbology-ng/qgssizescalewidget.cpp
|
||||
|
||||
effects/qgseffectdrawmodecombobox.cpp
|
||||
effects/qgspainteffectpropertieswidget.cpp
|
||||
@ -378,6 +379,7 @@ SET(QGIS_GUI_MOC_HDRS
|
||||
symbology-ng/qgsvectorfieldsymbollayerwidget.h
|
||||
symbology-ng/qgsvectorgradientcolorrampv2dialog.h
|
||||
symbology-ng/qgsvectorrandomcolorrampv2dialog.h
|
||||
symbology-ng/qgssizescalewidget.h
|
||||
|
||||
attributetable/qgsattributetabledelegate.h
|
||||
attributetable/qgsattributetablefiltermodel.h
|
||||
|
@ -434,13 +434,13 @@ void QgsDataDefinedButton::showAssistant()
|
||||
|
||||
if ( mAssistant->exec() == QDialog::Accepted )
|
||||
{
|
||||
QScopedPointer<QgsDataDefined> dd( mAssistant->dataDefined() );
|
||||
setUseExpression( dd->useExpression() );
|
||||
setActive( dd->isActive() );
|
||||
if ( dd->isActive() && dd->useExpression() )
|
||||
setExpression( dd->expressionString() );
|
||||
else if ( dd->isActive() )
|
||||
setField( dd->field() );
|
||||
QgsDataDefined dd = mAssistant->dataDefined();
|
||||
setUseExpression( dd.useExpression() );
|
||||
setActive( dd.isActive() );
|
||||
if ( dd.isActive() && dd.useExpression() )
|
||||
setExpression( dd.expressionString() );
|
||||
else if ( dd.isActive() )
|
||||
setField( dd.field() );
|
||||
updateGui();
|
||||
}
|
||||
activateWindow(); // reset focus to parent window
|
||||
|
@ -35,7 +35,7 @@ class QgsDataDefined;
|
||||
class GUI_EXPORT QgsDataDefinedAssistant: public QDialog
|
||||
{
|
||||
public:
|
||||
virtual QgsDataDefined* dataDefined() const = 0;
|
||||
virtual QgsDataDefined dataDefined() const = 0;
|
||||
};
|
||||
|
||||
/** \ingroup gui
|
||||
|
@ -45,6 +45,7 @@ QgsRendererV2Widget::QgsRendererV2Widget( QgsVectorLayer* layer, QgsStyleV2* sty
|
||||
else if ( mLayer && mLayer->geometryType() == QGis::Point )
|
||||
{
|
||||
contextMenu->addAction( tr( "Change size" ), this, SLOT( changeSymbolSize() ) );
|
||||
contextMenu->addAction( tr( "Change angle" ), this, SLOT( changeSymbolAngle() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,17 +128,17 @@ void QgsRendererV2Widget::changeSymbolWidth()
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
QgsLineSymbolV2* line = dynamic_cast<QgsLineSymbolV2*>( symbolList.at( 0 ) ) ;
|
||||
double width = QInputDialog::getDouble( this, tr( "Width" ), tr( "Change symbol width" ), line ? line->width() : 0.0 , 0.0, 999999, 1, &ok );
|
||||
if ( ok )
|
||||
QgsDataDefinedWidthDialog dlg( symbolList, mLayer );
|
||||
|
||||
if ( QMessageBox::Ok == dlg.exec() )
|
||||
{
|
||||
QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
|
||||
for ( ; symbolIt != symbolList.end(); ++symbolIt )
|
||||
if ( !dlg.mDDBtn->isActive() )
|
||||
{
|
||||
line = dynamic_cast<QgsLineSymbolV2*>( *symbolIt );
|
||||
if ( line )
|
||||
line->setWidth( width );
|
||||
QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
|
||||
for ( ; symbolIt != symbolList.end(); ++symbolIt )
|
||||
{
|
||||
dynamic_cast<QgsLineSymbolV2*>( *symbolIt )->setWidth( dlg.mSpinBox->value() );
|
||||
}
|
||||
}
|
||||
refreshSymbolView();
|
||||
}
|
||||
@ -151,18 +152,41 @@ void QgsRendererV2Widget::changeSymbolSize()
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
QgsMarkerSymbolV2* marker = dynamic_cast<QgsMarkerSymbolV2*>( symbolList.at( 0 ) );
|
||||
QgsDataDefinedSizeDialog dlg( symbolList, mLayer );
|
||||
|
||||
double size = QInputDialog::getDouble( this, tr( "Size" ), tr( "Change symbol size" ), marker ? marker->size() : 0.0 , 0.0, 999999, 1, &ok );
|
||||
if ( ok )
|
||||
if ( QMessageBox::Ok == dlg.exec() )
|
||||
{
|
||||
QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
|
||||
for ( ; symbolIt != symbolList.end(); ++symbolIt )
|
||||
if ( !dlg.mDDBtn->isActive() )
|
||||
{
|
||||
marker = dynamic_cast<QgsMarkerSymbolV2*>( *symbolIt );
|
||||
if ( marker )
|
||||
marker->setSize( size );
|
||||
QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
|
||||
for ( ; symbolIt != symbolList.end(); ++symbolIt )
|
||||
{
|
||||
dynamic_cast<QgsMarkerSymbolV2*>( *symbolIt )->setSize( dlg.mSpinBox->value() );
|
||||
}
|
||||
}
|
||||
refreshSymbolView();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRendererV2Widget::changeSymbolAngle()
|
||||
{
|
||||
QList<QgsSymbolV2*> symbolList = selectedSymbols();
|
||||
if ( symbolList.size() < 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QgsDataDefinedRotationDialog dlg( symbolList, mLayer );
|
||||
|
||||
if ( QMessageBox::Ok == dlg.exec() )
|
||||
{
|
||||
if ( !dlg.mDDBtn->isActive() )
|
||||
{
|
||||
QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
|
||||
for ( ; symbolIt != symbolList.end(); ++symbolIt )
|
||||
{
|
||||
dynamic_cast<QgsMarkerSymbolV2*>( *symbolIt )->setAngle( dlg.mSpinBox->value() );
|
||||
}
|
||||
}
|
||||
refreshSymbolView();
|
||||
}
|
||||
@ -355,3 +379,84 @@ void QgsRendererV2DataDefinedMenus::updateMenu( QActionGroup* actionGroup, QStri
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QgsDataDefinedValueDialog::QgsDataDefinedValueDialog( const QList<QgsSymbolV2*>& symbolList, QgsVectorLayer * layer, const QString & label )
|
||||
: mSymbolList( symbolList )
|
||||
, mLayer( layer )
|
||||
{
|
||||
setupUi( this );
|
||||
setWindowFlags( Qt::WindowStaysOnTopHint );
|
||||
mLabel->setText( label );
|
||||
connect( mDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( dataDefinedChanged() ) );
|
||||
connect( mDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( dataDefinedChanged() ) );
|
||||
|
||||
}
|
||||
|
||||
void QgsDataDefinedValueDialog::init( const QString & description )
|
||||
{
|
||||
QgsDataDefined dd = symbolDataDefined();
|
||||
mDDBtn->init( mLayer, &dd, QgsDataDefinedButton::Double, description );
|
||||
mSpinBox->setValue( value( mSymbolList.back() ) );
|
||||
mSpinBox->setEnabled( !mDDBtn->isActive() );
|
||||
}
|
||||
|
||||
QgsDataDefined QgsDataDefinedValueDialog::symbolDataDefined() const
|
||||
{
|
||||
// check that all symbols share the same size expression
|
||||
QgsDataDefined dd = symbolDataDefined( mSymbolList.back() );
|
||||
foreach ( QgsSymbolV2 * it, mSymbolList )
|
||||
{
|
||||
if ( symbolDataDefined( it ) != dd ) return QgsDataDefined();
|
||||
}
|
||||
return dd;
|
||||
}
|
||||
|
||||
void QgsDataDefinedValueDialog::dataDefinedChanged()
|
||||
{
|
||||
QgsDataDefined dd = mDDBtn->currentDataDefined();
|
||||
mSpinBox->setEnabled( !dd.isActive() );
|
||||
|
||||
if ( // shall we remove datadefined expressions for layers ?
|
||||
( symbolDataDefined().isActive() && !dd.isActive() )
|
||||
// shall we set the "en masse" expression for properties ?
|
||||
|| dd.isActive() )
|
||||
{
|
||||
foreach ( QgsSymbolV2 * it, mSymbolList )
|
||||
setDataDefined( it, dd );
|
||||
}
|
||||
}
|
||||
|
||||
QgsDataDefined QgsDataDefinedSizeDialog::symbolDataDefined( const QgsSymbolV2 *symbol ) const
|
||||
{
|
||||
const QgsMarkerSymbolV2* marker = static_cast<const QgsMarkerSymbolV2*>( symbol );
|
||||
return marker->dataDefinedSize();
|
||||
}
|
||||
|
||||
void QgsDataDefinedSizeDialog::setDataDefined( QgsSymbolV2* symbol, const QgsDataDefined& dd )
|
||||
{
|
||||
static_cast<QgsMarkerSymbolV2*>( symbol )->setDataDefinedSize( dd );
|
||||
}
|
||||
|
||||
|
||||
QgsDataDefined QgsDataDefinedRotationDialog::symbolDataDefined( const QgsSymbolV2 *symbol ) const
|
||||
{
|
||||
const QgsMarkerSymbolV2* marker = static_cast<const QgsMarkerSymbolV2*>( symbol );
|
||||
return marker->dataDefinedAngle();
|
||||
}
|
||||
|
||||
void QgsDataDefinedRotationDialog::setDataDefined( QgsSymbolV2 *symbol, const QgsDataDefined &dd )
|
||||
{
|
||||
static_cast<QgsMarkerSymbolV2*>( symbol )->setDataDefinedAngle( dd );
|
||||
}
|
||||
|
||||
|
||||
QgsDataDefined QgsDataDefinedWidthDialog::symbolDataDefined( const QgsSymbolV2 *symbol ) const
|
||||
{
|
||||
const QgsLineSymbolV2* line = static_cast<const QgsLineSymbolV2*>( symbol );
|
||||
return line->dataDefinedWidth();
|
||||
}
|
||||
|
||||
void QgsDataDefinedWidthDialog::setDataDefined( QgsSymbolV2 *symbol, const QgsDataDefined &dd )
|
||||
{
|
||||
static_cast<QgsLineSymbolV2*>( symbol )->setDataDefinedWidth( dd );
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <QWidget>
|
||||
#include <QMenu>
|
||||
#include "qgssymbolv2.h"
|
||||
#include "qgsdatadefined.h"
|
||||
|
||||
class QgsVectorLayer;
|
||||
class QgsStyleV2;
|
||||
@ -73,6 +74,8 @@ class GUI_EXPORT QgsRendererV2Widget : public QWidget
|
||||
void changeSymbolWidth();
|
||||
/**Change marker sizes of selected symbols*/
|
||||
void changeSymbolSize();
|
||||
/**Change marker angles of selected symbols*/
|
||||
void changeSymbolAngle();
|
||||
|
||||
virtual void copy() {}
|
||||
virtual void paste() {}
|
||||
@ -126,4 +129,98 @@ class QgsRendererV2DataDefinedMenus : public QObject
|
||||
QgsVectorLayer* mLayer;
|
||||
};
|
||||
|
||||
////////////
|
||||
|
||||
#include "ui_widget_set_dd_value.h"
|
||||
#include "qgssizescalewidget.h"
|
||||
|
||||
/**
|
||||
Utility classes for "en masse" size definition
|
||||
*/
|
||||
class GUI_EXPORT QgsDataDefinedValueDialog : public QDialog, public Ui::QgsDataDefinedValueDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
* @param symbolList must not be empty
|
||||
* @param layer must not be null
|
||||
*/
|
||||
QgsDataDefinedValueDialog( const QList<QgsSymbolV2*>& symbolList, QgsVectorLayer * layer, const QString & label );
|
||||
virtual ~QgsDataDefinedValueDialog() {}
|
||||
|
||||
public slots:
|
||||
void dataDefinedChanged();
|
||||
|
||||
protected:
|
||||
QgsDataDefined symbolDataDefined() const;
|
||||
void init( const QString & description ); // needed in children ctor to call virtual
|
||||
|
||||
virtual QgsDataDefined symbolDataDefined( const QgsSymbolV2 * ) const = 0;
|
||||
virtual double value( const QgsSymbolV2 * ) const = 0;
|
||||
virtual void setDataDefined( QgsSymbolV2* symbol, const QgsDataDefined& dd ) = 0;
|
||||
|
||||
QList<QgsSymbolV2*> mSymbolList;
|
||||
QgsVectorLayer* mLayer;
|
||||
};
|
||||
|
||||
class GUI_EXPORT QgsDataDefinedSizeDialog : public QgsDataDefinedValueDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsDataDefinedSizeDialog( const QList<QgsSymbolV2*>& symbolList, QgsVectorLayer * layer )
|
||||
: QgsDataDefinedValueDialog( symbolList, layer, tr( "Size" ) )
|
||||
{
|
||||
init( tr( "Symbol size" ) );
|
||||
if ( symbolList.length() )
|
||||
mDDBtn->setAssistant( new QgsSizeScaleWidget( mLayer, static_cast<const QgsMarkerSymbolV2*>( symbolList[0] ) ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
QgsDataDefined symbolDataDefined( const QgsSymbolV2 * symbol ) const override;
|
||||
|
||||
double value( const QgsSymbolV2 * symbol ) const override { return static_cast<const QgsMarkerSymbolV2*>( symbol )->size(); }
|
||||
|
||||
void setDataDefined( QgsSymbolV2* symbol, const QgsDataDefined& dd ) override;
|
||||
};
|
||||
|
||||
class GUI_EXPORT QgsDataDefinedRotationDialog : public QgsDataDefinedValueDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsDataDefinedRotationDialog( const QList<QgsSymbolV2*>& symbolList, QgsVectorLayer * layer )
|
||||
: QgsDataDefinedValueDialog( symbolList, layer, tr( "Rotation" ) )
|
||||
{
|
||||
init( tr( "Symbol rotation" ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
QgsDataDefined symbolDataDefined( const QgsSymbolV2 * symbol ) const override;
|
||||
|
||||
double value( const QgsSymbolV2 * symbol ) const override { return static_cast<const QgsMarkerSymbolV2*>( symbol )->angle(); }
|
||||
|
||||
void setDataDefined( QgsSymbolV2* symbol, const QgsDataDefined& dd ) override;
|
||||
};
|
||||
|
||||
|
||||
class GUI_EXPORT QgsDataDefinedWidthDialog : public QgsDataDefinedValueDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsDataDefinedWidthDialog( const QList<QgsSymbolV2*>& symbolList, QgsVectorLayer * layer )
|
||||
: QgsDataDefinedValueDialog( symbolList, layer, tr( "Width" ) )
|
||||
{
|
||||
init( tr( "Symbol width" ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
QgsDataDefined symbolDataDefined( const QgsSymbolV2 * symbol ) const override;
|
||||
|
||||
double value( const QgsSymbolV2 * symbol ) const override { return static_cast<const QgsLineSymbolV2*>( symbol )->width(); }
|
||||
|
||||
void setDataDefined( QgsSymbolV2* symbol, const QgsDataDefined& dd ) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // QGSRENDERERV2WIDGET_H
|
||||
|
204
src/gui/symbology-ng/qgssizescalewidget.cpp
Normal file
204
src/gui/symbology-ng/qgssizescalewidget.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
/***************************************************************************
|
||||
qgssizescalewidget.cpp - continuous size scale assistant
|
||||
|
||||
---------------------
|
||||
begin : March 2015
|
||||
copyright : (C) 2015 by Vincent Mora
|
||||
email : vincent dot mora at oslandia dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgssizescalewidget.h"
|
||||
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsmaplayerregistry.h"
|
||||
#include "qgssymbolv2.h"
|
||||
#include "qgslayertreelayer.h"
|
||||
#include "qgslayertreemodellegendnode.h"
|
||||
#include "qgssymbollayerv2utils.h"
|
||||
#include "qgsscaleexpression.h"
|
||||
#include "qgsdatadefined.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QItemDelegate>
|
||||
|
||||
#include <limits>
|
||||
|
||||
|
||||
class ItemDelegate : public QItemDelegate
|
||||
{
|
||||
public:
|
||||
ItemDelegate( QStandardItemModel* model ): mModel( model ) {}
|
||||
|
||||
QSize sizeHint( const QStyleOptionViewItem& /*option*/, const QModelIndex & index ) const override
|
||||
{
|
||||
return mModel->item( index.row() )->icon().actualSize( QSize( 512, 512 ) );
|
||||
}
|
||||
|
||||
private:
|
||||
QStandardItemModel* mModel;
|
||||
|
||||
};
|
||||
|
||||
QgsSizeScaleWidget::QgsSizeScaleWidget( const QgsVectorLayer * layer, const QgsMarkerSymbolV2 * symbol )
|
||||
: mSymbol( symbol )
|
||||
// we just use the minimumValue and maximumValue from the layer, unfortunately they are
|
||||
// non const, so we get the layer from the registry instead
|
||||
, mLayer( dynamic_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( layer->id() ) ) )
|
||||
{
|
||||
setupUi( this );
|
||||
setWindowFlags( Qt::WindowStaysOnTopHint );
|
||||
|
||||
mLayerTreeLayer = new QgsLayerTreeLayer( mLayer );
|
||||
mRoot.addChildNode( mLayerTreeLayer ); // takes ownership
|
||||
|
||||
treeView->setModel( &mPreviewList );
|
||||
treeView->setItemDelegate( new ItemDelegate( &mPreviewList ) );
|
||||
treeView->setHeaderHidden( true );
|
||||
treeView->expandAll();
|
||||
|
||||
QAction* computeFromLayer = new QAction( tr( "Compute from layer" ), this );
|
||||
connect( computeFromLayer, SIGNAL( triggered() ), this, SLOT( computeFromLayerTriggered() ) );
|
||||
|
||||
QMenu* menu = new QMenu();
|
||||
menu->addAction( computeFromLayer );
|
||||
computeValuesButton->setMenu( menu );
|
||||
connect( computeValuesButton, SIGNAL( clicked() ), computeValuesButton, SLOT( showMenu() ) );
|
||||
|
||||
//mExpressionWidget->setFilters( QgsFieldProxyModel::Numeric | QgsFieldProxyModel::Date );
|
||||
mExpressionWidget->setLayer( mLayer );
|
||||
|
||||
scaleMethodComboBox->addItem( tr( "Flannery" ), int( QgsScaleExpression::Flannery ) );
|
||||
scaleMethodComboBox->addItem( tr( "Surface" ), int( QgsScaleExpression::Area ) );
|
||||
scaleMethodComboBox->addItem( tr( "Radius" ), int( QgsScaleExpression::Linear ) );
|
||||
|
||||
minSizeSpinBox->setShowClearButton( false );
|
||||
maxSizeSpinBox->setShowClearButton( false );
|
||||
minValueSpinBox->setShowClearButton( false );
|
||||
maxValueSpinBox->setShowClearButton( false );
|
||||
|
||||
// setup ui from expression if any
|
||||
QgsDataDefined ddSize = mSymbol->dataDefinedSize();
|
||||
QgsScaleExpression expr( ddSize.expressionString() );
|
||||
if ( expr )
|
||||
{
|
||||
for ( int i = 0; i < scaleMethodComboBox->count(); i++ )
|
||||
{
|
||||
if ( scaleMethodComboBox->itemData( i ).toInt() == int( expr.type() ) )
|
||||
{
|
||||
scaleMethodComboBox->setCurrentIndex( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mExpressionWidget->setField( expr.baseExpression() );
|
||||
|
||||
minValueSpinBox->setValue( expr.minValue() );
|
||||
maxValueSpinBox->setValue( expr.maxValue() );
|
||||
minSizeSpinBox->setValue( expr.minSize() );
|
||||
maxSizeSpinBox->setValue( expr.maxSize() );
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
connect( minSizeSpinBox, SIGNAL( valueChanged( double ) ), this, SLOT( updatePreview() ) );
|
||||
connect( maxSizeSpinBox, SIGNAL( valueChanged( double ) ), this, SLOT( updatePreview() ) );
|
||||
connect( minValueSpinBox, SIGNAL( valueChanged( double ) ), this, SLOT( updatePreview() ) );
|
||||
connect( maxValueSpinBox, SIGNAL( valueChanged( double ) ), this, SLOT( updatePreview() ) );
|
||||
//potentially very expensive for large layers:
|
||||
connect( mExpressionWidget, SIGNAL( fieldChanged( QString ) ), this, SLOT( computeFromLayerTriggered() ) );
|
||||
connect( scaleMethodComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( updatePreview() ) );
|
||||
}
|
||||
|
||||
QgsDataDefined QgsSizeScaleWidget::dataDefined() const
|
||||
{
|
||||
QScopedPointer<QgsScaleExpression> exp( createExpression() );
|
||||
return QgsDataDefined( exp.data() );
|
||||
}
|
||||
|
||||
QgsScaleExpression *QgsSizeScaleWidget::createExpression() const
|
||||
{
|
||||
return new QgsScaleExpression( QgsScaleExpression::Type( scaleMethodComboBox->itemData( scaleMethodComboBox->currentIndex() ).toInt() ),
|
||||
mExpressionWidget->currentField(),
|
||||
minValueSpinBox->value(),
|
||||
maxValueSpinBox->value(),
|
||||
minSizeSpinBox->value(),
|
||||
maxSizeSpinBox->value() );
|
||||
}
|
||||
|
||||
void QgsSizeScaleWidget::updatePreview()
|
||||
{
|
||||
QScopedPointer<QgsScaleExpression> expr( createExpression() );
|
||||
QList<double> breaks = QgsSymbolLayerV2Utils::prettyBreaks( expr->minValue(), expr->maxValue(), 4 );
|
||||
|
||||
treeView->setIconSize( QSize( 512, 512 ) );
|
||||
mPreviewList.clear();
|
||||
int widthMax = 0;
|
||||
for ( int i = 0; i < breaks.length(); i++ )
|
||||
{
|
||||
QScopedPointer< QgsMarkerSymbolV2 > symbol( dynamic_cast<QgsMarkerSymbolV2*>( mSymbol->clone() ) );
|
||||
symbol->setDataDefinedSize( QgsDataDefined() );
|
||||
symbol->setDataDefinedAngle( "" ); // to avoid symbol not beeing drawn
|
||||
symbol->setSize( expr->size( breaks[i] ) );
|
||||
QgsSymbolV2LegendNode node( mLayerTreeLayer, QgsLegendSymbolItemV2( symbol.data(), QString::number( i ), 0 ) );
|
||||
const QSize sz( node.minimumIconSize() );
|
||||
node.setIconSize( sz );
|
||||
QScopedPointer< QStandardItem > item( new QStandardItem( node.data( Qt::DecorationRole ).value<QPixmap>(), QString::number( breaks[i] ) ) );
|
||||
widthMax = qMax( sz.width(), widthMax );
|
||||
mPreviewList.appendRow( item.take() );
|
||||
}
|
||||
|
||||
// center icon and align text left by giving icons the same width
|
||||
// @todo maybe add some space so that icons don't touch
|
||||
for ( int i = 0; i < breaks.length(); i++ )
|
||||
{
|
||||
QPixmap img( mPreviewList.item( i )->icon().pixmap( mPreviewList.item( i )->icon().actualSize( QSize( 512, 512 ) ) ) );
|
||||
QPixmap enlarged( widthMax, img.height() );
|
||||
// fill transparent and add original image
|
||||
enlarged.fill( Qt::transparent );
|
||||
QPainter p( &enlarged );
|
||||
p.drawPixmap( QPoint(( widthMax - img.width() ) / 2, 0 ), img );
|
||||
p.end();
|
||||
mPreviewList.item( i )->setIcon( enlarged );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsSizeScaleWidget::computeFromLayerTriggered()
|
||||
{
|
||||
QgsExpression expression( mExpressionWidget->currentField() );
|
||||
if ( ! expression.prepare( mLayer->pendingFields() ) )
|
||||
return;
|
||||
|
||||
QStringList lst( expression.referencedColumns() );
|
||||
|
||||
QgsFeatureIterator fit = mLayer->getFeatures(
|
||||
QgsFeatureRequest().setFlags( expression.needsGeometry()
|
||||
? QgsFeatureRequest::NoFlags
|
||||
: QgsFeatureRequest::NoGeometry )
|
||||
.setSubsetOfAttributes( lst, mLayer->pendingFields() ) );
|
||||
|
||||
// create list of non-null attribute values
|
||||
double min = DBL_MAX;
|
||||
double max = -DBL_MAX;
|
||||
QgsFeature f;
|
||||
while ( fit.nextFeature( f ) )
|
||||
{
|
||||
bool ok;
|
||||
const double value = expression.evaluate( f ).toDouble( &ok );
|
||||
if ( ok )
|
||||
{
|
||||
max = qMax( max, value );
|
||||
min = qMin( min, value );
|
||||
}
|
||||
}
|
||||
minValueSpinBox->setValue( min );
|
||||
maxValueSpinBox->setValue( max );
|
||||
updatePreview();
|
||||
}
|
||||
|
56
src/gui/symbology-ng/qgssizescalewidget.h
Normal file
56
src/gui/symbology-ng/qgssizescalewidget.h
Normal file
@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
qgssizescalewidget.h - continuous size scale assistant
|
||||
|
||||
---------------------
|
||||
begin : March 2015
|
||||
copyright : (C) 2015 by Vincent Mora
|
||||
email : vincent dot mora at oslandia dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSSIZESCALEWIDGET_H
|
||||
#define QGSSIZESCALEWIDGET_H
|
||||
|
||||
#include "qgslayertreegroup.h"
|
||||
#include "qgslayertreemodel.h"
|
||||
#include "qgsdatadefinedbutton.h"
|
||||
#include "ui_widget_size_scale.h"
|
||||
#include <QStandardItemModel>
|
||||
|
||||
class QgsVectorLayer;
|
||||
class QgsMarkerSymbolV2;
|
||||
class QgsLayerTreeLayer;
|
||||
class QgsScaleExpression;
|
||||
class QgsDataDefined;
|
||||
|
||||
class GUI_EXPORT QgsSizeScaleWidget : public QgsDataDefinedAssistant, private Ui_SizeScaleBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsSizeScaleWidget( const QgsVectorLayer * layer, const QgsMarkerSymbolV2 * symbol );
|
||||
|
||||
QgsDataDefined dataDefined() const override;
|
||||
|
||||
private slots:
|
||||
void computeFromLayerTriggered();
|
||||
void updatePreview();
|
||||
|
||||
private:
|
||||
|
||||
const QgsMarkerSymbolV2* mSymbol;
|
||||
QgsVectorLayer* mLayer;
|
||||
QgsLayerTreeLayer* mLayerTreeLayer;
|
||||
QgsLayerTreeGroup mRoot;
|
||||
QStandardItemModel mPreviewList;
|
||||
|
||||
QgsScaleExpression* createExpression() const;
|
||||
};
|
||||
|
||||
#endif //QGSSIZESCALEWIDGET_H
|
@ -16,11 +16,15 @@
|
||||
|
||||
#include "qgssymbolslistwidget.h"
|
||||
|
||||
#include "qgssizescalewidget.h"
|
||||
|
||||
#include "qgsstylev2managerdialog.h"
|
||||
#include "qgsdatadefined.h"
|
||||
|
||||
#include "qgssymbolv2.h"
|
||||
#include "qgsstylev2.h"
|
||||
#include "qgssymbollayerv2utils.h"
|
||||
#include "qgsmarkersymbollayerv2.h"
|
||||
|
||||
#include "qgsapplication.h"
|
||||
|
||||
@ -33,16 +37,17 @@
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QMenu>
|
||||
#include <QScopedPointer>
|
||||
|
||||
|
||||
QgsSymbolsListWidget::QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* style, QMenu* menu, QWidget* parent )
|
||||
QgsSymbolsListWidget::QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* style, QMenu* menu, QWidget* parent, const QgsVectorLayer * layer )
|
||||
: QWidget( parent )
|
||||
, mSymbol( symbol )
|
||||
, mStyle( style )
|
||||
, mAdvancedMenu( 0 )
|
||||
, mClipFeaturesAction( 0 )
|
||||
, mLayer( layer )
|
||||
{
|
||||
mSymbol = symbol;
|
||||
mStyle = style;
|
||||
|
||||
setupUi( this );
|
||||
|
||||
mSymbolUnitWidget->setUnits( QgsSymbolV2::OutputUnitList() << QgsSymbolV2::MM << QgsSymbolV2::MapUnit );
|
||||
@ -94,6 +99,16 @@ QgsSymbolsListWidget::QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* sty
|
||||
connect( spinSize, SIGNAL( valueChanged( double ) ), this, SLOT( setMarkerSize( double ) ) );
|
||||
connect( spinWidth, SIGNAL( valueChanged( double ) ), this, SLOT( setLineWidth( double ) ) );
|
||||
|
||||
connect( mRotationDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( updateDataDefinedMarkerAngle() ) );
|
||||
connect( mRotationDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( updateDataDefinedMarkerAngle() ) );
|
||||
connect( mSizeDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( updateDataDefinedMarkerSize() ) );
|
||||
connect( mSizeDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( updateDataDefinedMarkerSize() ) );
|
||||
connect( mWidthDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( updateDataDefinedLineWidth() ) );
|
||||
connect( mWidthDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( updateDataDefinedLineWidth() ) );
|
||||
|
||||
if ( mSymbol->type() == QgsSymbolV2::Marker && mLayer )
|
||||
mSizeDDBtn->setAssistant( new QgsSizeScaleWidget( mLayer, static_cast<const QgsMarkerSymbolV2*>( mSymbol ) ) );
|
||||
|
||||
// Live color updates are not undoable to child symbol layers
|
||||
btnColor->setAcceptLiveUpdates( false );
|
||||
btnColor->setAllowAlpha( true );
|
||||
@ -198,6 +213,23 @@ void QgsSymbolsListWidget::setMarkerAngle( double angle )
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void QgsSymbolsListWidget::updateDataDefinedMarkerAngle()
|
||||
{
|
||||
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
|
||||
QgsDataDefined dd = mRotationDDBtn->currentDataDefined();
|
||||
|
||||
bool isDefault = dd.hasDefaultValues();
|
||||
|
||||
if ( // shall we remove datadefined expressions for layers ?
|
||||
( markerSymbol->dataDefinedAngle().hasDefaultValues() && isDefault )
|
||||
// shall we set the "en masse" expression for properties ?
|
||||
|| !isDefault )
|
||||
{
|
||||
markerSymbol->setDataDefinedAngle( dd );
|
||||
emit changed();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsSymbolsListWidget::setMarkerSize( double size )
|
||||
{
|
||||
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
|
||||
@ -207,6 +239,23 @@ void QgsSymbolsListWidget::setMarkerSize( double size )
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void QgsSymbolsListWidget::updateDataDefinedMarkerSize()
|
||||
{
|
||||
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
|
||||
QgsDataDefined dd = mSizeDDBtn->currentDataDefined();
|
||||
|
||||
bool isDefault = dd.hasDefaultValues();
|
||||
|
||||
if ( // shall we remove datadefined expressions for layers ?
|
||||
( !markerSymbol->dataDefinedSize().hasDefaultValues() && isDefault )
|
||||
// shall we set the "en masse" expression for properties ?
|
||||
|| !isDefault )
|
||||
{
|
||||
markerSymbol->setDataDefinedSize( dd );
|
||||
emit changed();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsSymbolsListWidget::setLineWidth( double width )
|
||||
{
|
||||
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mSymbol );
|
||||
@ -216,6 +265,23 @@ void QgsSymbolsListWidget::setLineWidth( double width )
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void QgsSymbolsListWidget::updateDataDefinedLineWidth()
|
||||
{
|
||||
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mSymbol );
|
||||
QgsDataDefined dd = mWidthDDBtn->currentDataDefined();
|
||||
|
||||
bool isDefault = dd.hasDefaultValues();
|
||||
|
||||
if ( // shall we remove datadefined expressions for layers ?
|
||||
( !lineSymbol->dataDefinedWidth().hasDefaultValues() && isDefault )
|
||||
// shall we set the "en masse" expression for properties ?
|
||||
|| !isDefault )
|
||||
{
|
||||
lineSymbol->setDataDefinedWidth( dd );
|
||||
emit changed();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsSymbolsListWidget::symbolAddedToStyle( QString name, QgsSymbolV2* symbol )
|
||||
{
|
||||
Q_UNUSED( name );
|
||||
@ -297,11 +363,37 @@ void QgsSymbolsListWidget::updateSymbolInfo()
|
||||
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
|
||||
spinSize->setValue( markerSymbol->size() );
|
||||
spinAngle->setValue( markerSymbol->angle() );
|
||||
|
||||
if ( mLayer )
|
||||
{
|
||||
QgsDataDefined ddSize = markerSymbol->dataDefinedSize();
|
||||
mSizeDDBtn->init( mLayer, &ddSize, QgsDataDefinedButton::AnyType, QgsDataDefinedButton::doublePosDesc() );
|
||||
spinSize->setEnabled( !mSizeDDBtn->isActive() );
|
||||
QgsDataDefined ddAngle( markerSymbol->dataDefinedAngle() );
|
||||
mRotationDDBtn->init( mLayer, &ddAngle, QgsDataDefinedButton::AnyType, QgsDataDefinedButton::doubleDesc() );
|
||||
spinAngle->setEnabled( !mRotationDDBtn->isActive() );
|
||||
}
|
||||
else
|
||||
{
|
||||
mSizeDDBtn->setEnabled( false );
|
||||
mRotationDDBtn->setEnabled( false );
|
||||
}
|
||||
}
|
||||
else if ( mSymbol->type() == QgsSymbolV2::Line )
|
||||
{
|
||||
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mSymbol );
|
||||
spinWidth->setValue( lineSymbol->width() );
|
||||
|
||||
if ( mLayer )
|
||||
{
|
||||
QgsDataDefined dd( lineSymbol->dataDefinedWidth() );
|
||||
mWidthDDBtn->init( mLayer, &dd, QgsDataDefinedButton::AnyType, QgsDataDefinedButton::doubleDesc() );
|
||||
spinWidth->setEnabled( !mWidthDDBtn->isActive() );
|
||||
}
|
||||
else
|
||||
{
|
||||
mWidthDDBtn->setEnabled( false );
|
||||
}
|
||||
}
|
||||
|
||||
mSymbolUnitWidget->blockSignals( true );
|
||||
|
@ -30,7 +30,7 @@ class GUI_EXPORT QgsSymbolsListWidget : public QWidget, private Ui::SymbolsListW
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* style, QMenu* menu, QWidget* parent );
|
||||
QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* style, QMenu* menu, QWidget* parent, const QgsVectorLayer * layer = 0 );
|
||||
|
||||
public slots:
|
||||
void setSymbolFromStyle( const QModelIndex & index );
|
||||
@ -49,6 +49,10 @@ class GUI_EXPORT QgsSymbolsListWidget : public QWidget, private Ui::SymbolsListW
|
||||
void openStyleManager();
|
||||
void clipFeaturesToggled( bool checked );
|
||||
|
||||
void updateDataDefinedMarkerSize();
|
||||
void updateDataDefinedMarkerAngle();
|
||||
void updateDataDefinedLineWidth();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
@ -57,6 +61,7 @@ class GUI_EXPORT QgsSymbolsListWidget : public QWidget, private Ui::SymbolsListW
|
||||
QgsStyleV2* mStyle;
|
||||
QMenu* mAdvancedMenu;
|
||||
QAction* mClipFeaturesAction;
|
||||
const QgsVectorLayer* mLayer;
|
||||
|
||||
void populateSymbolView();
|
||||
void populateSymbols( QStringList symbols );
|
||||
|
@ -333,8 +333,10 @@ void QgsSymbolV2SelectorDialog::layerChanged()
|
||||
else
|
||||
{
|
||||
// then it must be a symbol
|
||||
currentItem->symbol()->setLayer( mVectorLayer );
|
||||
// Now populate symbols of that type using the symbols list widget:
|
||||
QWidget *symbolsList = new QgsSymbolsListWidget( currentItem->symbol(), mStyle, mAdvancedMenu, this );
|
||||
QWidget *symbolsList = new QgsSymbolsListWidget( currentItem->symbol(), mStyle, mAdvancedMenu, this, mVectorLayer );
|
||||
|
||||
setWidget( symbolsList );
|
||||
connect( symbolsList, SIGNAL( changed() ), this, SLOT( symbolChanged() ) );
|
||||
}
|
||||
|
93
src/ui/symbollayer/widget_set_dd_value.ui
Normal file
93
src/ui/symbollayer/widget_set_dd_value.ui
Normal file
@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsDataDefinedValueDialog</class>
|
||||
<widget class="QDialog" name="QgsDataDefinedValueDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>99</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="mLabel">
|
||||
<property name="text">
|
||||
<string>Label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="mSpinBox"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsDoubleSpinBox</class>
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
<header>qgsdoublespinbox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsDataDefinedButton</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>qgsdatadefinedbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>QgsDataDefinedValueDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>QgsDataDefinedValueDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
240
src/ui/symbollayer/widget_size_scale.ui
Normal file
240
src/ui/symbollayer/widget_size_scale.ui
Normal file
@ -0,0 +1,240 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SizeScaleBase</class>
|
||||
<widget class="QDialog" name="SizeScaleBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>576</width>
|
||||
<height>343</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Field</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Scale method</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Size from</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="minSizeSpinBox">
|
||||
<property name="decimals">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>to</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QgsDoubleSpinBox" name="maxSizeSpinBox">
|
||||
<property name="decimals">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Values from</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="minValueSpinBox">
|
||||
<property name="decimals">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-99999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>to</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QgsDoubleSpinBox" name="maxValueSpinBox">
|
||||
<property name="decimals">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-99999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QToolButton" name="computeValuesButton">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="3">
|
||||
<widget class="QgsFieldExpressionWidget" name="mExpressionWidget" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QComboBox" name="scaleMethodComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="2">
|
||||
<widget class="QTreeView" name="treeView"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>154</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsFieldExpressionWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">qgsfieldexpressionwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsDoubleSpinBox</class>
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
<header>qgsdoublespinbox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>mExpressionWidget</tabstop>
|
||||
<tabstop>scaleMethodComboBox</tabstop>
|
||||
<tabstop>minSizeSpinBox</tabstop>
|
||||
<tabstop>maxSizeSpinBox</tabstop>
|
||||
<tabstop>minValueSpinBox</tabstop>
|
||||
<tabstop>maxValueSpinBox</tabstop>
|
||||
<tabstop>computeValuesButton</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
<tabstop>treeView</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>SizeScaleBase</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>SizeScaleBase</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -84,6 +84,7 @@
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<zorder>stackedWidget</zorder>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
@ -104,7 +105,51 @@
|
||||
</property>
|
||||
<widget class="QWidget" name="pageMarker">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QgsDataDefinedButton" name="mSizeDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QgsDataDefinedButton" name="mRotationDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QgsDoubleSpinBox" name="spinAngle">
|
||||
<property name="suffix">
|
||||
<string> °</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>360.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Rotation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QgsDoubleSpinBox" name="spinSize">
|
||||
<property name="decimals">
|
||||
<number>5</number>
|
||||
@ -123,36 +168,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Rotation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="spinAngle">
|
||||
<property name="suffix">
|
||||
<string> °</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>360.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="pageLine">
|
||||
@ -176,6 +191,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QgsDataDefinedButton" name="mWidthDDBtn">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
@ -334,17 +356,25 @@
|
||||
<header>qgsunitselectionwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsDataDefinedButton</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>qgsdatadefinedbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>mTransparencySlider</tabstop>
|
||||
<tabstop>spinSize</tabstop>
|
||||
<tabstop>mSizeDDBtn</tabstop>
|
||||
<tabstop>spinWidth</tabstop>
|
||||
<tabstop>mWidthDDBtn</tabstop>
|
||||
<tabstop>btnColor</tabstop>
|
||||
<tabstop>spinAngle</tabstop>
|
||||
<tabstop>mRotationDDBtn</tabstop>
|
||||
<tabstop>groupsCombo</tabstop>
|
||||
<tabstop>openStyleManagerButton</tabstop>
|
||||
<tabstop>viewSymbols</tabstop>
|
||||
<tabstop>btnAdvanced</tabstop>
|
||||
<tabstop>spinWidth</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user