Show guide positions in rulers

This commit is contained in:
Nyall Dawson 2017-07-26 19:44:09 +10:00
parent ab726c4777
commit c6c9c6fabf
7 changed files with 129 additions and 11 deletions

View File

@ -181,10 +181,11 @@ class QgsLayoutGuideCollection : QAbstractTableModel
Updates the position (and visibility) of all guide line items.
%End
QList< QgsLayoutGuide * > guides( QgsLayoutGuide::Orientation orientation );
QList< QgsLayoutGuide * > guides( QgsLayoutGuide::Orientation orientation, int page = -1 );
%Docstring
Returns the list of guides contained in the collection with the specified
``orientation``.
``orientation`` and on a matching ``page``.
If ``page`` is -1, guides from all pages will be returned.
:rtype: list of QgsLayoutGuide
%End

View File

@ -117,10 +117,10 @@ double QgsLayoutGuide::layoutPosition() const
switch ( mOrientation )
{
case Horizontal:
return mLineItem->line().y1();
return mLineItem->mapToScene( mLineItem->line().p1() ).y();
case Vertical:
return mLineItem->line().x1();
return mLineItem->mapToScene( mLineItem->line().p1() ).x();
}
return -999; // avoid warning
}
@ -237,6 +237,7 @@ bool QgsLayoutGuideCollection::setData( const QModelIndex &index, const QVariant
m.setLength( newPos );
whileBlocking( guide )->setPosition( m );
guide->update();
emit dataChanged( index, index, QVector<int>() << role );
return true;
}
case PositionRole:
@ -250,6 +251,7 @@ bool QgsLayoutGuideCollection::setData( const QModelIndex &index, const QVariant
m.setLength( newPos );
whileBlocking( guide )->setPosition( m );
guide->update();
emit dataChanged( index, index, QVector<int>() << role );
return true;
}
case UnitsRole:
@ -263,6 +265,7 @@ bool QgsLayoutGuideCollection::setData( const QModelIndex &index, const QVariant
m.setUnits( static_cast< QgsUnitTypes::LayoutUnit >( units ) );
whileBlocking( guide )->setPosition( m );
guide->update();
emit dataChanged( index, index, QVector<int>() << role );
return true;
}
}
@ -325,12 +328,13 @@ void QgsLayoutGuideCollection::update()
}
}
QList<QgsLayoutGuide *> QgsLayoutGuideCollection::guides( QgsLayoutGuide::Orientation orientation )
QList<QgsLayoutGuide *> QgsLayoutGuideCollection::guides( QgsLayoutGuide::Orientation orientation, int page )
{
QList<QgsLayoutGuide *> res;
Q_FOREACH ( QgsLayoutGuide *guide, mGuides )
{
if ( guide->orientation() == orientation && guide->item()->isVisible() )
if ( guide->orientation() == orientation && guide->item()->isVisible() &&
( page < 0 || page == guide->page() ) )
res << guide;
}
return res;

View File

@ -207,9 +207,10 @@ class CORE_EXPORT QgsLayoutGuideCollection : public QAbstractTableModel
/**
* Returns the list of guides contained in the collection with the specified
* \a orientation.
* \a orientation and on a matching \a page.
* If \a page is -1, guides from all pages will be returned.
*/
QList< QgsLayoutGuide * > guides( QgsLayoutGuide::Orientation orientation );
QList< QgsLayoutGuide * > guides( QgsLayoutGuide::Orientation orientation, int page = -1 );
private:

View File

@ -16,6 +16,7 @@
#include "qgslayout.h"
#include "qgis.h"
#include "qgslayoutview.h"
#include "qgslogger.h"
#include <QDragEnterEvent>
#include <QGraphicsLineItem>
#include <QPainter>
@ -52,6 +53,20 @@ QgsLayoutRuler::QgsLayoutRuler( QWidget *parent, Qt::Orientation orientation )
mPixelsBetweenLineAndText = mRulerMinSize / 10;
mTextBaseline = mRulerMinSize / 1.667;
mMinSpacingVerticalLabels = mRulerMinSize / 5;
double guideMarkerSize = mRulerFontMetrics->width( "*" );
switch ( mOrientation )
{
case Qt::Horizontal:
mGuideMarker << QPoint( -guideMarkerSize / 2, mRulerMinSize - guideMarkerSize ) << QPoint( 0, mRulerMinSize ) <<
QPoint( guideMarkerSize / 2, mRulerMinSize - guideMarkerSize );
break;
case Qt::Vertical:
mGuideMarker << QPoint( mRulerMinSize - guideMarkerSize, -guideMarkerSize / 2 ) << QPoint( mRulerMinSize, 0 ) <<
QPoint( mRulerMinSize - guideMarkerSize, guideMarkerSize / 2 );
break;
}
}
QSize QgsLayoutRuler::minimumSizeHint() const
@ -70,6 +85,8 @@ void QgsLayoutRuler::paintEvent( QPaintEvent *event )
QgsLayout *layout = mView->currentLayout();
QPainter p( this );
drawGuideMarkers( &p, layout );
QTransform t = mTransform.inverted();
p.setFont( mRulerFont );
// keep same default color, but lower opacity a tad
@ -260,6 +277,56 @@ void QgsLayoutRuler::drawMarkerPos( QPainter *painter )
}
}
void QgsLayoutRuler::drawGuideMarkers( QPainter *p, QgsLayout *layout )
{
QList< int > visiblePageNumbers = mView->visiblePageNumbers();
QList< QgsLayoutGuide * > guides = layout->guides().guides( mOrientation == Qt::Horizontal ? QgsLayoutGuide::Vertical : QgsLayoutGuide::Horizontal );
p->save();
p->setRenderHint( QPainter::Antialiasing, true );
p->setBrush( QBrush( QColor( 255, 0, 0 ) ) );
p->setPen( Qt::NoPen );
Q_FOREACH ( QgsLayoutGuide *guide, guides )
{
if ( visiblePageNumbers.contains( guide->page() ) )
{
QPointF point;
switch ( mOrientation )
{
case Qt::Horizontal:
point = QPointF( guide->layoutPosition(), 0 );
break;
case Qt::Vertical:
point = QPointF( 0, guide->layoutPosition() );
break;
}
drawGuideAtPos( p, convertLayoutPointToLocal( point ) );
}
}
p->restore();
}
void QgsLayoutRuler::drawGuideAtPos( QPainter *painter, QPoint pos )
{
switch ( mOrientation )
{
case Qt::Horizontal:
{
painter->translate( pos.x(), 0 );
painter->drawPolygon( mGuideMarker );
painter->translate( -pos.x(), 0 );
break;
}
case Qt::Vertical:
{
painter->translate( 0, pos.y() );
painter->drawPolygon( mGuideMarker );
painter->translate( 0, -pos.y() );
break;
}
}
}
void QgsLayoutRuler::createTemporaryGuideItem()
{
mGuideItem.reset( new QGraphicsLineItem() );
@ -279,6 +346,12 @@ QPointF QgsLayoutRuler::convertLocalPointToLayout( QPoint localPoint ) const
return mView->mapToScene( viewPoint );
}
QPoint QgsLayoutRuler::convertLayoutPointToLocal( QPointF layoutPoint ) const
{
QPoint viewPoint = mView->mapFromScene( layoutPoint );
return mapFromGlobal( mView->mapToGlobal( viewPoint ) );
}
void QgsLayoutRuler::drawRotatedText( QPainter *painter, QPointF pos, const QString &text )
{
painter->save();
@ -467,20 +540,19 @@ void QgsLayoutRuler::mouseMoveEvent( QMouseEvent *event )
linePen.setColor( QColor( 255, 0, 0, 225 ) );
}
mGuideItem->setPen( linePen );
switch ( mOrientation )
{
case Qt::Horizontal:
{
//mouse is creating a horizontal ruler, so don't show x coordinate
mGuideItem->setLine( 0, displayPos.y(), page->rect().width(), displayPos.y() );
mGuideItem->setLine( page->scenePos().x(), displayPos.y(), page->scenePos().x() + page->rect().width(), displayPos.y() );
displayPos.setX( 0 );
break;
}
case Qt::Vertical:
{
//mouse is creating a vertical ruler, so don't show a y coordinate
mGuideItem->setLine( displayPos.x(), 0, displayPos.x(), page->rect().height() );
mGuideItem->setLine( displayPos.x(), page->scenePos().y(), displayPos.x(), page->scenePos().y() + page->rect().height() );
displayPos.setY( 0 );
break;
}

View File

@ -111,6 +111,9 @@ class GUI_EXPORT QgsLayoutRuler: public QWidget
bool mCreatingGuide = false;
std::unique_ptr< QGraphicsLineItem > mGuideItem;
//! Polygon for drawing guide markers
QPolygonF mGuideMarker;
//! Calculates the optimum labeled units for ruler so that labels are a good distance apart
int optimumScale( double minPixelDiff, int &magnitude, int &multiple );
@ -133,10 +136,17 @@ class GUI_EXPORT QgsLayoutRuler: public QWidget
//! Draw current marker pos on ruler
void drawMarkerPos( QPainter *painter );
void drawGuideMarkers( QPainter *painter, QgsLayout *layout );
//! Draw a guide marker on the ruler
void drawGuideAtPos( QPainter *painter, QPoint pos );
void createTemporaryGuideItem();
QPointF convertLocalPointToLayout( QPoint localPoint ) const;
QPoint convertLayoutPointToLocal( QPointF layoutPoint ) const;
};

View File

@ -73,6 +73,19 @@ void QgsLayoutView::setCurrentLayout( QgsLayout *layout )
mSnapMarker->hide();
layout->addItem( mSnapMarker.get() );
if ( mHorizontalRuler )
{
connect( &layout->guides(), &QAbstractItemModel::dataChanged, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
connect( &layout->guides(), &QAbstractItemModel::rowsInserted, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
}
if ( mVerticalRuler )
{
connect( &layout->guides(), &QAbstractItemModel::dataChanged, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
connect( &layout->guides(), &QAbstractItemModel::rowsInserted, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
}
//emit layoutSet, so that designer dialogs can update for the new layout
emit layoutSet( layout );
}
@ -148,6 +161,12 @@ void QgsLayoutView::setHorizontalRuler( QgsLayoutRuler *ruler )
{
mHorizontalRuler = ruler;
ruler->setLayoutView( this );
if ( QgsLayout *layout = currentLayout() )
{
connect( &layout->guides(), &QAbstractItemModel::dataChanged, ruler, [ = ] { mHorizontalRuler->update(); } );
connect( &layout->guides(), &QAbstractItemModel::rowsInserted, ruler, [ = ] { mHorizontalRuler->update(); } );
connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, ruler, [ = ] { mHorizontalRuler->update(); } );
}
viewChanged();
}
@ -155,6 +174,12 @@ void QgsLayoutView::setVerticalRuler( QgsLayoutRuler *ruler )
{
mVerticalRuler = ruler;
ruler->setLayoutView( this );
if ( QgsLayout *layout = currentLayout() )
{
connect( &layout->guides(), &QAbstractItemModel::dataChanged, ruler, [ = ] { mVerticalRuler->update(); } );
connect( &layout->guides(), &QAbstractItemModel::rowsInserted, ruler, [ = ] { mVerticalRuler->update(); } );
connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, ruler, [ = ] { mVerticalRuler->update(); } );
}
viewChanged();
}

View File

@ -149,7 +149,12 @@ class TestQgsLayoutGuide(unittest.TestCase):
self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.UnitsRole), QgsUnitTypes.LayoutMillimeters)
self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.PageRole), 1)
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal), [g1, g2])
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal, 0), [g1, g2])
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal, 1), [])
self.assertEqual(guides.guides(QgsLayoutGuide.Vertical), [g3])
self.assertEqual(guides.guides(QgsLayoutGuide.Vertical, 0), [])
self.assertEqual(guides.guides(QgsLayoutGuide.Vertical, 1), [g3])
self.assertEqual(guides.guides(QgsLayoutGuide.Vertical, 2), [])
def testDeleteRows(self):
p = QgsProject()