#include <QGraphicsSceneHoverEvent>
#include <cpPlugins/Interface/Object.h>
+#include <cpPlugins/Interface/DataObject.h>
#include <cpPlugins/Interface/ProcessObject.h>
-#define PORT_SIZE 10
+#define PORT_SIZE 15
// -------------------------------------------------------------------------
PipelineEditor::Node::
: QGraphicsItem( NULL ),
m_Canvas( canvas ),
m_Object( object ),
- m_UpdatedBounds( false )
+ m_SelectedPort( NULL ),
+ m_DraggingPort( false )
{
- this->setFlag( QGraphicsItem::ItemIsMovable );
- this->setFlag( QGraphicsItem::ItemSendsGeometryChanges );
+ this->setFlag( QGraphicsItem::ItemIsMovable, true );
+ this->setFlag( QGraphicsItem::ItemSendsGeometryChanges, true );
this->setCacheMode( QGraphicsItem::DeviceCoordinateCache );
this->setAcceptHoverEvents( true );
+ this->setAcceptDrops( true );
this->setZValue( -1 );
- this->setToolTip( this->m_Object->GetName( ) );
+ this->updateRepresentation( );
}
// -------------------------------------------------------------------------
}
// -------------------------------------------------------------------------
-QRectF PipelineEditor::Node::
-boundingRect( ) const
+void PipelineEditor::Node::
+updateRepresentation( )
{
+ typedef cpPlugins::Interface::DataObject _TData;
typedef cpPlugins::Interface::ProcessObject _TFilter;
- if( !this->m_UpdatedBounds )
+
+ if( this->m_Object == NULL )
+ return;
+
+ // Try to infere type
+ _TData* d = dynamic_cast< _TData* >( this->m_Object );
+ _TFilter* f = dynamic_cast< _TFilter* >( this->m_Object );
+ if( d == NULL && f == NULL )
+ return;
+
+ // Label and its bounds
+ QFontMetricsF fm( this->m_Canvas->font( ) );
+ this->m_Label = this->m_Object->GetName( );
+ this->m_Label += "\n";
+ this->m_Label += this->m_Object->GetClassName( ).c_str( );
+ this->m_Bounds = fm.boundingRect( this->m_Label );
+
+ // Create ports representation
+ this->m_Inputs.clear( );
+ this->m_Outputs.clear( );
+ this->m_InputPorts.clear( );
+ this->m_OutputPorts.clear( );
+ if( f != NULL )
{
- // Text bounding box
- QFontMetricsF fm( this->m_Canvas->font( ) );
- this->m_Label = this->m_Object->GetName( );
- this->m_Label += "\n";
- this->m_Label += this->m_Object->GetClassName( ).c_str( );
-
- // Ports
- this->m_Bounds = fm.boundingRect( this->m_Label );
- const _TFilter* f = dynamic_cast< const _TFilter* >( this->m_Object );
- if( f != NULL )
+ // Get filter's inputs and outputs
+ f->GetInputsNames( this->m_Inputs );
+ f->GetOutputsNames( this->m_Outputs );
+
+ // Correct height
+ unsigned int nIn = this->m_Inputs.size( );
+ unsigned int nOut = this->m_Outputs.size( );
+ qreal n =
+ qreal( ( ( ( ( nIn > nOut )? nIn: nOut ) << 1 ) + 1 ) * PORT_SIZE );
+ qreal h = this->m_Bounds.height( );
+ if( n > h )
+ this->m_Bounds.setHeight( n );
+
+ // Get bounds values
+ qreal rt = this->m_Bounds.top( ) - qreal( PORT_SIZE );
+ qreal rb = this->m_Bounds.bottom( ) + qreal( PORT_SIZE );
+ qreal rl = this->m_Bounds.left( ) - qreal( PORT_SIZE );
+ qreal rr = this->m_Bounds.right( ) + qreal( PORT_SIZE );
+
+ // Add some space to the geometry
+ this->m_Bounds.setTop( rt );
+ this->m_Bounds.setBottom( rb );
+ this->m_Bounds.setLeft( rl );
+ this->m_Bounds.setRight( rr );
+ qreal rh = this->m_Bounds.height( );
+
+ // Create ports
+ QSizeF ps( qreal( PORT_SIZE ), qreal( PORT_SIZE ) );
+ std::set< std::string >* ports[] =
+ { &( this->m_Inputs ), &( this->m_Outputs ) };
+ for( unsigned int pId = 0; pId < 2; ++pId )
{
- unsigned int nIn = f->GetNumberOfInputs( );
- unsigned int nOut = f->GetNumberOfOutputs( );
- qreal n =
- qreal( ( ( ( ( nIn > nOut )? nIn: nOut ) << 1 ) + 1 ) * PORT_SIZE );
- qreal h = this->m_Bounds.height( );
- if( n > h )
- this->m_Bounds.setHeight( n );
-
- // Let some space for ports
- this->m_Bounds.setLeft(
- this->m_Bounds.left( ) - qreal( PORT_SIZE )
- );
- this->m_Bounds.setTop(
- this->m_Bounds.top( ) - qreal( PORT_SIZE )
- );
- this->m_Bounds.setRight(
- this->m_Bounds.right( ) + qreal( PORT_SIZE )
- );
- this->m_Bounds.setBottom(
- this->m_Bounds.bottom( ) + qreal( PORT_SIZE )
- );
+ qreal h = qreal( ( ( ports[ pId ]->size( ) << 1 ) + 1 ) * PORT_SIZE );
+ qreal off = qreal( PORT_SIZE );
+ if( rh > h )
+ off += ( rh - h ) / qreal( 2 );
+ for( auto i = ports[ pId ]->begin( ); i != ports[ pId ]->end( ); ++i )
+ {
+ if( pId == 0 )
+ this->m_InputPorts[ *i ] =
+ QRectF( QPointF( rl, rt + off ), ps );
+ else
+ this->m_OutputPorts[ *i ] =
+ QRectF( QPointF( rr - qreal( PORT_SIZE ), rt + off ), ps );
+ off += qreal( PORT_SIZE < 1 );
+
+ } // rof
- } // fi
- this->m_UpdatedBounds = true;
+ } // rof
} // fi
+
+ // Some other initializations
+ this->m_SelectedPort = NULL;
+}
+
+// -------------------------------------------------------------------------
+QRectF PipelineEditor::Node::
+boundingRect( ) const
+{
return( this->m_Bounds );
}
shape( ) const
{
QPainterPath path;
- path.addRect( this->boundingRect( ) );
+ path.addRect( this->m_Bounds );
return( path );
}
QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget
)
{
- typedef cpPlugins::Interface::ProcessObject _TFilter;
-
+ // Draw main box
QRectF rect = this->boundingRect( );
painter->drawRect( rect );
painter->drawText( rect, Qt::AlignCenter, this->m_Label );
- // Show ports
- const _TFilter* f = dynamic_cast< const _TFilter* >( this->m_Object );
- if( f != NULL )
- {
- QSizeF port_size( qreal( PORT_SIZE ), qreal( PORT_SIZE ) );
- qreal rh = rect.height( );
- qreal rt = rect.top( );
- qreal rl = rect.left( );
- qreal rr = rect.right( );
-
- std::set< std::string > inputs, outputs;
- f->GetInputsNames( inputs );
- f->GetOutputsNames( outputs );
-
- qreal oh = qreal( ( ( inputs.size( ) << 1 ) + 1 ) * PORT_SIZE );
- qreal off = qreal( PORT_SIZE );
- if( rh > oh )
- off += ( rh - oh ) / qreal( 2 );
- for( auto it = inputs.begin( ); it != inputs.end( ); ++it )
- {
- painter->drawRect( QRectF( QPointF( rl, rt + off ), port_size ) );
- off += qreal( PORT_SIZE < 1 );
+ // Draw ports
+ std::map< std::string, QRectF >* ports[] =
+ { &( this->m_InputPorts ), &( this->m_OutputPorts ) };
+ for( unsigned int pId = 0; pId < 2; ++pId )
+ for( auto i = ports[ pId ]->begin( ); i != ports[ pId ]->end( ); ++i )
+ painter->drawRect( i->second );
- } // rof
-
- oh = qreal( ( ( outputs.size( ) << 1 ) + 1 ) * PORT_SIZE );
- off = qreal( PORT_SIZE );
- if( rh > oh )
- off += ( rh - oh ) / qreal( 2 );
- for( auto it = outputs.begin( ); it != outputs.end( ); ++it )
- {
- painter->drawRect(
- QRectF( QPointF( rr - qreal( PORT_SIZE ), rt + off ), port_size )
- );
- off += qreal( PORT_SIZE < 1 );
-
- } // rof
+ // Draw clicked port
+ if( this->m_SelectedPort != NULL )
+ {
+ painter->setBrush( Qt::green );
+ painter->drawEllipse( *( this->m_SelectedPort ) );
} // fi
}
QVariant PipelineEditor::Node::
itemChange( GraphicsItemChange change, const QVariant& value )
{
- /* TODO
- switch( change )
- {
- case QGraphicsItem::ItemPositionHasChanged:
- foreach( Edge* edge, this->m_Edges )
- edge->adjust( );
- this->m_Canvas->itemMoved( );
- break;
- default:
- break;
- } // hctiws
- */
+ switch( change )
+ {
+ case QGraphicsItem::ItemPositionHasChanged:
+ foreach( Edge* edge, this->m_Edges )
+ edge->update( );
+ this->m_Canvas->itemMoved( );
+ break;
+ default:
+ break;
+ } // hctiws
return( this->QGraphicsItem::itemChange( change, value ) );
}
void PipelineEditor::Node::
mousePressEvent( QGraphicsSceneMouseEvent* event )
{
+ if( this->m_SelectedPort != NULL && this->m_Canvas != NULL )
+ {
+ if( event->button( ) == Qt::LeftButton )
+ {
+ QDrag* drag = new QDrag( this->m_Canvas );
+ QMimeData* mimeData = new QMimeData( );
+
+ // mimeData->setText( "drag_data" );
+ qulonglong address = reinterpret_cast< qulonglong >( this );
+ QByteArray ba;
+ ba.setNum( address );
+ mimeData->setData( "source_node", ba );
+ drag->setMimeData( mimeData );
+ // TODO: drag->setPixmap( iconPixmap );
+
+ this->m_DraggingPort = true;
+ Qt::DropAction dropAction = drag->exec( );
+ this->m_DraggingPort = false;
+
+ } // fi
+ }
+ else
+ {
+ } // fi
+
+ /* TODO
+ Qt::MouseButton btn = event->button( );
+ if( btn == Qt::LeftButton )
+ {
+ std::string name = this->toolTip( ).toStdString( );
+ if( name != this->m_Object->GetName( ) )
+ {
+ // Get clicked port, if any
+ QPointF pos = event->buttonDownPos( btn );
+ auto iIt = this->m_InputPorts.find( name );
+ auto oIt = this->m_OutputPorts.find( name );
+ this->m_SelectedPort = NULL;
+ if( iIt != this->m_InputPorts.end( ) )
+ if( iIt->second.contains( pos ) )
+ this->m_SelectedPort = &( iIt->second );
+ if( this->m_SelectedPort == NULL && oIt != this->m_OutputPorts.end( ) )
+ if( oIt->second.contains( pos ) )
+ this->m_SelectedPort = &( oIt->second );
+
+ } // fi
+
+ } // fi
+ */
this->update( );
this->QGraphicsItem::mousePressEvent( event );
}
void PipelineEditor::Node::
hoverMoveEvent( QGraphicsSceneHoverEvent* event )
{
- QPointF pos = event->pos( );
+ this->_selectPort( event->pos( ) );
}
-/* TODO
- private:
- GraphCanvas* m_Canvas;
- QList< Edge* > m_Edges;
- std::string m_Label;
- };
-
- } // ecapseman
-
- #endif // __PIPELINEEDITOR__NODE__H__
-*/
+// -------------------------------------------------------------------------
+void PipelineEditor::Node::
+hoverLeaveEvent( QGraphicsSceneHoverEvent* event )
+{
+ this->_deselectPort( );
+}
-// eof - $RCSfile$
+// -------------------------------------------------------------------------
+void PipelineEditor::Node::
+dragMoveEvent( QGraphicsSceneDragDropEvent* event )
+{
+ this->_selectPort( event->pos( ) );
+}
+// -------------------------------------------------------------------------
+void PipelineEditor::Node::
+dragLeaveEvent( QGraphicsSceneDragDropEvent* event )
+{
+ this->_deselectPort( );
+}
-/*
-QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value)
+// -------------------------------------------------------------------------
+void PipelineEditor::Node::
+dropEvent( QGraphicsSceneDragDropEvent* event )
{
- switch (change) {
- case ItemPositionHasChanged:
- foreach (Edge *edge, edgeList)
- edge->adjust();
- graph->itemMoved();
- break;
- default:
- break;
- };
+ // Get vertices and directionality
+ bool ok;
+ qulonglong address =
+ event->mimeData( )->data( "source_node" ).toULongLong( &ok );
+ Node* src = reinterpret_cast< Node* >( address );
+ if( src == NULL )
+ return;
+ Node* des = this;
+ if( src->m_SelectedPortIsInput )
+ {
+ des = src;
+ src = this;
+
+ } // fi
- return QGraphicsItem::itemChange(change, value);
+ // Discard if a loop is detected
+ if( src == des )
+ return;
+
+ // Get edge data
+ const QRectF* srcPort = src->m_SelectedPort;
+ const QRectF* desPort = des->m_SelectedPort;
+ std::string srcName = src->m_Object->GetName( );
+ std::string desName = des->m_Object->GetName( );
+ std::string srcPortName = src->toolTip( ).toStdString( );
+ std::string desPortName = des->toolTip( ).toStdString( );
+
+ Edge* e = new Edge( src, des, srcPort, desPort );
+ src->addEdge( e );
+ des->addEdge( e );
+ if( this->m_Canvas != NULL )
+ this->m_Canvas->scene( )->addItem( e );
}
-void Node::mousePressEvent(QGraphicsSceneMouseEvent *event)
+// -------------------------------------------------------------------------
+void PipelineEditor::Node::
+_selectPort( const QPointF& pos )
{
- update();
- QGraphicsItem::mousePressEvent(event);
+ if( this->m_DraggingPort )
+ return;
+
+ const QRectF* prevPort = this->m_SelectedPort;
+
+ // Check ports
+ std::map< std::string, QRectF >* ports[] =
+ { &( this->m_InputPorts ), &( this->m_OutputPorts ) };
+ bool found = false;
+ for( unsigned int pId = 0; pId < 2 && !found; ++pId )
+ {
+ for(
+ auto i = ports[ pId ]->begin( );
+ i != ports[ pId ]->end( ) && !found;
+ ++i
+ )
+ {
+ if( i->second.contains( pos ) )
+ {
+ this->setToolTip( i->first.c_str( ) );
+ this->m_SelectedPort = &( i->second );
+ this->m_SelectedPortIsInput = ( pId == 0 );
+ found = true;
+
+ } // fi
+
+ } // rof
+
+ } // rof
+ if( !found )
+ {
+ this->setToolTip( this->m_Object->GetName( ) );
+ this->m_SelectedPort = NULL;
+
+ } // fi
+ if( prevPort != this->m_SelectedPort )
+ this->update( );
}
-void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+// -------------------------------------------------------------------------
+void PipelineEditor::Node::
+_deselectPort( )
{
- update();
- QGraphicsItem::mouseReleaseEvent(event);
+ if( !( this->m_DraggingPort ) )
+ {
+ this->m_SelectedPort = NULL;
+ this->update( );
+
+ } // fi
}
// eof - $RCSfile$
-*/