OpenWalnut  1.5.0dev
WQtNetworkItem.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <algorithm>
26 #include <iostream>
27 #include <memory>
28 #include <string>
29 
30 #include <QStyleOptionGraphicsItem>
31 #include <QTextCharFormat>
32 #include <QTextCursor>
33 
34 #include "../controlPanel/WQtPropertyGroupWidget.h"
35 #include "../controlPanel/WQtTreeItem.h"
36 #include "../guiElements/WQtDataModuleInput.h"
37 #include "WQtNetworkArrow.h"
38 #include "WQtNetworkColors.h"
39 #include "WQtNetworkEditor.h"
40 #include "WQtNetworkItem.h"
41 #include "WQtNetworkItemActivator.h"
42 #include "WQtNetworkItemGrid.h"
43 #include "WQtNetworkScene.h"
44 #include "WQtNetworkSceneLayout.h"
45 #include "core/common/WLogger.h"
46 #include "core/common/WStringUtils.h"
47 
48 
49 WQtNetworkItem::WQtNetworkItem( WQtNetworkEditor* editor, std::shared_ptr< WModule > module ):
51  m_isHovered( false ),
52  m_isSelected( false ),
53  m_busyIsDetermined( false ),
54  m_busyPercent( 0.0 ),
55  m_busyIndicatorShow( false ),
56  m_forceUpdate( true ),
57  m_propertyToolWindow( NULL ),
58  m_dragging( false ),
59  m_wasLayedOut( false ),
60  m_wasManuallyPlaced( false ),
61  m_noDrag( false )
62 {
63  m_networkEditor = editor;
64  m_module = module;
65 
66  // important to automatically update the arrows if the item moves around
67  setFlag( ItemSendsGeometryChanges );
68  setFlag( QGraphicsItem::ItemIsSelectable );
69  setFlag( QGraphicsItem::ItemIsMovable, false ); // < we manage movement for our own.
70 
71  setCacheMode( DeviceCoordinateCache );
72 
73  // keep track of runtime name changes of the module
74  m_runtimeNameConnection = module->getRuntimeName()->getValueChangeCondition()->subscribeSignal(
75  boost::bind( &WQtNetworkItem::runtimeNameChanged, this )
76  );
77 
78  // caption
79  m_textFull = module->getRuntimeName()->get();
80  m_text = new QGraphicsTextItem( m_textFull.c_str() );
81  m_text->setParentItem( this );
82  m_text->setDefaultTextColor( Qt::white );
83 
84  // for captions of data modules
85  std::shared_ptr< WDataModule > dataModule;
86  dataModule = std::dynamic_pointer_cast< WDataModule >( module );
87  if( dataModule )
88  {
89  if( dataModule->getInput() )
90  {
91  m_subtitleFull = dataModule->getInput()->asString();
92  }
93  else
94  {
95  m_subtitleFull = "";
96  }
97  }
98  else
99  {
100  m_subtitleFull = "Idle";
101  }
102 
103  // setup animation
104  m_animation = new QGraphicsItemAnimation;
105  m_animationTimer = new QTimeLine( WNETWORKITEM_BIRTH_DURATION );
106  m_animationTimer->setFrameRange( 0, 100 );
107  m_animation->setItem( this );
108  m_animation->setTimeLine( m_animationTimer );
109 
110  connect( m_animationTimer, SIGNAL( valueChanged( qreal ) ), this, SLOT( animationBlendInTick( qreal ) ) );
111  connect( m_animationTimer, SIGNAL( finished() ), this, SLOT( positionChanged() ) );
112  connect( m_animationTimer, SIGNAL( valueChanged( qreal ) ), this, SLOT( positionChanged() ) );
113 
114  // scale animation
115  float steps = 500.0;
116  for( int i = 0; i < steps; ++i )
117  {
118  float stepNorm = static_cast< float >( i ) / static_cast< float >( steps - 1 );
119  float s = stepNorm * stepNorm;
120  m_animation->setScaleAt( stepNorm, s, s );
121  }
122  m_animation->setScaleAt( 1.0, 1.0, 1.0 );
123 
124  // setup removal animation
125  m_removalAnimation = new QGraphicsItemAnimation;
126  m_removalAnimationTimer = new QTimeLine( WNETWORKITEM_DEATH_DURATION );
127  m_removalAnimationTimer->setFrameRange( 0, 100 );
128  m_removalAnimation->setItem( this );
130 
131  // notify when removal done.
132  connect( m_removalAnimationTimer, SIGNAL( finished() ), this, SLOT( removalAnimationDone() ) );
133  connect( m_removalAnimationTimer, SIGNAL( valueChanged( qreal ) ), this, SLOT( animationBlendOutTick( qreal ) ) );
134 
135  for( int i = 0; i < steps; ++i )
136  {
137  float stepNorm = static_cast< float >( i ) / static_cast< float >( steps - 1 );
138  float s = 1.0 - ( stepNorm * stepNorm );
139  m_removalAnimation->setScaleAt( stepNorm, s, s );
140  }
141  m_removalAnimation->setScaleAt( 1.0, 0.0, 0.0 );
142 
143  m_subtitle = new QGraphicsTextItem( m_subtitleFull.c_str() );
144  m_subtitle->setParentItem( this );
145  m_subtitle->setDefaultTextColor( Qt::white );
146  QFont f = m_subtitle->font();
147  f.setPointSizeF( f.pointSizeF() * 0.75 );
148  f.setBold( true );
149  m_subtitle->setFont( f );
150 
153 
154  //add input ports
155  WModule::InputConnectorList cons = module->getInputConnectors();
156  bool hasInput = cons.size();
157  for( WModule::InputConnectorList::const_iterator iter = cons.begin(); iter != cons.end(); ++iter )
158  {
159  WQtNetworkInputPort *port = new WQtNetworkInputPort( *iter );
160  port->setParentItem( this );
161  this->addInputPort( port );
162  }
163 
164  //add output ports
165  WModule::OutputConnectorList outCons = module->getOutputConnectors();
166  bool hasOutput = outCons.size();
167  for( WModule::OutputConnectorList::const_iterator iter = outCons.begin(); iter != outCons.end(); ++iter )
168  {
169  WQtNetworkOutputPort *port = new WQtNetworkOutputPort( *iter );
170  port->setParentItem( this );
171  this->addOutputPort( port );
172  }
173 
174  // Standard processing modules with in- and outputs are colored this way:
175  m_itemColor = WQtNetworkColors::Module;
176  if( !hasInput && !hasOutput )
177  {
178  // neither inputs nor outputs
179  m_itemColor = WQtNetworkColors::StandaloneModule;
180  }
181  else if( !hasInput )
182  {
183  // no inputs -> source
184  m_itemColor = WQtNetworkColors::SourceModule;
185  }
186  else if( !hasOutput )
187  {
188  // no outputs but inputs -> sink
189  m_itemColor = WQtNetworkColors::SinkModule;
190  }
191  m_itemColor.setAlpha( 240 );
192 
194  m_hidden->setParentItem( this );
195 
196  activate( false );
197 
198  fitLook();
199  // this now calculated the optimal size. We keep them for later use
200  m_itemBestWidth = boundingRect().width();
201 
202  // get notified on position changes:
203  connect( this, SIGNAL( xChanged() ), this, SLOT( positionChanged() ) );
204  connect( this, SIGNAL( yChanged() ), this, SLOT( positionChanged() ) );
205 
206  m_animationTimer->start();
207 }
208 
210 {
211  m_runtimeNameConnection.disconnect();
212 
213  delete m_animation;
214  delete m_animationTimer;
215  delete m_removalAnimation;
217 
218  if( m_hidden )
219  {
220  delete m_hidden;
221  }
222 
224  {
225  m_propertyToolWindow->close();
226  delete m_propertyToolWindow;
227  }
228 
229  foreach( WQtNetworkPort *port, m_inPorts )
230  {
231  delete port;
232  }
233 
234  foreach( WQtNetworkPort *port, m_outPorts )
235  {
236  delete port;
237  }
238  delete m_text;
239  delete m_subtitle;
240 }
241 
243 {
244  return Type;
245 }
246 
248 {
249  return m_rect;
250 }
251 
253 {
254  foreach( WQtNetworkPort *port, m_inPorts )
255  {
256  port->updateArrows();
257  }
258  foreach( WQtNetworkPort *port, m_outPorts )
259  {
260  port->updateArrows();
261  }
262 }
263 
265 {
266  if( !m_module )
267  {
268  return;
269  }
270 
271  // it is very important to avoid unnecessary changes to pen/brush and similar stuff to avoid permanent updates of the graphics item.
272  bool needUpdate = m_forceUpdate;
273  m_forceUpdate = false;
274 
275  // progress indication is only needed for running modules
276  if( m_currentState != Crashed )
277  {
278  // handle progress indication
279  std::shared_ptr< WProgressCombiner> p = m_module->getRootProgressCombiner();
280 
281  // update the progress combiners internal state
282  p->update();
283 
284  if( p->isPending() )
285  {
286  m_busyIndicatorShow = true;
287  m_busyIsDetermined = p->isDetermined();
288 
289  // update subtext
290  m_subtitleFull = p->getCombinedNames( true );
291  if( m_subtitleFull.empty() ) // if some lazy programmer did not provide names for the progress -> set one
292  {
293  m_subtitleFull = "Busy";
294  }
295 
296  // we add the percent-counter to the front because the fitLook method shortens the subtext string if it is too long. This might clip out
297  // the percentage if the p->getCombinedNames string is quite long.
298  if( m_busyIsDetermined ) // <- of course only add if we have a known percentage
299  {
300  // NOTE: Percentage of a WProgressCombiner always multiplicatively combines all percentages of the children
301  m_subtitleFull = string_utils::toString( static_cast< uint16_t >( p->getProgress() ) ) + "% - " + m_subtitleFull;
302  }
303 
304  // this method ensures the text is shortened and correctly placed in the iem
306 
307  // update indicator
308  if( m_busyIsDetermined )
309  {
310  m_busyPercent = p->getProgress() / 100.0;
311  }
312  else
313  {
314  m_busyPercent += 0.025;
315  if( m_busyPercent > 1.0 )
316  {
317  m_busyPercent = 0.0;
318  }
319  }
320  needUpdate = true;
321  }
322  else
323  {
324  // if busy indication was active -> update to remove it again
325  needUpdate |= m_busyIndicatorShow;
326  m_busyIndicatorShow = false;
327  WDataModule::SPtr dataModule = std::dynamic_pointer_cast< WDataModule >( m_module );
328  if( dataModule )
329  {
330  m_subtitleFull = "Idle";
331  if( dataModule->getInput() )
332  {
333  m_subtitleFull = dataModule->getInput()->asString();
334  }
335  }
336  else
337  {
338  m_subtitleFull = "Idle";
339  }
341  }
342  }
343  else if( m_propertyToolWindow )
344  {
345  m_propertyToolWindow->close();
346  delete m_propertyToolWindow;
347  m_propertyToolWindow = NULL;
348  }
349 
350  // show crash state as text too
351  if( ( m_currentState == Crashed ) && ( m_subtitleFull != "Error" ) )
352  {
353  m_subtitleFull = "Error";
354  // this method ensures the text is shortened and correctly placed in the iem
356  needUpdate = true;
357  }
358 
359  // update tooltip
360  setToolTip( WQtTreeItem::createTooltip( m_module ).c_str() );
361 
362  // if something has changed -> update
363  if( needUpdate )
364  {
365  update();
366  }
367 }
368 
369 void WQtNetworkItem::hoverEnterEvent( QGraphicsSceneHoverEvent *event )
370 {
371  Q_UNUSED( event );
372  m_isHovered = true;
373  update();
374 }
375 
376 void WQtNetworkItem::hoverLeaveEvent( QGraphicsSceneHoverEvent *event )
377 {
378  Q_UNUSED( event );
379  m_isHovered = false;
380  update();
381 }
382 
383 void WQtNetworkItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* /* w */ )
384 {
385  // This is the default appearance
386  QPen newPen = QPen( m_itemColor, 1, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin );
387  QColor fillColor = m_itemColor;
388  // change appearance due to state changes
389  switch( m_currentState )
390  {
391  case Disabled:
392  fillColor = m_itemColor.darker( 300 );
393  break;
394  case Crashed:
395  fillColor = WQtNetworkColors::ModuleCrashed;
396  break;
397  case Normal:
398  default:
399  // default behaviour
400  break;
401  }
402 
403  // if hovered:
404  if( m_isHovered )
405  {
406  fillColor = fillColor.lighter();
407  }
408  // if selected:
409  if( m_isSelected )
410  {
411  newPen = QPen( Qt::black, 2, Qt::DotLine, Qt::SquareCap, Qt::RoundJoin );
412  }
413 
414  // only set brush and pen if they have changed
415  QBrush newBrush = QBrush( fillColor );
416  painter->setBrush( newBrush );
417  painter->setPen( newPen );
418 
419  QStyleOptionGraphicsItem* o = const_cast<QStyleOptionGraphicsItem*>( option );
420  o->state &= ~QStyle::State_Selected;
421  // draw the rect
422  painter->drawRect( m_rect );
423 
424  // strike through crashed modules
425  if( m_currentState == Crashed )
426  {
427  painter->setPen( QPen( Qt::black, 1, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin ) );
428  painter->drawLine( QPoint( 0.0, 0.0 ), QPoint( m_width, m_height ) );
429  painter->drawLine( QPoint( 0.0, m_height ), QPoint( m_width, 0.0 ) );
430  }
431 
432  // draw busy indicator
433  if( m_busyIndicatorShow )
434  {
435  float busyBarMarginX = 5.0;
436  float busyIndicatorHeight = 2.0;
437  painter->setPen( QPen( WQtNetworkColors::BusyIndicatorBackground, busyIndicatorHeight, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin ) );
438  painter->drawLine( QPoint( busyBarMarginX, m_height / 2.0 ), QPoint( m_width - busyBarMarginX, m_height / 2.0 ) );
439  painter->setPen( QPen( WQtNetworkColors::BusyIndicator, busyIndicatorHeight, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin ) );
440  float pos = m_busyPercent * ( m_width - ( 2.0 * busyBarMarginX ) );
441 
442  // if the progress indicator is determined (known percentage) -> draw line from 0 to pos
443  if( m_busyIsDetermined )
444  {
445  painter->drawLine( QPoint( busyBarMarginX, m_height / 2.0 ), QPoint( busyBarMarginX + pos, m_height / 2.0 ) );
446  }
447  else
448  {
449  painter->drawLine( QPoint( busyBarMarginX + pos, m_height / 2.0 ), QPoint( busyBarMarginX + pos + 5, m_height / 2.0 ) );
450  }
451  }
452 }
453 
454 void WQtNetworkItem::mouseMoveEvent( QGraphicsSceneMouseEvent* event )
455 {
456  if( m_noDrag )
457  {
458  event->accept();
459  return;
460  }
461 
462  if( m_dragging )
463  {
464  // ask layouter
465  // suppress scene update - very annoying but if you remove this, QT segfaults somewhere
467  m_networkEditor->getLayout()->snapTemporarily( this, event->scenePos(), true );
468  // enable again
470 
471  // move item. If commenting this out you can enable discrete grid move (remember to set the third param in snapTemporarily to false ).
472  QPointF p = event->scenePos() - m_draggingStart;
473  m_draggingStart = event->scenePos();
474  setPos( pos() + p );
475  }
476 
477  // do not forward event. We handled it.
478  event->accept();
479  QGraphicsItem::mouseMoveEvent( event );
480 }
481 
482 void WQtNetworkItem::mousePressEvent( QGraphicsSceneMouseEvent* event )
483 {
484  if( m_noDrag )
485  {
486  event->accept();
487  return;
488  }
489 
490  if( event->button() == Qt::LeftButton )
491  {
492  m_dragging = true;
493  m_draggingStart = event->scenePos();
495  event->accept();
496  }
497  if( event->button() == Qt::RightButton )
498  {
499  event->accept();
500  }
501 
502  m_networkEditor->getScene()->clearSelection();
503  setSelected( true );
504 
505  // do not accept all events to allow right clicks
506  //QGraphicsItem::mousePressEvent( event );
507 }
508 
509 void WQtNetworkItem::mouseReleaseEvent( QGraphicsSceneMouseEvent* event )
510 {
511  if( m_noDrag )
512  {
513  event->accept();
514  return;
515  }
516 
517  if( m_dragging )
518  {
519  m_dragging = false;
520 
521  // when released, update layouter
522  m_networkEditor->getLayout()->snapAccept( this, event->scenePos() );
523  }
524 
526 
527  // make visible if clicked at the border of the view
528  QList< QGraphicsView* > allViews = scene()->views();
529  foreach( QGraphicsView* v, allViews )
530  {
531  // Our own view offers a smooth version of ensureVisible. Try to use it.
532  WQtNetworkEditorView* nv = dynamic_cast< WQtNetworkEditorView* >( v );
533  if( nv )
534  {
535  nv->ensureVisibleSmooth( this );
536  }
537  else
538  {
539  v->ensureVisible( this );
540  }
541  }
542 
543  event->accept();
544  QGraphicsItem::mouseReleaseEvent( event );
545 }
546 
547 void WQtNetworkItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent* event )
548 {
550  {
551  m_propertyToolWindow->show();
552  m_propertyToolWindow->activateWindow();
553  m_propertyToolWindow->raise();
554  }
555  else
556  {
557  if( !m_module->isCrashed() )
558  {
559  std::string name = m_module->getName();
560  WPropString runtimeName = m_module->getRuntimeName();
561  name = ( name == runtimeName->get() ) ? name : name + " - " + runtimeName->get();
562 
564  m_module->getProperties(), QString::fromStdString( name ), 0, m_networkEditor
565  );
566 
567  QWidget* contents = new QWidget();
568  QVBoxLayout* contentLayout = new QVBoxLayout();
569  contents->setLayout( contentLayout );
570  contentLayout->setContentsMargins( QMargins( 0, 0, 0, 0 ) );
571  contentLayout->setSpacing( 0 );
572  contentLayout->setAlignment( Qt::AlignTop );
573 
574  // if this module is a data module:
575  WDataModule::SPtr dataModule = std::dynamic_pointer_cast< WDataModule >( m_module );
576  if( dataModule )
577  {
578  contentLayout->addWidget( new WQtDataModuleInput( dataModule ) );
579  }
580 
581  contentLayout->addWidget( props );
582 
583  QScrollArea* sa = new QScrollArea( m_networkEditor );
584  sa->setWidget( contents );
585  sa->setWidgetResizable( true );
586  sa->setWindowFlags( Qt::Window );
587  sa->setWindowRole( "Properties" );
588  sa->setWindowTitle( QString::fromStdString( "Properties: " + name ) );
589  sa->show();
591  }
592  }
593 
594  event->accept();
595  // QGraphicsItem::mouseReleaseEvent( event );
596 }
597 
598 QVariant WQtNetworkItem::itemChange( GraphicsItemChange change, const QVariant &value )
599 {
600  switch( change )
601  {
602  case ItemSelectedHasChanged:
603  m_isSelected = isSelected();
604  break;
605  case ItemPositionHasChanged:
606  positionChanged();
607  default:
608  break;
609  }
610 
611  return QGraphicsItem::itemChange( change, value );
612 }
613 
615 {
616  m_inPorts.append( port );
617 }
618 
620 {
621  m_outPorts.append( port );
622 }
623 
625 {
626  return m_inPorts;
627 }
628 
630 {
631  return m_outPorts;
632 }
633 
634 /**
635  * This function cuts away some text and attaches "..." to ensure a maximum width.
636  *
637  * \param item the item to clip
638  * \param maxWidth the maximum width. After this function finished, the item is <=maxWidth.
639  * \param fullText the original full text
640  */
641 void clipText( QGraphicsTextItem* item, float maxWidth, std::string fullText )
642 {
643  item->setPlainText( fullText.c_str() );
644  //item->adjustSize();
645 
646  // get size
647  float w = item->boundingRect().width();
648  std::string newText = fullText;
649 
650  // as long as the width is too large, cut away some letters
651  while( w > maxWidth )
652  {
653  // shorten the text
654  newText = newText.substr( 0, newText.length() - 1 );
655  item->setPlainText( ( newText + "..." ).c_str() );
656  // and measure new size
657  w = item->boundingRect().width();
658  }
659 }
660 
661 void WQtNetworkItem::fitLook( float maximumWidth, float minimumWidth )
662 {
663  // NOTE: this is very important to allow QGraphicsScene updating its index before geometry change
664  prepareGeometryChange();
665 
666  // The purpose of this method is to ensure proper dimensions of the item and the contained text. This method ensures:
667  // * an item maximum size is WNETWORKITEM_MINIMUM_WIDTH or the width of the connectors!
668  // * text exceeding size limits is cut
669 
670  m_width = minimumWidth;
671  m_height = WNETWORKITEM_MINIMUM_HEIGHT;
672 
673  // we need to respect the size minimally needed by ports
674  float portWidth = WQtNetworkPort::getMultiplePortWidth( std::max( m_outPorts.size(), m_inPorts.size() ) );
675 
676  // the item needs a maximum size constraint to avoid enormously large items
677  // NOTE: the specified size max can only be overwritten by the
678  float maxWidth = std::max( static_cast< float >( maximumWidth ), portWidth );
679 
680  // the width of the text elements
681  float textWidth = 0.0;
682  float textHeight = 0.0;
683 
684  // the width and height of the subtext elements
685  float subtextWidth = 0.0;
686  float subtextHeight = 0.0;
687  float subtextMargin = 0.0; // the margin between text and subtext
688 
689  // 1: query sizes of sub elements
690  if( m_text != 0 )
691  {
692  textWidth = static_cast< float >( m_text->boundingRect().width() );
693  textHeight = static_cast< float >( m_text->boundingRect().height() );
694  }
695  if( m_subtitle != 0 )
696  {
697  subtextWidth = static_cast< float >( m_subtitle->boundingRect().width() );
698  subtextHeight = static_cast< float >( m_subtitle->boundingRect().height() );
699  subtextMargin = 1.0f * WNETWORKITEM_MARGINY;
700  }
701 
702  // and another height: the height of text and subtext
703  float wholeTextHeight = textHeight + subtextHeight + subtextMargin;
704 
705  // get the required width and height
706  float maxTextWidth = maxWidth - ( 2.0f * WNETWORKITEM_MARGINX );
707 
708  // 2: limit sizes of sub elements if needed (especially the subtext)
709  if( ( m_text != 0 ) )
710  {
711  clipText( m_text, maxTextWidth, m_textFull );
712  }
713  if( ( m_subtitle != 0 ) )
714  {
715  clipText( m_subtitle, maxTextWidth, m_subtitleFull );
716  }
717 
718  // the new text boxes now define the final sizes:
719  if( m_text != 0 )
720  {
721  textWidth = static_cast< float >( m_text->boundingRect().width() );
722  textHeight = static_cast< float >( m_text->boundingRect().height() );
723  }
724  if( m_subtitle != 0 )
725  {
726  subtextWidth = static_cast< float >( m_subtitle->boundingRect().width() );
727  subtextHeight = static_cast< float >( m_subtitle->boundingRect().height() );
728  }
729  float requiredWidth = std::max( portWidth, std::max( subtextWidth, textWidth ) + ( 2.0f * WNETWORKITEM_MARGINX ) );
730  float requiredHeight = wholeTextHeight + ( 2.0f * WNETWORKITEM_MARGINY );
731 
732  // 3: set the final sizes
733  m_height = std::max( requiredHeight, static_cast< float >( WNETWORKITEM_MINIMUM_HEIGHT ) );
734  m_width = std::min( std::max( requiredWidth, static_cast< float >( minimumWidth ) ), maxWidth );
735 
736  QRectF rect( 0, 0, m_width, m_height );
737  m_rect = rect;
738 
739  // 4: use the sizes and set the positions and sizes of the text elements properly
740  if( m_text != 0 )
741  {
742  qreal x = ( m_width / 2.0 ) - ( m_text->boundingRect().width() / 2.0 );
743  qreal y = ( m_height / 2.0 ) - ( wholeTextHeight / 2.0 );
744  m_text->setPos( x, y );
745  }
746 
747  if( m_subtitle != 0 )
748  {
749  qreal x = ( m_width / 2.0 ) - ( m_subtitle->boundingRect().width() / 2.0 );
750  qreal y = ( m_height / 2.0 ) - ( subtextMargin );
751  m_subtitle->setPos( x, y );
752  }
753 
754  // 5: handle the ports
755  int portNumber = 1;
756  foreach( WQtNetworkPort *port, m_inPorts )
757  {
758  port->alignPosition( m_inPorts.size(), portNumber, m_rect, false );
759  portNumber++;
760  }
761 
762  portNumber = 1;
763  foreach( WQtNetworkPort *port, m_outPorts )
764  {
765  port->alignPosition( m_outPorts.size(), portNumber, m_rect, true );
766  portNumber++;
767  }
768 }
769 
770 void WQtNetworkItem::setTextItem( QGraphicsTextItem *text )
771 {
772  m_text = text;
773 }
774 
776 {
777  return QString::fromStdString( m_textFull );
778 }
779 
780 void WQtNetworkItem::setText( std::string text )
781 {
782  m_textFull = text;
783  updater();
784 }
785 
787 {
788  changeState( Crashed );
789 }
790 
792 {
793  m_forceUpdate = ( m_currentState != state );
794  m_currentState = state;
795  update();
796 }
797 
798 std::shared_ptr< WModule > WQtNetworkItem::getModule()
799 {
800  return m_module;
801 }
802 
803 void WQtNetworkItem::activate( bool active )
804 {
805  if( !m_module )
806  {
807  return;
808  }
809 
810  setEnabled( active );
811 
812  if( active == true )
813  {
814  setAcceptHoverEvents( true );
815  setFlag( QGraphicsItem::ItemIsSelectable, true );
816  changeState( m_module->isCrashed() ? Crashed : Normal );
817  }
818  if( active == false )
819  {
820  setAcceptHoverEvents( false );
821  setFlag( QGraphicsItem::ItemIsSelectable, false );
822  changeState( Disabled );
823  }
824 }
825 
827 {
828  // this one also keeps a ref on m_module
829  delete m_hidden;
830  m_hidden = NULL;
831 
832  // free module: we do not need it anymore
834 
835  // start removal animation
836  m_removalAnimationTimer->start();
838 }
839 
841 {
842  // remove from scene
843  if( scene() != NULL )
844  {
845  scene()->removeItem( this );
847  }
848 
849  // tell everyone that we are done
850  emit dead( this );
851 
852  // this ensures that this item gets deleted by the main loop in the main thread
853  deleteLater();
854 }
855 
857 {
858  setOpacity( 1.0 - ( value * value ) );
859 }
860 
862 {
863  setOpacity( value * value );
864 }
865 
866 void WQtNetworkItem::animatedMoveTo( QPointF newPos )
867 {
868  // create a timer and an animation object
869  QGraphicsItemAnimation* animation = new QGraphicsItemAnimation;
870  QTimeLine* animationTimer = new QTimeLine( WNETWORKITEM_MOVE_DURATION );
871 
872  // set them up properly
873  animationTimer->setFrameRange( 0, 100 );
874  animation->setItem( this );
875  animation->setTimeLine( animationTimer );
876 
877  // delete timer when done
878  connect( animationTimer, SIGNAL( finished() ), this, SLOT( moveFinished() ) );
879  connect( animationTimer, SIGNAL( finished() ), animation, SLOT( deleteLater() ) );
880  connect( animationTimer, SIGNAL( finished() ), animationTimer, SLOT( deleteLater() ) );
881 
882  // linearly move item
883  float steps = 500.0;
884  QPointF oldPos = pos();
885  for( int i = 0; i < steps; ++i )
886  {
887  float stepNorm = static_cast< float >( i ) / static_cast< float >( steps - 1 );
888  QPointF p = ( ( 1.0 - stepNorm ) * oldPos ) + ( stepNorm * newPos );
889  animation->setPosAt( stepNorm, p );
890  }
891  animation->setPosAt( 1.0, newPos );
892 
893  // disable item during animation to avoid click+drag.
894  // NOTE: using setEnabled causes the active selection of the module to vanish. So we use our own flag which is then handled in the event
895  // methods
896  m_noDrag = true;
897 
898  // go
899  animationTimer->start();
900 }
901 
902 void WQtNetworkItem::animatedMoveTo( qreal x, qreal y )
903 {
904  animatedMoveTo( QPointF( x, y ) );
905 }
906 
907 void WQtNetworkItem::moveTo( QPointF pos )
908 {
909  moveTo( pos.x(), pos.y() );
910 }
911 
912 void WQtNetworkItem::moveTo( qreal x, qreal y )
913 {
914  setPos( x, y );
915  moveFinished();
916 }
917 
919 {
920  // we have disabled the item to avoid clicking and dragging during move
921  m_noDrag = false;
922  positionChanged();
923  if( isSelected() )
924  {
925  // ensure visible if moved
926  m_networkEditor->getView()->focusOn( this );
927  }
928 }
929 
930 void WQtNetworkItem::setLayedOut( bool layedOut )
931 {
932  m_wasLayedOut = layedOut;
933 }
934 
936 {
937  return m_wasLayedOut;
938 }
939 
941 {
942  m_wasManuallyPlaced = manual;
943 }
944 
946 {
947  return m_wasManuallyPlaced;
948 }
949 
951 {
952  // move to gui thread, non-blocking.
953  WQtGui::execInGUIThreadAsync( boost::bind( &WQtNetworkItem::setText, this, m_module->getRuntimeName()->get() ) );
954 }
std::shared_ptr< WDataModule > SPtr
Convenience typedef for a std::shared_ptr< WDataModule >.
Definition: WDataModule.h:52
std::shared_ptr< WModule > SPtr
Shared pointer to a WModule.
Definition: WModule.h:106
std::vector< std::shared_ptr< WModuleOutputConnector > > OutputConnectorList
The type for the list of output connectors.
Definition: WModule.h:101
std::vector< std::shared_ptr< WModuleInputConnector > > InputConnectorList
The type for the list of input connectors.
Definition: WModule.h:96
Widget that handles WDataModuleInputs of WDtaModules.
static void execInGUIThreadAsync(boost::function< void(void) > functor, WCondition::SPtr notify=WCondition::SPtr())
Call a given function from within the GUI thread.
Definition: WQtGui.cpp:421
This class extends the basic functionality of QGraphicsView to allow comfortable panning and zooming.
void ensureVisibleSmooth(QGraphicsItem *item, int xmargin=50, int ymargin=50)
Improved version of QGraphicsView::ensureVisible for smooth scrolling.
void focusOn(QGraphicsItem *item)
The Item to focus on.
Container widget to hold the WQtNetworkScene.
WQtNetworkEditorView * getView()
Get the view handling the scene.
WQtNetworkScene * getScene()
Returns the current scene.
WQtNetworkSceneLayout * getLayout()
Get the layouter of the scene.
This class represents the ports a module have.
Small graphics item that respresents whether a module in the network editor is active or not.
void disableBoundsUpdate(bool disable=true)
Allows for temporarily disabling bounds update signal.
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value)
If the item is changed we want to get notified.
void changeState(State state)
Update the visual state of the item.
QString getText()
Get the caption as QString.
void setLayedOut(bool layedOut=true)
Marks the item as already layed out.
State
Denotes the current state this item is in.
std::string m_subtitleFull
always contains the unclipped text of m_subtitle
void dead(WQtNetworkItem *item)
The item is now dead.
WQtNetworkItemActivator * m_hidden
indicator showing if module's graphics are activated (allows to activate it)
void addOutputPort(WQtNetworkOutputPort *outPort)
Add a port to the item.
void addInputPort(WQtNetworkInputPort *inPort)
Add a port to the item.
void setManuallyPlaced(bool manual=true)
Mark item as manually placed.
bool m_noDrag
If true, the mouse events do not cause a drag and move operation.
virtual ~WQtNetworkItem()
Destructor.
bool m_busyIsDetermined
If true, a percentage is shown.
void activate(bool active)
Here the module can be enabled when the WModule is ready.
bool m_dragging
Dragging?
void animatedMoveTo(QPointF pos)
Move item to specified position smoothly, via animation.
float m_width
the width of the rect
bool m_isSelected
If true, the item is selected.
bool m_isHovered
If true, the item is hovered.
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
If the cursor leaves the item, the item gets his default color.
bool m_busyIndicatorShow
If true, the busy indication is active.
virtual void updater()
Can be used for polling the module states.
boost::signals2::connection m_runtimeNameConnection
Keep track of runtime name changes of this module.
void moveFinished()
Called whenever a animated move was finished.
QColor m_itemColor
the color of the item. Depends on type (source, sink, ...).
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
If the WQtNetworkItem is moved, then the contained ports have to update the connected WQtNetworkArrow...
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event)
Reimplemented from QGraphicsRectItem.
std::shared_ptr< WModule > getModule()
Get the WModule represented by this object.
void fitLook(float maximumWidth=WNETWORKITEM_MAXIMUM_WIDTH, float minimumWidth=WNETWORKITEM_MINIMUM_WIDTH)
This method aligns the in- and outports as well as the modulename in a regular way.
bool wasLayedOut() const
Checks whether the item was layed out earlier.
QGraphicsItemAnimation * m_animation
Animation for appearance and deletion.
void setTextItem(QGraphicsTextItem *text)
Set the QGraphicsTextItem ( the caption ) of the item.
QList< WQtNetworkInputPort * > getInPorts()
Returns the item inports.
WQtNetworkEditor * m_networkEditor
the related WQtNetworkEditor
void setCrashed()
Mark this module as crashed.
QTimeLine * m_removalAnimationTimer
Timer for the animation.
QList< WQtNetworkOutputPort * > m_outPorts
the output ports of the item
void removalAnimationDone()
Called when the m_removalAnimationTimer finishes.
std::string m_textFull
always contains the unclipped text of m_text
bool m_wasManuallyPlaced
Item has been placed manually.
bool m_wasLayedOut
Mark item as already positioned.
QGraphicsItemAnimation * m_removalAnimation
Animation for appearance and deletion.
void moveTo(QPointF pos)
Move item to specified position smoothly, no animation.
QGraphicsTextItem * m_subtitle
the caption
float m_itemBestWidth
Optimal width for this module.
int type() const
Reimplementation from QGraphicsItem.
void animationBlendOutTick(qreal value)
Called when the animation timers tick and progress in timeline.
bool m_forceUpdate
If true, the next call to update() will force a redraw.
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
Called upon double click.
QGraphicsTextItem * m_text
the caption
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
Mouse was released.
void setText(std::string text)
Set the new title text.
State m_currentState
denotes the state the item currently is in
QWidget * m_propertyToolWindow
The property toolbox window if any.
void positionChanged()
Called whenever the item moves around.
WQtNetworkItem(WQtNetworkEditor *editor, std::shared_ptr< WModule > module)
Constructs new item in the network scene.
float m_height
the height of the rect
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
If the cursor enters the item, the item gets a green color.
std::shared_ptr< WModule > m_module
the module
QTimeLine * die()
Animate removal and finally, instruct the owning network editor to remove the item.
QList< WQtNetworkInputPort * > m_inPorts
the input ports of the item
QRectF m_rect
the size of the items rect
void animationBlendInTick(qreal value)
Called when the animation timers tick and progress in timeline.
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *w)
Draw some customized stuff in the scene.
QTimeLine * m_animationTimer
Timer for the animation.
bool wasManuallyPlaced() const
Item was placed by hand.
QList< WQtNetworkOutputPort * > getOutPorts()
Returns the item outports.
QPointF m_draggingStart
Start position of dragging.
virtual QRectF boundingRect() const
The bounding area of the item.
void runtimeNameChanged()
Update name as it has been changed.
float m_busyPercent
Counter used for busy indication.
This class represents the ports a module have.
Abstract class to distinguish between input- and output ports from a module.
void alignPosition(int size, int portNumber, QRectF rect, bool outPort)
Calculates the position inside a item for each port to get a correct alignment.
static float getMultiplePortWidth(size_t nbPorts)
Calculates the spaced needed for the given amount of ports.
virtual void updateArrows()
The position of every arrow connected with this port is updating its position in the scene.
void snapAccept(WQtNetworkItem *item, QPointF worldCoords)
Accept the current item position and update layout accordingly.
void blendOut()
Allows blending out the underlaying layout structure.
virtual void removeItem(WQtNetworkItem *item)
Remove the item from the layout.
void blendIn()
Allows blending in the underlaying layout structure.
WQtNetworkItemGrid * getGrid() const
Get the grid used for the layout.
void snapTemporarily(WQtNetworkItem *item, QPointF worldCoords, bool noPhysicalMove=false)
Snap the item to the nearest layout element.
static QWidget * createPropertyGroupBox(QWidget *widget, bool asScrollArea=false, QWidget *parent=NULL, const QString &title="", int nestingLevel=0)
This function creates the fancy box around your specified group widget.
static std::string createTooltip(WModule::SPtr module)
Create tooltip for a given module.
std::string toString(const T &value)
Convert a given value to a string.
Definition: WStringUtils.h:120