11 #include "ui_VuoPublishedPortSidebar.h"
36 this->composition = composition;
37 this->isInput = isInput;
38 this->portTypeMenusPopulated =
false;
40 setWindowTitle(isInput ? tr(
"Inputs") : tr(
"Outputs"));
43 setFocusPolicy(Qt::ClickFocus);
46 widget()->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
47 widget()->setMinimumWidth(100);
48 widget()->setMaximumWidth(100);
50 ui->newPublishedPortButton->setIcon(QIcon(
":/Icons/new.svg"));
52 menuAddPort =
new QMenu(
this);
53 menuAddPort->setSeparatorsCollapsible(
false);
54 menuAddPort->setTitle(tr(
"New Port"));
55 ui->newPublishedPortButton->setMenu(menuAddPort);
56 connect(menuAddPort, &QMenu::aboutToShow,
this, &VuoPublishedPortSidebar::populatePortTypeMenus);
60 ui->publishedPortList->setAttribute(Qt::WA_MacShowFocusRect,
false);
63 contextMenuPortOptions =
new QMenu(
this);
64 contextMenuPortOptions->setSeparatorsCollapsible(
false);
66 menuChangeProtocol =
new QMenu(contextMenuPortOptions);
67 menuChangeProtocol->setSeparatorsCollapsible(
false);
68 menuChangeProtocol->setTitle(tr(
"Change Protocol"));
69 if (enableProtocolChanges)
70 contextMenuPortOptions->addMenu(menuChangeProtocol);
72 contextMenuRemoveProtocol =
new QMenu(
this);
73 contextMenuRemoveProtocol->setSeparatorsCollapsible(
false);
74 contextMenuActionRemoveProtocol =
new QAction(tr(
"Remove Protocol"), NULL);
76 if (enableProtocolChanges)
77 contextMenuRemoveProtocol->addAction(contextMenuActionRemoveProtocol);
88 connect(
this, &VuoPublishedPortSidebar::visibilityChanged, ui->publishedPortList, &VuoPublishedPortList::setVisible);
91 ui->publishedPortList->setInput(isInput);
92 ui->publishedPortList->setComposition(composition);
95 setMouseTracking(
true);
99 connect(editor, SIGNAL(darkInterfaceToggled(
bool)), ui->publishedPortList, SLOT(repaint()));
102 VuoPublishedPortSidebar_Pro();
112 set<QString> previouslySelectedPorts;
113 QList<QListWidgetItem *> previouslySelectedPortListItems = ui->publishedPortList->selectedItems();
114 for (QList<QListWidgetItem *>::iterator portListItem = previouslySelectedPortListItems.begin(); portListItem != previouslySelectedPortListItems.end(); ++portListItem)
115 previouslySelectedPorts.insert(((*portListItem)->data(Qt::DisplayRole).value<QString>()));
117 ui->publishedPortList->clear();
120 ui->publishedPortList->getInput());
123 bool portWasSelected = previouslySelectedPorts.find(publishedPort->
getClass()->
getName().c_str()) != previouslySelectedPorts.end();
124 appendPublishedPortToList(publishedPort, portWasSelected);
128 ui->publishedPortList->setFixedHeight(ui->publishedPortList->sizeHint().height());
129 ui->publishedPortList->update();
130 ui->publishedPortList->updatePublishedPortLocs();
139 void VuoPublishedPortSidebar::appendPublishedPortToList(
VuoPublishedPort *port,
bool select)
144 QListWidgetItem *item =
new QListWidgetItem(ui->publishedPortList);
146 item->setData(Qt::DisplayRole, publishedPortName.c_str());
149 QString formattedPublishedPortName = QString(
"<b><font size=+2>%1</font></b>").arg(publishedPortName.c_str());
152 QString formattedPublishedPortDataType =
"<font size=+1 color=\"gray\">" + tr(
"Data type") +
": <b>" + QString::fromStdString(publishedPortType) +
"</b></font>";
163 if (publishedPortName ==
"time")
165 if (filter || generator || transition)
166 description = tr(
"A number that changes over time, used to control animations or other changing effects.");
168 description +=
" " + tr(
"<code>time</code> is independent of <code>progress</code>.");
170 else if (publishedPortName ==
"image")
172 if (filter || generator || transition)
173 description = tr(
"The image to be filtered.");
175 else if (publishedPortName ==
"width")
178 description = tr(
"The requested width of the image, in pixels.");
180 else if (publishedPortName ==
"height")
183 description = tr(
"The requested height of the image, in pixels.");
185 else if (publishedPortName ==
"startImage")
188 description = tr(
"The image to transition from.");
190 else if (publishedPortName ==
"endImage")
193 description = tr(
"The image to transition to.");
195 else if (publishedPortName ==
"progress")
198 description = tr(
"A number from 0 to 1 for how far the transition has progressed. At 0, the transition is at the beginning, with only <code>startImage</code> showing. At 0.5, the transition is halfway through. At 1, the transition is complete, with only <code>endImage</code> showing. When previewing the composition in Vuo, the mouse position left to right controls <code>progress</code>.");
202 else if (publishedPortName ==
"outputImage")
205 description = tr(
"The altered image.");
207 description = tr(
"The created image. Its width and height should match the <code>width</code> and <code>height</code> published input ports.");
209 description = tr(
"The resulting image.");
213 else if (publishedPortName ==
"offlineRender")
216 description = tr(
"For movie export: <code>true</code> if the composition is being exported to a movie and <code>false</code> otherwise.");
218 else if (publishedPortName ==
"motionBlur")
221 description = tr(
"For movie export: The number of frames rendered per output frame. 1 means motion blur is disabled; 2, 4, 8, 16, 32, or 64 means motion blur is enabled.");
223 else if (publishedPortName ==
"duration")
226 description = tr(
"For FxPlug: The length, in seconds, of the clip to be filtered.");
228 description = tr(
"For movie export and FxPlug: The length, in seconds, of the movie/clip.");
230 description = tr(
"For FxPlug: The length, in seconds, of the transition.");
232 else if (publishedPortName ==
"framerate")
234 if (filter || transition)
235 description = tr(
"For FxPlug: The framerate of the project, in frames per second.");
237 description = tr(
"For movie export and FxPlug: The framerate of the movie/project, in frames per second.");
239 else if (publishedPortName ==
"frameNumber")
242 description = tr(
"For FxPlug: The number of frames since the beginning of the clip, starting at 0.");
244 description = tr(
"For movie export and FxPlug: The number of frames since the beginning of the movie/clip, starting at 0.");
246 description = tr(
"For FxPlug: The number of frames since the beginning of the transition, starting at 0.");
248 else if (publishedPortName ==
"quality")
250 if (filter || generator || transition)
251 description = tr(
"For FxPlug: The rendering quality or level of detail.");
253 else if (publishedPortName ==
"screen")
256 description = tr(
"For screen savers: Which display the screen saver is running on. (macOS runs a separate instance of the composition on each display.)");
258 else if (publishedPortName ==
"preview")
261 description = tr(
"For screen savers: <code>true</code> when the screen saver is running in the System Preferences preview thumbnail.");
264 if (!description.isEmpty())
265 description =
"<p><font size=+1>" + description +
"</font></p>";
268 item->setToolTip(formattedPublishedPortName.append(
"<BR>")
269 .append(formattedPublishedPortDataType)
270 .append(description));
274 item->setFlags(item->flags() &~ Qt::ItemIsEnabled);
276 ui->publishedPortList->addItem(item);
277 item->setSelected(select);
292 int numPorts = ui->publishedPortList->count();
293 for (
int portIndex = 0; portIndex < numPorts; ++portIndex)
295 QListWidgetItem *portItem = ui->publishedPortList->item(portIndex);
298 QGraphicsItem::CacheMode normalCacheMode = publishedPortToHighlight->cacheMode();
299 publishedPortToHighlight->setCacheMode(QGraphicsItem::NoCache);
305 publishedPortToHighlight->setCacheMode(normalCacheMode);
308 bool publishedPortWellShouldAcceptDrops = (internalFixedPort && canListPublishedPortAliasFor(internalFixedPort) && internalFixedPort->
getPublishable());
309 ui->publishedPortDropBox->setCurrentlyAcceptingDrops(publishedPortWellShouldAcceptDrops);
310 ui->publishedPortDropBox->update();
314 ui->publishedPortList->setFillVerticalSpace(!publishedPortWellShouldAcceptDrops);
315 ui->publishedPortList->viewport()->update();
324 int numPorts = ui->publishedPortList->count();
325 for (
int portIndex = 0; portIndex < numPorts; ++portIndex)
327 QListWidgetItem *portItem = ui->publishedPortList->item(portIndex);
330 QGraphicsItem::CacheMode normalCacheMode = publishedPort->cacheMode();
331 publishedPort->setCacheMode(QGraphicsItem::NoCache);
334 publishedPort->setCacheMode(normalCacheMode);
337 ui->publishedPortDropBox->setCurrentlyAcceptingDrops(
false);
338 ui->publishedPortDropBox->update();
342 ui->publishedPortList->setFillVerticalSpace(
true);
343 ui->publishedPortList->viewport()->update();
355 ui->activeProtocolLabel->setStyleSheet(VUO_QSTRINGIFY(
357 background-color: %1;
358 color: rgba(255,255,255,224);
361 .arg(getActiveProtocolHeadingColor(0, !isInput).name())
365 ui->activeProtocolLabel->setHidden(
false);
370 ui->activeProtocolLabel->setText(
"");
371 ui->activeProtocolLabel->setHidden(
true);
380 return menuChangeProtocol;
388 return contextMenuActionRemoveProtocol;
405 int numPorts = ui->publishedPortList->count();
406 for (
int portIndex = 0; portIndex < numPorts; ++portIndex)
408 QListWidgetItem *portItem = ui->publishedPortList->item(portIndex);
411 if (publishedPort == publishedPortUnderCursor)
420 ui->publishedPortDropBox->setHovered(isPublishedPortDropBoxUnderCursorForEvent(event));
423 ui->publishedPortList->viewport()->update();
435 int numPorts = ui->publishedPortList->count();
436 for (
int portIndex = 0; portIndex < numPorts; ++portIndex)
438 QListWidgetItem *portItem = ui->publishedPortList->item(portIndex);
443 ui->publishedPortDropBox->setHovered(
false);
446 ui->publishedPortList->viewport()->update();
471 string typecastToInsert =
"";
475 string specializedTypeName =
"";
479 bool isCursorOverPublishedPortDropBox = isPublishedPortDropBoxUnderCursorForEvent(event);
482 if (isCursorOverPublishedPortDropBox && canListPublishedPortAliasFor(fixedPort))
487 forceEventOnlyPublication,
497 bool isPublishedInput = !publishedPort->
getInput();
503 || (isPublishedInput? composition->
selectBridgingSolution(publishedPort, fixedPort,
false, &portToSpecialize, specializedTypeName, typecastToInsert) :
504 composition->
selectBridgingSolution(fixedPort, publishedPort,
true, &portToSpecialize, specializedTypeName, typecastToInsert)))
507 VuoCable *dataCableToDisplace = NULL;
508 if (!forceEventOnlyPublication && !ui->publishedPortList->getInput())
511 for (vector<VuoCable *>::iterator cable = previousConnectedCables.begin(); (! dataCableToDisplace) && (cable != previousConnectedCables.end()); ++cable)
512 if ((*cable)->getRenderer()->effectivelyCarriesData())
513 dataCableToDisplace = *cable;
519 bool cableToReplaceHasMatchingDataCarryingStatus = (cableToReplace?
521 cableInProgressExpectedToCarryData) :
523 if (cableToReplace && cableToReplaceHasMatchingDataCarryingStatus)
535 if (recreatingSameConnection)
544 if (dataCableToDisplace)
546 QList<QGraphicsItem *> removedComponents;
547 removedComponents.append(dataCableToDisplace->
getRenderer());
553 if (cableToReplace && !cableToReplaceHasMatchingDataCarryingStatus)
555 QList<QGraphicsItem *> removedComponents;
556 removedComponents.append(cableToReplace->
getRenderer());
562 forceEventOnlyPublication,
563 (portToSpecialize? portToSpecialize->
getBase() : NULL),
581 if (isActiveProtocolLabelUnderCursorForEvent(event))
583 contextMenuActionRemoveProtocol->setData(qVariantFromValue((
void *)composition->
getActiveProtocol()));
584 contextMenuRemoveProtocol->exec(event->globalPos());
588 contextMenuPortOptions->addMenu(menuAddPort);
589 contextMenuPortOptions->exec(event->globalPos());
590 contextMenuPortOptions->removeAction(menuAddPort->menuAction());
608 ui->publishedPortList->clearSelection();
621 ui->publishedPortList->updatePublishedPortLocs();
629 if (event->source() == ui->publishedPortList)
640 QDropEvent modifiedEvent(QPoint(10,10),
643 event->mouseButtons(),
644 event->keyboardModifiers());
645 ui->publishedPortList->adoptDropEvent(&modifiedEvent);
655 QDockWidget::closeEvent(event);
662 bool VuoPublishedPortSidebar::canListPublishedPortAliasFor(
VuoRendererPort *port)
664 return ((ui->publishedPortList->getInput() && port->
getInput()) || ((! ui->publishedPortList->getInput()) && port->
getOutput()));
671 bool VuoPublishedPortSidebar::isPublishedPortDropBoxUnderCursorForEvent(QMouseEvent *event)
673 QPoint cursorPosition = ((QMouseEvent *)(event))->globalPos();
675 QRect publishedPortDropBoxRect = ui->publishedPortDropBox->geometry();
676 publishedPortDropBoxRect.moveTopLeft(ui->publishedPortDropBox->parentWidget()->mapToGlobal(publishedPortDropBoxRect.topLeft()));
678 bool dropBoxUnderCursor = (!ui->publishedPortDropBox->isHidden() && publishedPortDropBoxRect.contains(cursorPosition));
679 return dropBoxUnderCursor;
686 bool VuoPublishedPortSidebar::isActiveProtocolLabelUnderCursorForEvent(QContextMenuEvent *event)
688 QPoint cursorPosition = ((QContextMenuEvent *)(event))->globalPos();
690 QRect activeProtocolLabelRect = ui->activeProtocolLabel->geometry();
691 activeProtocolLabelRect.moveTopLeft(ui->activeProtocolLabel->parentWidget()->mapToGlobal(activeProtocolLabelRect.topLeft()));
693 bool activeProtocolLabelUnderCursor = (!ui->activeProtocolLabel->isHidden() && activeProtocolLabelRect.contains(cursorPosition));
694 return activeProtocolLabelUnderCursor;
703 QPoint cursorPosition = ((QMouseEvent *)(event))->globalPos();
704 return ui->publishedPortList->getPublishedPortAtGlobalPos(cursorPosition, tolerance, limitPortCollisionRange);
712 return ui->publishedPortList->getGlobalPosOfPublishedPort(port);
720 return ui->publishedPortList->getMenuSelectionInProgress();
727 QColor VuoPublishedPortSidebar::getActiveProtocolHeadingColor(
int protocolIndex,
bool isInput)
730 VuoRendererColors::noSelection,
733 return activeProtocolColor.nodeFrame();
743 VuoRendererColors::noSelection,
746 return activeProtocolColor.
nodeFill();
761 int yCenter = portLeftCenterGlobal.y();
762 int xRight = parentWidget()->mapToGlobal( QPoint(x() + width(), 0) ).x();
763 QPoint publishedPortRightCenterGlobal = QPoint(xRight, yCenter);
766 const int focusGlowWidth = 2;
767 publishedPortRightCenterGlobal = publishedPortRightCenterGlobal - QPoint(focusGlowWidth, 0);
768 nameEditor->
setWidth(width() - 2*focusGlowWidth);
771 json_object_object_add(details,
"isDark", json_object_new_boolean(
static_cast<VuoEditor *
>(qApp)->isInterfaceDark()));
773 json_object *originalValueAsJson = json_object_new_string(originalValue.c_str());
774 json_object *newValueAsJson = nameEditor->
show(publishedPortRightCenterGlobal, originalValueAsJson, details);
775 string newValue = json_object_get_string(newValueAsJson);
776 json_object_put(originalValueAsJson);
777 json_object_put(newValueAsJson);
790 if (publishedPort && type &&
799 bool isPublishedInput = !port->
getInput();
804 if (!originalDetails || json_object_get_type(originalDetails) != json_type_object)
805 originalDetails = json_object_new_object();
807 json_object_object_add(originalDetails,
"isDark", json_object_new_boolean(editor->
isInterfaceDark()));
813 newDetails = numericDetailsEditor->
show(portLeftCenterGlobal, originalDetails);
814 numericDetailsEditor->deleteLater();
821 newDetails = pointDetailsEditor->
show(portLeftCenterGlobal, originalDetails);
822 pointDetailsEditor->deleteLater();
826 string originalSuggestedMin, newSuggestedMin, originalSuggestedMax, newSuggestedMax, originalSuggestedStep, newSuggestedStep =
"";
830 if (json_object_object_get_ex(originalDetails,
"suggestedMin", &originalSuggestedMinValue))
831 originalSuggestedMin = json_object_to_json_string(originalSuggestedMinValue);
834 if (json_object_object_get_ex(newDetails,
"suggestedMin", &newSuggestedMinValue))
835 newSuggestedMin = json_object_to_json_string(newSuggestedMinValue);
837 json_object_object_add(newDetails,
"suggestedMin", NULL);
841 if (json_object_object_get_ex(originalDetails,
"suggestedMax", &originalSuggestedMaxValue))
842 originalSuggestedMax = json_object_to_json_string(originalSuggestedMaxValue);
845 if (json_object_object_get_ex(newDetails,
"suggestedMax", &newSuggestedMaxValue))
846 newSuggestedMax = json_object_to_json_string(newSuggestedMaxValue);
848 json_object_object_add(newDetails,
"suggestedMax", NULL);
852 if (json_object_object_get_ex(originalDetails,
"suggestedStep", &originalSuggestedStepValue))
853 originalSuggestedStep = json_object_to_json_string(originalSuggestedStepValue);
856 if (json_object_object_get_ex(newDetails,
"suggestedStep", &newSuggestedStepValue))
857 newSuggestedStep = json_object_to_json_string(newSuggestedStepValue);
859 json_object_object_add(newDetails,
"suggestedStep", NULL);
861 if ((originalSuggestedMin != newSuggestedMin) ||
862 (originalSuggestedMax != newSuggestedMax) ||
863 (originalSuggestedStep != newSuggestedStep))
875 void VuoPublishedPortSidebar::newPublishedPortTypeSelected()
877 QAction *sender = (QAction *)QObject::sender();
878 QList<QVariant> actionData = sender->data().toList();
879 QString typeName = actionData[1].toString();
888 void VuoPublishedPortSidebar::populatePortTypeMenus()
890 if (this->portTypeMenusPopulated)
893 menuAddPort->clear();
896 QAction *addEventOnlyPortAction = menuAddPort->addAction(tr(
"Event-Only"));
897 string typeName =
"";
898 QList<QVariant> portAndSpecializedType;
899 portAndSpecializedType.append(qVariantFromValue((
void *)NULL));
900 portAndSpecializedType.append(typeName.c_str());
901 addEventOnlyPortAction->setData(QVariant(portAndSpecializedType));
904 QMenu *menuNonListType =
new QMenu(menuAddPort);
905 menuNonListType->setSeparatorsCollapsible(
false);
906 menuNonListType->setTitle(tr(
"Single Value"));
907 menuNonListType->setToolTipsVisible(
true);
908 menuAddPort->addMenu(menuNonListType);
911 QMenu *menuListType =
new QMenu(menuAddPort);
912 menuListType->setSeparatorsCollapsible(
false);
913 menuListType->setTitle(tr(
"List"));
914 menuListType->setToolTipsVisible(
true);
915 menuAddPort->addMenu(menuListType);
922 if (allowedPortTypes.empty())
923 types.insert(singleValueTypes.begin(), singleValueTypes.end());
926 vector<string> sortedAllowedPortTypes(allowedPortTypes.begin(), allowedPortTypes.end());
927 std::sort(sortedAllowedPortTypes.begin(), sortedAllowedPortTypes.end());
928 std::sort(singleValueTypes.begin(), singleValueTypes.end());
930 std::set_intersection(singleValueTypes.begin(), singleValueTypes.end(),
931 sortedAllowedPortTypes.begin(), sortedAllowedPortTypes.end(),
932 std::inserter(types, types.begin()));
942 QList<QAction *> allNodeSetActionsToAdd;
943 for (map<
string, set<VuoCompilerType *> >::iterator i = loadedTypesForNodeSet.begin(); i != loadedTypesForNodeSet.end(); ++i)
945 string nodeSetName = i->first;
946 if (!nodeSetName.empty())
947 allNodeSetActionsToAdd += composition->
getCompatibleTypesForMenu(NULL, types, types,
true, nodeSetName, menuNonListType);
950 if ((menuNonListType->actions().size() > 0) && (allNodeSetActionsToAdd.size() > 0))
951 menuNonListType->addSeparator();
961 if (allowedPortTypes.empty())
962 types.insert(listTypes.begin(), listTypes.end());
965 vector<string> sortedAllowedPortTypes(allowedPortTypes.begin(), allowedPortTypes.end());
966 std::sort(sortedAllowedPortTypes.begin(), sortedAllowedPortTypes.end());
967 std::sort(listTypes.begin(), listTypes.end());
969 std::set_intersection(listTypes.begin(), listTypes.end(),
970 sortedAllowedPortTypes.begin(), sortedAllowedPortTypes.end(),
971 std::inserter(types, types.begin()));
981 QList<QAction *> allNodeSetActionsToAdd;
982 for (map<
string, set<VuoCompilerType *> >::iterator i = loadedTypesForNodeSet.begin(); i != loadedTypesForNodeSet.end(); ++i)
984 string nodeSetName = i->first;
985 if (!nodeSetName.empty())
989 if ((menuListType->actions().size() > 0) && (allNodeSetActionsToAdd.size() > 0))
990 menuListType->addSeparator();
996 connect(addEventOnlyPortAction, &QAction::triggered,
this, &VuoPublishedPortSidebar::newPublishedPortTypeSelected);
997 addEventOnlyPortAction->setCheckable(
false);
999 foreach (QAction *setTypeAction, menuAddPort->actions())
1001 QMenu *setTypeSubmenu = setTypeAction->menu();
1004 foreach (QAction *setTypeSubaction, setTypeSubmenu->actions())
1006 QMenu *setTypeSubmenu = setTypeSubaction->menu();
1009 foreach (QAction *setTypeSubSubaction, setTypeSubmenu->actions())
1011 connect(setTypeSubSubaction, &QAction::triggered,
this, &VuoPublishedPortSidebar::newPublishedPortTypeSelected);
1012 setTypeSubSubaction->setCheckable(
false);
1017 connect(setTypeSubaction, &QAction::triggered,
this, &VuoPublishedPortSidebar::newPublishedPortTypeSelected);
1018 setTypeSubaction->setCheckable(
false);
1024 this->portTypeMenusPopulated =
true;
1034 this->allowedPortTypes = allowedPortTypes;
1040 void VuoPublishedPortSidebar::updateColor(
bool isDark)
1042 QString titleTextColor = isDark ?
"#303030" :
"#808080";
1043 QString titleBackgroundColor = isDark ?
"#919191" :
"#efefef";
1044 QString dockwidgetBackgroundColor = isDark ?
"#404040" :
"#efefef";
1045 QString buttonTextColor = isDark ?
"#a0a0a0" :
"#707070";
1047 setStyleSheet(VUO_QSTRINGIFY(
1049 titlebar-close-icon: url(:/Icons/dockwidget-close-%3.png);
1054 QDockWidget::title {
1057 background-color: %2;
1060 .arg(titleTextColor)
1061 .arg(titleBackgroundColor)
1062 .arg(isDark ?
"dark" :
"light")
1065 ui->VuoPublishedPortSidebarContents->setStyleSheet(VUO_QSTRINGIFY(
1066 QWidget#VuoPublishedPortSidebarContents {
1067 background-color: %1;
1070 .arg(dockwidgetBackgroundColor)
1073 ui->publishedPortList->setStyleSheet(
1074 ui->publishedPortList->styleSheet().append(
1077 background-color: %1;
1080 .arg(dockwidgetBackgroundColor)
1084 ui->newPublishedPortButton->setStyleSheet(VUO_QSTRINGIFY(
1091 QToolButton::menu-indicator {
1094 ).arg(buttonTextColor));