Skip to content

Commit

Permalink
Show guide positions in rulers
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Aug 7, 2017
1 parent ab726c4 commit c6c9c6f
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 11 deletions.
5 changes: 3 additions & 2 deletions python/core/layout/qgslayoutguidecollection.sip
Expand Up @@ -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

Expand Down
12 changes: 8 additions & 4 deletions src/core/layout/qgslayoutguidecollection.cpp
Expand Up @@ -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
}
Expand Down Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions src/core/layout/qgslayoutguidecollection.h
Expand Up @@ -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:

Expand Down
78 changes: 75 additions & 3 deletions src/gui/layout/qgslayoutruler.cpp
Expand Up @@ -16,6 +16,7 @@
#include "qgslayout.h"
#include "qgis.h"
#include "qgslayoutview.h"
#include "qgslogger.h"
#include <QDragEnterEvent>
#include <QGraphicsLineItem>
#include <QPainter>
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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() );
Expand All @@ -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();
Expand Down Expand Up @@ -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;
}
Expand Down
10 changes: 10 additions & 0 deletions src/gui/layout/qgslayoutruler.h
Expand Up @@ -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 );

Expand All @@ -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;


};

Expand Down
25 changes: 25 additions & 0 deletions src/gui/layout/qgslayoutview.cpp
Expand Up @@ -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 );
}
Expand Down Expand Up @@ -148,13 +161,25 @@ 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();
}

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();
}

Expand Down
5 changes: 5 additions & 0 deletions tests/src/python/test_qgslayoutguides.py
Expand Up @@ -149,7 +149,12 @@ def testCollection(self):
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()
Expand Down

0 comments on commit c6c9c6f

Please sign in to comment.