[QGIS Commit] r13333 - in trunk/qgis: python/core
src/core/symbology-ng src/gui/symbology-ng src/ui
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Tue Apr 20 08:25:46 EDT 2010
Author: wonder
Date: 2010-04-20 08:25:42 -0400 (Tue, 20 Apr 2010)
New Revision: 13333
Modified:
trunk/qgis/python/core/conversions.sip
trunk/qgis/python/core/symbology-ng-core.sip
trunk/qgis/src/core/symbology-ng/qgsvectorcolorrampv2.cpp
trunk/qgis/src/core/symbology-ng/qgsvectorcolorrampv2.h
trunk/qgis/src/gui/symbology-ng/qgsvectorgradientcolorrampv2dialog.cpp
trunk/qgis/src/gui/symbology-ng/qgsvectorgradientcolorrampv2dialog.h
trunk/qgis/src/ui/qgsvectorgradientcolorrampv2dialogbase.ui
Log:
[FEATURE] gradient color ramps now support multiple stops - for adding intermediate colors
Modified: trunk/qgis/python/core/conversions.sip
===================================================================
--- trunk/qgis/python/core/conversions.sip 2010-04-20 11:51:20 UTC (rev 13332)
+++ trunk/qgis/python/core/conversions.sip 2010-04-20 12:25:42 UTC (rev 13333)
@@ -9,6 +9,7 @@
- QMap<int, QMap<int, TYPE> >
- QMap<QString, QVariant::Type>
- QMap<TYPE1, TYPE2*>
+- QMap<double, TYPE>
- QMultiMap<double, TYPE2>
- QMap<int, QgsOverlayObject*>*
*/
@@ -730,6 +731,107 @@
%End
};
+
+
+template<double, TYPE>
+%MappedType QMap<double, TYPE>
+{
+%TypeHeaderCode
+#include <QMap>
+%End
+
+%ConvertFromTypeCode
+ // Create the dictionary.
+ PyObject *d = PyDict_New();
+
+ if (!d)
+ return NULL;
+
+ // Set the dictionary elements.
+ QMap<double, TYPE>::iterator i;
+
+ for (i = sipCpp->begin(); i != sipCpp->end(); ++i)
+ {
+ PyObject *t1obj = PyFloat_FromDouble(i.key());
+ TYPE* t2 = &i.value();
+ PyObject *t2obj = sipConvertFromInstance(t2, sipClass_TYPE, sipTransferObj);
+
+ if (t1obj == NULL || t2obj == NULL || PyDict_SetItem(d, t1obj, t2obj) < 0)
+ {
+ Py_DECREF(d);
+
+ if (t1obj)
+ Py_DECREF(t1obj);
+
+ if (t2obj)
+ Py_DECREF(t2obj);
+
+ return NULL;
+ }
+
+ Py_DECREF(t1obj);
+ Py_DECREF(t2obj);
+ }
+
+ return d;
+%End
+
+%ConvertToTypeCode
+ PyObject *t1obj, *t2obj;
+#if PY_VERSION_HEX >= 0x02050000
+ Py_ssize_t i = 0;
+#else
+ int i = 0;
+#endif
+
+ // Check the type if that is all that is required.
+ if (sipIsErr == NULL)
+ {
+ if (!PyDict_Check(sipPy))
+ return 0;
+
+ while (PyDict_Next(sipPy, &i, &t1obj, &t2obj))
+ {
+ if (!PyFloat_Check(t1obj))
+ return 0;
+
+ if (!sipCanConvertToInstance(t2obj, sipClass_TYPE, SIP_NOT_NONE))
+ return 0;
+ }
+
+ return 1;
+ }
+
+ QMap<double, TYPE> *qm = new QMap<double, TYPE>;
+
+ while (PyDict_Next(sipPy, &i, &t1obj, &t2obj))
+ {
+ int state;
+
+ double k = PyFloat_AsDouble(t1obj);
+ TYPE *t2 = reinterpret_cast<TYPE *>(sipConvertToInstance(t2obj, sipClass_TYPE, sipTransferObj, SIP_NOT_NONE, &state, sipIsErr));
+
+ if (*sipIsErr)
+ {
+ sipReleaseInstance(t2, sipClass_TYPE, state);
+ delete qm;
+ return 0;
+ }
+
+ qm->insert(k, *t2);
+
+ sipReleaseInstance(t2, sipClass_TYPE, state);
+ }
+
+ *sipCppPtr = qm;
+
+ return sipGetState(sipTransferObj);
+%End
+};
+
+
+
+
template<double, TYPE2>
%MappedType QMultiMap<double, TYPE2>
{
Modified: trunk/qgis/python/core/symbology-ng-core.sip
===================================================================
--- trunk/qgis/python/core/symbology-ng-core.sip 2010-04-20 11:51:20 UTC (rev 13332)
+++ trunk/qgis/python/core/symbology-ng-core.sip 2010-04-20 12:25:42 UTC (rev 13333)
@@ -762,6 +762,15 @@
#include <qgsvectorcolorrampv2.h>
%End
+%ConvertToSubClassCode
+ if (sipCpp->type() == "gradient")
+ {
+ sipClass = sipClass_QgsVectorGradientColorRampV2;
+ }
+ else
+ sipClass = 0;
+%End
+
public:
virtual ~QgsVectorColorRampV2();
@@ -769,12 +778,43 @@
virtual QString type() const = 0;
- virtual QgsVectorColorRampV2* clone() const = 0;
+ virtual QgsVectorColorRampV2* clone() const = 0 /Factory/;
virtual QgsStringMap properties() const = 0;
};
+class QgsVectorGradientColorRampV2 : QgsVectorColorRampV2
+{
+ public:
+ QgsVectorGradientColorRampV2( QColor color1 = QColor(0,0,255),
+ QColor color2 = QColor(0,255,0) );
+
+ static QgsVectorColorRampV2* create( const QgsStringMap& properties = QgsStringMap() ) /Factory/;
+
+ virtual QColor color( double value ) const;
+
+ virtual QString type() const;
+
+ virtual QgsVectorColorRampV2* clone() const /Factory/;
+
+ virtual QgsStringMap properties() const;
+
+ QColor color1() const;
+ QColor color2() const;
+
+ void setColor1( QColor color );
+ void setColor2( QColor color );
+
+ typedef QMultiMap<double, QColor> StopsMap;
+
+ void setStops(const StopsMap& stops);
+ const StopsMap& stops() const;
+
+};
+
+
+
//////////
class QgsSymbologyV2Conversion
@@ -858,3 +898,5 @@
QgsRendererV2Registry();
~QgsRendererV2Registry();
};
+
+///////////////
Modified: trunk/qgis/src/core/symbology-ng/qgsvectorcolorrampv2.cpp
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgsvectorcolorrampv2.cpp 2010-04-20 11:51:20 UTC (rev 13332)
+++ trunk/qgis/src/core/symbology-ng/qgsvectorcolorrampv2.cpp 2010-04-20 12:25:42 UTC (rev 13333)
@@ -18,21 +18,68 @@
color1 = QgsSymbolLayerV2Utils::decodeColor( props["color1"] );
if ( props.contains( "color2" ) )
color2 = QgsSymbolLayerV2Utils::decodeColor( props["color2"] );
- return new QgsVectorGradientColorRampV2( color1, color2 );
+
+ StopsMap stops;
+ if ( props.contains( "stops" ) )
+ {
+ foreach( QString stop, props["stops"].split( ':' ) )
+ {
+ int i = stop.indexOf( ';' );
+ if ( i == -1 ) continue;
+
+ QColor c = QgsSymbolLayerV2Utils::decodeColor( stop.mid( i + 1 ) );
+ stops.insert( stop.left( i ).toDouble(), c );
+ }
+ }
+
+ QgsVectorGradientColorRampV2* r = new QgsVectorGradientColorRampV2( color1, color2 );
+ r->setStops( stops );
+ return r;
}
-QColor QgsVectorGradientColorRampV2::color( double value ) const
+static QColor _interpolate( QColor c1, QColor c2, double value )
{
- int r = ( int )( mColor1.red() + value * ( mColor2.red() - mColor1.red() ) );
- int g = ( int )( mColor1.green() + value * ( mColor2.green() - mColor1.green() ) );
- int b = ( int )( mColor1.blue() + value * ( mColor2.blue() - mColor1.blue() ) );
+ int r = ( int )( c1.red() + value * ( c2.red() - c1.red() ) );
+ int g = ( int )( c1.green() + value * ( c2.green() - c1.green() ) );
+ int b = ( int )( c1.blue() + value * ( c2.blue() - c1.blue() ) );
return QColor::fromRgb( r, g, b );
}
+QColor QgsVectorGradientColorRampV2::color( double value ) const
+{
+ if ( mStops.isEmpty() )
+ {
+ return _interpolate( mColor1, mColor2, value );
+ }
+ else
+ {
+ double lower = 0, upper;
+ QColor c1 = mColor1, c2;
+ for ( StopsMap::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
+ {
+ if ( it.key() >= value )
+ {
+ upper = it.key();
+ c2 = it.value();
+
+ return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
+ }
+ lower = it.key();
+ c1 = it.value();
+ }
+
+ upper = 1;
+ c2 = mColor2;
+ return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
+ }
+}
+
QgsVectorColorRampV2* QgsVectorGradientColorRampV2::clone() const
{
- return new QgsVectorGradientColorRampV2( mColor1, mColor2 );
+ QgsVectorGradientColorRampV2* r = new QgsVectorGradientColorRampV2( mColor1, mColor2 );
+ r->setStops( mStops );
+ return r;
}
QgsStringMap QgsVectorGradientColorRampV2::properties() const
@@ -40,6 +87,15 @@
QgsStringMap map;
map["color1"] = QgsSymbolLayerV2Utils::encodeColor( mColor1 );
map["color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
+ if ( !mStops.isEmpty() )
+ {
+ QStringList lst;
+ for ( StopsMap::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
+ {
+ lst.append( QString( "%1;%2" ).arg( it.key() ).arg( QgsSymbolLayerV2Utils::encodeColor( it.value() ) ) );
+ }
+ map["stops"] = lst.join( ":" );
+ }
return map;
}
Modified: trunk/qgis/src/core/symbology-ng/qgsvectorcolorrampv2.h
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgsvectorcolorrampv2.h 2010-04-20 11:51:20 UTC (rev 13332)
+++ trunk/qgis/src/core/symbology-ng/qgsvectorcolorrampv2.h 2010-04-20 12:25:42 UTC (rev 13333)
@@ -46,8 +46,14 @@
void setColor1( QColor color ) { mColor1 = color; }
void setColor2( QColor color ) { mColor2 = color; }
+ typedef QMap<double, QColor> StopsMap;
+
+ void setStops( const StopsMap& stops ) { mStops = stops; }
+ const StopsMap& stops() const { return mStops; }
+
protected:
QColor mColor1, mColor2;
+ StopsMap mStops;
};
#define DEFAULT_RANDOM_COUNT 10
Modified: trunk/qgis/src/gui/symbology-ng/qgsvectorgradientcolorrampv2dialog.cpp
===================================================================
--- trunk/qgis/src/gui/symbology-ng/qgsvectorgradientcolorrampv2dialog.cpp 2010-04-20 11:51:20 UTC (rev 13332)
+++ trunk/qgis/src/gui/symbology-ng/qgsvectorgradientcolorrampv2dialog.cpp 2010-04-20 12:25:42 UTC (rev 13333)
@@ -4,8 +4,9 @@
#include "qgsvectorcolorrampv2.h"
#include <QColorDialog>
+#include <QInputDialog>
+#include <QPainter>
-
QgsVectorGradientColorRampV2Dialog::QgsVectorGradientColorRampV2Dialog( QgsVectorGradientColorRampV2* ramp, QWidget* parent )
: QDialog( parent ), mRamp( ramp )
{
@@ -15,11 +16,54 @@
connect( btnColor1, SIGNAL( clicked() ), this, SLOT( setColor1() ) );
connect( btnColor2, SIGNAL( clicked() ), this, SLOT( setColor2() ) );
+ // handle stops
+ QgsVectorGradientColorRampV2::StopsMap stops = ramp->stops();
+ groupStops->setChecked( !stops.isEmpty() );
+
+ QgsVectorGradientColorRampV2::StopsMap::iterator i;
+ QList<QTreeWidgetItem *> items;
+ for ( i = stops.begin(); i != stops.end(); ++i )
+ {
+ QStringList lst;
+ lst << "." << QString::number( i.key()*100, 'f', 0 );
+ QTreeWidgetItem* item = new QTreeWidgetItem( lst );
+
+ setStopColor( item, i.value() );
+ item->setData( 0, StopOffsetRole, i.key() );
+
+ items.append( item );
+ }
+ treeStops->insertTopLevelItems( 0, items );
+ treeStops->resizeColumnToContents( 0 );
+ treeStops->sortByColumn( 1, Qt::AscendingOrder );
+ treeStops->setSortingEnabled( true );
+
+ connect( groupStops, SIGNAL( toggled( bool ) ), this, SLOT( toggledStops( bool ) ) );
+ connect( btnAddStop, SIGNAL( clicked() ), this, SLOT( addStop() ) );
+ connect( btnRemoveStop, SIGNAL( clicked() ), this, SLOT( removeStop() ) );
+ connect( treeStops, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( stopDoubleClicked( QTreeWidgetItem*, int ) ) );
+
updatePreview();
}
void QgsVectorGradientColorRampV2Dialog::updatePreview()
{
+ // update ramp stops from the tree widget
+ QgsVectorGradientColorRampV2::StopsMap map;
+ if ( groupStops->isChecked() )
+ {
+ int count = treeStops->topLevelItemCount();
+ for ( int i = 0; i < count; i++ )
+ {
+ QTreeWidgetItem* item = treeStops->topLevelItem( i );
+ double key = item->data( 0, StopOffsetRole ).toDouble();
+ QColor c = item->data( 0, StopColorRole ).value<QColor>();
+ map.insert( key, c );
+ }
+ }
+ mRamp->setStops( map );
+
+ // generate the preview
QSize size( 300, 40 );
lblPreview->setPixmap( QgsSymbolLayerV2Utils::colorRampPreviewPixmap( mRamp, size ) );
@@ -44,3 +88,100 @@
mRamp->setColor2( color );
updatePreview();
}
+
+void QgsVectorGradientColorRampV2Dialog::setStopColor( QTreeWidgetItem* item, QColor color )
+{
+ QSize iconSize( 16, 16 );
+ QPixmap pixmap( iconSize );
+ pixmap.fill( QColor( 0, 0, 0, 0 ) );
+ QRect rect( 1, 1, iconSize.width() - 2, iconSize.height() - 2 );
+
+ // draw a slightly rounded rectangle
+ QPainter p;
+ p.begin( &pixmap );
+ p.setPen( Qt::NoPen );
+ p.setRenderHint( QPainter::Antialiasing );
+ p.setBrush( color );
+ p.drawRoundedRect( rect, 4, 4 );
+ p.end();
+
+ item->setIcon( 0, QIcon( pixmap ) );
+ item->setData( 0, StopColorRole, color );
+ item->setText( 0, color.name() );
+}
+
+void QgsVectorGradientColorRampV2Dialog::stopDoubleClicked( QTreeWidgetItem* item, int column )
+{
+ if ( column == 0 )
+ {
+ QColor color = QColorDialog::getColor( item->data( 0, StopColorRole ).value<QColor>(), this );
+ if ( !color.isValid() )
+ return;
+ setStopColor( item, color );
+
+ updatePreview();
+ }
+ else
+ {
+ bool ok;
+ double key = item->data( 0, StopOffsetRole ).toDouble();
+ int val = ( int )( key * 100 );
+ val = QInputDialog::getInt( this, tr( "Offset of the stop" ),
+ tr( "Please enter offset in percents (%) of the new stop" ),
+ val, 0, 100, 1, &ok );
+ if ( !ok )
+ return;
+
+ double newkey = val / 100.0;
+ item->setText( 1, QString::number( val ) );
+
+ item->setData( 0, StopOffsetRole, newkey );
+
+ updatePreview();
+ }
+}
+
+void QgsVectorGradientColorRampV2Dialog::addStop()
+{
+ QColor color = QColorDialog::getColor( QColor(), this );
+ if ( !color.isValid() )
+ return;
+
+ bool ok;
+ int val = 50;
+ val = QInputDialog::getInt( this, tr( "Offset of the stop" ),
+ tr( "Please enter offset in percents (%) of the new stop" ),
+ val, 0, 100, 1, &ok );
+ if ( !ok )
+ return;
+
+ double key = val / 100.0;
+ QStringList lst;
+ lst << "." << QString::number( val, 'f', 0 );
+ QTreeWidgetItem* item = new QTreeWidgetItem( lst );
+
+ setStopColor( item, color );
+ item->setData( 0, StopOffsetRole, key );
+
+ treeStops->addTopLevelItem( item );
+
+ treeStops->resizeColumnToContents( 0 );
+
+ updatePreview();
+}
+
+void QgsVectorGradientColorRampV2Dialog::removeStop()
+{
+ QTreeWidgetItem* item = treeStops->currentItem();
+ if ( !item )
+ return;
+ int index = treeStops->indexOfTopLevelItem( item );
+ treeStops->takeTopLevelItem( index );
+
+ updatePreview();
+}
+
+void QgsVectorGradientColorRampV2Dialog::toggledStops( bool on )
+{
+ updatePreview();
+}
Modified: trunk/qgis/src/gui/symbology-ng/qgsvectorgradientcolorrampv2dialog.h
===================================================================
--- trunk/qgis/src/gui/symbology-ng/qgsvectorgradientcolorrampv2dialog.h 2010-04-20 11:51:20 UTC (rev 13332)
+++ trunk/qgis/src/gui/symbology-ng/qgsvectorgradientcolorrampv2dialog.h 2010-04-20 12:25:42 UTC (rev 13333)
@@ -19,11 +19,21 @@
void setColor1();
void setColor2();
+ void toggledStops( bool on );
+ void addStop();
+ void removeStop();
+
+ void stopDoubleClicked( QTreeWidgetItem* item, int column );
+
protected:
void updatePreview();
+ void setStopColor( QTreeWidgetItem* item, QColor color );
QgsVectorGradientColorRampV2* mRamp;
+
+ static const int StopColorRole = Qt::UserRole + 1;
+ static const int StopOffsetRole = Qt::UserRole + 2;
};
#endif
Modified: trunk/qgis/src/ui/qgsvectorgradientcolorrampv2dialogbase.ui
===================================================================
--- trunk/qgis/src/ui/qgsvectorgradientcolorrampv2dialogbase.ui 2010-04-20 11:51:20 UTC (rev 13332)
+++ trunk/qgis/src/ui/qgsvectorgradientcolorrampv2dialogbase.ui 2010-04-20 12:25:42 UTC (rev 13333)
@@ -7,13 +7,13 @@
<x>0</x>
<y>0</y>
<width>400</width>
- <height>300</height>
+ <height>364</height>
</rect>
</property>
<property name="windowTitle">
<string>Gradient color ramp</string>
</property>
- <layout class="QVBoxLayout">
+ <layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout">
<item row="0" column="0">
@@ -63,20 +63,53 @@
</layout>
</item>
<item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
+ <widget class="QGroupBox" name="groupStops">
+ <property name="title">
+ <string>Multiple stops</string>
</property>
- <property name="sizeType">
- <enum>QSizePolicy::Preferred</enum>
+ <property name="checkable">
+ <bool>true</bool>
</property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
+ <property name="checked">
+ <bool>false</bool>
</property>
- </spacer>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QPushButton" name="btnAddStop">
+ <property name="text">
+ <string>Add stop</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="btnRemoveStop">
+ <property name="text">
+ <string>Remove stop</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" rowspan="2">
+ <widget class="QTreeWidget" name="treeStops">
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="columnCount">
+ <number>2</number>
+ </property>
+ <column>
+ <property name="text">
+ <string>Color</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Offset</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
More information about the QGIS-commit
mailing list