]> Creatis software - cpPlugins.git/blobdiff - appli/cpPipelineEditor/Node.cxx
More on graph editor
[cpPlugins.git] / appli / cpPipelineEditor / Node.cxx
index a1026dc6260e211eeb1255c13a13a2fd6901bc89..34c4d96fddc1f314503331b54f1dc7a0d0303fdb 100644 (file)
@@ -7,9 +7,10 @@
 #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::
@@ -17,14 +18,16 @@ Node( GraphCanvas* canvas, cpPlugins::Interface::Object* object )
   : 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( );
 }
 
 // -------------------------------------------------------------------------
@@ -49,49 +52,95 @@ edges( ) const
 }
 
 // -------------------------------------------------------------------------
-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 );
 }
 
@@ -100,7 +149,7 @@ QPainterPath PipelineEditor::Node::
 shape( ) const
 {
   QPainterPath path;
-  path.addRect( this->boundingRect( ) );
+  path.addRect( this->m_Bounds );
   return( path );
 }
 
@@ -110,49 +159,23 @@ paint(
   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
 }
@@ -161,18 +184,16 @@ paint(
 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 ) );
 }
 
@@ -180,6 +201,54 @@ itemChange( GraphicsItemChange change, const QVariant& 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 );
 }
@@ -202,51 +271,121 @@ mouseDoubleClickEvent( QGraphicsSceneMouseEvent* 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$
-*/