1 /* Copyright (c) 2012, STANISLAW ADASZEWSKI
\r
4 Redistribution and use in source and binary forms, with or without
\r
5 modification, are permitted provided that the following conditions are met:
\r
6 * Redistributions of source code must retain the above copyright
\r
7 notice, this list of conditions and the following disclaimer.
\r
8 * Redistributions in binary form must reproduce the above copyright
\r
9 notice, this list of conditions and the following disclaimer in the
\r
10 documentation and/or other materials provided with the distribution.
\r
11 * Neither the name of STANISLAW ADASZEWSKI nor the
\r
12 names of its contributors may be used to endorse or promote products
\r
13 derived from this software without specific prior written permission.
\r
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
\r
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
\r
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
\r
18 DISCLAIMED. IN NO EVENT SHALL STANISLAW ADASZEWSKI BE LIABLE FOR ANY
\r
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
\r
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
\r
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
\r
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
\r
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
\r
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 #include "QNodesEditor.h"
\r
29 #include <QGraphicsScene>
\r
31 #include <QGraphicsSceneContextMenuEvent>
\r
32 #include <QGraphicsSceneDragDropEvent>
\r
33 #include <QGraphicsSceneHelpEvent>
\r
34 #include <QGraphicsSceneHoverEvent>
\r
35 #include <QGraphicsSceneMouseEvent>
\r
36 #include <QGraphicsSceneMoveEvent>
\r
37 #include <QGraphicsSceneResizeEvent>
\r
38 #include <QGraphicsSceneWheelEvent>
\r
39 #include <QInputDialog>
\r
41 #include "QNEPort.h"
\r
42 #include "QNEConnection.h"
\r
43 #include "QNEBlock.h"
\r
45 // -------------------------------------------------------------------------
\r
46 PipelineEditor::QNodesEditor::
\r
47 QNodesEditor( QObject* parent )
\r
48 : Superclass( parent ),
\r
54 // -------------------------------------------------------------------------
\r
55 PipelineEditor::QNodesEditor::
\r
60 // -------------------------------------------------------------------------
\r
61 PipelineEditor::QNodesEditor::
\r
62 TWorkspace* PipelineEditor::QNodesEditor::
\r
65 return( this->m_Workspace );
\r
68 // -------------------------------------------------------------------------
\r
69 const PipelineEditor::QNodesEditor::
\r
70 TWorkspace* PipelineEditor::QNodesEditor::
\r
73 return( this->m_Workspace );
\r
76 // -------------------------------------------------------------------------
\r
77 void PipelineEditor::QNodesEditor::
\r
78 setWorkspace( TWorkspace* ws )
\r
80 this->m_Workspace = ws;
\r
81 this->m_Graph = TGraph::New( );
\r
84 auto vIt = this->m_Workspace->GetGraph( )->BeginVertices( );
\r
85 auto vIt_end = this->m_Workspace->GetGraph( )->EndVertices( );
\r
86 for( ; vIt != vIt_end; ++vIt )
\r
89 dynamic_cast< TFilter* >( vIt->second.GetPointer( ) ),
\r
90 QPointF( vIt->second->GetViewX( ), vIt->second->GetViewY( ) )
\r
96 auto rIt = this->m_Workspace->GetGraph( )->BeginEdgesRows( );
\r
97 auto rIt_end = this->m_Workspace->GetGraph( )->EndEdgesRows( );
\r
98 for( ; rIt != rIt_end; ++rIt )
\r
100 if( !this->m_Graph->HasVertexIndex( rIt->first ) )
\r
102 QNEBlock* orig = this->m_Graph->GetVertex( rIt->first );
\r
105 QVector< QNEOutputPort* >& oPorts = orig->outputPorts( );
\r
107 auto cIt = rIt->second.begin( );
\r
108 for( ; cIt != rIt->second.end( ); ++cIt )
\r
110 if( !this->m_Graph->HasVertexIndex( cIt->first ) )
\r
112 QNEBlock* dest = this->m_Graph->GetVertex( cIt->first );
\r
115 QVector< QNEInputPort* >& iPorts = dest->inputPorts( );
\r
117 auto eIt = cIt->second.begin( );
\r
118 for( ; eIt != cIt->second.end( ); ++eIt )
\r
120 QNEOutputPort* op = NULL;
\r
121 auto opIt = oPorts.begin( );
\r
122 for( ; opIt != oPorts.end( ) && op == NULL; ++opIt )
\r
123 if( ( *opIt )->name( ).toStdString( ) == eIt->first )
\r
126 QNEInputPort* ip = NULL;
\r
127 auto ipIt = iPorts.begin( );
\r
128 for( ; ipIt != iPorts.end( ) && ip == NULL; ++ipIt )
\r
129 if( ( *ipIt )->name( ).toStdString( ) == eIt->second )
\r
132 if( op == NULL || ip == NULL )
\r
135 QNEConnection* conn = new QNEConnection( 0, this->m_Scene );
\r
136 conn->setPort1( op );
\r
137 conn->setPort2( ip );
\r
138 conn->updatePosFromPorts( );
\r
139 conn->updatePath( );
\r
140 this->m_Graph->AddConnection( rIt->first, cIt->first, conn );
\r
149 // -------------------------------------------------------------------------
\r
150 std::string PipelineEditor::QNodesEditor::
\r
151 createFilter( const std::string& filter, const QPointF& pnt )
\r
153 std::string name = filter;
\r
154 while( this->m_Workspace->HasFilter( name ) )
\r
155 name += std::string( "_" );
\r
156 if( this->m_Workspace->CreateFilter( filter, name ) )
\r
158 this->_CreateBlock( this->m_Workspace->GetFilter( name ), pnt );
\r
165 // -------------------------------------------------------------------------
\r
166 void PipelineEditor::QNodesEditor::
\r
167 synchronizeBlockPositions( )
\r
169 auto bIt = this->m_Graph->BeginVertices( );
\r
170 auto fIt = this->m_Workspace->GetGraph( )->BeginVertices( );
\r
172 bIt != this->m_Graph->EndVertices( ) &&
\r
173 fIt != this->m_Workspace->GetGraph( )->EndVertices( )
\r
176 auto pos = bIt->second->scenePos( );
\r
177 fIt->second->SetViewCoords( pos.x( ), pos.y( ) );
\r
184 // -------------------------------------------------------------------------
\r
185 void PipelineEditor::QNodesEditor::
\r
186 install( QGraphicsScene* s )
\r
188 s->installEventFilter( this );
\r
192 // -------------------------------------------------------------------------
\r
193 QGraphicsItem* PipelineEditor::QNodesEditor::
\r
194 itemAt( const QPointF& pos )
\r
196 QList< QGraphicsItem* > items =
\r
197 this->m_Scene->items( QRectF( pos - QPointF( 1, 1 ), QSize( 3, 3 ) ) );
\r
199 foreach( QGraphicsItem* item, items )
\r
200 if( item->type( ) > QGraphicsItem::UserType )
\r
205 // -------------------------------------------------------------------------
\r
206 void PipelineEditor::QNodesEditor::
\r
207 _CreateBlock( TFilter* f, const QPointF& pnt )
\r
213 QNEBlock* b = new QNEBlock( 0, this->m_Scene );
\r
214 b->setNamePort( f->GetName( ) );
\r
215 b->setTypePort( f->GetClassName( ) );
\r
219 std::set< std::string > inputs;
\r
220 f->GetInputsNames( inputs );
\r
221 for( auto iIt = inputs.begin( ); iIt != inputs.end( ); ++iIt )
\r
222 b->addInputPort( iIt->c_str( ) );
\r
224 // Add output ports
\r
225 std::set< std::string > outputs;
\r
226 f->GetOutputsNames( outputs );
\r
227 for( auto oIt = outputs.begin( ); oIt != outputs.end( ); ++oIt )
\r
228 b->addOutputPort( oIt->c_str( ) );
\r
230 // Keep a trace of this visual graph
\r
231 this->m_Graph->SetVertex( f->GetName( ), b );
\r
234 // -------------------------------------------------------------------------
\r
235 void PipelineEditor::QNodesEditor::
\r
236 _DoubleClick( QGraphicsSceneMouseEvent* evt, QGraphicsItem* item )
\r
238 switch( evt->button( ) )
\r
240 case Qt::LeftButton:
\r
242 QNEBlock* block = dynamic_cast< QNEBlock* >( item );
\r
243 QNEPort* port = dynamic_cast< QNEPort* >( item );
\r
244 QNEConnection* conn = dynamic_cast< QNEConnection* >( item );
\r
246 if( block != NULL )
\r
248 QString old_name = block->namePort( )->name( );
\r
251 QInputDialog::getText(
\r
252 dynamic_cast< QWidget* >( this->parent( ) ),
\r
253 "Change filter name",
\r
259 if( ok && !new_name.isEmpty( ) && old_name != new_name )
\r
261 ok = this->m_Graph->RenameVertex(
\r
262 old_name.toStdString( ),
\r
263 new_name.toStdString( )
\r
267 block->namePort( )->setName( new_name );
\r
268 this->m_Workspace->GetGraph( )->RenameVertex(
\r
269 old_name.toStdString( ),
\r
270 new_name.toStdString( )
\r
278 auto ports = block->ports( );
\r
279 std::string name = "";
\r
281 auto pIt = ports.begin( );
\r
282 pIt != ports.end( ) && name == "";
\r
286 ( *pIt )->portFlags( ) && QNEPort::NamePort == QNEPort::NamePort
\r
288 name = ( *pIt )->portName( ).toStdString( );
\r
291 TFilter* filter = this->m_Workspace->GetFilter( name );
\r
292 if( filter != NULL )
\r
297 else if( port != NULL )
\r
300 else if( conn != NULL )
\r
306 case Qt::RightButton:
\r
310 case Qt::MiddleButton:
\r
320 // -------------------------------------------------------------------------
\r
321 bool PipelineEditor::QNodesEditor::
\r
322 eventFilter( QObject* o, QEvent* e )
\r
325 switch( int( e->type( ) ) )
\r
327 case QEvent::GraphicsSceneContextMenu:
\r
329 QGraphicsSceneContextMenuEvent* evt =
\r
330 dynamic_cast< QGraphicsSceneContextMenuEvent* >( e );
\r
336 case QEvent::GraphicsSceneDragEnter:
\r
338 QGraphicsSceneDragDropEvent* evt =
\r
339 dynamic_cast< QGraphicsSceneDragDropEvent* >( e );
\r
345 case QEvent::GraphicsSceneDragLeave:
\r
347 QGraphicsSceneDragDropEvent* evt =
\r
348 dynamic_cast< QGraphicsSceneDragDropEvent* >( e );
\r
354 case QEvent::GraphicsSceneDragMove:
\r
356 QGraphicsSceneDragDropEvent* evt =
\r
357 dynamic_cast< QGraphicsSceneDragDropEvent* >( e );
\r
363 case QEvent::GraphicsSceneDrop:
\r
365 QGraphicsSceneDragDropEvent* evt =
\r
366 dynamic_cast< QGraphicsSceneDragDropEvent* >( e );
\r
372 case QEvent::GraphicsSceneHelp:
\r
374 QGraphicsSceneHelpEvent* evt =
\r
375 dynamic_cast< QGraphicsSceneHelpEvent* >( e );
\r
381 case QEvent::GraphicsSceneHoverEnter:
\r
383 QGraphicsSceneHoverEvent* evt =
\r
384 dynamic_cast< QGraphicsSceneHoverEvent* >( e );
\r
390 case QEvent::GraphicsSceneHoverLeave:
\r
392 QGraphicsSceneHoverEvent* evt =
\r
393 dynamic_cast< QGraphicsSceneHoverEvent* >( e );
\r
399 case QEvent::GraphicsSceneHoverMove:
\r
401 QGraphicsSceneHoverEvent* evt =
\r
402 dynamic_cast< QGraphicsSceneHoverEvent* >( e );
\r
408 case QEvent::GraphicsSceneMouseDoubleClick:
\r
410 QGraphicsSceneMouseEvent* evt =
\r
411 dynamic_cast< QGraphicsSceneMouseEvent* >( e );
\r
414 QGraphicsItem* item = this->itemAt( evt->scenePos( ) );
\r
417 this->_DoubleClick( evt, item );
\r
425 case QEvent::GraphicsSceneMouseMove:
\r
427 QGraphicsSceneMouseEvent* evt =
\r
428 dynamic_cast< QGraphicsSceneMouseEvent* >( e );
\r
433 this->m_Conn->setPos2( evt->scenePos( ) );
\r
434 this->m_Conn->updatePath( );
\r
442 case QEvent::GraphicsSceneMousePress:
\r
444 QGraphicsSceneMouseEvent* evt =
\r
445 dynamic_cast< QGraphicsSceneMouseEvent* >( e );
\r
448 switch( evt->button( ) )
\r
450 case Qt::LeftButton:
\r
452 QNEOutputPort* port =
\r
453 dynamic_cast< QNEOutputPort* >( this->itemAt( evt->scenePos( ) ) );
\r
456 this->m_Conn = new QNEConnection( 0, this->m_Scene );
\r
457 this->m_Conn->setPort1( port );
\r
458 this->m_Conn->setPos1( port->scenePos( ) );
\r
459 this->m_Conn->setPos2( evt->scenePos( ) );
\r
460 this->m_Conn->updatePath( );
\r
474 case QEvent::GraphicsSceneMouseRelease:
\r
476 QGraphicsSceneMouseEvent* evt =
\r
477 dynamic_cast< QGraphicsSceneMouseEvent* >( e );
\r
480 if( this->m_Conn != NULL && evt->button( ) == Qt::LeftButton )
\r
482 QNEInputPort* port2 =
\r
483 dynamic_cast< QNEInputPort* >( this->itemAt( evt->scenePos( ) ) );
\r
484 if( port2 != NULL )
\r
486 QNEOutputPort* port1 =
\r
487 dynamic_cast< QNEOutputPort* >( this->m_Conn->port1( ) );
\r
488 if( port1 != NULL )
\r
491 port1->block( ) != port2->block( ) &&
\r
492 !port2->hasConnection( ) &&
\r
493 !port1->isConnected( port2 )
\r
496 this->m_Conn->setPos2( port2->scenePos( ) );
\r
497 this->m_Conn->setPort2( port2 );
\r
498 this->m_Conn->updatePath( );
\r
500 this->m_Workspace->Connect(
\r
501 port1->block( )->namePort( )->name( ).toStdString( ),
\r
502 port2->block( )->namePort( )->name( ).toStdString( ),
\r
503 port1->name( ).toStdString( ),
\r
504 port2->name( ).toStdString( )
\r
506 this->m_Graph->AddConnection(
\r
507 port1->block( )->namePort( )->name( ).toStdString( ),
\r
508 port2->block( )->namePort( )->name( ).toStdString( ),
\r
512 this->m_Conn = NULL;
\r
520 delete this->m_Conn;
\r
521 this->m_Conn = NULL;
\r
529 case QEvent::GraphicsSceneMove:
\r
531 QGraphicsSceneMoveEvent* evt =
\r
532 dynamic_cast< QGraphicsSceneMoveEvent* >( e );
\r
538 case QEvent::GraphicsSceneResize:
\r
540 QGraphicsSceneResizeEvent* evt =
\r
541 dynamic_cast< QGraphicsSceneResizeEvent* >( e );
\r
547 case QEvent::GraphicsSceneWheel:
\r
549 QGraphicsSceneWheelEvent* evt =
\r
550 dynamic_cast< QGraphicsSceneWheelEvent* >( e );
\r
562 QGraphicsSceneMouseEvent* me =
\r
563 dynamic_cast< QGraphicsSceneMouseEvent* >( e );
\r
570 switch( ( int ) e->type( ) )
\r
572 case QEvent::GraphicsSceneMouseMove:
\r
576 this->m_Conn->setPos2( me->scenePos( ) );
\r
577 this->m_Conn->updatePath( );
\r
582 case QEvent::GraphicsSceneMouseRelease:
\r
584 if( this->m_Conn && me->button( ) == Qt::LeftButton )
\r
586 QGraphicsItem* item = itemAt( me->scenePos( ) );
\r
587 if( item && item->type( ) == QNEPort::Type )
\r
589 QNEPort* port1 = this->m_Conn->port1( );
\r
590 QNEPort* port2 = ( QNEPort* ) item;
\r
591 if( port1->block( ) != port2->block( ) && port1->isOutput( ) != port2->isOutput( ) && !port1->isConnected( port2 ) )
\r
593 this->m_Conn->setPos2( port2->scenePos( ) );
\r
594 this->m_Conn->setPort2( port2 );
\r
595 this->m_Conn->updatePath( );
\r
596 this->m_Conn = NULL;
\r
601 delete this->m_Conn;
\r
602 this->m_Conn = NULL;
\r
610 return( this->Superclass::eventFilter( o, e ) );
\r