#include "Node.h" #include "Edge.h" #include "GraphCanvas.h" #include #include #include #include #include #include #define PORT_SIZE 15 // ------------------------------------------------------------------------- PipelineEditor::Node:: Node( GraphCanvas* canvas, cpPlugins::Interface::Object* object ) : QGraphicsItem( NULL ), m_Canvas( canvas ), m_Object( object ), m_SelectedPort( NULL ), m_DraggingPort( false ) { this->setFlag( QGraphicsItem::ItemIsMovable, true ); this->setFlag( QGraphicsItem::ItemSendsGeometryChanges, true ); this->setCacheMode( QGraphicsItem::DeviceCoordinateCache ); this->setAcceptHoverEvents( true ); this->setAcceptDrops( true ); this->setZValue( -1 ); this->updateRepresentation( ); } // ------------------------------------------------------------------------- PipelineEditor::Node:: ~Node( ) { } // ------------------------------------------------------------------------- void PipelineEditor::Node:: addEdge( PipelineEditor::Edge* edge ) { this->m_Edges << edge; edge->adjust( ); } // ------------------------------------------------------------------------- QList< PipelineEditor::Edge* > PipelineEditor::Node:: edges( ) const { return( this->m_Edges ); } // ------------------------------------------------------------------------- void PipelineEditor::Node:: updateRepresentation( ) { typedef cpPlugins::Interface::DataObject _TData; typedef cpPlugins::Interface::ProcessObject _TFilter; 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 ) { // 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 ) { 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 } // rof } // fi // Some other initializations this->m_SelectedPort = NULL; } // ------------------------------------------------------------------------- QRectF PipelineEditor::Node:: boundingRect( ) const { return( this->m_Bounds ); } // ------------------------------------------------------------------------- QPainterPath PipelineEditor::Node:: shape( ) const { QPainterPath path; path.addRect( this->m_Bounds ); return( path ); } // ------------------------------------------------------------------------- void PipelineEditor::Node:: paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget ) { // Draw main box QRectF rect = this->boundingRect( ); painter->drawRect( rect ); painter->drawText( rect, Qt::AlignCenter, this->m_Label ); // 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 ); // 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 ) { 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:: mouseReleaseEvent( QGraphicsSceneMouseEvent* event ) { this->update( ); this->QGraphicsItem::mouseReleaseEvent( event ); } // ------------------------------------------------------------------------- void PipelineEditor::Node:: mouseDoubleClickEvent( QGraphicsSceneMouseEvent* event ) { } // ------------------------------------------------------------------------- void PipelineEditor::Node:: hoverMoveEvent( QGraphicsSceneHoverEvent* event ) { this->_selectPort( event->pos( ) ); } // ------------------------------------------------------------------------- void PipelineEditor::Node:: hoverLeaveEvent( QGraphicsSceneHoverEvent* event ) { this->_deselectPort( ); } // ------------------------------------------------------------------------- void PipelineEditor::Node:: dragMoveEvent( QGraphicsSceneDragDropEvent* event ) { this->_selectPort( event->pos( ) ); } // ------------------------------------------------------------------------- void PipelineEditor::Node:: dragLeaveEvent( QGraphicsSceneDragDropEvent* event ) { this->_deselectPort( ); } // ------------------------------------------------------------------------- void PipelineEditor::Node:: dropEvent( QGraphicsSceneDragDropEvent* event ) { // 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 // 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 PipelineEditor::Node:: _selectPort( const QPointF& pos ) { 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 PipelineEditor::Node:: _deselectPort( ) { if( !( this->m_DraggingPort ) ) { this->m_SelectedPort = NULL; this->update( ); } // fi } // eof - $RCSfile$