X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=appli%2FcpPipelineEditor%2FNode.cxx;h=34c4d96fddc1f314503331b54f1dc7a0d0303fdb;hb=ef8b6e12859181d3faa8019ce7319c539c0f86ec;hp=2ecb9e5b1f8a6e8eaace212844d1fb8efceb1ea9;hpb=950ea6d252c9a5bc5be29d413497fe0ef69e6703;p=cpPlugins.git diff --git a/appli/cpPipelineEditor/Node.cxx b/appli/cpPipelineEditor/Node.cxx index 2ecb9e5..34c4d96 100644 --- a/appli/cpPipelineEditor/Node.cxx +++ b/appli/cpPipelineEditor/Node.cxx @@ -1,207 +1,391 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include - -#include "Edge.h" #include "Node.h" -#include "GraphWidget.h" +#include "Edge.h" +#include "GraphCanvas.h" + +#include +#include +#include -Node::Node(GraphWidget *graphWidget, const std::string& label) - : graph(graphWidget), - m_Label( label ) +#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 ) { - setFlag(ItemIsMovable); - setFlag(ItemSendsGeometryChanges); - setCacheMode(DeviceCoordinateCache); - setZValue(-1); - this->setToolTip( this->m_Label.c_str( ) ); + 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( ); } -void Node::addEdge(Edge *edge) +// ------------------------------------------------------------------------- +PipelineEditor::Node:: +~Node( ) { - edgeList << edge; - edge->adjust(); } -QList Node::edges() const +// ------------------------------------------------------------------------- +void PipelineEditor::Node:: +addEdge( PipelineEditor::Edge* edge ) { - return edgeList; + this->m_Edges << edge; + edge->adjust( ); } -void Node::calculateForces() +// ------------------------------------------------------------------------- +QList< PipelineEditor::Edge* > PipelineEditor::Node:: +edges( ) const { - if (!scene() || scene()->mouseGrabberItem() == this) { - newPos = pos(); - return; - } + 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 ); - // Sum up all forces pushing this item away - qreal xvel = 0; - qreal yvel = 0; - foreach (QGraphicsItem *item, scene()->items()) { - Node *node = qgraphicsitem_cast(item); - if (!node) - continue; + // 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 ); - QPointF vec = mapToItem(node, 0, 0); - qreal dx = vec.x(); - qreal dy = vec.y(); - double l = 2.0 * (dx * dx + dy * dy); - if (l > 0) { - xvel += (dx * 150.0) / l; - yvel += (dy * 150.0) / l; - } - } + // 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 ); - // Now subtract all forces pulling items together - double weight = (edgeList.size() + 1) * 10; - foreach (Edge *edge, edgeList) { - QPointF vec; - if (edge->sourceNode() == this) - vec = mapToItem(edge->destNode(), 0, 0); + // 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 - vec = mapToItem(edge->sourceNode(), 0, 0); - xvel -= vec.x() / weight; - yvel -= vec.y() / weight; - } + this->m_OutputPorts[ *i ] = + QRectF( QPointF( rr - qreal( PORT_SIZE ), rt + off ), ps ); + off += qreal( PORT_SIZE < 1 ); + + } // rof - if (qAbs(xvel) < 0.1 && qAbs(yvel) < 0.1) - xvel = yvel = 0; + } // rof - QRectF sceneRect = scene()->sceneRect(); - newPos = pos() + QPointF(xvel, yvel); - newPos.setX(qMin(qMax(newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10)); - newPos.setY(qMin(qMax(newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10)); + } // fi - newPos = pos(); // + QPointF(xvel, yvel); + // Some other initializations + this->m_SelectedPort = NULL; } -bool Node::advance() +// ------------------------------------------------------------------------- +QRectF PipelineEditor::Node:: +boundingRect( ) const { - if (newPos == pos()) - return false; + return( this->m_Bounds ); +} - setPos(newPos); - return true; +// ------------------------------------------------------------------------- +QPainterPath PipelineEditor::Node:: +shape( ) const +{ + QPainterPath path; + path.addRect( this->m_Bounds ); + return( path ); } -QRectF Node::boundingRect() const +// ------------------------------------------------------------------------- +void PipelineEditor::Node:: +paint( + QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget + ) { -#if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5) - // Add some extra space around the circle for easier touching with finger - qreal adjust = 30; - return QRectF( -10 - adjust, -10 - adjust, - 20 + adjust * 2, 20 + adjust * 2); -#else - qreal adjust = 2; - return QRectF( -10 - adjust, -10 - adjust, - 23 + adjust, 23 + adjust); -#endif + // 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 } -QPainterPath Node::shape() const +// ------------------------------------------------------------------------- +QVariant PipelineEditor::Node:: +itemChange( GraphicsItemChange change, const QVariant& value ) { - QPainterPath path; -#if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5) - // Add some extra space around the circle for easier touching with finger - path.addEllipse( -40, -40, 80, 80); -#else - path.addEllipse(-10, -10, 20, 20); -#endif - return path; + 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 Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +// ------------------------------------------------------------------------- +void PipelineEditor::Node:: +mousePressEvent( QGraphicsSceneMouseEvent* event ) { - painter->setPen(Qt::NoPen); - painter->setBrush(Qt::darkGray); - painter->drawEllipse(-7, -7, 20, 20); + 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( ); - QPointF text_point = this->boundingRect( ).bottomRight( ) + this->pos( ); - painter->drawText( text_point, this->m_Label.c_str( ) ); - std::cout << text_point.x( ) << " " << text_point.y( ) << std::endl; + // 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 ); - QRadialGradient gradient(-3, -3, 10); - if (option->state & QStyle::State_Sunken) { - gradient.setCenter(3, 3); - gradient.setFocalPoint(3, 3); - gradient.setColorAt(1, QColor(Qt::yellow).light(120)); - gradient.setColorAt(0, QColor(Qt::darkYellow).light(120)); - } else { - gradient.setColorAt(0, Qt::yellow); - gradient.setColorAt(1, Qt::darkYellow); - } - painter->setBrush(gradient); + this->m_DraggingPort = true; + Qt::DropAction dropAction = drag->exec( ); + this->m_DraggingPort = false; - painter->setPen(QPen(Qt::black, 0)); - painter->drawEllipse(-10, -10, 20, 20); + } // 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 ); } -QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) +// ------------------------------------------------------------------------- +void PipelineEditor::Node:: +mouseReleaseEvent( QGraphicsSceneMouseEvent* event ) { - switch (change) { - case ItemPositionHasChanged: - foreach (Edge *edge, edgeList) - edge->adjust(); - graph->itemMoved(); - break; - default: - break; - }; + this->update( ); + this->QGraphicsItem::mouseReleaseEvent( event ); +} - return QGraphicsItem::itemChange(change, value); +// ------------------------------------------------------------------------- +void PipelineEditor::Node:: +mouseDoubleClickEvent( QGraphicsSceneMouseEvent* event ) +{ } -void Node::mousePressEvent(QGraphicsSceneMouseEvent *event) +// ------------------------------------------------------------------------- +void PipelineEditor::Node:: +hoverMoveEvent( QGraphicsSceneHoverEvent* event ) { - update(); - QGraphicsItem::mousePressEvent(event); + this->_selectPort( event->pos( ) ); } -void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +// ------------------------------------------------------------------------- +void PipelineEditor::Node:: +hoverLeaveEvent( QGraphicsSceneHoverEvent* event ) { - update(); - QGraphicsItem::mouseReleaseEvent(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$