Skip to content

Commit

Permalink
[FEATURE][composer] Implement different resize modes for composer pic…
Browse files Browse the repository at this point in the history
…ture items, including zoom, stretch, clip, frame to image size (fix #7886). (Sponsored by City of Uster, Switzerland)
  • Loading branch information
nyalldawson committed Apr 28, 2014
1 parent 8ab3ce4 commit 23b660e
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 28 deletions.
20 changes: 20 additions & 0 deletions src/app/composer/qgscomposerpicturewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,21 @@ void QgsComposerPictureWidget::on_mRemoveDirectoryButton_clicked()
s.setValue( "/Composer/PictureWidgetDirectories", userDirList );
}

void QgsComposerPictureWidget::on_mResizeModeComboBox_currentIndexChanged( int index )
{
if ( !mPicture )
{
return;
}

mPicture->beginCommand( tr( "Picture resize mode changed" ) );
mPicture->setResizeMode(( QgsComposerPicture::ResizeMode )index );
mPicture->endCommand();

//disable picture rotation for non-zoom modes
mRotationGroupBox->setEnabled( mPicture->resizeMode() == QgsComposerPicture::Zoom );
}

void QgsComposerPictureWidget::on_mRotationFromComposerMapCheckBox_stateChanged( int state )
{
if ( !mPicture )
Expand Down Expand Up @@ -326,6 +341,7 @@ void QgsComposerPictureWidget::setGuiElementValues()
mPictureLineEdit->blockSignals( true );
mComposerMapComboBox->blockSignals( true );
mRotationFromComposerMapCheckBox->blockSignals( true );
mResizeModeComboBox->blockSignals( true );

mPictureLineEdit->setText( mPicture->pictureFile() );
// QRectF pictureRect = mPicture->rect();
Expand All @@ -352,11 +368,15 @@ void QgsComposerPictureWidget::setGuiElementValues()
mComposerMapComboBox->setEnabled( false );
}

mResizeModeComboBox->setCurrentIndex(( int )mPicture->resizeMode() );
//disable picture rotation for non-zoom modes
mRotationGroupBox->setEnabled( mPicture->resizeMode() == QgsComposerPicture::Zoom );

mRotationFromComposerMapCheckBox->blockSignals( false );
mPictureRotationSpinBox->blockSignals( false );
mPictureLineEdit->blockSignals( false );
mComposerMapComboBox->blockSignals( false );
mResizeModeComboBox->blockSignals( false );
}
}

Expand Down
1 change: 1 addition & 0 deletions src/app/composer/qgscomposerpicturewidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class QgsComposerPictureWidget: public QWidget, private Ui::QgsComposerPictureWi
void on_mRemoveDirectoryButton_clicked();
void on_mRotationFromComposerMapCheckBox_stateChanged( int state );
void on_mComposerMapComboBox_activated( const QString & text );
void on_mResizeModeComboBox_currentIndexChanged( int index );

protected:
void showEvent( QShowEvent * event );
Expand Down
123 changes: 103 additions & 20 deletions src/core/composer/qgscomposerpicture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@


QgsComposerPicture::QgsComposerPicture( QgsComposition *composition )
: QgsComposerItem( composition ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
: QgsComposerItem( composition ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 ),
mResizeMode( QgsComposerPicture::Zoom )
{
mPictureWidth = rect().width();
}

QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 ), mResizeMode( QgsComposerPicture::Zoom )
{
mPictureHeight = rect().height();
}
Expand All @@ -58,21 +59,47 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte

if ( mMode != Unknown )
{
double boundRectWidthMM = mPictureWidth;
double boundRectHeightMM = mPictureHeight;

double boundRectWidthMM;
double boundRectHeightMM;
double imageRectWidthMM;
double imageRectHeightMM;
if ( mResizeMode == QgsComposerPicture::Zoom || mResizeMode == QgsComposerPicture::ZoomResizeFrame )
{
boundRectWidthMM = mPictureWidth;
boundRectHeightMM = mPictureHeight;
imageRectWidthMM = mImage.width();
imageRectHeightMM = mImage.height();
}
else if ( mResizeMode == QgsComposerPicture::Stretch )
{
boundRectWidthMM = rect().width();
boundRectHeightMM = rect().height();
imageRectWidthMM = mImage.width();
imageRectHeightMM = mImage.height();
}
else
{
boundRectWidthMM = rect().width();
boundRectHeightMM = rect().height();
imageRectWidthMM = rect().width() * mComposition->printResolution() / 25.4;
imageRectHeightMM = rect().height() * mComposition->printResolution() / 25.4;
}
painter->save();
painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
painter->rotate( mPictureRotation );
painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );

if ( mResizeMode == Zoom )
{
painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
painter->rotate( mPictureRotation );
painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );
}

if ( mMode == SVG )
{
mSVG.render( painter, QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ) );
}
else if ( mMode == RASTER )
{
painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, imageRectWidthMM, imageRectHeightMM ) );
}

painter->restore();
Expand Down Expand Up @@ -204,14 +231,53 @@ QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeig

void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
{
QgsComposerItem::setSceneRect( rectangle );

//find largest scaling of picture with this rotation which fits in item
QSizeF currentPictureSize = pictureSize();
QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rectangle, mPictureRotation );
mPictureWidth = rotatedImageRect.width();
mPictureHeight = rotatedImageRect.height();

if ( mResizeMode == QgsComposerPicture::Clip )
{
QgsComposerItem::setSceneRect( rectangle );
mPictureWidth = rectangle.width();
mPictureHeight = rectangle.height();
return;
}

QRectF newRect = rectangle;

if ( mResizeMode == ZoomResizeFrame && !rect().isEmpty() )
{
//if width has changed less than height, then fix width and set height correspondingly
//else, do the opposite
if ( qAbs( rect().width() - rectangle.width() ) <
qAbs( rect().height() - rectangle.height() ) )
{
newRect.setHeight( currentPictureSize.height() * newRect.width() / currentPictureSize.width() );
}
else
{
newRect.setWidth( currentPictureSize.width() * newRect.height() / currentPictureSize.height() );
}
}
else if ( mResizeMode == FrameToImageSize )
{
newRect.setWidth( currentPictureSize.width() * 25.4 / mComposition->printResolution() );
newRect.setHeight( currentPictureSize.height() * 25.4 / mComposition->printResolution() );
}

//find largest scaling of picture with this rotation which fits in item
if ( mResizeMode == Zoom )
{
QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), newRect, mPictureRotation );
mPictureWidth = rotatedImageRect.width();
mPictureHeight = rotatedImageRect.height();
}
else
{
mPictureWidth = newRect.width();
mPictureHeight = newRect.height();
}

QgsComposerItem::setSceneRect( newRect );
emit itemChanged();
}

Expand All @@ -225,13 +291,16 @@ void QgsComposerPicture::setPictureRotation( double r )
{
mPictureRotation = r;

//find largest scaling of picture with this rotation which fits in item
QSizeF currentPictureSize = pictureSize();
QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rect(), mPictureRotation );
mPictureWidth = rotatedImageRect.width();
mPictureHeight = rotatedImageRect.height();
if ( mResizeMode == Zoom )
{
//find largest scaling of picture with this rotation which fits in item
QSizeF currentPictureSize = pictureSize();
QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rect(), mPictureRotation );
mPictureWidth = rotatedImageRect.width();
mPictureHeight = rotatedImageRect.height();
update();
}

update();
emit pictureRotationChanged( mPictureRotation );
}

Expand Down Expand Up @@ -264,6 +333,18 @@ void QgsComposerPicture::setRotationMap( int composerMapId )
emit pictureRotationChanged( mPictureRotation );
}

void QgsComposerPicture::setResizeMode( QgsComposerPicture::ResizeMode mode )
{
mResizeMode = mode;
if ( mode == QgsComposerPicture::ZoomResizeFrame || mode == QgsComposerPicture::FrameToImageSize
|| ( mode == QgsComposerPicture::Zoom && mPictureRotation != 0 ) )
{
//call set scene rect to force item to resize to fit picture
setSceneRect( QRectF( pos().x(), pos().y(), rect().width(), rect().height() ) );
}
update();
}

QString QgsComposerPicture::pictureFile() const
{
return mSourceFile.fileName();
Expand All @@ -279,6 +360,7 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) );
composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) );
composerPictureElem.setAttribute( "resizeMode", QString::number(( int )mResizeMode ) );

//rotation
composerPictureElem.setAttribute( "pictureRotation", QString::number( mPictureRotation ) );
Expand All @@ -305,6 +387,7 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen

mPictureWidth = itemElem.attribute( "pictureWidth", "10" ).toDouble();
mPictureHeight = itemElem.attribute( "pictureHeight", "10" ).toDouble();
mResizeMode = QgsComposerPicture::ResizeMode( itemElem.attribute( "resizeMode", "0" ).toInt() );

QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
if ( composerItemList.size() > 0 )
Expand Down
36 changes: 29 additions & 7 deletions src/core/composer/qgscomposerpicture.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
{
Q_OBJECT
public:

enum ResizeMode
{
Zoom,
Stretch,
Clip,
ZoomResizeFrame,
FrameToImageSize
};

enum Mode //SVG or raster graphic format
{
SVG,
RASTER,
Unknown
};

QgsComposerPicture( QgsComposition *composition );
~QgsComposerPicture();

Expand Down Expand Up @@ -76,6 +93,10 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
/**True if the rotation is taken from a map item*/
bool useRotationMap() const {return mRotationMap;}

/**Returns the resize mode used for drawing the picture within the composer item
*/
ResizeMode resizeMode() const { return mResizeMode;};

/**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation
* @deprecated Use bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation )
* instead
Expand All @@ -92,6 +113,8 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
*/
Q_DECL_DEPRECATED void sizeChangedByRotation( double& width, double& height );

Mode mode() const { return mMode; };

public slots:
/**Sets the picture rotation within the item bounds. This does not affect the item rectangle,
only the way the picture is drawn within the item.
Expand All @@ -104,19 +127,16 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
@note this function was added in version 2.1*/
virtual void setPictureRotation( double r );

/**Sets the resize mode used for drawing the picture within the item bounds
@note this function was added in version 2.1*/
virtual void setResizeMode( ResizeMode mode );

signals:
/**Is emitted on picture rotation change*/
void pictureRotationChanged( double newRotation );

private:

enum Mode //SVG or raster graphic format
{
SVG,
RASTER,
Unknown
};

//default constructor is forbidden
QgsComposerPicture();
/**Calculates bounding rect for svg file (mSourcefile) such that aspect ratio is correct*/
Expand All @@ -142,6 +162,8 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
double mPictureWidth;
/**Height of the picture (in mm)*/
double mPictureHeight;

ResizeMode mResizeMode;
};

#endif
38 changes: 37 additions & 1 deletion src/ui/qgscomposerpicturewidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,42 @@
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Resize mode</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mResizeModeComboBox">
<item>
<property name="text">
<string>Zoom</string>
</property>
</item>
<item>
<property name="text">
<string>Stretch</string>
</property>
</item>
<item>
<property name="text">
<string>Clip</string>
</property>
</item>
<item>
<property name="text">
<string>Zoom and resize frame</string>
</property>
</item>
<item>
<property name="text">
<string>Resize frame to image size</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down Expand Up @@ -211,7 +247,7 @@
</widget>
</item>
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox">
<widget class="QgsCollapsibleGroupBoxBasic" name="mRotationGroupBox">
<property name="title">
<string>Image rotation</string>
</property>
Expand Down

0 comments on commit 23b660e

Please sign in to comment.