Vuo  2.0.3
VuoPublishedPortList.cc
Go to the documentation of this file.
1 
10 #include "VuoPublishedPortList.hh"
11 #include "VuoCompilerPortClass.hh"
12 #include "VuoEditorComposition.hh"
13 #include "VuoInputEditor.hh"
14 #include "VuoInputEditorManager.hh"
16 
20 class InsertionIndicatorStyle : public QProxyStyle
21 {
22 public:
26  void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
27  {
28  if (element == QStyle::PE_IndicatorItemViewItemDrop)
29  {
30  QPen pen(QColor(160, 160, 160));
31  pen.setWidth(2);
32  painter->setPen(pen);
33  if (option->rect.height() == 0)
34  painter->drawLine(option->rect.topLeft(), option->rect.topRight());
35  else
36  painter->drawRect(option->rect);
37  }
38  else
39  QProxyStyle::drawPrimitive(element, option, painter, widget);
40  }
41 };
42 
45 
50  QListWidget(parent)
51 {
52  composition = NULL;
53 
54  contextMenuSetPortConstant = new QAction(tr("Edit Value…"), NULL);
55  contextMenuSetPortDetails = new QAction(tr("Edit Details…"), NULL);
56  contextMenuRenamePublishedPort = new QAction(tr("Rename Port…"), NULL);
57  contextMenuUnpublishPort = new QAction(tr("Delete Port"), NULL);
58 
59  connect(contextMenuSetPortConstant, &QAction::triggered, this, static_cast<void (VuoPublishedPortList::*)()>(&VuoPublishedPortList::editPublishedPortValue));
60  connect(contextMenuSetPortDetails, &QAction::triggered, this, &VuoPublishedPortList::editPublishedPortDetails);
61  connect(contextMenuRenamePublishedPort, &QAction::triggered, this, static_cast<void (VuoPublishedPortList::*)()>(&VuoPublishedPortList::renamePublishedPort));
62  connect(contextMenuUnpublishPort, &QAction::triggered, this, &VuoPublishedPortList::unpublishExternalPort);
63 
64  setDragDropMode(QAbstractItemView::InternalMove);
65  setDefaultDropAction(Qt::MoveAction);
66  setAutoFillBackground(true);
67  setStyle(new InsertionIndicatorStyle());
68  setStyleSheet(QString("VuoPublishedPortList {"
69  "border: 0px;"
70  "}"
71  )
72  );
73 
74  setMouseTracking(true);
75  this->fillVerticalSpace = true;
76  this->forwardingEventsToCanvas = false;
77  menuSelectionInProgress = false;
78 }
79 
85 {
86  return isInput;
87 }
88 
94 {
95  this->isInput = isInput;
96 }
97 
102 {
103  this->composition = composition;
104 }
105 
110 void VuoPublishedPortList::contextMenuEvent(QContextMenuEvent *event)
111 {
112  QListWidgetItem* activeListItem = itemAt(event->pos());
113  if (! activeListItem)
114  {
115  // If the context menu event took place on empty space within the list, let the parent sidebar handle it.
116  event->ignore();
117  return;
118  }
119 
120  QMenu contextMenu(this);
121  contextMenu.setSeparatorsCollapsible(false);
122 
123  VuoRendererPublishedPort *rendererPort = static_cast<VuoRendererPublishedPort *>(activeListItem->data(VuoPublishedPortList::publishedPortPointerIndex).value<void *>());
124  VuoPublishedPort *port = static_cast<VuoPublishedPort *>(rendererPort->getBase());
125  if (!port->isProtocolPort())
126  {
127  if (valueEditableForPublishedPort(port))
128  contextMenu.addAction(contextMenuSetPortConstant);
129 
130  if (detailsEditableForPublishedPort(port))
131  contextMenu.addAction(contextMenuSetPortDetails);
132 
133  if (!rendererPort->isPermanent())
134  {
135  contextMenu.addAction(contextMenuRenamePublishedPort);
136  contextMenu.addAction(contextMenuUnpublishPort);
137  }
138 
139  // Associate the right-clicked VuoRendererPublishedPort item with the context menu actions.
140  contextMenuSetPortConstant->setData(activeListItem->data(VuoPublishedPortList::publishedPortPointerIndex));
141  contextMenuSetPortDetails->setData(activeListItem->data(VuoPublishedPortList::publishedPortPointerIndex));
142  contextMenuRenamePublishedPort->setData(qVariantFromValue((void *)activeListItem));
143  contextMenuUnpublishPort->setData(activeListItem->data(VuoPublishedPortList::publishedPortPointerIndex));
144  }
145 
146  if (!contextMenu.actions().isEmpty())
147  {
148  menuSelectionInProgress = true;
149  contextMenu.exec(event->globalPos());
150  menuSelectionInProgress = false;
151  }
152 }
153 
158 bool VuoPublishedPortList::valueEditableForPublishedPort(VuoPublishedPort *port)
159 {
160  // Ports that are part of an active protocol cannot have their values edited.
161  if (port->isProtocolPort())
162  return false;
163 
164  // Neither output ports nor event-only ports can have their values edited.
165  bool hasData = static_cast<VuoCompilerPortClass *>(port->getClass()->getCompiler())->getDataVuoType();
166  if (!(getInput() && hasData))
167  return false;
168 
169  // Ports whose data types don't have available input editors cannot have their values edited.
170  VuoInputEditorManager *inputEditorManager = composition->getInputEditorManager();
171  VuoType *dataType = static_cast<VuoCompilerPortClass *>(port->getClass()->getCompiler())->getDataVuoType();
172  VuoInputEditor *inputEditorLoadedForPortDataType = (inputEditorManager? inputEditorManager->newInputEditor(dataType) : NULL);
173 
174  if (inputEditorLoadedForPortDataType)
175  inputEditorLoadedForPortDataType->deleteLater();
176 
177  return inputEditorLoadedForPortDataType;
178 }
179 
184 bool VuoPublishedPortList::detailsEditableForPublishedPort(VuoPublishedPort *port)
185 {
186  // Ports that are part of an active protocol cannot have their details edited.
187  if (port->isProtocolPort())
188  return false;
189 
190  // Output ports cannot have their details edited.
191  if (!getInput())
192  return false;
193 
194  // For now, only ports with data types of VuoInteger, VuoReal, or VuoPoint*d can have their details edited.
195  // Output ports cannot have their details edited.
196  VuoType *dataType = static_cast<VuoCompilerPortClass *>(port->getClass()->getCompiler())->getDataVuoType();
197 
198  return (dataType && ((dataType->getModuleKey() == "VuoReal")
199  || (dataType->getModuleKey() == "VuoInteger")
200  || (dataType->getModuleKey() == "VuoPoint2d")
201  || (dataType->getModuleKey() == "VuoPoint3d")
202  || (dataType->getModuleKey() == "VuoPoint4d")));
203 }
204 
211 {
212  QListWidgetItem* activeListItem = itemAt(event->pos());
213 
214  if (activeListItem)
215  {
216  VuoRendererPublishedPort *port = static_cast<VuoRendererPublishedPort *>(activeListItem->data(VuoPublishedPortList::publishedPortPointerIndex).value<void *>());
217  if (valueEditableForPublishedPort(dynamic_cast<VuoPublishedPort *>(port->getBase())))
218  editPublishedPortValue(port);
219  }
220 
221  else
222  QListWidget::mouseDoubleClickEvent(event);
223 }
224 
229 {
230  if (! composition->views().empty())
231  {
232  // If clicking directly on a port shape, let the composition handle the mouseclick to the port.
233  VuoRendererPublishedPort *nearbyPort = getPublishedPortAtGlobalPos(event->globalPos(),
235  true);
236  if (nearbyPort)
237  {
238  QGraphicsSceneMouseEvent mouseEvent;
239  mouseEvent.setButton(event->button());
240  mouseEvent.setButtons(event->buttons());
241  mouseEvent.setScenePos(composition->views()[0]->mapToScene(composition->views()[0]->mapFromGlobal(static_cast<QMouseEvent *>(event)->globalPos())));
242  composition->leftMousePressEventAtNearbyItem(static_cast<QGraphicsItem *>(nearbyPort), &mouseEvent);
243 
244  forwardingEventsToCanvas = true;
245  event->accept();
246  return;
247  }
248  }
249 
250  // Clicking on a disabled item (e.g., a protocol port) should clear the previous selection.
251  QListWidgetItem* activeListItem = itemAt(event->pos());
252  if (activeListItem && (!(activeListItem->flags() & Qt::ItemIsEnabled)))
253  clearSelection();
254 
255  QListWidget::mousePressEvent(event);
256 }
257 
261 void VuoPublishedPortList::mouseMoveEvent(QMouseEvent *event)
262 {
263  if (forwardingEventsToCanvas)
264  {
265  QMouseEvent mouseEvent(QEvent::MouseMove,
266  composition->views()[0]->mapFromGlobal(event->globalPos()),
267  event->screenPos(),
268  event->button(),
269  event->buttons(),
270  event->modifiers());
271 
272  QApplication::sendEvent(composition->views()[0]->viewport(), &mouseEvent);
273 
274  event->accept();
275  return;
276  }
277 
279 
280  QListWidget::mouseMoveEvent(event);
281 }
282 
287 {
288  if (forwardingEventsToCanvas)
289  {
290  QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
291  composition->views()[0]->mapFromGlobal(event->globalPos()),
292  event->screenPos(),
293  event->button(),
294  event->buttons(),
295  event->modifiers());
296 
297  QApplication::sendEvent(composition->views()[0]->viewport(), &mouseEvent);
298 
299  forwardingEventsToCanvas = false;
300  event->accept();
301  return;
302  }
303 
304  QListWidget::mouseReleaseEvent(event);
305 }
306 
310 void VuoPublishedPortList::dragMoveEvent(QDragMoveEvent *event)
311 {
312  // Don't show the drop indicator for drops that would end among protocol ports.
313  bool dropWouldFallWithinProtocolPorts = false;
314  QListWidgetItem* activeListItem = (count()? itemAt(event->pos()+QPoint(0,0.5*sizeHintForRow(0))) : NULL);
315  if (activeListItem)
316  {
317  VuoRendererPublishedPort *port = static_cast<VuoRendererPublishedPort *>(activeListItem->data(VuoPublishedPortList::publishedPortPointerIndex).value<void *>());
318  if (port && dynamic_cast<VuoPublishedPort *>(port->getBase())->isProtocolPort())
319  dropWouldFallWithinProtocolPorts = true;
320  }
321 
322  setDropIndicatorShown(!dropWouldFallWithinProtocolPorts);
323  QListWidget::dragMoveEvent(event);
324 }
325 
332 {
333  dropEvent(event);
334 }
335 
340 {
341  return menuSelectionInProgress;
342 }
343 
347 void VuoPublishedPortList::dropEvent(QDropEvent *event)
348 {
349  if (!count())
350  return;
351 
352  // Shift drops among protocol ports to just below the bottommost protocol port.
353  QListWidgetItem* activeListItem = itemAt(event->pos()+QPoint(0,0.5*sizeHintForRow(0)));
354  if (activeListItem)
355  {
356  VuoRendererPublishedPort *port = static_cast<VuoRendererPublishedPort *>(activeListItem->data(VuoPublishedPortList::publishedPortPointerIndex).value<void *>());
357  if (port && dynamic_cast<VuoPublishedPort *>(port->getBase())->isProtocolPort())
358  {
359  // Shift down one row at a time while we're still within the protocol port section.
360  QDropEvent modifiedEvent(event->pos()+QPoint(0,sizeHintForRow(0)),
361  event->dropAction(),
362  event->mimeData(),
363  event->mouseButtons(),
364  event->keyboardModifiers());
365 
366  dropEvent(&modifiedEvent);
367  return;
368  }
369  }
370 
371  QListWidget::dropEvent(event);
372 
373  // Respond to changes in port order via mouse drag.
374  updatePortOrder();
375 }
376 
384 {
385  if (forwardingEventsToCanvas)
386  {
387  QKeyEvent keyEvent(QEvent::KeyPress, event->key(), event->modifiers());
388  QApplication::sendEvent(composition->views()[0]->viewport(), &keyEvent);
389 
390  event->accept();
391  return;
392  }
393 
394  if (event->key() == Qt::Key_Return)
395  {
396  QList<QListWidgetItem *> selectedPorts = selectedItems();
397  for (QList<QListWidgetItem *>::iterator portItem = selectedPorts.begin(); portItem != selectedPorts.end(); ++portItem)
398  {
399  VuoRendererPublishedPort *port = static_cast<VuoRendererPublishedPort *>((*portItem)->data(VuoPublishedPortList::publishedPortPointerIndex).value<void *>());
400  if (valueEditableForPublishedPort(dynamic_cast<VuoPublishedPort *>(port->getBase())))
401  editPublishedPortValue(port);
402  }
403  }
404 
405  else
406  QListWidget::keyPressEvent(event);
407 }
408 
413 {
414  if (forwardingEventsToCanvas)
415  {
416  QKeyEvent keyEvent(QEvent::KeyRelease, event->key(), event->modifiers());
417  QApplication::sendEvent(composition->views()[0]->viewport(), &keyEvent);
418 
419  event->accept();
420  return;
421  }
422 
423  QListWidget::keyReleaseEvent(event);
424 }
425 
429 void VuoPublishedPortList::editPublishedPortValue()
430 {
431  QAction *sender = static_cast<QAction *>(QObject::sender());
432  VuoRendererPublishedPort *port = static_cast<VuoRendererPublishedPort *>(sender->data().value<void *>());
433 
434  editPublishedPortValue(port);
435 }
436 
440 void VuoPublishedPortList::editPublishedPortValue(VuoRendererPublishedPort *port)
441 {
442  emit inputEditorRequested(port);
443 }
444 
448 void VuoPublishedPortList::editPublishedPortDetails()
449 {
450  QAction *sender = static_cast<QAction *>(QObject::sender());
451  VuoRendererPublishedPort *port = static_cast<VuoRendererPublishedPort *>(sender->data().value<void *>());
452 
454 }
455 
456 
460 void VuoPublishedPortList::renamePublishedPort()
461 {
462  QAction *sender = (QAction *)QObject::sender();
463  QListWidgetItem * portListItem = (QListWidgetItem *)(sender->data().value<void *>());
464  renamePublishedPort(portListItem);
465 }
466 
470 void VuoPublishedPortList::renamePublishedPort(QListWidgetItem* portListItem)
471 {
473  if (!dynamic_cast<VuoPublishedPort *>(port->getBase())->isProtocolPort())
474  emit publishedPortNameEditorRequested(port, true);
475 }
476 
481 void VuoPublishedPortList::updatePortOrder()
482 {
483  vector<VuoPublishedPort *> publishedPorts;
484  int numPorts = count();
485  for (int portIndex = 0; portIndex < numPorts; ++portIndex)
486  {
487  QListWidgetItem *currentPortItem = this->item(portIndex);
488  VuoRendererPublishedPort *currentRenderedPublishedPort = ((VuoRendererPublishedPort *)(currentPortItem->data(VuoPublishedPortList::publishedPortPointerIndex).value<void *>()));
489  publishedPorts.push_back(dynamic_cast<VuoPublishedPort *>(currentRenderedPublishedPort->getBase()));
490  }
491 
492  emit publishedPortsReordered(publishedPorts, isInput);
493  emit publishedPortModified();
494 }
495 
499 void VuoPublishedPortList::unpublishExternalPort()
500 {
501  QAction *sender = (QAction *)QObject::sender();
502  VuoRendererPublishedPort *port = (VuoRendererPublishedPort *)(sender->data().value<void *>());
503 
505  emit publishedPortModified();
506 }
507 
512 {
513  if (this->fillVerticalSpace)
514  return QSize(QListWidget::sizeHint().width(), QWIDGETSIZE_MAX);
515 
516  else
517  {
518  int cumulativeListHeight = 0;
519  int numRows = count();
520  for (int rowIndex = 0; rowIndex < numRows; ++rowIndex)
521  cumulativeListHeight += sizeHintForRow(rowIndex);
522 
523  return QSize(QListWidget::sizeHint().width(), cumulativeListHeight);
524  }
525 }
526 
532 {
533  int numPorts = count();
534  for (int portIndex = 0; portIndex < numPorts; ++portIndex)
535  {
536  QListWidgetItem *currentPortItem = this->item(portIndex);
537  VuoRendererPublishedPort *currentRenderedPublishedPort = ((VuoRendererPublishedPort *)(currentPortItem->data(VuoPublishedPortList::publishedPortPointerIndex).value<void *>()));
538  QPoint connectionPoint = QPoint(isInput? viewport()->geometry().right() :
539  viewport()->geometry().left(),
540  viewport()->mapToParent(visualItemRect(currentPortItem).center()).y());
541 
542  QPoint globalPos = viewport()->parentWidget()->mapToGlobal(connectionPoint);
543 
544  if (composition && ! composition->views().empty())
545  {
546  QPoint compositionViewportPos = composition->views()[0]->mapFromGlobal(globalPos);
547  currentRenderedPublishedPort->setCompositionViewportPos(compositionViewportPos);
548  }
549 
550  currentRenderedPublishedPort->setVisible(isVisible());
551  }
552 
554 }
555 
568 VuoRendererPublishedPort * VuoPublishedPortList::getPublishedPortAtGlobalPos(QPoint globalPos, qreal xTolerance, bool limitPortCollisionRange)
569 {
570  QPoint localPos = viewport()->parentWidget()->mapFromGlobal(globalPos);
571 
572  int numPorts = count();
573  for (int portIndex = 0; portIndex < numPorts; ++portIndex)
574  {
575  QListWidgetItem *currentPortItem = this->item(portIndex);
576  QRectF currentPortRect = visualItemRect(currentPortItem);
577 
578  if (limitPortCollisionRange)
579  {
580  if (isInput)
581  currentPortRect = QRectF(currentPortRect.right()-VuoRendererPort::portRadius,
582  currentPortRect.top(),
584  currentPortRect.height());
585  else
586  currentPortRect = QRectF(currentPortRect.left(),
587  currentPortRect.top(),
589  currentPortRect.height());
590  }
591 
592  currentPortRect.adjust(-xTolerance, 0, xTolerance, 0);
593 
594  if (currentPortRect.contains(localPos))
595  return ((VuoRendererPublishedPort *)(currentPortItem->data(VuoPublishedPortList::publishedPortPointerIndex).value<void *>()));
596  }
597 
598  return NULL;
599 }
600 
605 {
606  int numPorts = count();
607  for (int portIndex = 0; portIndex < numPorts; ++portIndex)
608  {
609  QListWidgetItem *currentPortItem = this->item(portIndex);
610  VuoRendererPublishedPort *currentPort = static_cast<VuoRendererPublishedPort *>( currentPortItem->data(VuoPublishedPortList::publishedPortPointerIndex).value<void *>() );
611  if (currentPort == port)
612  {
613  QPoint connectionPoint = QPoint(isInput? viewport()->geometry().right() :
614  viewport()->geometry().left(),
615  viewport()->mapToParent(visualItemRect(currentPortItem).center()).y());
616 
617  return viewport()->parentWidget()->mapToGlobal(connectionPoint);
618  }
619  }
620 
621  return QPoint(0,0);
622 }
623 
628 {
629  int numPorts = count();
630  for (int portIndex = 0; portIndex < numPorts; ++portIndex)
631  {
632  QListWidgetItem *currentPortItem = this->item(portIndex);
633  currentPortItem->setSelected(false);
634  }
635 }
636 
641 {
642  this->fillVerticalSpace = fill;
643  setFixedHeight(sizeHint().height());
644 }