Working move item content tool

This commit is contained in:
Nyall Dawson 2017-10-21 12:24:11 +10:00
parent b276f4c4b9
commit 7f0142c86a
20 changed files with 312 additions and 32 deletions

View File

@ -65,6 +65,7 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt
UndoNodeMove,
UndoAtlasMargin,
UndoMapRotation,
UndoZoomContent,
};
explicit QgsLayoutItem( QgsLayout *layout, bool manageZValue = true );
@ -531,7 +532,16 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt
%Docstring
Moves the content of the item, by a specified ``dx`` and ``dy`` in layout units.
The default implementation has no effect.
.. seealso:: setMoveContentPreviewOffset()
.. seealso:: zoomContent()
%End
virtual void setMoveContentPreviewOffset( double dx, double dy );
%Docstring
Sets temporary offset for the item, by a specified ``dx`` and ``dy`` in layout units.
This is useful for live updates when moving item content in a QgsLayoutView.
The default implementation has no effect.
.. seealso:: moveContent()
%End
virtual void zoomContent( double factor, QPointF point );

View File

@ -250,6 +250,9 @@ class QgsLayoutItemMap : QgsLayoutItem
virtual void moveContent( double dx, double dy );
virtual void setMoveContentPreviewOffset( double dx, double dy );
virtual void zoomContent( double factor, QPointF point );
@ -386,11 +389,6 @@ True if a draw is already in progress
void setOffset( double xOffset, double yOffset );
%Docstring
Sets offset values to shift image (useful for live updates when moving item content)
%End
virtual QRectF boundingRect() const;

View File

@ -297,6 +297,7 @@
%Include layout/qgslayoutviewtooladditem.sip
%Include layout/qgslayoutviewtooladdnodeitem.sip
%Include layout/qgslayoutviewtooleditnodes.sip
%Include layout/qgslayoutviewtoolmoveitemcontent.sip
%Include layout/qgslayoutviewtoolpan.sip
%Include layout/qgslayoutviewtoolselect.sip
%Include layout/qgslayoutviewtooltemporarykeypan.sip

View File

@ -0,0 +1,45 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutviewtoolmoveitemcontent.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutViewToolMoveItemContent : QgsLayoutViewTool
{
%Docstring
Layout view tool for moving and zooming item content.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutviewtoolmoveitemcontent.h"
%End
public:
QgsLayoutViewToolMoveItemContent( QgsLayoutView *view /TransferThis/ );
%Docstring
Constructor for QgsLayoutViewToolMoveItemContent.
%End
virtual void layoutPressEvent( QgsLayoutViewMouseEvent *event );
virtual void layoutMoveEvent( QgsLayoutViewMouseEvent *event );
virtual void layoutReleaseEvent( QgsLayoutViewMouseEvent *event );
virtual void wheelEvent( QWheelEvent *event );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutviewtoolmoveitemcontent.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -26,6 +26,7 @@
#include "qgslayoutviewtooladditem.h"
#include "qgslayoutviewtooladdnodeitem.h"
#include "qgslayoutviewtoolpan.h"
#include "qgslayoutviewtoolmoveitemcontent.h"
#include "qgslayoutviewtoolzoom.h"
#include "qgslayoutviewtoolselect.h"
#include "qgslayoutviewtooleditnodes.h"
@ -251,6 +252,11 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
mToolsActionGroup->addAction( mActionEditNodesItem );
connect( mActionEditNodesItem, &QAction::triggered, mNodesTool, [ = ] { mView->setTool( mNodesTool ); } );
mMoveContentTool = new QgsLayoutViewToolMoveItemContent( mView );
mMoveContentTool->setAction( mActionMoveItemContent );
mToolsActionGroup->addAction( mActionMoveItemContent );
connect( mActionMoveItemContent, &QAction::triggered, mMoveContentTool, [ = ] { mView->setTool( mMoveContentTool ); } );
//Ctrl+= should also trigger zoom in
QShortcut *ctrlEquals = new QShortcut( QKeySequence( QStringLiteral( "Ctrl+=" ) ), this );
connect( ctrlEquals, &QShortcut::activated, mActionZoomIn, &QAction::trigger );

View File

@ -29,6 +29,7 @@ class QgsLayoutViewToolPan;
class QgsLayoutViewToolZoom;
class QgsLayoutViewToolSelect;
class QgsLayoutViewToolEditNodes;
class QgsLayoutViewToolMoveItemContent;
class QgsLayoutRuler;
class QComboBox;
class QSlider;
@ -277,6 +278,7 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
QgsLayoutViewToolZoom *mZoomTool = nullptr;
QgsLayoutViewToolSelect *mSelectTool = nullptr;
QgsLayoutViewToolEditNodes *mNodesTool = nullptr;
QgsLayoutViewToolMoveItemContent *mMoveContentTool = nullptr;
QMap< QString, QToolButton * > mItemGroupToolButtons;
QMap< QString, QMenu * > mItemGroupSubmenus;

View File

@ -104,7 +104,6 @@ QgsLayoutMapWidget::QgsLayoutMapWidget( QgsLayoutItemMap *item )
if ( item )
{
mLabel->setText( tr( "Map %1" ).arg( item->id() ) );
connect( item, &QgsLayoutObject::changed, this, &QgsLayoutMapWidget::updateGuiElements );
#if 0 //TODO
@ -491,9 +490,8 @@ void QgsLayoutMapWidget::mScaleLineEdit_editingFinished()
return;
}
bool conversionSuccess;
double scaleDenominator = mScaleLineEdit->text().toDouble( &conversionSuccess );
bool conversionSuccess = false;
double scaleDenominator = QLocale::system().toDouble( mScaleLineEdit->text(), &conversionSuccess );
if ( !conversionSuccess )
{
return;
@ -612,6 +610,7 @@ void QgsLayoutMapWidget::updateGuiElements()
}
blockAllSignals( true );
mLabel->setText( tr( "Map %1" ).arg( item->id() ) );
whileBlocking( mCrsSelector )->setCrs( mMapItem->presetCrs() );

View File

@ -802,6 +802,11 @@ void QgsLayoutItem::moveContent( double, double )
}
void QgsLayoutItem::setMoveContentPreviewOffset( double, double )
{
}
void QgsLayoutItem::zoomContent( double, QPointF )
{

View File

@ -98,6 +98,7 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
UndoNodeMove, //!< Node move
UndoAtlasMargin, //!< Map atlas margin changed
UndoMapRotation, //!< Map rotation changed
UndoZoomContent, //!< Item content zoomed
};
/**
@ -528,10 +529,19 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
/**
* Moves the content of the item, by a specified \a dx and \a dy in layout units.
* The default implementation has no effect.
* \see setMoveContentPreviewOffset()
* \see zoomContent()
*/
virtual void moveContent( double dx, double dy );
/**
* Sets temporary offset for the item, by a specified \a dx and \a dy in layout units.
* This is useful for live updates when moving item content in a QgsLayoutView.
* The default implementation has no effect.
* \see moveContent()
*/
virtual void setMoveContentPreviewOffset( double dx, double dy );
/**
* Zooms content of item. Does nothing by default.
* \param factor zoom factor, where > 1 results in a zoom in and < 1 results in a zoom out

View File

@ -300,7 +300,7 @@ void QgsLayoutItemMap::moveContent( double dx, double dy )
transformShift( dx, dy );
mExtent.setXMinimum( mExtent.xMinimum() + dx );
mExtent.setXMaximum( mExtent.xMaximum() + dx );
mExtent.setYMinimum( mExtent.xMinimum() + dy );
mExtent.setYMinimum( mExtent.yMinimum() + dy );
mExtent.setYMaximum( mExtent.yMaximum() + dy );
//in case data defined extents are set, these override the calculated values
@ -746,7 +746,7 @@ QgsMapSettings QgsLayoutItemMap::mapSettings( const QgsRectangle &extent, QSizeF
return jobMapSettings;
}
void QgsLayoutItemMap::setOffset( double xOffset, double yOffset )
void QgsLayoutItemMap::setMoveContentPreviewOffset( double xOffset, double yOffset )
{
mXOffset = xOffset;
mYOffset = yOffset;

View File

@ -265,6 +265,8 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
void setFollowVisibilityPresetName( const QString &name ) { mFollowVisibilityPresetName = name; }
void moveContent( double dx, double dy ) override;
void setMoveContentPreviewOffset( double dx, double dy ) override;
void zoomContent( double factor, QPointF point ) override;
@ -390,9 +392,6 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
QgsRectangle extent() const {return mExtent;}
#endif
//! Sets offset values to shift image (useful for live updates when moving item content)
void setOffset( double xOffset, double yOffset );
#if 0
/**

View File

@ -172,6 +172,7 @@ SET(QGIS_GUI_SRCS
layout/qgslayoutviewtooladditem.cpp
layout/qgslayoutviewtooladdnodeitem.cpp
layout/qgslayoutviewtooleditnodes.cpp
layout/qgslayoutviewtoolmoveitemcontent.cpp
layout/qgslayoutviewtoolpan.cpp
layout/qgslayoutviewtoolselect.cpp
layout/qgslayoutviewtooltemporarykeypan.cpp
@ -677,6 +678,7 @@ SET(QGIS_GUI_MOC_HDRS
layout/qgslayoutviewtooladditem.h
layout/qgslayoutviewtooladdnodeitem.h
layout/qgslayoutviewtooleditnodes.h
layout/qgslayoutviewtoolmoveitemcontent.h
layout/qgslayoutviewtoolpan.h
layout/qgslayoutviewtoolselect.h
layout/qgslayoutviewtooltemporarykeypan.h

View File

@ -689,11 +689,13 @@ void QgsLayoutMouseHandles::mouseReleaseEvent( QGraphicsSceneMouseEvent *event )
void QgsLayoutMouseHandles::resetStatusBar()
{
if ( !mView )
return;
const QList<QgsLayoutItem *> selectedItems = mLayout->selectedLayoutItems( false );
int selectedCount = selectedItems.size();
if ( selectedCount > 1 )
{
//set status bar message to count of selected items
mView->pushStatusMessage( tr( "%1 items selected" ).arg( selectedCount ) );
}

View File

@ -338,7 +338,8 @@ void QgsLayoutRuler::drawGuideAtPos( QPainter *painter, QPoint pos )
void QgsLayoutRuler::createTemporaryGuideItem()
{
mGuideItem.reset( new QGraphicsLineItem() );
delete mGuideItem;
mGuideItem = new QGraphicsLineItem();
mGuideItem->setZValue( QgsLayout::ZGuide );
QPen linePen( Qt::DotLine );
@ -346,7 +347,7 @@ void QgsLayoutRuler::createTemporaryGuideItem()
linePen.setWidthF( 0 );
mGuideItem->setPen( linePen );
mView->currentLayout()->addItem( mGuideItem.get() );
mView->currentLayout()->addItem( mGuideItem );
}
QPointF QgsLayoutRuler::convertLocalPointToLayout( QPoint localPoint ) const
@ -735,7 +736,8 @@ void QgsLayoutRuler::mouseReleaseEvent( QMouseEvent *event )
{
mCreatingGuide = false;
QApplication::restoreOverrideCursor();
mGuideItem.reset();
delete mGuideItem;
mGuideItem = nullptr;
// check that cursor left the ruler
switch ( mOrientation )

View File

@ -121,7 +121,7 @@ class GUI_EXPORT QgsLayoutRuler: public QWidget
QgsLayoutGuide *mHoverGuide = nullptr;
bool mCreatingGuide = false;
std::unique_ptr< QGraphicsLineItem > mGuideItem;
QGraphicsLineItem *mGuideItem = nullptr;
//! Polygon for drawing guide markers
QPolygonF mGuideMarker;

View File

@ -54,7 +54,7 @@ QgsLayoutView::QgsLayoutView( QWidget *parent )
mSpacePanTool = new QgsLayoutViewToolTemporaryKeyPan( this );
mMidMouseButtonPanTool = new QgsLayoutViewToolTemporaryMousePan( this );
mSpaceZoomTool = new QgsLayoutViewToolTemporaryKeyZoom( this );
mSnapMarker.reset( new QgsLayoutViewSnapMarker() );
mSnapMarker = new QgsLayoutViewSnapMarker();
mPreviewEffect = new QgsPreviewEffect( this );
viewport()->setGraphicsEffect( mPreviewEffect );
@ -81,16 +81,19 @@ void QgsLayoutView::setCurrentLayout( QgsLayout *layout )
viewChanged();
mSnapMarker.reset( new QgsLayoutViewSnapMarker() );
delete mSnapMarker;
mSnapMarker = new QgsLayoutViewSnapMarker();
mSnapMarker->hide();
layout->addItem( mSnapMarker.get() );
layout->addItem( mSnapMarker );
mHorizontalSnapLine.reset( createSnapLine() );
delete mHorizontalSnapLine;
mHorizontalSnapLine = createSnapLine();
mHorizontalSnapLine->hide();
layout->addItem( mHorizontalSnapLine.get() );
mVerticalSnapLine.reset( createSnapLine() );
layout->addItem( mHorizontalSnapLine );
delete mVerticalSnapLine;
mVerticalSnapLine = createSnapLine();
mVerticalSnapLine->hide();
layout->addItem( mVerticalSnapLine.get() );
layout->addItem( mVerticalSnapLine );
if ( mHorizontalRuler )
{
@ -771,7 +774,7 @@ void QgsLayoutView::mouseMoveEvent( QMouseEvent *event )
std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, false ) );
if ( mTool->flags() & QgsLayoutViewTool::FlagSnaps )
{
me->snapPoint( mHorizontalSnapLine.get(), mVerticalSnapLine.get(), mTool->ignoredSnapItems() );
me->snapPoint( mHorizontalSnapLine, mVerticalSnapLine, mTool->ignoredSnapItems() );
}
if ( mTool->flags() & QgsLayoutViewTool::FlagSnaps )
{

View File

@ -470,10 +470,10 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView
QgsLayoutRuler *mVerticalRuler = nullptr;
std::unique_ptr< QgsLayoutViewMenuProvider > mMenuProvider;
std::unique_ptr< QgsLayoutViewSnapMarker > mSnapMarker;
QgsLayoutViewSnapMarker *mSnapMarker = nullptr;
std::unique_ptr< QGraphicsLineItem > mHorizontalSnapLine;
std::unique_ptr< QGraphicsLineItem > mVerticalSnapLine;
QGraphicsLineItem *mHorizontalSnapLine = nullptr;
QGraphicsLineItem *mVerticalSnapLine = nullptr;
int mCurrentPage = 0;

View File

@ -0,0 +1,122 @@
/***************************************************************************
qgslayoutviewtoolmoveitemcontent.cpp
------------------------------------
Date : October 2017
Copyright : (C) 2017 Nyall Dawson
Email : nyall dot dawson at gmail 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 "qgslayoutviewtoolmoveitemcontent.h"
#include "qgslayoutviewmouseevent.h"
#include "qgslayoutview.h"
#include "qgslayout.h"
#include "qgslayoutitemnodeitem.h"
#include "qgssettings.h"
QgsLayoutViewToolMoveItemContent::QgsLayoutViewToolMoveItemContent( QgsLayoutView *view )
: QgsLayoutViewTool( view, tr( "Select" ) )
{
setCursor( Qt::ArrowCursor );
}
void QgsLayoutViewToolMoveItemContent::layoutPressEvent( QgsLayoutViewMouseEvent *event )
{
if ( event->button() != Qt::LeftButton )
{
event->ignore();
return;
}
const QList<QGraphicsItem *> itemsAtCursorPos = view()->items( event->pos() );
if ( itemsAtCursorPos.isEmpty() )
return;
//find highest non-locked QgsLayoutItem at clicked position
//(other graphics items may be higher, e.g., selection handles)
for ( QGraphicsItem *graphicsItem : itemsAtCursorPos )
{
QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
if ( item && !item->isLocked() )
{
//we've found the highest QgsLayoutItem
mMoveContentStartPos = event->layoutPoint();
mMoveContentItem = item;
mMovingItemContent = true;
break;
}
}
}
void QgsLayoutViewToolMoveItemContent::layoutMoveEvent( QgsLayoutViewMouseEvent *event )
{
if ( !mMovingItemContent || !mMoveContentItem )
{
event->ignore();
return;
}
//update item preview
mMoveContentItem->setMoveContentPreviewOffset( event->layoutPoint().x() - mMoveContentStartPos.x(),
event->layoutPoint().y() - mMoveContentStartPos.y() );
mMoveContentItem->update();
}
void QgsLayoutViewToolMoveItemContent::layoutReleaseEvent( QgsLayoutViewMouseEvent *event )
{
if ( event->button() != Qt::LeftButton || !mMovingItemContent || !mMoveContentItem )
{
event->ignore();
return;
}
//update item preview
mMoveContentItem->setMoveContentPreviewOffset( 0, 0 );
double moveX = event->layoutPoint().x() - mMoveContentStartPos.x();
double moveY = event->layoutPoint().y() - mMoveContentStartPos.y();
mMoveContentItem->layout()->undoStack()->beginCommand( mMoveContentItem, tr( "Move Item Content" ) );
mMoveContentItem->moveContent( -moveX, -moveY );
mMoveContentItem->layout()->undoStack()->endCommand();
mMoveContentItem = nullptr;
mMovingItemContent = false;
}
void QgsLayoutViewToolMoveItemContent::wheelEvent( QWheelEvent *event )
{
event->accept();
QPointF scenePoint = view()->mapToScene( event->pos() );
//select topmost item at position of event
QgsLayoutItem *item = layout()->layoutItemAt( scenePoint, true );
if ( !item || !item->isSelected() )
return;
QgsSettings settings;
double zoomFactor = settings.value( QStringLiteral( "qgis/zoom_factor" ), 2.0 ).toDouble();
// "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * std::fabs( event->angleDelta().y() );
if ( event->modifiers() & Qt::ControlModifier )
{
//holding ctrl while wheel zooming results in a finer zoom
zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
}
//calculate zoom scale factor
bool zoomIn = event->angleDelta().y() > 0;
double scaleFactor = ( zoomIn ? zoomFactor : 1 / zoomFactor );
QPointF itemPoint = item->mapFromScene( scenePoint );
item->layout()->undoStack()->beginCommand( item, tr( "Zoom Item Content" ), QgsLayoutItem::UndoZoomContent );
item->zoomContent( scaleFactor, itemPoint );
item->layout()->undoStack()->endCommand();
}

View File

@ -0,0 +1,56 @@
/***************************************************************************
qgslayoutviewtoolmoveitemcontent.h
-------------------------
Date : October 2017
Copyright : (C) 2017 Nyall Dawson
Email : nyall dot dawson at gmail 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 QGSLAYOUTVIEWTOOLMOVEITEMCONTENT_H
#define QGSLAYOUTVIEWTOOLMOVEITEMCONTENT_H
#include "qgis.h"
#include "qgis_gui.h"
#include "qgslayoutviewtool.h"
/**
* \ingroup gui
* Layout view tool for moving and zooming item content.
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLayoutViewToolMoveItemContent : public QgsLayoutViewTool
{
Q_OBJECT
public:
/**
* Constructor for QgsLayoutViewToolMoveItemContent.
*/
QgsLayoutViewToolMoveItemContent( QgsLayoutView *view SIP_TRANSFERTHIS );
void layoutPressEvent( QgsLayoutViewMouseEvent *event ) override;
void layoutMoveEvent( QgsLayoutViewMouseEvent *event ) override;
void layoutReleaseEvent( QgsLayoutViewMouseEvent *event ) override;
void wheelEvent( QWheelEvent *event ) override;
private:
//! Item to move content
QgsLayoutItem *mMoveContentItem = nullptr;
//! Start position of content move
QPointF mMoveContentStartPos;
bool mMovingItemContent = false;
};
#endif // QGSLAYOUTVIEWTOOLMOVEITEMCONTENT_H

View File

@ -76,6 +76,7 @@
<addaction name="mActionPan"/>
<addaction name="mActionZoomTool"/>
<addaction name="mActionSelectMoveItem"/>
<addaction name="mActionMoveItemContent"/>
<addaction name="mActionEditNodesItem"/>
</widget>
<widget class="QMenuBar" name="menuBar">
@ -84,7 +85,7 @@
<x>0</x>
<y>0</y>
<width>1083</width>
<height>25</height>
<height>42</height>
</rect>
</property>
<widget class="QMenu" name="mLayoutMenu">
@ -1025,6 +1026,24 @@
<string>Edit Nodes Item</string>
</property>
</action>
<action name="mActionMoveItemContent">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../../images/images.qrc">
<normaloff>:/images/themes/default/mActionMoveItemContent.svg</normaloff>:/images/themes/default/mActionMoveItemContent.svg</iconset>
</property>
<property name="text">
<string>Move &amp;Content</string>
</property>
<property name="toolTip">
<string>Move item content</string>
</property>
<property name="shortcut">
<string>C</string>
</property>
</action>
</widget>
<resources>
<include location="../../../images/images.qrc"/>
@ -1053,7 +1072,6 @@
<include location="../../../images/images.qrc"/>
<include location="../../../images/images.qrc"/>
<include location="../../../images/images.qrc"/>
<include location="../../../images/images.qrc"/>
</resources>
<connections/>
</ui>