[QGIS Commit] r12248 - in trunk/qgis: images/themes/default src/app
src/app/composer src/core src/core/composer src/gui src/ui
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Wed Nov 25 05:17:29 EST 2009
Author: mhugent
Date: 2009-11-25 05:17:28 -0500 (Wed, 25 Nov 2009)
New Revision: 12248
Added:
trunk/qgis/images/themes/default/mActionAddArrow.png
trunk/qgis/src/app/composer/qgscomposerarrowwidget.cpp
trunk/qgis/src/app/composer/qgscomposerarrowwidget.h
trunk/qgis/src/core/composer/qgscomposerarrow.cpp
trunk/qgis/src/core/composer/qgscomposerarrow.h
Modified:
trunk/qgis/src/app/CMakeLists.txt
trunk/qgis/src/app/composer/qgscomposer.cpp
trunk/qgis/src/app/composer/qgscomposer.h
trunk/qgis/src/core/CMakeLists.txt
trunk/qgis/src/gui/qgscomposerview.cpp
trunk/qgis/src/gui/qgscomposerview.h
trunk/qgis/src/ui/qgscomposerbase.ui
Log:
[FEATURE]: arrow item for composer. Custom arrow heads from svg files are planned for the near future
Added: trunk/qgis/images/themes/default/mActionAddArrow.png
===================================================================
(Binary files differ)
Property changes on: trunk/qgis/images/themes/default/mActionAddArrow.png
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:mime-type
+ application/octet-stream
Modified: trunk/qgis/src/app/CMakeLists.txt
===================================================================
--- trunk/qgis/src/app/CMakeLists.txt 2009-11-25 10:00:05 UTC (rev 12247)
+++ trunk/qgis/src/app/CMakeLists.txt 2009-11-25 10:17:28 UTC (rev 12248)
@@ -73,6 +73,7 @@
qgsquerybuilder.cpp
composer/qgscomposer.cpp
+ composer/qgscomposerarrowwidget.cpp
composer/qgscomposeritemwidget.cpp
composer/qgscomposerlabelwidget.cpp
composer/qgscomposerpicturewidget.cpp
@@ -171,6 +172,7 @@
qgsquerybuilder.h
composer/qgscomposer.h
+ composer/qgscomposerarrowwidget.h
composer/qgscomposeritemwidget.h
composer/qgscomposerlabelwidget.h
composer/qgscomposerlegendwidget.h
Modified: trunk/qgis/src/app/composer/qgscomposer.cpp
===================================================================
--- trunk/qgis/src/app/composer/qgscomposer.cpp 2009-11-25 10:00:05 UTC (rev 12247)
+++ trunk/qgis/src/app/composer/qgscomposer.cpp 2009-11-25 10:17:28 UTC (rev 12248)
@@ -21,6 +21,8 @@
#include "qgscomposerview.h"
#include "qgscomposition.h"
#include "qgscompositionwidget.h"
+#include "qgscomposerarrow.h"
+#include "qgscomposerarrowwidget.h"
#include "qgscomposerlabel.h"
#include "qgscomposerlabelwidget.h"
#include "qgscomposerlegend.h"
@@ -109,6 +111,7 @@
toggleActionGroup->addAction( mActionAddImage );
toggleActionGroup->addAction( mActionSelectMoveItem );
toggleActionGroup->addAction( mActionAddBasicShape );
+ toggleActionGroup->addAction( mActionAddArrow );
toggleActionGroup->setExclusive( true );
mActionAddNewMap->setCheckable( true );
@@ -119,6 +122,7 @@
mActionAddImage->setCheckable( true );
mActionMoveItemContent->setCheckable( true );
mActionAddBasicShape->setCheckable( true );
+ mActionAddArrow->setCheckable( true );
#ifdef Q_WS_MAC
QMenu *appMenu = menuBar()->addMenu( tr( "QGIS" ) );
@@ -155,6 +159,7 @@
layoutMenu->addAction( mActionSelectMoveItem );
layoutMenu->addAction( mActionMoveItemContent );
layoutMenu->addAction( mActionAddBasicShape );
+ layoutMenu->addAction( mActionAddArrow );
layoutMenu->addSeparator();
layoutMenu->addAction( mActionGroupItems );
layoutMenu->addAction( mActionUngroupItems );
@@ -249,6 +254,7 @@
mActionAddNewLegend->setIcon( QgisApp::getThemeIcon( "/mActionAddLegend.png" ) );
mActionAddNewScalebar->setIcon( QgisApp::getThemeIcon( "/mActionScaleBar.png" ) );
mActionAddBasicShape->setIcon( QgisApp::getThemeIcon( "/mActionAddBasicShape.png" ) );
+ mActionAddArrow->setIcon( QgisApp::getThemeIcon( "/mActionAddArrow.png" ) );
mActionSelectMoveItem->setIcon( QgisApp::getThemeIcon( "/mActionSelectPan.png" ) );
mActionMoveItemContent->setIcon( QgisApp::getThemeIcon( "/mActionMoveItemContent.png" ) );
mActionGroupItems->setIcon( QgisApp::getThemeIcon( "/mActionGroupItems.png" ) );
@@ -275,6 +281,7 @@
connect( mView, SIGNAL( composerLegendAdded( QgsComposerLegend* ) ), this, SLOT( addComposerLegend( QgsComposerLegend* ) ) );
connect( mView, SIGNAL( composerPictureAdded( QgsComposerPicture* ) ), this, SLOT( addComposerPicture( QgsComposerPicture* ) ) );
connect( mView, SIGNAL( composerShapeAdded( QgsComposerShape* ) ), this, SLOT( addComposerShape( QgsComposerShape* ) ) );
+ connect( mView, SIGNAL( composerArrowAdded( QgsComposerArrow* ) ), this, SLOT( addComposerArrow( QgsComposerArrow* ) ) );
connect( mView, SIGNAL( actionFinished() ), this, SLOT( setSelectionTool() ) );
}
@@ -805,6 +812,14 @@
}
}
+void QgsComposer::on_mActionAddArrow_triggered()
+{
+ if ( mView )
+ {
+ mView->setCurrentTool( QgsComposerView::AddArrow );
+ }
+}
+
void QgsComposer::on_mActionSaveAsTemplate_triggered()
{
//show file dialog
@@ -1217,6 +1232,21 @@
showItemOptions( newShape );
}
+ //composer arrows
+ QDomNodeList composerArrowList = composerElem.elementsByTagName( "ComposerArrow" );
+ for ( int i = 0; i < composerArrowList.size(); ++i )
+ {
+ QDomElement currentArrowElem = composerArrowList.at( i ).toElement();
+ QgsComposerArrow* newArrow = new QgsComposerArrow( mComposition );
+ newArrow->readXML( currentArrowElem, doc );
+ addComposerArrow( newArrow );
+ mComposition->addItem( newArrow );
+ mComposition->update();
+ mComposition->clearSelection();
+ newArrow->setSelected( true );
+ showItemOptions( newArrow );
+ }
+
mComposition->sortZList();
mView->setComposition( mComposition );
@@ -1235,6 +1265,17 @@
mItemWidgetMap.clear();
}
+void QgsComposer::addComposerArrow( QgsComposerArrow* arrow )
+{
+ if ( !arrow )
+ {
+ return;
+ }
+
+ QgsComposerArrowWidget* arrowWidget = new QgsComposerArrowWidget( arrow );
+ mItemWidgetMap.insert( arrow, arrowWidget );
+}
+
void QgsComposer::addComposerMap( QgsComposerMap* map )
{
if ( !map )
Modified: trunk/qgis/src/app/composer/qgscomposer.h
===================================================================
--- trunk/qgis/src/app/composer/qgscomposer.h 2009-11-25 10:00:05 UTC (rev 12247)
+++ trunk/qgis/src/app/composer/qgscomposer.h 2009-11-25 10:17:28 UTC (rev 12248)
@@ -22,6 +22,7 @@
#include "qgscontexthelp.h"
class QgisApp;
+class QgsComposerArrow;
class QgsComposerLabel;
class QgsComposerLegend;
class QgsComposerMap;
@@ -128,6 +129,9 @@
//! Select item
void on_mActionSelectMoveItem_triggered();
+ //! Add arrow
+ void on_mActionAddArrow_triggered();
+
//! Add new map
void on_mActionAddNewMap_triggered();
@@ -193,6 +197,9 @@
//! Save window state
void saveWindowState();
+ /**Add a composer arrow to the item/widget map and crete a configuration widget for it*/
+ void addComposerArrow( QgsComposerArrow* arrow );
+
/**Add a composer map to the item/widget map and creates a configuration widget for it*/
void addComposerMap( QgsComposerMap* map );
Added: trunk/qgis/src/app/composer/qgscomposerarrowwidget.cpp
===================================================================
--- trunk/qgis/src/app/composer/qgscomposerarrowwidget.cpp (rev 0)
+++ trunk/qgis/src/app/composer/qgscomposerarrowwidget.cpp 2009-11-25 10:17:28 UTC (rev 12248)
@@ -0,0 +1,121 @@
+/***************************************************************************
+ qgscomposerarrowwidget.cpp
+ --------------------------
+ begin : November 2009
+ copyright : (C) 2009 by Marco Hugentobler
+ email : marco at hugis.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 "qgscomposerarrowwidget.h"
+#include "qgscomposerarrow.h"
+#include "qgscomposeritemwidget.h"
+#include <QColorDialog>
+
+QgsComposerArrowWidget::QgsComposerArrowWidget( QgsComposerArrow* arrow ): QWidget( 0 ), mArrow( arrow )
+{
+ setupUi( this );
+
+ //add widget for general composer item properties
+ QgsComposerItemWidget* itemPropertiesWidget = new QgsComposerItemWidget( this, mArrow );
+ toolBox->addItem( itemPropertiesWidget, tr( "General options" ) );
+
+ setGuiElementValues();
+}
+
+QgsComposerArrowWidget::~QgsComposerArrowWidget()
+{
+
+}
+
+void QgsComposerArrowWidget::on_mOutlineWidthSpinBox_valueChanged( double d )
+{
+ if ( !mArrow )
+ {
+ return;
+ }
+
+ mArrow->setOutlineWidth( d );
+ mArrow->update();
+}
+
+void QgsComposerArrowWidget::on_mArrowHeadWidthSpinBox_valueChanged( double d )
+{
+ if ( !mArrow )
+ {
+ return;
+ }
+
+ mArrow->setArrowHeadWidth( d );
+ mArrow->update();
+}
+
+void QgsComposerArrowWidget::on_mShowArrowHeadCheckBox_stateChanged( int state )
+{
+ if ( !mArrow )
+ {
+ return;
+ }
+
+ if ( state == Qt::Checked )
+ {
+ mArrow->setShowArrowMarker( true );
+ }
+ else
+ {
+ mArrow->setShowArrowMarker( false );
+ }
+ mArrow->update();
+}
+
+void QgsComposerArrowWidget::on_mArrowColorButton_clicked()
+{
+ if ( !mArrow )
+ {
+ return;
+ }
+
+ QColor newColor = QColorDialog::getColor( mArrow->arrowColor(), 0, tr( "Arrow color" ), QColorDialog::ShowAlphaChannel );
+ if ( newColor.isValid() )
+ {
+ mArrow->setArrowColor( newColor );
+ mArrow->update();
+ }
+}
+
+void QgsComposerArrowWidget::blockAllSignals( bool block )
+{
+ mArrowColorButton->blockSignals( block );
+ mShowArrowHeadCheckBox->blockSignals( block );
+ mOutlineWidthSpinBox->blockSignals( block );
+ mArrowHeadWidthSpinBox->blockSignals( block );
+}
+
+void QgsComposerArrowWidget::setGuiElementValues()
+{
+ if ( !mArrow )
+ {
+ return;
+ }
+
+ blockAllSignals( true );
+ mOutlineWidthSpinBox->setValue( mArrow->outlineWidth() );
+ mArrowHeadWidthSpinBox->setValue( mArrow->arrowHeadWidth() );
+ if ( mArrow->showArrowMarker() )
+ {
+ mShowArrowHeadCheckBox->setCheckState( Qt::Checked );
+ }
+ else
+ {
+ mShowArrowHeadCheckBox->setCheckState( Qt::Unchecked );
+ }
+ blockAllSignals( false );
+}
Added: trunk/qgis/src/app/composer/qgscomposerarrowwidget.h
===================================================================
--- trunk/qgis/src/app/composer/qgscomposerarrowwidget.h (rev 0)
+++ trunk/qgis/src/app/composer/qgscomposerarrowwidget.h 2009-11-25 10:17:28 UTC (rev 12248)
@@ -0,0 +1,45 @@
+/***************************************************************************
+ qgscomposerarrowwidget.h
+ ------------------------
+ begin : November 2009
+ copyright : (C) 2009 by Marco Hugentobler
+ email : marco at hugis.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 QGSCOMPOSERARROWWIDGET_H
+#define QGSCOMPOSERARROWWIDGET_H
+
+#include "ui_qgscomposerarrowwidgetbase.h"
+
+class QgsComposerArrow;
+
+class QgsComposerArrowWidget: public QWidget, private Ui::QgsComposerArrowWidgetBase
+{
+ Q_OBJECT
+ public:
+ QgsComposerArrowWidget( QgsComposerArrow* arrow );
+ ~QgsComposerArrowWidget();
+
+ private:
+ QgsComposerArrow* mArrow;
+
+ void blockAllSignals( bool block );
+ void setGuiElementValues();
+
+ private slots:
+ void on_mOutlineWidthSpinBox_valueChanged( double d );
+ void on_mArrowHeadWidthSpinBox_valueChanged( double d );
+ void on_mShowArrowHeadCheckBox_stateChanged( int state );
+ void on_mArrowColorButton_clicked();
+};
+
+#endif // QGSCOMPOSERARROWWIDGET_H
Modified: trunk/qgis/src/core/CMakeLists.txt
===================================================================
--- trunk/qgis/src/core/CMakeLists.txt 2009-11-25 10:00:05 UTC (rev 12247)
+++ trunk/qgis/src/core/CMakeLists.txt 2009-11-25 10:17:28 UTC (rev 12248)
@@ -70,6 +70,7 @@
qgsvectorlayerundocommand.cpp
qgsvectoroverlay.cpp
+ composer/qgscomposerarrow.cpp
composer/qgscomposeritem.cpp
composer/qgscomposeritemgroup.cpp
composer/qgscomposerlabel.cpp
Added: trunk/qgis/src/core/composer/qgscomposerarrow.cpp
===================================================================
--- trunk/qgis/src/core/composer/qgscomposerarrow.cpp (rev 0)
+++ trunk/qgis/src/core/composer/qgscomposerarrow.cpp 2009-11-25 10:17:28 UTC (rev 12248)
@@ -0,0 +1,384 @@
+/***************************************************************************
+ qgscomposerarrow.cpp
+ ----------------------
+ begin : November 2009
+ copyright : (C) 2009 by Marco Hugentobler
+ email : marco at hugis.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 "qgscomposerarrow.h"
+#include <QPainter>
+#include <QSvgRenderer>
+
+#ifndef Q_OS_MACX
+#include <cmath>
+#else
+#include <math.h>
+#endif
+
+QgsComposerArrow::QgsComposerArrow( QgsComposition* c ): QgsComposerItem( c ), mStartPoint( 0, 0 ), mStopPoint( 0, 0 ), mArrowColor( QColor( 0, 0, 0 ) )
+{
+ initGraphicsSettings();
+}
+
+QgsComposerArrow::QgsComposerArrow( const QPointF& startPoint, const QPointF& stopPoint, QgsComposition* c ): QgsComposerItem( c ), mStartPoint( startPoint ), \
+ mStopPoint( stopPoint ), mArrowColor( QColor( 0, 0, 0 ) )
+{
+ //setStartMarker( "/home/marco/src/qgis/images/svg/north_arrows/NorthArrow11.svg" );
+ //setEndMarker( "/home/marco/src/qgis/images/svg/north_arrows/NorthArrow11.svg" );
+ initGraphicsSettings();
+ adaptItemSceneRect();
+}
+
+QgsComposerArrow::~QgsComposerArrow()
+{
+
+}
+
+void QgsComposerArrow::initGraphicsSettings()
+{
+ setArrowHeadWidth( 4 );
+ mPen.setColor( QColor( 0, 0, 0 ) );
+ mPen.setWidthF( 1 );
+ mShowArrowMarker = true;
+
+ //set composer item brush and pen to transparent white by default
+ setPen( QPen( QColor( 255, 255, 255, 0 ) ) );
+ setBrush( QBrush( QColor( 255, 255, 255, 0 ) ) );
+}
+
+void QgsComposerArrow::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
+{
+ if ( !painter )
+ {
+ return;
+ }
+
+ drawBackground( painter );
+
+ //draw arrow
+ QPen arrowPen = mPen;
+ arrowPen.setCapStyle( Qt::FlatCap );
+ arrowPen.setColor( mArrowColor );
+ painter->setPen( arrowPen );
+ painter->setBrush( QBrush( mArrowColor ) );
+ painter->drawLine( QPointF( mStartPoint.x() - transform().dx(), mStartPoint.y() - transform().dy() ), QPointF( mStopPoint.x() - transform().dx(), mStopPoint.y() - transform().dy() ) );
+
+ if ( mShowArrowMarker )
+ {
+ drawHardcodedMarker( painter, EndMarker );
+ //drawSVGMarker( painter, StartMarker, mStartMarkerFile );
+ //drawSVGMarker( painter, EndMarker, mEndMarkerFile );
+ }
+
+ drawFrame( painter );
+ if ( isSelected() )
+ {
+ drawSelectionBoxes( painter );
+ }
+}
+
+void QgsComposerArrow::QgsComposerArrow::setSceneRect( const QRectF& rectangle )
+{
+ //maintain the relative position of start and stop point in the rectangle
+ double startPointXPos = ( mStartPoint.x() - transform().dx() ) / rect().width();
+ double startPointYPos = ( mStartPoint.y() - transform().dy() ) / rect().height();
+ double stopPointXPos = ( mStopPoint.x() - transform().dx() ) / rect().width();
+ double stopPointYPos = ( mStopPoint.y() - transform().dy() ) / rect().height();
+
+ mStartPoint.setX( rectangle.left() + startPointXPos * rectangle.width() );
+ mStartPoint.setY( rectangle.top() + startPointYPos * rectangle.height() );
+ mStopPoint.setX( rectangle.left() + stopPointXPos * rectangle.width() );
+ mStopPoint.setY( rectangle.top() + stopPointYPos * rectangle.height() );
+
+ adaptItemSceneRect();
+}
+
+void QgsComposerArrow::drawHardcodedMarker( QPainter* p, MarkerType type )
+{
+ double angle = arrowAngle();
+ //qWarning(QString::number(angle).toLocal8Bit().data());
+ double angleRad = angle / 180.0 * M_PI;
+ QPointF middlePoint = QPointF( mStopPoint.x() - transform().dx(), mStopPoint.y() - transform().dy() );
+
+ //rotate both arrow points
+ QPointF p1 = QPointF( -mArrowHeadWidth / 2.0, mArrowHeadWidth );
+ QPointF p2 = QPointF( mArrowHeadWidth / 2.0, mArrowHeadWidth );
+
+ QPointF p1Rotated, p2Rotated;
+ p1Rotated.setX( p1.x() * cos( angleRad ) + p1.y() * -sin( angleRad ) );
+ p1Rotated.setY( p1.x() * sin( angleRad ) + p1.y() * cos( angleRad ) );
+ p2Rotated.setX( p2.x() * cos( angleRad ) + p2.y() * -sin( angleRad ) );
+ p2Rotated.setY( p2.x() * sin( angleRad ) + p2.y() * cos( angleRad ) );
+
+ QPolygonF arrowHeadPoly;
+ arrowHeadPoly << middlePoint;
+ arrowHeadPoly << QPointF( middlePoint.x() + p1Rotated.x(), middlePoint.y() + p1Rotated.y() );
+ arrowHeadPoly << QPointF( middlePoint.x() + p2Rotated.x(), middlePoint.y() + p2Rotated.y() );
+
+ p->save();
+
+ QPen arrowPen = p->pen();
+ arrowPen.setJoinStyle( Qt::RoundJoin );
+ QBrush arrowBrush = p->brush();
+ arrowBrush.setColor( mArrowColor );
+ arrowBrush.setStyle( Qt::SolidPattern );
+ p->setPen( arrowPen );
+ p->setBrush( arrowBrush );
+ p->drawPolygon( arrowHeadPoly );
+
+ p->restore();
+}
+
+void QgsComposerArrow::drawSVGMarker( QPainter* p, MarkerType type, const QString& markerPath )
+{
+ double angle = arrowAngle();
+
+ double arrowHeadHeight;
+ if ( type == StartMarker )
+ {
+ arrowHeadHeight = mStartArrowHeadHeight;
+ }
+ else
+ {
+ arrowHeadHeight = mStopArrowHeadHeight;
+ }
+
+ //prepare paint device
+ int dpi = ( p->device()->logicalDpiX() + p->device()->logicalDpiY() ) / 2;
+ int imageWidth = mArrowHeadWidth / 25.4 * dpi;
+ int imageHeight = arrowHeadHeight / 25.4 * dpi;
+ QImage markerImage( imageWidth, imageHeight, QImage::Format_ARGB32 );
+
+ QPointF imageFixPoint;
+ imageFixPoint.setX( mArrowHeadWidth / 2.0 );
+ QPointF canvasPoint;
+ if ( type == StartMarker )
+ {
+ canvasPoint = QPointF( mStartPoint.x() - transform().dx(), mStartPoint.y() - transform().dy() );
+ imageFixPoint.setY( mStartArrowHeadHeight );
+ }
+ else //end marker
+ {
+ canvasPoint = QPointF( mStopPoint.x() - transform().dx(), mStopPoint.y() - transform().dy() );
+ imageFixPoint.setY( 0 );
+ }
+
+ //rasterize svg
+ QSvgRenderer r;
+ if ( type == StartMarker )
+ {
+ if ( !r.load( mStartMarkerFile ) )
+ {
+ return;
+ }
+ }
+ else //end marker
+ {
+ if ( !r.load( mEndMarkerFile ) )
+ {
+ return;
+ }
+ }
+
+ //rotate image fix point for backtransform
+ QPointF fixPoint;
+ if ( type == StartMarker )
+ {
+ fixPoint.setX( 0 ); fixPoint.setY( arrowHeadHeight / 2.0 );
+ }
+ else
+ {
+ fixPoint.setX( 0 ); fixPoint.setY( -arrowHeadHeight / 2.0 );
+ }
+ QPointF rotatedFixPoint;
+ double angleRad = angle / 180 * M_PI;
+ rotatedFixPoint.setX( fixPoint.x() * cos( angleRad ) + fixPoint.y() * sin( angleRad ) );
+ rotatedFixPoint.setY( fixPoint.x() * -sin( angleRad ) + fixPoint.y() * cos( angleRad ) );
+
+
+ QPainter imagePainter( &markerImage );
+ r.render( &imagePainter );
+
+ p->save();
+ p->translate( canvasPoint.x() - rotatedFixPoint.x() , canvasPoint.y() - rotatedFixPoint.y() );
+ p->rotate( angle );
+ p->translate( -mArrowHeadWidth / 2.0, -arrowHeadHeight / 2.0 );
+
+ p->drawImage( QRectF( 0, 0, mArrowHeadWidth, arrowHeadHeight ), markerImage, QRectF( 0, 0, imageWidth, imageHeight ) );
+ p->restore();
+
+ return;
+}
+
+double QgsComposerArrow::arrowAngle() const
+{
+ double xDiff = mStopPoint.x() - mStartPoint.x();
+ double yDiff = mStopPoint.y() - mStartPoint.y();
+ double length = sqrt( xDiff * xDiff + yDiff * yDiff );
+
+ double angle = acos(( -yDiff * length ) / ( length * length ) ) * 180 / M_PI;
+ if ( xDiff < 0 )
+ {
+ return ( 360 - angle );
+ }
+ return angle;
+}
+
+void QgsComposerArrow::setStartMarker( const QString& svgPath )
+{
+ QSvgRenderer r;
+ if ( !r.load( svgPath ) )
+ {
+ return;
+ mStartArrowHeadHeight = 0;
+ }
+ mStartMarkerFile = svgPath;
+
+ //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
+ QRect viewBox = r.viewBox();
+ mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
+ adaptItemSceneRect();
+}
+
+void QgsComposerArrow::setEndMarker( const QString& svgPath )
+{
+ QSvgRenderer r;
+ if ( !r.load( svgPath ) )
+ {
+ return;
+ mStopArrowHeadHeight = 0;
+ }
+ mEndMarkerFile = svgPath;
+
+ //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
+ QRect viewBox = r.viewBox();
+ mStopArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
+ adaptItemSceneRect();
+}
+
+void QgsComposerArrow::setOutlineWidth( double width )
+{
+ mPen.setWidthF( width );
+ adaptItemSceneRect();
+}
+
+void QgsComposerArrow::setArrowHeadWidth( double width )
+{
+ mArrowHeadWidth = width;
+ adaptItemSceneRect();
+}
+
+void QgsComposerArrow::setShowArrowMarker( bool show )
+{
+ mShowArrowMarker = show;
+ adaptItemSceneRect();
+}
+
+void QgsComposerArrow::adaptItemSceneRect()
+{
+ //rectangle containing start and end point
+ QRectF rect = QRectF( std::min( mStartPoint.x(), mStopPoint.x() ), std::min( mStartPoint.y(), mStopPoint.y() ), \
+ std::abs( mStopPoint.x() - mStartPoint.x() ), std::abs( mStopPoint.y() - mStartPoint.y() ) );
+ double enlarge;
+ if ( mShowArrowMarker )
+ {
+ double maxArrowHeight = std::max( mStartArrowHeadHeight, mStopArrowHeadHeight );
+ enlarge = mPen.widthF() / 2 + std::max( mArrowHeadWidth / 2.0, maxArrowHeight / 2.0 );
+ }
+ else
+ {
+ enlarge = mPen.widthF() / 2.0;
+ }
+ rect.adjust( -enlarge, -enlarge, enlarge, enlarge );
+ QgsComposerItem::setSceneRect( rect );
+}
+
+bool QgsComposerArrow::writeXML( QDomElement& elem, QDomDocument & doc ) const
+{
+ QDomElement composerArrowElem = doc.createElement( "ComposerArrow" );
+ composerArrowElem.setAttribute( "outlineWidth", outlineWidth() );
+ composerArrowElem.setAttribute( "showArrowMarker", mShowArrowMarker );
+ composerArrowElem.setAttribute( "arrowHeadWidth", mArrowHeadWidth );
+
+ //arrow color
+ QDomElement arrowColorElem = doc.createElement( "ArrowColor" );
+ arrowColorElem.setAttribute( "red", mArrowColor.red() );
+ arrowColorElem.setAttribute( "green", mArrowColor.green() );
+ arrowColorElem.setAttribute( "blue", mArrowColor.blue() );
+ arrowColorElem.setAttribute( "alpha", mArrowColor.alpha() );
+ composerArrowElem.appendChild( arrowColorElem );
+
+ //start point
+ QDomElement startPointElem = doc.createElement( "StartPoint" );
+ startPointElem.setAttribute( "x", mStartPoint.x() );
+ startPointElem.setAttribute( "y", mStartPoint.y() );
+ composerArrowElem.appendChild( startPointElem );
+
+ //stop point
+ QDomElement stopPointElem = doc.createElement( "StopPoint" );
+ stopPointElem.setAttribute( "x", mStopPoint.x() );
+ stopPointElem.setAttribute( "y", mStopPoint.y() );
+ composerArrowElem.appendChild( stopPointElem );
+
+ elem.appendChild( composerArrowElem );
+ return true;
+}
+
+bool QgsComposerArrow::readXML( const QDomElement& itemElem, const QDomDocument& doc )
+{
+ mShowArrowMarker = itemElem.attribute( "showArrowMarker", "1" ).toInt();
+ mArrowHeadWidth = itemElem.attribute( "arrowHeadWidth", "2.0" ).toDouble();
+ mPen.setWidthF( itemElem.attribute( "outlineWidth", "1.0" ).toDouble() );
+
+ //arrow color
+ QDomNodeList arrowColorList = itemElem.elementsByTagName( "ArrowColor" );
+ if ( arrowColorList.size() > 0 )
+ {
+ QDomElement arrowColorElem = arrowColorList.at( 0 ).toElement();
+ int red = arrowColorElem.attribute( "red", "0" ).toInt();
+ int green = arrowColorElem.attribute( "green", "0" ).toInt();
+ int blue = arrowColorElem.attribute( "blue", "0" ).toInt();
+ int alpha = arrowColorElem.attribute( "alpha", "255" ).toInt();
+ mArrowColor = QColor( red, green, blue, alpha );
+ }
+
+ //start point
+ QDomNodeList startPointList = itemElem.elementsByTagName( "StartPoint" );
+ if ( startPointList.size() > 0 )
+ {
+ QDomElement startPointElem = startPointList.at( 0 ).toElement();
+ mStartPoint.setX( startPointElem.attribute( "x", "0.0" ).toDouble() );
+ mStartPoint.setY( startPointElem.attribute( "y", "0.0" ).toDouble() );
+ }
+
+ //stop point
+ QDomNodeList stopPointList = itemElem.elementsByTagName( "StopPoint" );
+ if ( stopPointList.size() > 0 )
+ {
+ QDomElement stopPointElem = stopPointList.at( 0 ).toElement();
+ mStopPoint.setX( stopPointElem.attribute( "x", "0.0" ).toDouble() );
+ mStopPoint.setY( stopPointElem.attribute( "y", "0.0" ).toDouble() );
+ }
+
+
+ //restore general composer item properties
+ QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
+ if ( composerItemList.size() > 0 )
+ {
+ QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
+ _readXML( composerItemElem, doc );
+ }
+
+ adaptItemSceneRect();
+ return true;
+}
Added: trunk/qgis/src/core/composer/qgscomposerarrow.h
===================================================================
--- trunk/qgis/src/core/composer/qgscomposerarrow.h (rev 0)
+++ trunk/qgis/src/core/composer/qgscomposerarrow.h 2009-11-25 10:17:28 UTC (rev 12248)
@@ -0,0 +1,105 @@
+/***************************************************************************
+ qgscomposerarrow.h
+ ----------------------
+ begin : November 2009
+ copyright : (C) 2009 by Marco Hugentobler
+ email : marco at hugis.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 QGSCOMPOSERARROW_H
+#define QGSCOMPOSERARROW_H
+
+#include "qgscomposeritem.h"
+
+/**An item that draws an arrow between to points*/
+class QgsComposerArrow: public QgsComposerItem
+{
+ public:
+ QgsComposerArrow( QgsComposition* c );
+ QgsComposerArrow( const QPointF& startPoint, const QPointF& stopPoint, QgsComposition* c );
+ ~QgsComposerArrow();
+
+ /** \brief Reimplementation of QCanvasItem::paint - draw on canvas */
+ void paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget );
+
+ /**Modifies position of start and endpoint and calls QgsComposerItem::setSceneRect*/
+ void setSceneRect( const QRectF& rectangle );
+
+ /**Sets the width of the arrow head in mm*/
+ void setArrowHeadWidth( double width );
+ double arrowHeadWidth() const {return mArrowHeadWidth;}
+
+ void setOutlineWidth( double width );
+ double outlineWidth() const {return mPen.widthF();}
+
+ void setStartMarker( const QString& svgPath );
+ void setEndMarker( const QString& svgPath );
+
+ bool showArrowMarker() const { return mShowArrowMarker;}
+ void setShowArrowMarker( bool show );
+
+ QColor arrowColor() const { return mArrowColor; }
+ void setArrowColor( const QColor& c ) { mArrowColor = c; }
+
+ /** stores state in Dom node
+ * @param node is Dom node corresponding to 'Composer' tag
+ * @param temp write template file
+ */
+ bool writeXML( QDomElement& elem, QDomDocument & doc ) const;
+
+ /** sets state from Dom document
+ * @param itemElem is Dom node corresponding to item tag
+ */
+ bool readXML( const QDomElement& itemElem, const QDomDocument& doc );
+
+ private:
+
+ enum MarkerType
+ {
+ StartMarker,
+ EndMarker
+ };
+
+ QPointF mStartPoint;
+ QPointF mStopPoint;
+
+ QPen mPen;
+ QBrush mBrush;
+
+ /**Width of the arrow marker in mm. May be specified by the user. The height is automatically adapted*/
+ double mArrowHeadWidth;
+ /**Height of the arrow marker in mm. Is calculated from arrow marker width and apsect ratio of svg*/
+ double mStartArrowHeadHeight;
+ double mStopArrowHeadHeight;
+
+ /**Path to the start marker file*/
+ QString mStartMarkerFile;
+ /**Path to the end marker file*/
+ QString mEndMarkerFile;
+
+ /**True if arrow head marker is drawn*/
+ bool mShowArrowMarker;
+ QColor mArrowColor;
+
+ /**Adapts the item scene rect to contain the start point, the stop point including the arrow marker and the outline.
+ Needs to be called whenever the arrow width/height, the outline with or the endpoints are changed*/
+ void adaptItemSceneRect();
+
+ void drawHardcodedMarker( QPainter* p, MarkerType type );
+ void drawSVGMarker( QPainter* p, MarkerType type, const QString& markerPath );
+ /**Calculates arrow angle (for marker rotation)*/
+ double arrowAngle() const;
+ /**Apply default graphics settings*/
+ void initGraphicsSettings();
+};
+
+#endif // QGSCOMPOSERARROW_H
Modified: trunk/qgis/src/gui/qgscomposerview.cpp
===================================================================
--- trunk/qgis/src/gui/qgscomposerview.cpp 2009-11-25 10:00:05 UTC (rev 12247)
+++ trunk/qgis/src/gui/qgscomposerview.cpp 2009-11-25 10:17:28 UTC (rev 12248)
@@ -20,6 +20,7 @@
#include <QKeyEvent>
#include "qgscomposerview.h"
+#include "qgscomposerarrow.h"
#include "qgscomposerlabel.h"
#include "qgscomposerlegend.h"
#include "qgscomposermap.h"
@@ -29,7 +30,7 @@
#include "qgscomposershape.h"
QgsComposerView::QgsComposerView( QWidget* parent, const char* name, Qt::WFlags f ) :
- QGraphicsView( parent ), mShiftKeyPressed( false ), mRubberBandItem( 0 ), mMoveContentItem( 0 )
+ QGraphicsView( parent ), mShiftKeyPressed( false ), mRubberBandItem( 0 ), mRubberBandLineItem( 0 ), mMoveContentItem( 0 )
{
setResizeAnchor( QGraphicsView::AnchorViewCenter );
setMouseTracking( true );
@@ -97,6 +98,15 @@
break;
}
+ case AddArrow:
+ {
+ mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
+ mRubberBandLineItem = new QGraphicsLineItem( snappedScenePoint.x(), snappedScenePoint.y(), snappedScenePoint.x(), snappedScenePoint.y() );
+ mRubberBandLineItem->setZValue( 100 );
+ scene()->addItem( mRubberBandLineItem );
+ scene()->update();
+ }
+
//create rubber band for map and ellipse items
case AddMap:
case AddShape:
@@ -187,6 +197,18 @@
}
break;
}
+ case AddArrow:
+ {
+ QPointF scenePoint = mapToScene( e->pos() );
+ QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
+ QgsComposerArrow* composerArrow = new QgsComposerArrow( mRubberBandStartPos, QPointF( snappedScenePoint.x(), snappedScenePoint.y() ), composition() );
+ addComposerArrow( composerArrow );
+ scene()->removeItem( mRubberBandLineItem );
+ delete mRubberBandLineItem;
+ mRubberBandLineItem = 0;
+ emit actionFinished();
+ break;
+ }
case AddShape:
{
@@ -194,6 +216,7 @@
{
scene()->removeItem( mRubberBandItem );
delete mRubberBandItem;
+ mRubberBandItem = 0;
return;
}
@@ -218,6 +241,7 @@
addComposerMap( composerMap );
scene()->removeItem( mRubberBandItem );
delete mRubberBandItem;
+ mRubberBandItem = 0;
emit actionFinished();
}
break;
@@ -251,6 +275,15 @@
QGraphicsView::mouseMoveEvent( e );
break;
+ case AddArrow:
+ {
+ if ( mRubberBandLineItem )
+ {
+ mRubberBandLineItem->setLine( mRubberBandStartPos.x(), mRubberBandStartPos.y(), scenePoint.x(), scenePoint.y() );
+ }
+ break;
+ }
+
case AddMap:
case AddShape:
//adjust rubber band item
@@ -285,10 +318,13 @@
height = dy;
}
- mRubberBandItem->setRect( 0, 0, width, height );
- QTransform t;
- t.translate( x, y );
- mRubberBandItem->setTransform( t );
+ if ( mRubberBandItem )
+ {
+ mRubberBandItem->setRect( 0, 0, width, height );
+ QTransform t;
+ t.translate( x, y );
+ mRubberBandItem->setTransform( t );
+ }
break;
}
@@ -410,6 +446,15 @@
return 0;
}
+void QgsComposerView::addComposerArrow( QgsComposerArrow* arrow )
+{
+ composition()->addItem( arrow );
+ emit composerArrowAdded( arrow );
+ scene()->clearSelection();
+ arrow->setSelected( true );
+ emit selectedItemChanged( arrow );
+}
+
void QgsComposerView::addComposerLabel( QgsComposerLabel* label )
{
composition()->addItem( label );
Modified: trunk/qgis/src/gui/qgscomposerview.h
===================================================================
--- trunk/qgis/src/gui/qgscomposerview.h 2009-11-25 10:00:05 UTC (rev 12247)
+++ trunk/qgis/src/gui/qgscomposerview.h 2009-11-25 10:17:28 UTC (rev 12248)
@@ -24,6 +24,7 @@
class QMainWindow;
class QMouseEvent;
class QgsComposition;
+class QgsComposerArrow;
class QgsComposerItem;
class QgsComposerLabel;
class QgsComposerLegend;
@@ -49,6 +50,7 @@
enum Tool
{
Select = 0, // Select/Move item
+ AddArrow, //add arrow
AddMap, // add new map
AddLegend, // add vector legend
AddLabel, // add label
@@ -74,6 +76,8 @@
/**Returns the composition or 0 in case of error*/
QgsComposition* composition();
+ /**Adds an arrow item to the graphics scene and advices composer to create a widget for it (through signal)*/
+ void addComposerArrow( QgsComposerArrow* arrow );
/**Adds label to the graphics scene and advices composer to create a widget for it (through signal)*/
void addComposerLabel( QgsComposerLabel* label );
/**Adds map to the graphics scene and advices composer to create a widget for it (through signal)*/
@@ -107,6 +111,8 @@
QgsComposerView::Tool mCurrentTool;
/**Rubber band item*/
QGraphicsRectItem* mRubberBandItem;
+ /**Rubber band item for arrows*/
+ QGraphicsLineItem* mRubberBandLineItem;
/**Item to move content*/
QgsComposerItem* mMoveContentItem;
/**Start position of content move*/
@@ -121,7 +127,9 @@
signals:
/**Is emitted when selected item changed. If 0, no item is selected*/
void selectedItemChanged( const QgsComposerItem* selected );
- /**Ist emittted when new composer label has been added to the view*/
+ /**Is emitted when new composer arrow has been added to the view*/
+ void composerArrowAdded( QgsComposerArrow* arrow );
+ /**Is emitted when new composer label has been added to the view*/
void composerLabelAdded( QgsComposerLabel* label );
/**Is emitted when new composer map has been added to the view*/
void composerMapAdded( QgsComposerMap* map );
Modified: trunk/qgis/src/ui/qgscomposerbase.ui
===================================================================
--- trunk/qgis/src/ui/qgscomposerbase.ui 2009-11-25 10:00:05 UTC (rev 12247)
+++ trunk/qgis/src/ui/qgscomposerbase.ui 2009-11-25 10:17:28 UTC (rev 12248)
@@ -170,6 +170,7 @@
<addaction name="mActionAddNewLegend"/>
<addaction name="mActionAddNewScalebar"/>
<addaction name="mActionAddBasicShape"/>
+ <addaction name="mActionAddArrow"/>
<addaction name="mActionSelectMoveItem"/>
<addaction name="mActionMoveItemContent"/>
<addaction name="mActionGroupItems"/>
@@ -452,6 +453,14 @@
<string>Add Basic Shape</string>
</property>
</action>
+ <action name="mActionAddArrow">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Add arrow</string>
+ </property>
+ </action>
</widget>
<tabstops>
<tabstop>mCompositionNameComboBox</tabstop>
More information about the QGIS-commit
mailing list