Vuo 2.4.4
Loading...
Searching...
No Matches
VuoCommandConnect.cc
Go to the documentation of this file.
1
10#include "VuoCommandCommon.hh"
11#include "VuoCommandConnect.hh"
12
13#include "VuoCable.hh"
14#include "VuoCompilerCable.hh"
16#include "VuoCompilerNode.hh"
17#include "VuoCompilerType.hh"
19#include "VuoEditorWindow.hh"
21#include "VuoNodeClass.hh"
22#include "VuoPort.hh"
23#include "VuoRendererCable.hh"
24#include "VuoRendererPort.hh"
26#include "VuoStringUtilities.hh"
27#include "VuoGenericType.hh"
28
33 VuoRendererPort *targetPort,
34 VuoRendererCable *displacedCable,
35 VuoRendererPort *portToUnpublish,
36 VuoEditorWindow *window,
37 VuoInputEditorManager *inputEditorManager)
38 : VuoCommandCommon(window)
39{
40 setText(QApplication::translate("VuoEditorWindow", "Cable Connection"));
41 this->window = window;
42
43 // Normally we would take the composition's "Before" snapshot here, but in the case
44 // of a cable connection we need to reconstruct what the composition looked like before
45 // the cable drag began, so we do this a little bit later within the constructor.
46
47 this->cableInProgress = cableInProgress;
48 this->displacedCable = displacedCable;
49 this->fromPortForAddedCable = NULL;
50 this->toPortForAddedCable = NULL;
51 this->addedNode = NULL;
52 this->inputEditorManager = inputEditorManager;
53
54 // @todo: Let cable deletion handle port unpublication.
55 VuoPort *internalPortToUnpublish = (portToUnpublish? portToUnpublish->getBase() : NULL);
56 vector<VuoRendererPublishedPort *> externalPortsToUnpublish = (portToUnpublish? portToUnpublish->getPublishedPortsConnectedByDataCarryingCables() : vector<VuoRendererPublishedPort *>());
57
58 // Start of command content.
59 {
60 VuoEditorComposition *composition = window->getComposition();
61 VuoRendererCable *addedCable = NULL;
62
63 // Completing a connection to an input port
64 if (targetPort->getInput())
65 {
66 // Re-connecting an existing cable to a new input port
67 if (cableInProgress->getFloatingEndpointPreviousToPort() &&
68 cableInProgress->getFloatingEndpointPreviousToPort()->hasRenderer() &&
69 cableInProgress->getFloatingEndpointPreviousToPort()->getRenderer()->scene())
70 {
71 revertedFromPortForCable[cableInProgress] = cableInProgress->getBase()->getFromPort();
72 revertedToPortForCable[cableInProgress] = cableInProgress->getFloatingEndpointPreviousToPort();
73
74 // Mark the previous 'To' port's constant value to be updated to match
75 // the port's last value in the running composition, if applicable.
76 if (cableInProgress->effectivelyCarriesData())
77 {
78 VuoPort *toPort = cableInProgress->getBase()->getToPort();
79 if (!toPort)
80 toPort = cableInProgress->getFloatingEndpointPreviousToPort();
81
82 if (toPort && toPort->hasRenderer())
83 {
84 VuoCompilerInputEventPort *eventPort = static_cast<VuoCompilerInputEventPort *>(toPort->getCompiler());
85 if (eventPort)
86 {
87 if (inputEditorManager->doesTypeAllowOfflineSerialization(eventPort->getDataVuoType()))
88 {
89 revertedConstantForPort[toPort] = eventPort->getData()->getInitialValue();
90
91 json_object *currentRunningValue = composition->getPortValueInRunningComposition(toPort);
92 updatedConstantForPort[toPort] = (currentRunningValue? json_object_to_json_string_ext(currentRunningValue, JSON_C_TO_STRING_PLAIN) :
93 revertedConstantForPort[toPort]);
94 }
95 }
96 }
97 }
98 }
99
100 // Connecting the cable for the first time
101 else
102 {
103 revertedFromPortForCable[cableInProgress] = NULL;
104 revertedToPortForCable[cableInProgress] = NULL;
105 }
106
107 updatedFromPortForCable[cableInProgress] = cableInProgress->getBase()->getFromPort();
108 updatedToPortForCable[cableInProgress] = targetPort->getBase();
109
110 // Displacing some other cable
111 if (displacedCable)
112 {
113 revertedFromPortForCable[displacedCable] = displacedCable->getBase()->getFromPort();
114 revertedToPortForCable[displacedCable] = displacedCable->getBase()->getToPort();
115
116 updatedFromPortForCable[displacedCable] = NULL;
117 updatedToPortForCable[displacedCable] = NULL;
118 }
119 }
120
121 // Completing a ("backwards") connection to an output port
122 else
123 {
124 // Only possibility: Connecting the cable for the first time
125 revertedFromPortForCable[cableInProgress] = NULL;
126 revertedToPortForCable[cableInProgress] = NULL;
127
128 updatedFromPortForCable[cableInProgress] = targetPort->getBase();
129 updatedToPortForCable[cableInProgress] = cableInProgress->getBase()->getToPort();
130 }
131
132 // Reconstruct the state of the composition before the beginning of the cable drag
133 // that concluded with this connection, for the composition's "Before" snapshot.
134 {
135 VuoPort *currentFromPortForCableInProgress = cableInProgress->getBase()->getFromPort();
136 VuoPort *currentToPortForCableInProgress = cableInProgress->getBase()->getToPort();
137 bool currentAlwaysEventOnlyStatusForCableInProgress = cableInProgress->getBase()->getCompiler()->getAlwaysEventOnly();
138
139 bool mustReconstructRevertedSnapshot = ((currentFromPortForCableInProgress != revertedFromPortForCable[cableInProgress]) ||
140 (currentToPortForCableInProgress != revertedToPortForCable[cableInProgress]));
141
142 if (mustReconstructRevertedSnapshot)
143 {
144 VuoCommandCommon::updateCable(cableInProgress, revertedFromPortForCable[cableInProgress], revertedToPortForCable[cableInProgress], composition, true);
145 cableInProgress->getBase()->getCompiler()->setAlwaysEventOnly(cableInProgress->getPreviouslyAlwaysEventOnly());
146 }
147
148 this->revertedSnapshot = window->getComposition()->takeSnapshot();
149
150 if (mustReconstructRevertedSnapshot)
151 {
152 cableInProgress->getBase()->getCompiler()->setAlwaysEventOnly(currentAlwaysEventOnlyStatusForCableInProgress);
153 VuoCommandCommon::updateCable(cableInProgress, currentFromPortForCableInProgress, currentToPortForCableInProgress, composition, true);
154 }
155 }
156
157 // Connect a "Make List" node if the connection leaves a list input port without an incoming data cable.
158 if (targetPort->getInput())
159 {
160 VuoPort *previousInputPort = cableInProgress->getFloatingEndpointPreviousToPort();
161 if (previousInputPort && previousInputPort->hasRenderer() && previousInputPort->getRenderer()->scene() &&
162 (previousInputPort != targetPort->getBase()))
163 {
164 VuoCompilerInputEventPort *inputEventPort = dynamic_cast<VuoCompilerInputEventPort *>(previousInputPort->getCompiler());
165 if (inputEventPort && VuoCompilerType::isListType(inputEventPort->getDataType()) && !inputEventPort->hasConnectedDataCable())
166 {
167 VuoNode *toNode = previousInputPort->getRenderer()->getUnderlyingParentNode()->getBase();
168 VuoRendererCable *cable = NULL;
169 VuoRendererNode *makeListNode = composition->createAndConnectMakeListNode(toNode, previousInputPort, cable);
170
171 addedNode = makeListNode;
172 addedCable = cable;
173 fromPortForAddedCable = addedCable->getBase()->getFromPort();
174 toPortForAddedCable = previousInputPort;
175 }
176 }
177 }
178
179 // If connecting the first data+event cable from the output port of a "Share Value" node to an input port
180 // with a constant value, propagate the constant value back to the "Share Value" node's input port.
181 inventorySharedValueToBackpropagate();
182
183 this->operationInvolvesGenericPort = modifiedComponentsIncludeGenericPorts();
184
185 // Disconnect the displaced cable, if applicable.
186 if (displacedCable)
187 VuoCommandCommon::updateCable(displacedCable, updatedFromPortForCable[displacedCable], updatedToPortForCable[displacedCable], composition);
188
189 // Unpublish the published port, if applicable.
190 if (internalPortToUnpublish)
191 {
192 bool unpublishIsolatedExternalPorts = false;
193 foreach (VuoRendererPublishedPort *externalPortToUnpublish, externalPortsToUnpublish)
194 VuoCommandCommon::unpublishInternalExternalPortCombination(internalPortToUnpublish, dynamic_cast<VuoPublishedPort *>(externalPortToUnpublish->getBase()), composition, unpublishIsolatedExternalPorts);
195 }
196
197 // Connect the new cable
198 VuoCommandCommon::updateCable(cableInProgress, updatedFromPortForCable[cableInProgress], updatedToPortForCable[cableInProgress], composition);
199
200 // Add the "Make List" node and cable, if applicable.
201 if (addedNode)
202 {
203 VuoCommandCommon::addCable(addedCable, fromPortForAddedCable, toPortForAddedCable, composition);
204 composition->addNode(addedNode->getBase());
205 }
206
207 // Collapse any typecasts possible.
208 composition->collapseTypecastNodes();
209
210 // For each deleted data+event cable, set the 'To' port's constant value to the last value
211 // that flowed through the cable before its disconnection, if applicable.
212 for (map<VuoPort *, string>::iterator i = updatedConstantForPort.begin(); i != updatedConstantForPort.end(); ++i)
213 {
214 VuoPort *toPort = i->first;
215
216 if (revertedConstantForPort[toPort] != updatedConstantForPort[toPort])
217 {
218 composition->updatePortConstant(static_cast<VuoCompilerInputEventPort *>(toPort->getCompiler()), updatedConstantForPort[toPort], false);
219 updatedPortIDs.insert(window->getComposition()->getIdentifierForStaticPort(toPort));
220 }
221 }
222 }
223 // End of command content.
224
225 this->updatedSnapshot = window->getComposition()->takeSnapshot();
226
227 setDescription("Connect %s:%s -> %s:%s",
228 cableInProgress->getBase()->getFromNode() && cableInProgress->getBase()->getFromNode()->hasCompiler()?
229 cableInProgress->getBase()->getFromNode()->getCompiler()->getIdentifier().c_str() : "?",
230 cableInProgress->getBase()->getFromPort()?
231 cableInProgress->getBase()->getFromPort()->getClass()->getName().c_str() : "?",
232 cableInProgress->getBase()->getToNode() && cableInProgress->getBase()->getToNode()->hasCompiler()?
233 cableInProgress->getBase()->getToNode()->getCompiler()->getIdentifier().c_str() : "?",
234 cableInProgress->getBase()->getToPort()?
235 cableInProgress->getBase()->getToPort()->getClass()->getName().c_str() : "?");
236}
237
245
250{
252
253 window->resetCompositionWithSnapshot(revertedSnapshot);
254
255 if (operationInvolvesGenericPort)
257
258 window->coalesceSnapshots(updatedSnapshot, revertedSnapshot);
259
260 foreach (string updatedPortID, updatedPortIDs)
261 window->coalesceInternalPortConstantsToSync(updatedPortID);
262}
263
268{
270
271 window->resetCompositionWithSnapshot(updatedSnapshot);
272
273 if (operationInvolvesGenericPort)
275
276 window->coalesceSnapshots(revertedSnapshot, updatedSnapshot);
277
278 foreach (string updatedPortID, updatedPortIDs)
279 window->coalesceInternalPortConstantsToSync(updatedPortID);
280}
281
287bool VuoCommandConnect::modifiedComponentsIncludeGenericPorts()
288{
289 bool revertedFromPortIsGeneric = (revertedFromPortForCable[cableInProgress] && dynamic_cast<VuoGenericType *>(revertedFromPortForCable[cableInProgress]->getRenderer()->getDataType()));
290 bool revertedToPortIsGeneric = (revertedToPortForCable[cableInProgress] && dynamic_cast<VuoGenericType *>(revertedToPortForCable[cableInProgress]->getRenderer()->getDataType()));
291 bool updatedFromPortIsGeneric = (updatedFromPortForCable[cableInProgress] && dynamic_cast<VuoGenericType *>(updatedFromPortForCable[cableInProgress]->getRenderer()->getDataType()));
292 bool updatedToPortIsGeneric = (updatedToPortForCable[cableInProgress] && dynamic_cast<VuoGenericType *>(updatedToPortForCable[cableInProgress]->getRenderer()->getDataType()));
293
294 bool revertedDisplacedFromPortIsGeneric = (revertedFromPortForCable[displacedCable] && dynamic_cast<VuoGenericType *>(revertedFromPortForCable[displacedCable]->getRenderer()->getDataType()));
295 bool revertedDisplacedToPortIsGeneric = (revertedToPortForCable[displacedCable] && dynamic_cast<VuoGenericType *>(revertedToPortForCable[displacedCable]->getRenderer()->getDataType()));
296 bool updatedDisplacedFromPortIsGeneric = (updatedFromPortForCable[displacedCable] && dynamic_cast<VuoGenericType *>(updatedFromPortForCable[displacedCable]->getRenderer()->getDataType()));
297 bool updatedDisplacedToPortIsGeneric = (updatedToPortForCable[displacedCable] && dynamic_cast<VuoGenericType *>(updatedToPortForCable[displacedCable]->getRenderer()->getDataType()));
298
299 bool addedNodeIsGeneric = (addedNode && addedNode->hasGenericPort());
300 bool fromPortForAddedCableIsGeneric = (fromPortForAddedCable && dynamic_cast<VuoGenericType *>(fromPortForAddedCable->getRenderer()->getDataType()));
301 bool toPortForAddedCableIsGeneric = (toPortForAddedCable && dynamic_cast<VuoGenericType *>(toPortForAddedCable->getRenderer()->getDataType()));
302
303 return (revertedFromPortIsGeneric || revertedToPortIsGeneric || updatedFromPortIsGeneric || updatedToPortIsGeneric ||
304 revertedDisplacedFromPortIsGeneric || revertedDisplacedToPortIsGeneric || updatedDisplacedFromPortIsGeneric || updatedDisplacedToPortIsGeneric ||
305 addedNodeIsGeneric || fromPortForAddedCableIsGeneric || toPortForAddedCableIsGeneric);
306}
307
318void VuoCommandConnect::inventorySharedValueToBackpropagate()
319{
320
321 VuoPort *fromPort = updatedFromPortForCable[cableInProgress];
322 VuoPort *toPort = updatedToPortForCable[cableInProgress];
323 bool fromPortIsSharedValue = (fromPort &&
325 "vuo.data.share."));
326 bool toPortHasCopyableConstant = (toPort &&
327 toPort->getRenderer()->getDataType() &&
328 toPort->hasCompiler() &&
329 inputEditorManager->doesTypeAllowOfflineSerialization(static_cast<VuoCompilerInputEventPort *>(toPort->getCompiler())->getDataVuoType()));
330 bool isReconnection = cableInProgress->getFloatingEndpointPreviousToPort();
331
332 bool fromPortHasOtherDataConnections = false;
333 if (fromPort)
334 {
335 vector<VuoCable *> connectedCables = fromPort->getConnectedCables(true);
336 foreach (VuoCable *cable, connectedCables)
337 {
338 if (cable->hasRenderer() &&
339 (cable->getRenderer() != cableInProgress) &&
341 {
342 fromPortHasOtherDataConnections = true;
343 break;
344 }
345 }
346 }
347
348 VuoPort *shareValueInputPort = (fromPort? fromPort->getRenderer()->getUnderlyingParentNode()->getBase()->getInputPortWithName("value") : NULL);
349 bool shareValueInputPortConstantNotYetSet = shareValueInputPort &&
350 shareValueInputPort->getRenderer()->isConstant() &&
351 shareValueInputPort->getRenderer()->getConstantAsString().empty();
352
353 if (fromPortIsSharedValue && toPortHasCopyableConstant && !isReconnection && !fromPortHasOtherDataConnections && cableInProgress->effectivelyCarriesData() && shareValueInputPortConstantNotYetSet)
354 {
355 revertedConstantForPort[shareValueInputPort] = shareValueInputPort->getRenderer()->getConstantAsString();
356 updatedConstantForPort[shareValueInputPort] = toPort->getRenderer()->getConstantAsString();
357 }
358}