]> Creatis software - cpPlugins.git/blob - appli/cpPipelineEditor/Node.cxx
...
[cpPlugins.git] / appli / cpPipelineEditor / Node.cxx
1 #include "Node.h"
2 #include "Edge.h"
3 #include "GraphCanvas.h"
4
5 #include <QFontMetricsF>
6 #include <QGraphicsWidget>
7 #include <QGraphicsSceneHoverEvent>
8
9 #include <cpPlugins/Interface/Object.h>
10 #include <cpPlugins/Interface/DataObject.h>
11 #include <cpPlugins/Interface/ProcessObject.h>
12
13 #define PORT_SIZE 15
14
15 // -------------------------------------------------------------------------
16 PipelineEditor::Node::
17 Node( GraphCanvas* canvas, cpPlugins::Interface::Object* object )
18   : QGraphicsItem( NULL ),
19     m_Canvas( canvas ),
20     m_Object( object ),
21     m_SelectedPort( NULL ),
22     m_DraggingPort( false )
23 {
24   this->setFlag( QGraphicsItem::ItemIsMovable, true );
25   this->setFlag( QGraphicsItem::ItemSendsGeometryChanges, true );
26   this->setCacheMode( QGraphicsItem::DeviceCoordinateCache );
27   this->setAcceptHoverEvents( true );
28   this->setAcceptDrops( true );
29   this->setZValue( -1 );
30   this->updateRepresentation( );
31 }
32
33 // -------------------------------------------------------------------------
34 PipelineEditor::Node::
35 ~Node( )
36 {
37 }
38
39 // -------------------------------------------------------------------------
40 void PipelineEditor::Node::
41 addEdge( PipelineEditor::Edge* edge )
42 {
43   this->m_Edges << edge;
44   edge->adjust( );
45 }
46
47 // -------------------------------------------------------------------------
48 QList< PipelineEditor::Edge* > PipelineEditor::Node::
49 edges( ) const
50 {
51   return( this->m_Edges );
52 }
53
54 // -------------------------------------------------------------------------
55 void PipelineEditor::Node::
56 updateRepresentation( )
57 {
58   typedef cpPlugins::Interface::DataObject    _TData;
59   typedef cpPlugins::Interface::ProcessObject _TFilter;
60
61   if( this->m_Object == NULL )
62     return;
63
64   // Try to infere type
65   _TData* d = dynamic_cast< _TData* >( this->m_Object );
66   _TFilter* f = dynamic_cast< _TFilter* >( this->m_Object );
67   if( d == NULL && f == NULL )
68     return;
69
70   // Label and its bounds
71   QFontMetricsF fm( this->m_Canvas->font( ) );
72   this->m_Label  = this->m_Object->GetName( );
73   this->m_Label += "\n";
74   this->m_Label += this->m_Object->GetClassName( ).c_str( );
75   this->m_Bounds = fm.boundingRect( this->m_Label );
76
77   // Create ports representation
78   this->m_Inputs.clear( );
79   this->m_Outputs.clear( );
80   this->m_InputPorts.clear( );
81   this->m_OutputPorts.clear( );
82   if( f != NULL )
83   {
84     // Get filter's inputs and outputs
85     f->GetInputsNames( this->m_Inputs );
86     f->GetOutputsNames( this->m_Outputs );
87
88     // Correct height
89     unsigned int nIn = this->m_Inputs.size( );
90     unsigned int nOut = this->m_Outputs.size( );
91     qreal n =
92       qreal( ( ( ( ( nIn > nOut )? nIn: nOut ) << 1 ) + 1 ) * PORT_SIZE );
93     qreal h = this->m_Bounds.height( );
94     if( n > h )
95       this->m_Bounds.setHeight( n );
96
97     // Get bounds values
98     qreal rt = this->m_Bounds.top( ) - qreal( PORT_SIZE );
99     qreal rb = this->m_Bounds.bottom( ) + qreal( PORT_SIZE );
100     qreal rl = this->m_Bounds.left( ) - qreal( PORT_SIZE );
101     qreal rr = this->m_Bounds.right( ) + qreal( PORT_SIZE );
102
103     // Add some space to the geometry
104     this->m_Bounds.setTop( rt );
105     this->m_Bounds.setBottom( rb );
106     this->m_Bounds.setLeft( rl );
107     this->m_Bounds.setRight( rr );
108     qreal rh = this->m_Bounds.height( );
109
110     // Create ports
111     QSizeF ps( qreal( PORT_SIZE ), qreal( PORT_SIZE ) );
112     std::set< std::string >* ports[] =
113       { &( this->m_Inputs ), &( this->m_Outputs ) };
114     for( unsigned int pId = 0; pId < 2; ++pId )
115     {
116       qreal h = qreal( ( ( ports[ pId ]->size( ) << 1 ) + 1 ) * PORT_SIZE );
117       qreal off = qreal( PORT_SIZE );
118       if( rh > h )
119         off += ( rh - h ) / qreal( 2 );
120       for( auto i = ports[ pId ]->begin( ); i != ports[ pId ]->end( ); ++i )
121       {
122         if( pId == 0 )
123           this->m_InputPorts[ *i ] =
124             QRectF( QPointF( rl, rt + off ), ps );
125         else
126           this->m_OutputPorts[ *i ] =
127             QRectF( QPointF( rr - qreal( PORT_SIZE ), rt + off ), ps );
128         off += qreal( PORT_SIZE < 1 );
129
130       } // rof
131
132     } // rof
133
134   } // fi
135
136   // Some other initializations
137   this->m_SelectedPort = NULL;
138 }
139
140 // -------------------------------------------------------------------------
141 QRectF PipelineEditor::Node::
142 boundingRect( ) const
143 {
144   return( this->m_Bounds );
145 }
146
147 // -------------------------------------------------------------------------
148 QPainterPath PipelineEditor::Node::
149 shape( ) const
150 {
151   QPainterPath path;
152   path.addRect( this->m_Bounds );
153   return( path );
154 }
155
156 // -------------------------------------------------------------------------
157 void PipelineEditor::Node::
158 paint(
159   QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget
160   )
161 {
162   // Draw main box
163   QRectF rect = this->boundingRect( );
164   painter->drawRect( rect );
165   painter->drawText( rect, Qt::AlignCenter, this->m_Label );
166
167   // Draw ports
168   std::map< std::string, QRectF >* ports[] =
169     { &( this->m_InputPorts ), &( this->m_OutputPorts ) };
170   for( unsigned int pId = 0; pId < 2; ++pId )
171     for( auto i = ports[ pId ]->begin( ); i != ports[ pId ]->end( ); ++i )
172       painter->drawRect( i->second );
173
174   // Draw clicked port
175   if( this->m_SelectedPort != NULL )
176   {
177     painter->setBrush( Qt::green );
178     painter->drawEllipse( *( this->m_SelectedPort ) );
179
180   } // fi
181 }
182
183 // -------------------------------------------------------------------------
184 QVariant PipelineEditor::Node::
185 itemChange( GraphicsItemChange change, const QVariant& value )
186 {
187   switch( change )
188   {
189   case QGraphicsItem::ItemPositionHasChanged:
190     foreach( Edge* edge, this->m_Edges )
191       edge->update( );
192     this->m_Canvas->itemMoved( );
193     break;
194   default:
195     break;
196   } // hctiws
197   return( this->QGraphicsItem::itemChange( change, value ) );
198 }
199
200 // -------------------------------------------------------------------------
201 void PipelineEditor::Node::
202 mousePressEvent( QGraphicsSceneMouseEvent* event )
203 {
204   if( this->m_SelectedPort != NULL && this->m_Canvas != NULL )
205   {
206     if( event->button( ) == Qt::LeftButton )
207     {
208       QDrag* drag = new QDrag( this->m_Canvas );
209       QMimeData* mimeData = new QMimeData( );
210
211       // mimeData->setText( "drag_data" );
212       qulonglong address = reinterpret_cast< qulonglong >( this );
213       QByteArray ba;
214       ba.setNum( address );
215       mimeData->setData( "source_node", ba );
216       drag->setMimeData( mimeData );
217       // TODO: drag->setPixmap( iconPixmap );
218
219       this->m_DraggingPort = true;
220       Qt::DropAction dropAction = drag->exec( );
221       this->m_DraggingPort = false;
222
223     } // fi
224   }
225   else
226   {
227   } // fi
228
229   /* TODO
230      Qt::MouseButton btn = event->button( );
231      if( btn == Qt::LeftButton )
232      {
233      std::string name = this->toolTip( ).toStdString( );
234      if( name != this->m_Object->GetName( ) )
235      {
236      // Get clicked port, if any
237      QPointF pos = event->buttonDownPos( btn );
238      auto iIt = this->m_InputPorts.find( name );
239      auto oIt = this->m_OutputPorts.find( name );
240      this->m_SelectedPort = NULL;
241      if( iIt != this->m_InputPorts.end( ) )
242      if( iIt->second.contains( pos ) )
243      this->m_SelectedPort = &( iIt->second );
244       if( this->m_SelectedPort == NULL && oIt != this->m_OutputPorts.end( ) )
245       if( oIt->second.contains( pos ) )
246       this->m_SelectedPort = &( oIt->second );
247
248       } // fi
249
250       } // fi
251   */
252   this->update( );
253   this->QGraphicsItem::mousePressEvent( event );
254 }
255
256 // -------------------------------------------------------------------------
257 void PipelineEditor::Node::
258 mouseReleaseEvent( QGraphicsSceneMouseEvent* event )
259 {
260   this->update( );
261   this->QGraphicsItem::mouseReleaseEvent( event );
262 }
263
264 // -------------------------------------------------------------------------
265 void PipelineEditor::Node::
266 mouseDoubleClickEvent( QGraphicsSceneMouseEvent* event )
267 {
268 }
269
270 // -------------------------------------------------------------------------
271 void PipelineEditor::Node::
272 hoverMoveEvent( QGraphicsSceneHoverEvent* event )
273 {
274   this->_selectPort( event->pos( ) );
275 }
276
277 // -------------------------------------------------------------------------
278 void PipelineEditor::Node::
279 hoverLeaveEvent( QGraphicsSceneHoverEvent* event )
280 {
281   this->_deselectPort( );
282 }
283
284 // -------------------------------------------------------------------------
285 void PipelineEditor::Node::
286 dragMoveEvent( QGraphicsSceneDragDropEvent* event )
287 {
288   this->_selectPort( event->pos( ) );
289 }
290
291 // -------------------------------------------------------------------------
292 void PipelineEditor::Node::
293 dragLeaveEvent( QGraphicsSceneDragDropEvent* event )
294 {
295   this->_deselectPort( );
296 }
297
298 // -------------------------------------------------------------------------
299 void PipelineEditor::Node::
300 dropEvent( QGraphicsSceneDragDropEvent* event )
301 {
302   // Get vertices and directionality
303   bool ok;
304   qulonglong address =
305     event->mimeData( )->data( "source_node" ).toULongLong( &ok );
306   Node* src = reinterpret_cast< Node* >( address );
307   if( src == NULL )
308     return;
309   Node* des = this;
310   if( src->m_SelectedPortIsInput )
311   {
312     des = src;
313     src = this;
314
315   } // fi
316
317   // Discard if a loop is detected
318   if( src == des )
319     return;
320
321   // Get edge data
322   const QRectF* srcPort = src->m_SelectedPort;
323   const QRectF* desPort = des->m_SelectedPort;
324   std::string srcName = src->m_Object->GetName( );
325   std::string desName = des->m_Object->GetName( );
326   std::string srcPortName = src->toolTip( ).toStdString( );
327   std::string desPortName = des->toolTip( ).toStdString( );
328
329   Edge* e = new Edge( src, des, srcPort, desPort );
330   src->addEdge( e );
331   des->addEdge( e );
332   if( this->m_Canvas != NULL )
333     this->m_Canvas->scene( )->addItem( e );
334 }
335
336 // -------------------------------------------------------------------------
337 void PipelineEditor::Node::
338 _selectPort( const QPointF& pos )
339 {
340   if( this->m_DraggingPort )
341     return;
342
343   const QRectF* prevPort = this->m_SelectedPort;
344
345   // Check ports
346   std::map< std::string, QRectF >* ports[] =
347     { &( this->m_InputPorts ), &( this->m_OutputPorts ) };
348   bool found = false;
349   for( unsigned int pId = 0; pId < 2 && !found; ++pId )
350   {
351     for(
352       auto i = ports[ pId ]->begin( );
353       i != ports[ pId ]->end( ) && !found;
354       ++i
355       )
356     {
357       if( i->second.contains( pos ) )
358       {
359         this->setToolTip( i->first.c_str( ) );
360         this->m_SelectedPort = &( i->second );
361         this->m_SelectedPortIsInput = ( pId == 0 );
362         found = true;
363
364       } // fi
365
366     } // rof
367
368   } // rof
369   if( !found )
370   {
371     this->setToolTip( this->m_Object->GetName( ) );
372     this->m_SelectedPort = NULL;
373
374   } // fi
375   if( prevPort != this->m_SelectedPort )
376     this->update( );
377 }
378
379 // -------------------------------------------------------------------------
380 void PipelineEditor::Node::
381 _deselectPort( )
382 {
383   if( !( this->m_DraggingPort ) )
384   {
385     this->m_SelectedPort = NULL;
386     this->update( );
387
388   } // fi
389 }
390
391 // eof - $RCSfile$