Skip to content

Commit

Permalink
[processing modeler] Show arrowheads for parent/child relations
Browse files Browse the repository at this point in the history
  • Loading branch information
olivierdalang committed Apr 16, 2020
1 parent 43c6ea9 commit 915b67d
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 40 deletions.
Expand Up @@ -28,35 +28,41 @@ A link arrow item for use in the model designer.
%End
public:

QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, bool startIsOutgoing,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex, bool endIsIncoming );
enum Marker
{
Circle,
ArrowHead,
};

QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, bool startIsOutgoing, Marker startMarker,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex, bool endIsIncoming, Marker endMarker );
%Docstring
Constructor for QgsModelArrowItem, with the specified ``parent`` item.

The arrow will link ``startItem`` to ``endItem``, joining the specified ``startEdge`` and ``startIndex``
to ``endEdge`` and ``endIndex``.
%End

QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex,
QgsModelComponentGraphicItem *endItem );
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, Marker startMarker,
QgsModelComponentGraphicItem *endItem, Marker endMarker );
%Docstring
Constructor for QgsModelArrowItem, with the specified ``parent`` item.

The arrow will link ``startItem`` to ``endItem``, joining the specified ``startEdge`` and ``startIndex``
to an automatic point on ``endItem``.
%End

QgsModelArrowItem( QgsModelComponentGraphicItem *startItem,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex );
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Marker startMarker,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex, Marker endMarker );
%Docstring
Constructor for QgsModelArrowItem, with the specified ``parent`` item.

The arrow will link ``startItem`` to ``endItem``, joining an automatic point on ``startItem`` to the specified
``endEdge`` and ``endIndex``.
%End

QgsModelArrowItem( QgsModelComponentGraphicItem *startItem,
QgsModelComponentGraphicItem *endItem );
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Marker startMarker,
QgsModelComponentGraphicItem *endItem, Marker endMarker );
%Docstring
Constructor for QgsModelArrowItem, with the specified ``parent`` item.

Expand Down
62 changes: 47 additions & 15 deletions src/gui/processing/models/qgsmodelarrowitem.cpp
Expand Up @@ -13,6 +13,8 @@
* *
***************************************************************************/

#include <math.h>

#include "qgsmodelarrowitem.h"
#include "qgsapplication.h"
#include "qgsmodelgraphicsscene.h"
Expand All @@ -24,17 +26,19 @@
///@cond NOT_STABLE


QgsModelArrowItem::QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, bool startIsOutgoing,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex, bool endIsIncoming )
QgsModelArrowItem::QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, bool startIsOutgoing, Marker startMarker,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex, bool endIsIncoming, Marker endMarker )
: QObject( nullptr )
, mStartItem( startItem )
, mStartEdge( startEdge )
, mStartIndex( startIndex )
, mStartIsOutgoing( startIsOutgoing )
, mStartMarker( startMarker )
, mEndItem( endItem )
, mEndEdge( endEdge )
, mEndIndex( endIndex )
, mEndIsIncoming( endIsIncoming )
, mEndMarker( endMarker )
{
setCacheMode( QGraphicsItem::DeviceCoordinateCache );
setFlag( QGraphicsItem::ItemIsSelectable, false );
Expand All @@ -50,21 +54,22 @@ QgsModelArrowItem::QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Q
connect( mEndItem, &QgsModelComponentGraphicItem::repaintArrows, this, [ = ] { update(); } );
}

QgsModelArrowItem::QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, QgsModelComponentGraphicItem *endItem )
: QgsModelArrowItem( startItem, startEdge, startIndex, true, endItem, Qt::LeftEdge, -1, true )
QgsModelArrowItem::QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, Marker startMarker, QgsModelComponentGraphicItem *endItem, Marker endMarker )
: QgsModelArrowItem( startItem, startEdge, startIndex, true, startMarker, endItem, Qt::LeftEdge, -1, true, endMarker )
{
}

QgsModelArrowItem::QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex )
: QgsModelArrowItem( startItem, Qt::LeftEdge, -1, true, endItem, endEdge, endIndex, true )
QgsModelArrowItem::QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Marker startMarker, QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex, Marker endMarker )
: QgsModelArrowItem( startItem, Qt::LeftEdge, -1, true, startMarker, endItem, endEdge, endIndex, true, endMarker )
{
}

QgsModelArrowItem::QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, QgsModelComponentGraphicItem *endItem )
: QgsModelArrowItem( startItem, Qt::LeftEdge, -1, true, endItem, Qt::LeftEdge, -1, true )
QgsModelArrowItem::QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Marker startMarker, QgsModelComponentGraphicItem *endItem, Marker endMarker )
: QgsModelArrowItem( startItem, Qt::LeftEdge, -1, true, startMarker, endItem, Qt::LeftEdge, -1, true, endMarker )
{
}


void QgsModelArrowItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget * )
{
QColor color = mColor;
Expand All @@ -83,15 +88,43 @@ void QgsModelArrowItem::paint( QPainter *painter, const QStyleOptionGraphicsItem
painter->setBrush( color );
painter->setRenderHint( QPainter::Antialiasing );

for ( const QPointF &point : qgis::as_const( mNodePoints ) )

switch ( mStartMarker )
{
painter->drawEllipse( point, 3.0, 3.0 );
case Marker::Circle:
painter->drawEllipse( mStartPoint, 3.0, 3.0 );
break;
case Marker::ArrowHead:
drawArrowHead( painter, mStartPoint, path().pointAtPercent( 0.0 ) - path().pointAtPercent( 0.05 ) );
break;
}

switch ( mEndMarker )
{
case Marker::Circle:
painter->drawEllipse( mEndPoint, 3.0, 3.0 );
break;
case Marker::ArrowHead:
drawArrowHead( painter, mEndPoint, path().pointAtPercent( 1.0 ) - path().pointAtPercent( 0.95 ) );
break;
}

painter->setBrush( Qt::NoBrush );
painter->drawPath( path() );
}

void QgsModelArrowItem::drawArrowHead( QPainter *painter, const QPointF &position, const QPointF &vector )
{
float angle = atan2( vector.y(), vector.x() ) * 180.0 / M_PI;
painter->translate( position );
painter->rotate( angle );
QPolygonF arrowHead;
arrowHead << QPointF( 0, 0 ) << QPointF( -6, 4 ) << QPointF( -6, -4 ) << QPointF( 0, 0 );
painter->drawPolygon( arrowHead );
painter->rotate( -angle );
painter->translate( -position );
}

void QgsModelArrowItem::setPenStyle( Qt::PenStyle style )
{
QPen p = pen();
Expand All @@ -102,7 +135,6 @@ void QgsModelArrowItem::setPenStyle( Qt::PenStyle style )

void QgsModelArrowItem::updatePath()
{
mNodePoints.clear();
QList< QPointF > controlPoints;

// is there a fixed start or end point?
Expand Down Expand Up @@ -131,12 +163,12 @@ void QgsModelArrowItem::updatePath()
pt = mStartItem->calculateAutomaticLinkPoint( endPt + mEndItem->pos(), startEdge );

controlPoints.append( pt );
mNodePoints.append( pt );
mStartPoint = pt;
controlPoints.append( bezierPointForCurve( pt, startEdge, !mStartIsOutgoing ) );
}
else
{
mNodePoints.append( mStartItem->pos() + startPt );
mStartPoint = mStartItem->pos() + startPt;
controlPoints.append( mStartItem->pos() + startPt );
controlPoints.append( bezierPointForCurve( mStartItem->pos() + startPt, mStartEdge == Qt::BottomEdge ? Qt::RightEdge : Qt::LeftEdge, !mStartIsOutgoing ) );
}
Expand All @@ -152,11 +184,11 @@ void QgsModelArrowItem::updatePath()

controlPoints.append( bezierPointForCurve( pt, endEdge, mEndIsIncoming ) );
controlPoints.append( pt );
mNodePoints.append( pt );
mEndPoint = pt;
}
else
{
mNodePoints.append( mEndItem->pos() + endPt );
mEndPoint = mEndItem->pos() + endPt ;
controlPoints.append( bezierPointForCurve( mEndItem->pos() + endPt, mEndEdge == Qt::BottomEdge ? Qt::RightEdge : Qt::LeftEdge, mEndIsIncoming ) );
controlPoints.append( mEndItem->pos() + endPt );
}
Expand Down
29 changes: 20 additions & 9 deletions src/gui/processing/models/qgsmodelarrowitem.h
Expand Up @@ -37,40 +37,46 @@ class GUI_EXPORT QgsModelArrowItem : public QObject, public QGraphicsPathItem
Q_OBJECT
public:

enum Marker
{
Circle,
ArrowHead,
};

/**
* Constructor for QgsModelArrowItem, with the specified \a parent item.
*
* The arrow will link \a startItem to \a endItem, joining the specified \a startEdge and \a startIndex
* to \a endEdge and \a endIndex.
*/
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, bool startIsOutgoing,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex, bool endIsIncoming );
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, bool startIsOutgoing, Marker startMarker,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex, bool endIsIncoming, Marker endMarker );

/**
* Constructor for QgsModelArrowItem, with the specified \a parent item.
*
* The arrow will link \a startItem to \a endItem, joining the specified \a startEdge and \a startIndex
* to an automatic point on \a endItem.
*/
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex,
QgsModelComponentGraphicItem *endItem );
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Qt::Edge startEdge, int startIndex, Marker startMarker,
QgsModelComponentGraphicItem *endItem, Marker endMarker );

/**
* Constructor for QgsModelArrowItem, with the specified \a parent item.
*
* The arrow will link \a startItem to \a endItem, joining an automatic point on \a startItem to the specified
* \a endEdge and \a endIndex.
*/
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex );
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Marker startMarker,
QgsModelComponentGraphicItem *endItem, Qt::Edge endEdge, int endIndex, Marker endMarker );

/**
* Constructor for QgsModelArrowItem, with the specified \a parent item.
*
* The arrow will link \a startItem to \a endItem, joining an automatic points on both items.
*/
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem,
QgsModelComponentGraphicItem *endItem );
QgsModelArrowItem( QgsModelComponentGraphicItem *startItem, Marker startMarker,
QgsModelComponentGraphicItem *endItem, Marker endMarker );

void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr ) override;

Expand All @@ -90,17 +96,22 @@ class GUI_EXPORT QgsModelArrowItem : public QObject, public QGraphicsPathItem

QPointF bezierPointForCurve( const QPointF &point, Qt::Edge edge, bool incoming ) const;

void drawArrowHead( QPainter *painter, const QPointF &point, const QPointF &vector );

QgsModelComponentGraphicItem *mStartItem = nullptr;
Qt::Edge mStartEdge = Qt::LeftEdge;
int mStartIndex = -1;
bool mStartIsOutgoing = true;
Marker mStartMarker;

QgsModelComponentGraphicItem *mEndItem = nullptr;
Qt::Edge mEndEdge = Qt::LeftEdge;
int mEndIndex = -1;
bool mEndIsIncoming = false;
Marker mEndMarker;

QList< QPointF > mNodePoints;
QPointF mStartPoint;
QPointF mEndPoint;

QColor mColor;
};
Expand Down
17 changes: 9 additions & 8 deletions src/gui/processing/models/qgsmodelgraphicsscene.cpp
Expand Up @@ -123,7 +123,7 @@ void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, Qgs
{
if ( mParameterItems.contains( it.key() ) && mParameterItems.contains( otherName ) )
{
std::unique_ptr< QgsModelArrowItem > arrow = qgis::make_unique< QgsModelArrowItem >( mParameterItems.value( otherName ), mParameterItems.value( it.key() ) );
std::unique_ptr< QgsModelArrowItem > arrow = qgis::make_unique< QgsModelArrowItem >( mParameterItems.value( otherName ), QgsModelArrowItem::Marker::Circle, mParameterItems.value( it.key() ), QgsModelArrowItem::Marker::ArrowHead );
arrow->setPenStyle( Qt::DotLine );
addItem( arrow.release() );
}
Expand Down Expand Up @@ -172,13 +172,14 @@ void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, Qgs
continue;
QgsModelArrowItem *arrow = nullptr;
if ( link.linkIndex == -1 )
arrow = new QgsModelArrowItem( link.item, mChildAlgorithmItems.value( it.value().childId() ), parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge, parameter->isDestination() ? bottomIdx : topIdx );
arrow = new QgsModelArrowItem( link.item, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge, parameter->isDestination() ? bottomIdx : topIdx, QgsModelArrowItem::Marker::Circle );
else
arrow = new QgsModelArrowItem( link.item, link.edge, link.linkIndex, true,
arrow = new QgsModelArrowItem( link.item, link.edge, link.linkIndex, true, QgsModelArrowItem::Marker::Circle,
mChildAlgorithmItems.value( it.value().childId() ),
parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge,
parameter->isDestination() ? bottomIdx : topIdx,
true );
true,
QgsModelArrowItem::Marker::Circle );
addItem( arrow );
}
}
Expand All @@ -193,7 +194,7 @@ void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, Qgs
{
if ( depend.conditionalBranch.isEmpty() || !model->childAlgorithm( depend.childId ).algorithm() )
{
addItem( new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), mChildAlgorithmItems.value( it.value().childId() ) ) );
addItem( new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
}
else
{
Expand All @@ -206,7 +207,7 @@ void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, Qgs
break;
i++;
}
addItem( new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), Qt::BottomEdge, i, mChildAlgorithmItems.value( it.value().childId() ) ) );
addItem( new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), Qt::BottomEdge, i, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
}
}
}
Expand Down Expand Up @@ -245,7 +246,7 @@ void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, Qgs

item->setPos( pos );
outputItems.insert( outputIt.key(), item );
addItem( new QgsModelArrowItem( mChildAlgorithmItems[it.value().childId()], Qt::BottomEdge, idx, item ) );
addItem( new QgsModelArrowItem( mChildAlgorithmItems[it.value().childId()], Qt::BottomEdge, idx, QgsModelArrowItem::Marker::Circle, item, QgsModelArrowItem::Marker::Circle ) );

addCommentItemForComponent( model, outputIt.value(), item );
}
Expand Down Expand Up @@ -446,7 +447,7 @@ void QgsModelGraphicsScene::addCommentItemForComponent( QgsProcessingModelAlgori
connect( commentItem, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged );
connect( commentItem, &QgsModelComponentGraphicItem::aboutToChange, this, &QgsModelGraphicsScene::componentAboutToChange );

std::unique_ptr< QgsModelArrowItem > arrow = qgis::make_unique< QgsModelArrowItem >( parentItem, commentItem );
std::unique_ptr< QgsModelArrowItem > arrow = qgis::make_unique< QgsModelArrowItem >( parentItem, QgsModelArrowItem::Circle, commentItem, QgsModelArrowItem::Circle );
arrow->setPenStyle( Qt::DotLine );
addItem( arrow.release() );
}
Expand Down

0 comments on commit 915b67d

Please sign in to comment.