1 
2 
3 #include "toonzqt/fxschematicscene.h"
4 
5 // TnzQt includes
6 #include "toonzqt/fxtypes.h"
7 #include "toonzqt/fxschematicnode.h"
8 #include "toonzqt/gutil.h"
9 #include "toonzqt/dvdialog.h"
10 #include "toonzqt/fxselection.h"
11 #include "toonzqt/schematicgroupeditor.h"
12 #include "toonzqt/swatchviewer.h"
13 #include "toonzqt/tselectionhandle.h"
14 
15 // TnzLib includes
16 #include "toonz/txsheet.h"
17 #include "toonz/toonzscene.h"
18 #include "toonz/tcolumnfxset.h"
19 #include "toonz/fxdag.h"
20 #include "toonz/txshlevelcolumn.h"
21 #include "toonz/tcolumnfx.h"
22 #include "toonz/txshpalettecolumn.h"
23 #include "toonz/txshzeraryfxcolumn.h"
24 #include "toonz/fxcommand.h"
25 #include "toonz/txsheethandle.h"
26 #include "toonz/tfxhandle.h"
27 #include "toonz/tscenehandle.h"
28 #include "toonz/tcolumnhandle.h"
29 #include "toonz/tframehandle.h"
30 #include "toonz/tobjecthandle.h"
31 #include "toonz/childstack.h"
32 
33 // TnzBase includes
34 #include "tmacrofx.h"
35 #include "fxdata.h"
36 #include "tpassivecachemanager.h"
37 #include "tfxattributes.h"
38 
39 // TnzCore includes
40 #include "tconst.h"
41 #include "tenv.h"
42 
43 // Qt includes
44 #include <QMenu>
45 #include <QApplication>
46 #include <QGraphicsSceneContextMenuEvent>
47 
48 TEnv::IntVar IconifyFxSchematicNodes("IconifyFxSchematicNodes", 0);
49 
50 namespace {
51 
52 class MatchesFx {
53   TFxP m_fx;
54 
55 public:
MatchesFx(const TFxP & fx)56   MatchesFx(const TFxP &fx) : m_fx(fx) {}
57 
operator ()(const TFxP & fx)58   bool operator()(const TFxP &fx) {
59     TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx.getPointer());
60     return (m_fx.getPointer() == fx.getPointer()) ||
61            (zfx && m_fx.getPointer() == zfx->getZeraryFx());
62   }
63 };
64 
65 //-----------------------------------------------------------
66 
keepSubgroup(QMap<int,QList<SchematicNode * >> & editedGroup)67 void keepSubgroup(QMap<int, QList<SchematicNode *>> &editedGroup) {
68   QMap<int, QList<SchematicNode *>>::iterator it;
69   for (it = editedGroup.begin(); it != editedGroup.end(); it++) {
70     QList<SchematicNode *> groupedNodes = it.value();
71     int i;
72     for (i = 0; i < groupedNodes.size(); i++) {
73       FxSchematicNode *node = dynamic_cast<FxSchematicNode *>(groupedNodes[i]);
74       if (!node) continue;
75       TFx *fx = node->getFx();
76       assert(fx);
77       QMap<int, QList<SchematicNode *>>::iterator it2;
78       for (it2 = editedGroup.begin(); it2 != editedGroup.end(); it2++) {
79         if (fx->getAttributes()->isContainedInGroup(it2.key()) &&
80             !editedGroup[it2.key()].contains(node))
81           editedGroup[it2.key()].append(node);
82       }
83     }
84   }
85 }
86 
87 //-----------------------------------------------------------
88 
89 //! Find the input and the output fx contained in \b visitedFxs.
90 //! \b visitedFxs must be a connected fx selection. In \b outputFx is put the
91 //! root of the connected fx selection.
92 //! In \b inputFx is put a leaf of the connected fx selection.
findBoundariesFxs(TFx * & inputFx,TFx * & outputFx,QMap<TFx *,bool> & visitedFxs,TFx * currentFx=0)93 void findBoundariesFxs(TFx *&inputFx, TFx *&outputFx,
94                        QMap<TFx *, bool> &visitedFxs, TFx *currentFx = 0) {
95   if (visitedFxs.isEmpty()) return;
96   if (!currentFx) currentFx = visitedFxs.begin().key();
97   int inputPortCount        = currentFx->getInputPortCount();
98   int outputConnectionCount = currentFx->getOutputConnectionCount();
99 
100   if (inputPortCount > 0 && !visitedFxs[currentFx]) {
101     visitedFxs[currentFx] = true;
102     TFxPort *fxPort       = currentFx->getInputPort(0);
103     TFx *fx               = fxPort->getFx();
104     if (fx && visitedFxs.count(fx) == 1) {
105       if (!visitedFxs[fx]) findBoundariesFxs(inputFx, outputFx, visitedFxs, fx);
106     } else
107       inputFx = currentFx;
108   } else
109     inputFx = currentFx;
110   if (!outputFx) {
111     if (outputConnectionCount > 0) {
112       TFx *fx = currentFx->getOutputConnection(0)->getOwnerFx();
113       if (fx && visitedFxs.count(fx) == 1) {
114         if (!visitedFxs[fx])
115           findBoundariesFxs(inputFx, outputFx, visitedFxs, fx);
116       } else
117         outputFx = currentFx;
118     } else
119       outputFx = currentFx;
120   }
121 }
122 
123 //-----------------------------------------------------------
124 
canDisconnectSelection(FxSelection * selection)125 bool canDisconnectSelection(FxSelection *selection) {
126   QList<TFxP> selectedFx = selection->getFxs();
127   int i;
128   for (i = 0; i < selectedFx.size(); i++)  // .....
129   {
130     TFx *fx = selectedFx[i].getPointer();
131 
132     TLevelColumnFx *lcFx  = dynamic_cast<TLevelColumnFx *>(fx);
133     TPaletteColumnFx *pfx = dynamic_cast<TPaletteColumnFx *>(fx);
134     TXsheetFx *xfx        = dynamic_cast<TXsheetFx *>(fx);
135     TOutputFx *ofx        = dynamic_cast<TOutputFx *>(fx);
136     TZeraryColumnFx *zfx  = dynamic_cast<TZeraryColumnFx *>(fx);
137 
138     return (!lcFx && !pfx && !xfx && !ofx &&
139             (!zfx || zfx->getInputPortCount() > 0));  // !!!!!
140   }
141   return false;
142 }
143 
144 //------------------------------------------------------------------
145 
getRoots(const QList<TFxP> & fxs,TFxSet * terminals)146 QList<TFxP> getRoots(const QList<TFxP> &fxs, TFxSet *terminals) {
147   QList<TFxP> roots;
148   int i;
149   for (i = 0; i < fxs.size(); i++) {
150     TFx *fx = fxs[i].getPointer();
151     int j;
152     bool isRoot = true;
153     for (j = 0; j < fx->getOutputConnectionCount(); j++) {
154       TFx *outFx = fx->getOutputConnection(j)->getOwnerFx();
155       if (outFx &&
156           std::find_if(fxs.begin(), fxs.end(), MatchesFx(outFx)) != fxs.end() &&
157           !terminals->containsFx(fx))
158         isRoot = false;
159     }
160     if (isRoot) roots.append(fx);
161   }
162   return roots;
163 }
164 
165 bool resizingNodes = false;
166 bool updatingScene = false;
167 }  // namespace
168 
169 //==================================================================
170 //
171 // FxSchematicScene::SupportLinks
172 //
173 //==================================================================
174 
addBridgeLink(SchematicLink * link)175 void FxSchematicScene::SupportLinks::addBridgeLink(SchematicLink *link) {
176   if (link && !m_bridges.contains(link)) m_bridges.push_back(link);
177 }
178 
179 //------------------------------------------------------------------
180 
addOutputLink(SchematicLink * link)181 void FxSchematicScene::SupportLinks::addOutputLink(SchematicLink *link) {
182   if (link && !m_outputs.contains(link)) m_outputs.push_back(link);
183 }
184 
185 //------------------------------------------------------------------
186 
addInputLink(SchematicLink * link)187 void FxSchematicScene::SupportLinks::addInputLink(SchematicLink *link) {
188   if (link && !m_inputs.contains(link)) m_inputs.push_back(link);
189 }
190 
191 //------------------------------------------------------------------
192 
hideBridgeLinks()193 void FxSchematicScene::SupportLinks::hideBridgeLinks() {
194   int i;
195   for (i = 0; i < m_bridges.size(); i++) m_bridges[i]->hide();
196 }
197 
198 //------------------------------------------------------------------
199 
hideInputLinks()200 void FxSchematicScene::SupportLinks::hideInputLinks() {
201   int i;
202   for (i = 0; i < m_inputs.size(); i++) m_inputs[i]->hide();
203 }
204 
205 //------------------------------------------------------------------
206 
hideOutputLinks()207 void FxSchematicScene::SupportLinks::hideOutputLinks() {
208   int i;
209   for (i = 0; i < m_outputs.size(); i++) m_outputs[i]->hide();
210 }
211 
212 //------------------------------------------------------------------
213 
showBridgeLinks()214 void FxSchematicScene::SupportLinks::showBridgeLinks() {
215   int i;
216   for (i = 0; i < m_bridges.size(); i++) m_bridges[i]->show();
217 }
218 
219 //------------------------------------------------------------------
220 
showInputLinks()221 void FxSchematicScene::SupportLinks::showInputLinks() {
222   int i;
223   for (i = 0; i < m_inputs.size(); i++) m_inputs[i]->show();
224 }
225 
226 //------------------------------------------------------------------
227 
showOutputLinks()228 void FxSchematicScene::SupportLinks::showOutputLinks() {
229   int i;
230   for (i = 0; i < m_outputs.size(); i++) m_outputs[i]->show();
231 }
232 
233 //------------------------------------------------------------------
234 
removeBridgeLinks(bool deleteLink)235 void FxSchematicScene::SupportLinks::removeBridgeLinks(bool deleteLink) {
236   int i;
237   for (i = 0; i < m_bridges.size(); i++) {
238     SchematicLink *link = m_bridges[i];
239     m_bridges.removeAt(i);
240     if (deleteLink) {
241       link->getStartPort()->removeLink(link);
242       link->getEndPort()->removeLink(link);
243       delete link;
244     }
245   }
246 }
247 
248 //------------------------------------------------------------------
249 
removeInputLinks(bool deleteLink)250 void FxSchematicScene::SupportLinks::removeInputLinks(bool deleteLink) {
251   int i;
252   for (i = 0; i < m_inputs.size(); i++) {
253     SchematicLink *link = m_inputs[i];
254     m_inputs.removeAt(i);
255     if (deleteLink) {
256       link->getStartPort()->removeLink(link);
257       link->getEndPort()->removeLink(link);
258       delete link;
259     }
260   }
261 }
262 
263 //------------------------------------------------------------------
264 
removeOutputLinks(bool deleteLink)265 void FxSchematicScene::SupportLinks::removeOutputLinks(bool deleteLink) {
266   int i;
267   for (i = 0; i < m_outputs.size(); i++) {
268     SchematicLink *link = m_outputs[i];
269     m_outputs.removeAt(i);
270     if (deleteLink) {
271       link->getStartPort()->removeLink(link);
272       link->getEndPort()->removeLink(link);
273       delete link;
274     }
275   }
276 }
277 
278 //------------------------------------------------------------------
279 
clearAll()280 void FxSchematicScene::SupportLinks::clearAll() {
281   m_bridges.clear();
282   m_inputs.clear();
283   m_outputs.clear();
284 }
285 
286 //------------------------------------------------------------------
287 
size()288 int FxSchematicScene::SupportLinks::size() {
289   return m_bridges.size() + m_inputs.size() + m_outputs.size();
290 }
291 
292 //==================================================================
293 //
294 // FxSchematicScene
295 //
296 //==================================================================
297 
FxSchematicScene(QWidget * parent)298 FxSchematicScene::FxSchematicScene(QWidget *parent)
299     : SchematicScene(parent)
300     , m_firstPoint(sceneRect().center())
301     , m_xshHandle(0)
302     , m_fxHandle(0)
303     , m_addFxContextMenu()
304     , m_disconnectionLinks()
305     , m_connectionLinks()
306     , m_isConnected(false)
307     , m_linkUnlinkSimulation(false)
308     , m_altPressed(false)
309     , m_lastPos(0, 0)
310     , m_currentFxNode(0)
311     , m_gridDimension(eSmall)
312     , m_isNormalIconView(!IconifyFxSchematicNodes)
313     , m_viewer() {
314   m_viewer = (SchematicViewer *)parent;
315 
316   m_selection = new FxSelection();
317   m_selection->setFxSchematicScene(this);
318 
319   connect(m_selection, SIGNAL(doCollapse(const QList<TFxP> &)), this,
320           SLOT(onCollapse(const QList<TFxP> &)));
321   connect(m_selection, SIGNAL(doExplodeChild(const QList<TFxP> &)), this,
322           SIGNAL(doExplodeChild(const QList<TFxP> &)));
323   connect(this, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
324 
325   m_addFxContextMenu.setSelection(m_selection);
326   m_highlightedLinks.clear();
327 }
328 
329 //------------------------------------------------------------------
330 
~FxSchematicScene()331 FxSchematicScene::~FxSchematicScene() {
332   if (m_selection) delete m_selection;
333 }
334 
335 //------------------------------------------------------------------
336 
setApplication(TApplication * app)337 void FxSchematicScene::setApplication(TApplication *app) {
338   m_app = app;
339 
340   m_xshHandle    = app->getCurrentXsheet();
341   m_fxHandle     = app->getCurrentFx();
342   m_frameHandle  = app->getCurrentFrame();
343   m_columnHandle = app->getCurrentColumn();
344 
345   if (m_fxHandle)
346     connect(m_fxHandle, SIGNAL(fxSwitched()), this,
347             SLOT(onCurrentFxSwitched()));
348 
349   m_addFxContextMenu.setApplication(app);
350 
351   m_selection->setXsheetHandle(m_xshHandle);
352   m_selection->setFxHandle(m_fxHandle);
353 }
354 
355 //------------------------------------------------------------------
356 
updateScene()357 void FxSchematicScene::updateScene() {
358   if (updatingScene) return;
359   updatingScene = true;
360   if (!views().empty()) m_disconnectionLinks.clearAll();
361   m_connectionLinks.clearAll();
362   m_selectionOldPos.clear();
363 
364   clearSelection();
365   clearAllItems();
366 
367   m_table.clear();
368   m_groupedTable.clear();
369   m_groupEditorTable.clear();
370   m_macroEditorTable.clear();
371 
372   m_currentFxNode = 0;
373 
374   // GroupId->Fx
375   QMap<int, QList<TFxP>> groupedFxs;
376   QMap<int, QList<SchematicNode *>> editedGroup;
377   QMap<TMacroFx *, QList<SchematicNode *>> editedMacro;
378 
379   TXsheet *xsh    = m_xshHandle->getXsheet();
380   m_gridDimension = xsh->getFxDag()->getDagGridDimension();
381   TFxSet *fxSet   = xsh->getFxDag()->getInternalFxs();
382   int i;
383 
384   FxDag *fxDag = xsh->getFxDag();
385   // Add XSheetFX node
386   addFxSchematicNode(fxDag->getXsheetFx());
387 
388   // Add outputFx nodes
389   int k;
390   for (k = 0; k < fxDag->getOutputFxCount(); k++) {
391     TOutputFx *fx = fxDag->getOutputFx(k);
392     if (fx->getAttributes()->isGrouped() &&
393         !fx->getAttributes()->isGroupEditing()) {
394       groupedFxs[fx->getAttributes()->getGroupId()].push_back(fx);
395       continue;
396     }
397     SchematicNode *node = addFxSchematicNode(fx);
398     if (fx->getAttributes()->isGrouped())
399       editedGroup[fx->getAttributes()->getEditingGroupId()].append(node);
400   }
401 
402   // Add columnFx and zeraryFx nodes
403   for (i = 0; i < xsh->getColumnCount(); i++) {
404     TXshColumn *column = xsh->getColumn(i);
405     TFx *fx            = 0;
406     if (TXshLevelColumn *lc = column->getLevelColumn())
407       fx = lc->getLevelColumnFx();
408     else if (TXshPaletteColumn *pc = dynamic_cast<TXshPaletteColumn *>(column))
409       fx = pc->getPaletteColumnFx();
410     else if (TXshZeraryFxColumn *zc =
411                  dynamic_cast<TXshZeraryFxColumn *>(column))
412       fx = zc->getZeraryColumnFx();
413     if (!fx) continue;
414 
415     if (fx->getAttributes()->isGrouped() &&
416         !fx->getAttributes()->isGroupEditing()) {
417       groupedFxs[fx->getAttributes()->getGroupId()].push_back(fx);
418       continue;
419     }
420     if (column->isEmpty() && fx && fx->getOutputConnectionCount() == 0)
421       continue;
422     SchematicNode *node = addFxSchematicNode(fx);
423     if (fx->getAttributes()->isGrouped())
424       editedGroup[fx->getAttributes()->getEditingGroupId()].append(node);
425   }
426 
427   // Add normalFx
428   for (i = 0; i < fxSet->getFxCount(); i++) {
429     TFx *fx         = fxSet->getFx(i);
430     TMacroFx *macro = dynamic_cast<TMacroFx *>(fx);
431     if (fx->getAttributes()->isGrouped() &&
432         !fx->getAttributes()->isGroupEditing()) {
433       groupedFxs[fx->getAttributes()->getGroupId()].push_back(fx);
434       continue;
435     } else if (macro && macro->isEditing()) {
436       std::vector<TFxP> fxs = macro->getFxs();
437       int j;
438       for (j = 0; j < (int)fxs.size(); j++) {
439         SchematicNode *node = addFxSchematicNode(fxs[j].getPointer());
440         editedMacro[macro].append(node);
441         if (fxs[j]->getAttributes()->isGrouped() &&
442             macro->getAttributes()->isGroupEditing())
443           editedGroup[fx->getAttributes()->getEditingGroupId()].append(node);
444       }
445       continue;
446     }
447     SchematicNode *node = addFxSchematicNode(fx);
448     if (fx->getAttributes()->isGrouped())
449       editedGroup[fx->getAttributes()->getEditingGroupId()].append(node);
450     // If adding an unedited macro and nodes are not yet set, let's position the
451     // internal nodes now
452     if (macro) {
453       double minY           = macro->getAttributes()->getDagNodePos().y;
454       double maxX           = macro->getAttributes()->getDagNodePos().x;
455       double y              = minY;
456       double x              = maxX;
457       std::vector<TFxP> fxs = macro->getFxs();
458       for (int j = 0; j < (int)fxs.size(); j++) {
459         TFx *macroFx = fxs[j].getPointer();
460         if (macroFx && !m_placedFxs.contains(macroFx)) {
461           placeNodeAndParents(macroFx, x, maxX, minY);
462           y -= (m_gridDimension == eLarge ? 100 : 50);
463           minY = std::min(y, minY);
464         }
465       }
466     }
467   }
468 
469   // grouped node
470   QMap<int, QList<TFxP>>::const_iterator it;
471   for (it = groupedFxs.begin(); it != groupedFxs.end(); it++) {
472     FxSchematicNode *node = addGroupedFxSchematicNode(it.key(), it.value());
473     TFx *fx               = node->getFx();
474     assert(fx);
475     int editingGroupId = fx->getAttributes()->getEditingGroupId();
476     if (editingGroupId != -1) editedGroup[editingGroupId].append(node);
477   }
478 
479   keepSubgroup(editedGroup);
480   updateEditedGroups(editedGroup);
481   updateEditedMacros(editedMacro);
482   updateLink();
483   m_nodesToPlace.clear();
484   updatingScene = false;
485 }
486 
487 //------------------------------------------------------------------
488 
updateEditedGroups(const QMap<int,QList<SchematicNode * >> & editedGroup)489 void FxSchematicScene::updateEditedGroups(
490     const QMap<int, QList<SchematicNode *>> &editedGroup) {
491   QMap<int, QList<SchematicNode *>>::const_iterator it;
492   for (it = editedGroup.begin(); it != editedGroup.end(); it++) {
493     int zValue                                            = 2;
494     QMap<int, QList<SchematicNode *>>::const_iterator it2 = editedGroup.begin();
495     while (it2 != editedGroup.end()) {
496       FxSchematicNode *placedFxNode =
497           dynamic_cast<FxSchematicNode *>(it2.value()[0]);
498       FxSchematicNode *fxNode = dynamic_cast<FxSchematicNode *>(it.value()[0]);
499       if (!placedFxNode || !fxNode) {
500         it2++;
501         continue;
502       }
503       int placedGroupedId =
504           placedFxNode->getFx()->getAttributes()->getEditingGroupId();
505       if (fxNode->getFx()->getAttributes()->isContainedInGroup(
506               placedGroupedId) &&
507           fxNode->getFx()->getAttributes()->getEditingGroupId() != it2.key())
508         zValue += 2;
509       it2++;
510     }
511     FxSchematicGroupEditor *node =
512         addEditedGroupedFxSchematicNode(it.key(), it.value());
513     node->setZValue(zValue);
514     node->setGroupedNodeZValue(zValue + 1);
515   }
516 }
517 
518 //------------------------------------------------------------------
519 
updateEditedMacros(const QMap<TMacroFx *,QList<SchematicNode * >> & editedMacro)520 void FxSchematicScene::updateEditedMacros(
521     const QMap<TMacroFx *, QList<SchematicNode *>> &editedMacro) {
522   QMap<TMacroFx *, QList<SchematicNode *>>::const_iterator it;
523   for (it = editedMacro.begin(); it != editedMacro.end(); it++) {
524     TMacroFx *macro = it.key();
525     int zValue      = 2;
526     if (macro->getAttributes()->isGrouped()) {
527       FxSchematicGroupEditor *containingGroup =
528           m_groupEditorTable[macro->getAttributes()->getEditingGroupId()];
529       assert(containingGroup);
530       zValue = containingGroup->zValue() + 2;
531     }
532     FxSchematicMacroEditor *node =
533         addEditedMacroFxSchematicNode(it.key(), it.value());
534     node->setZValue(zValue);
535     node->setGroupedNodeZValue(zValue + 1);
536   }
537 }
538 
539 //------------------------------------------------------------------
540 
addFxSchematicNode(TFx * fx)541 FxSchematicNode *FxSchematicScene::addFxSchematicNode(TFx *fx) {
542   FxSchematicNode *node = createFxSchematicNode(fx);
543   if (!node) return 0;
544   connect(node, SIGNAL(sceneChanged()), this, SLOT(onSceneChanged()));
545   connect(node, SIGNAL(xsheetChanged()), this, SLOT(onXsheetChanged()));
546   connect(node, SIGNAL(switchCurrentFx(TFx *)), this,
547           SLOT(onSwitchCurrentFx(TFx *)));
548   connect(node, SIGNAL(currentColumnChanged(int)), this,
549           SLOT(onCurrentColumnChanged(int)));
550 
551   connect(node, SIGNAL(fxNodeDoubleClicked()), this,
552           SLOT(onFxNodeDoubleClicked()));
553 
554   connect(node, SIGNAL(nodeChangedSize()), this, SLOT(onNodeChangedSize()));
555 
556   if (fx->getAttributes()->getDagNodePos() == TConst::nowhere) {
557     node->resize(m_gridDimension == 0);
558     placeNode(node);
559   } else
560     updatePosition(node, fx->getAttributes()->getDagNodePos());
561   m_table[fx] = node;
562   return node;
563 }
564 
565 //------------------------------------------------------------------
566 
addGroupedFxSchematicNode(int groupId,const QList<TFxP> & groupedFxs)567 FxSchematicNode *FxSchematicScene::addGroupedFxSchematicNode(
568     int groupId, const QList<TFxP> &groupedFxs) {
569   TFxSet *terminals = getXsheet()->getFxDag()->getTerminalFxs();
570   QList<TFxP> roots = getRoots(groupedFxs, terminals);
571   if (roots.isEmpty()) return 0;
572   std::wstring name = roots[0]->getAttributes()->getGroupName(false);
573   FxGroupNode *node = new FxGroupNode(this, groupedFxs, roots, groupId, name);
574   if (!node) return 0;
575   connect(node, SIGNAL(sceneChanged()), this, SLOT(onSceneChanged()));
576   connect(node, SIGNAL(xsheetChanged()), this, SLOT(onXsheetChanged()));
577   connect(node, SIGNAL(switchCurrentFx(TFx *)), this,
578           SLOT(onSwitchCurrentFx(TFx *)));
579   connect(node, SIGNAL(currentColumnChanged(int)), this,
580           SLOT(onCurrentColumnChanged(int)));
581   connect(node, SIGNAL(fxNodeDoubleClicked()), this,
582           SLOT(onFxNodeDoubleClicked()));
583   m_groupedTable[groupId] = node;
584   return node;
585 }
586 
587 //------------------------------------------------------------------
588 
addEditedGroupedFxSchematicNode(int groupId,const QList<SchematicNode * > & groupedFxs)589 FxSchematicGroupEditor *FxSchematicScene::addEditedGroupedFxSchematicNode(
590     int groupId, const QList<SchematicNode *> &groupedFxs) {
591   FxSchematicGroupEditor *editorGroup =
592       new FxSchematicGroupEditor(groupId, groupedFxs, this);
593   m_groupEditorTable[groupId] = editorGroup;
594   return editorGroup;
595 }
596 
597 //------------------------------------------------------------------
598 
addEditedMacroFxSchematicNode(TMacroFx * macro,const QList<SchematicNode * > & groupedFxs)599 FxSchematicMacroEditor *FxSchematicScene::addEditedMacroFxSchematicNode(
600     TMacroFx *macro, const QList<SchematicNode *> &groupedFxs) {
601   FxSchematicMacroEditor *editorMacro =
602       new FxSchematicMacroEditor(macro, groupedFxs, this);
603   m_macroEditorTable[macro] = editorMacro;
604   return editorMacro;
605 }
606 
607 //------------------------------------------------------------------
608 
updatePosition(FxSchematicNode * node,const TPointD & pos)609 void FxSchematicScene::updatePosition(FxSchematicNode *node,
610                                       const TPointD &pos) {
611   node->setPos(QPointF(pos.x, pos.y));
612   node->getFx()->getAttributes()->setDagNodePos(pos);
613   QVector<SchematicNode *> placedNodes = getPlacedNode(node);
614   int step                             = m_gridDimension == eLarge ? 100 : 50;
615   TPointD offset(0, -step);
616   int i;
617   for (i = 0; i < placedNodes.size(); i++) {
618     FxSchematicNode *placedNode =
619         dynamic_cast<FxSchematicNode *>(placedNodes[i]);
620     assert(placedNode);
621     TPointD newPos =
622         placedNode->getFx()->getAttributes()->getDagNodePos() + offset;
623     updatePosition(placedNode, newPos);
624   }
625 }
626 
627 //------------------------------------------------------------------
628 /*! create node depends on the fx type
629  */
createFxSchematicNode(TFx * fx)630 FxSchematicNode *FxSchematicScene::createFxSchematicNode(TFx *fx) {
631   if (TLevelColumnFx *lcFx = dynamic_cast<TLevelColumnFx *>(fx))
632     return new FxSchematicColumnNode(this, lcFx);
633   else if (TPaletteColumnFx *pfx = dynamic_cast<TPaletteColumnFx *>(fx))
634     return new FxSchematicPaletteNode(this, pfx);
635   else if (TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx))
636     return new FxSchematicZeraryNode(this, zfx);
637   else if (TXsheetFx *xfx = dynamic_cast<TXsheetFx *>(fx))
638     return new FxSchematicXSheetNode(this, xfx);
639   else if (TOutputFx *ofx = dynamic_cast<TOutputFx *>(fx))
640     return new FxSchematicOutputNode(this, ofx);
641   else
642     return new FxSchematicNormalFxNode(this, fx);
643 }
644 
645 //------------------------------------------------------------------
646 /*! place nodes of which positions are not specified manually
647  */
placeNode(FxSchematicNode * node)648 void FxSchematicScene::placeNode(FxSchematicNode *node) {
649   if (!node) return;
650   int step        = m_gridDimension == eLarge ? 100 : 50;
651   FxDag *fxDag    = m_xshHandle->getXsheet()->getFxDag();
652   QRectF nodeRect = node->boundingRect();
653   if (node->isA(eOutpuFx)) {
654     // I'm placing an output node
655     TFx *xsheetFx        = fxDag->getXsheetFx();
656     TFxPort *outPort     = xsheetFx->getOutputConnection(0);
657     TFx *connectedOutput = outPort ? outPort->getOwnerFx() : 0;
658     if (connectedOutput && connectedOutput == node->getFx()) {
659       // The output node is connected to the xsheet node
660       TPointD pos = xsheetFx->getAttributes()->getDagNodePos();
661       if (pos != TConst::nowhere)
662         nodeRect.translate(pos.x + 120, pos.y);
663       else
664         nodeRect.translate(sceneRect().center());
665       while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, step);
666     } else {
667       // The output node is not connected to the xsheet node
668       TFx *fx       = node->getFx();
669       TFxPort *port = fx->getInputPort(0);
670       TFx *inputFx  = port->getFx();
671       if (inputFx) {
672         // The output node is connected to another node
673         TPointD pos = inputFx->getAttributes()->getDagNodePos();
674         if (pos != TConst::nowhere)
675           nodeRect.translate(pos.x + 120, pos.y);
676         else {
677           m_nodesToPlace[inputFx].append(node);
678           return;
679         }
680       } else {
681         // The output node is not connected
682         QPointF pos = sceneRect().center();
683         nodeRect.translate(pos);
684       }
685     }
686     while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, step);
687     QPointF newPos = nodeRect.topLeft();
688     node->getFx()->getAttributes()->setDagNodePos(
689         TPointD(newPos.x(), newPos.y()));
690     node->setPos(newPos);
691     return;
692   } else if (node->isA(eXSheetFx)) {
693     // I'm placing the xsheet node
694     TFxSet *terminalFxs = fxDag->getTerminalFxs();
695     int i;
696     double maxX = m_firstPoint.x();
697     for (i = 0; i < terminalFxs->getFxCount(); i++) {
698       TFx *terminalFx = terminalFxs->getFx(i);
699       if (terminalFx->getAttributes()->getDagNodePos() == TConst::nowhere)
700         continue;
701       maxX = std::max(maxX, terminalFx->getAttributes()->getDagNodePos().x);
702     }
703     TPointD oldPos = node->getFx()->getAttributes()->getDagNodePos();
704     QPointF pos;
705     if (oldPos == TConst::nowhere)
706       pos = QPointF(maxX + 120, m_firstPoint.y());
707     else
708       pos = QPointF(maxX + 120 > oldPos.x ? maxX + 120 : oldPos.x, oldPos.y);
709     node->getFx()->getAttributes()->setDagNodePos(TPointD(pos.x(), pos.y()));
710     node->setPos(pos);
711     return;
712   } else if (node->isA(eMacroFx)) {
713     double minX = TConst::nowhere.x, minY = TConst::nowhere.y, maxY;
714     QPointF pos;
715     TMacroFx *macroFx     = dynamic_cast<TMacroFx *>(node->getFx());
716     std::vector<TFxP> fxs = macroFx->getFxs();
717     int k;
718     for (k = 0; k < (int)fxs.size(); k++) {
719       TFx *fx = fxs[k].getPointer();
720       if (fx->getAttributes()->getDagNodePos() == TConst::nowhere) continue;
721       if (QPointF(minX, minY) ==
722           QPointF(TConst::nowhere.x, TConst::nowhere.y)) {
723         minX = fx->getAttributes()->getDagNodePos().x;
724         minY = maxY = fx->getAttributes()->getDagNodePos().y;
725         continue;
726       }
727       minX = std::min(fx->getAttributes()->getDagNodePos().x, minX);
728       minY = std::min(fx->getAttributes()->getDagNodePos().y, minY);
729       maxY = std::max(fx->getAttributes()->getDagNodePos().y, maxY);
730     }
731     if (QPointF(minX, minY) == QPointF(TConst::nowhere.x, TConst::nowhere.y)) {
732       TFx *inputFx = node->getFx()->getInputPort(0)->getFx();
733       if (inputFx &&
734           inputFx->getAttributes()->getDagNodePos() != TConst::nowhere) {
735         TPointD dagPos =
736             inputFx->getAttributes()->getDagNodePos() + TPointD(150, 0);
737         pos = QPointF(dagPos.x, dagPos.y);
738       } else
739         pos = sceneRect().center();
740       nodeRect.moveTopLeft(pos);
741       while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, -step);
742       pos = nodeRect.topLeft();
743     } else {
744       pos.setX(minX);
745       pos.setY((maxY + minY) / 2);
746     }
747     node->getFx()->getAttributes()->setDagNodePos(TPointD(pos.x(), pos.y()));
748     node->setPos(QPointF(pos));
749     if (m_nodesToPlace.contains(node->getFx())) {
750       QList<FxSchematicNode *> nodes = m_nodesToPlace[node->getFx()];
751       int i;
752       for (i = 0; i < nodes.size(); i++) placeNode(nodes[i]);
753     }
754     return;
755   } else if (node->isA(eNormalFx) || node->isA(eNormalLayerBlendingFx) ||
756              node->isA(eNormalMatteFx) || node->isA(eNormalImageAdjustFx)) {
757     // I'm placing an effect or a macro
758     TFx *inputFx = node->getFx()->getInputPort(0)->getFx();
759     QPointF pos;
760     if (inputFx) {
761       if (inputFx->getAttributes()->getDagNodePos() != TConst::nowhere) {
762         TPointD dagPos =
763             inputFx->getAttributes()->getDagNodePos() + TPointD(150, 0);
764         pos = QPointF(dagPos.x, dagPos.y);
765         nodeRect.moveTopLeft(pos);
766         while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, -step);
767         pos = nodeRect.topLeft();
768       } else {
769         m_nodesToPlace[inputFx].append(node);
770         return;
771       }
772     } else {
773       pos = sceneRect().center();
774       nodeRect.moveTopLeft(pos);
775       while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, -step);
776       pos = nodeRect.topLeft();
777     }
778     node->getFx()->getAttributes()->setDagNodePos(TPointD(pos.x(), pos.y()));
779     node->setPos(QPointF(pos));
780     if (m_nodesToPlace.contains(node->getFx())) {
781       QList<FxSchematicNode *> nodes = m_nodesToPlace[node->getFx()];
782       int i;
783       for (i = 0; i < nodes.size(); i++) placeNode(nodes[i]);
784     }
785     return;
786   } else if (node->isA(eZeraryFx) || node->isA(eColumnFx) ||
787              node->isA(eGroupedFx)) {
788     // I'm placing a column
789     nodeRect.translate(m_firstPoint);
790     nodeRect.translate(10, 10);
791     while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, -step);
792     QPointF newPos = nodeRect.topLeft();
793     node->getFx()->getAttributes()->setDagNodePos(
794         TPointD(newPos.x(), newPos.y()));
795     node->setPos(QPointF(newPos));
796     return;
797   }
798 }
799 
800 //------------------------------------------------------------------
801 
updateLink()802 void FxSchematicScene::updateLink() {
803   TXsheet *xsh = m_xshHandle->getXsheet();
804 
805   // Iterate the fxs table
806   QMap<TFx *, FxSchematicNode *>::iterator it;
807   for (it = m_table.begin(); it != m_table.end(); ++it) {
808     FxSchematicNode *node = it.value();
809     if (!node) continue;  // Should be asserted? Is it legal?
810 
811     TFx *fx           = it.key();
812     TFx *inputPortsFx = fx;
813 
814     if (TZeraryColumnFx *fx2 = dynamic_cast<TZeraryColumnFx *>(fx)) {
815       inputPortsFx = fx2->getZeraryFx();
816       if (!inputPortsFx)
817         return;  // Should really never happen. Should be asserted...
818     }
819 
820     for (int i = 0; i != inputPortsFx->getInputPortCount(); ++i) {
821       TFxPort *port = inputPortsFx->getInputPort(i);
822 
823       if (TFx *linkedFx = port->getFx()) {
824         if (!linkedFx->getAttributes()->isGrouped() ||
825             linkedFx->getAttributes()->isGroupEditing()) {
826           // Not in a group / open group case
827           assert(m_table.contains(linkedFx));
828 
829           if (m_table.contains(linkedFx)) {
830             FxSchematicNode *linkedNode = m_table[linkedFx];
831             SchematicPort *p0           = linkedNode->getOutputPort();
832             SchematicPort *p1           = node->getInputPort(i);
833             if (p0 && p1) p0->makeLink(p1);
834           }
835         } else {
836           assert(
837               m_groupedTable.contains(linkedFx->getAttributes()->getGroupId()));
838 
839           if (m_groupedTable.contains(
840                   linkedFx->getAttributes()->getGroupId())) {
841             FxSchematicNode *linkedNode =
842                 m_groupedTable[linkedFx->getAttributes()->getGroupId()];
843             SchematicPort *p0 = linkedNode->getOutputPort();
844             SchematicPort *p1 = node->getInputPort(i);
845             if (p0 && p1) p0->makeLink(p1);
846           }
847         }
848       }
849     }
850     if (xsh->getFxDag()->getTerminalFxs()->containsFx(fx)) {
851       SchematicPort *p0 = node->getOutputPort();
852       SchematicPort *p1 =
853           m_table[xsh->getFxDag()->getXsheetFx()]->getInputPort(0);
854       p0->makeLink(p1);
855     }
856   }
857   QMap<int, FxGroupNode *>::iterator it2;
858   for (it2 = m_groupedTable.begin(); it2 != m_groupedTable.end(); it2++) {
859     FxGroupNode *node = it2.value();
860     if (!node) continue;
861     int i, fxCount = node->getFxCount();
862     bool xsheetConnected = false;
863     for (i = 0; i < fxCount; i++) {
864       TFx *fx = node->getFx(i);
865       if (xsh->getFxDag()->getTerminalFxs()->containsFx(fx) &&
866           !xsheetConnected) {
867         SchematicPort *p0 = node->getOutputPort();
868         SchematicPort *p1 =
869             m_table[xsh->getFxDag()->getXsheetFx()]->getInputPort(0);
870         p0->makeLink(p1);
871         xsheetConnected = true;
872       }
873 
874       TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx);
875       if (zfx) fx = zfx->getZeraryFx();
876       if (fx) {
877         int j;
878         for (j = 0; j < fx->getInputPortCount(); j++) {
879           TFx *linkedFx = fx->getInputPort(j)->getFx();
880           if (!linkedFx) continue;
881           if (!linkedFx->getAttributes()->isGrouped() ||
882               linkedFx->getAttributes()->isGroupEditing()) {
883             assert(m_table.contains(linkedFx));
884             if (m_table.contains(linkedFx)) {
885               FxSchematicNode *linkedNode = m_table[linkedFx];
886               SchematicPort *p0           = linkedNode->getOutputPort();
887               SchematicPort *p1           = node->getInputPort(0);
888               if (p0 && p1) p0->makeLink(p1);
889             }
890           } else {
891             int linkedGroupId = linkedFx->getAttributes()->getGroupId();
892             assert(m_groupedTable.contains(linkedGroupId));
893             if (m_groupedTable.contains(linkedGroupId)) {
894               FxGroupNode *linkedNode = m_groupedTable[linkedGroupId];
895               if (linkedNode == node) continue;
896               SchematicPort *p0 = linkedNode->getOutputPort();
897               SchematicPort *p1 = node->getInputPort(0);
898               if (p0 && p1 && !p0->isLinkedTo(p1)) p0->makeLink(p1);
899             }
900           }
901         }
902       }
903     }
904   }
905 
906   // to solve an edit macro problem: create a dummy link
907   QMap<TMacroFx *, FxSchematicMacroEditor *>::iterator it3;
908   for (it3 = m_macroEditorTable.begin(); it3 != m_macroEditorTable.end();
909        it3++) {
910     TMacroFx *macro = it3.key();
911     int i;
912     FxSchematicNode *root = m_table[macro->getRoot()];
913     SchematicPort *p0     = root->getOutputPort();
914     for (i = 0; i < macro->getOutputConnectionCount(); i++) {
915       TFxPort *outConnection = macro->getOutputConnection(i);
916       TFx *outFx             = outConnection->getOwnerFx();
917       TMacroFx *outMacroFx   = dynamic_cast<TMacroFx *>(outFx);
918       if (outMacroFx && outMacroFx->isEditing()) {
919         std::vector<TFxP> fxs = outMacroFx->getFxs();
920         int k;
921         for (k = 0; k < (int)fxs.size(); k++) {
922           TFx *fx = fxs[k].getPointer();
923           int j;
924           for (j = 0; j < fx->getInputPortCount(); j++)
925             if (outConnection == fx->getInputPort(j)) {
926               outFx = fx;
927               break;
928             }
929           if (outFx != outMacroFx) break;
930         }
931       }
932 
933       int j;
934       for (j = 0; j < outFx->getInputPortCount(); j++)
935         if (outFx->getInputPort(j)->getFx() == macro) {
936           SchematicPort *p1 = m_table[outFx]->getInputPort(j);
937           p0->makeLink(p1);
938           break;
939         }
940     }
941     if (xsh->getFxDag()->getTerminalFxs()->containsFx(macro)) {
942       assert(root);
943       if (!root) continue;
944       SchematicPort *p1 =
945           m_table[xsh->getFxDag()->getXsheetFx()]->getInputPort(0);
946       p0->makeLink(p1);
947     }
948   }
949   updateDuplcatedNodesLink();
950 }
951 
952 //------------------------------------------------------------------
953 
contextMenuEvent(QGraphicsSceneContextMenuEvent * cme)954 void FxSchematicScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *cme) {
955   QPointF scenePos                = cme->scenePos();
956   QList<QGraphicsItem *> itemList = items(scenePos);
957   if (!itemList.isEmpty()) {
958     SchematicScene::contextMenuEvent(cme);
959     return;
960   }
961 
962   QMenu menu(views()[0]);
963 
964   if (cme->modifiers() & Qt::ControlModifier) {
965     menu.addAction(m_addFxContextMenu.getAgainCommand(AddFxContextMenu::Add));
966     if (!menu.actions().isEmpty()) {
967       menu.exec(cme->screenPos());
968       return;
969     }
970   }
971 
972   QAction *addOutputFx =
973       CommandManager::instance()->getAction("MI_NewOutputFx");
974   QAction *copy  = CommandManager::instance()->getAction("MI_Copy");
975   QAction *cut   = CommandManager::instance()->getAction("MI_Cut");
976   QAction *paste = CommandManager::instance()->getAction("MI_Paste");
977 
978   m_addFxContextMenu.setCurrentCursorScenePos(cme->scenePos());
979 
980   menu.addMenu(m_addFxContextMenu.getAddMenu());
981   if (addOutputFx) menu.addAction(addOutputFx);
982 
983   // Close sub xsheet and move to parent sheet
984   ToonzScene *scene      = getXsheet()->getScene();
985   ChildStack *childStack = scene->getChildStack();
986   if (childStack && childStack->getAncestorCount() > 0) {
987     menu.addSeparator();
988     menu.addAction(CommandManager::instance()->getAction("MI_CloseChild"));
989   }
990 
991   menu.addSeparator();
992   menu.addAction(copy);
993   menu.addAction(cut);
994   menu.addAction(paste);
995   m_selection->setPastePosition(TPointD(scenePos.x(), scenePos.y()));
996   menu.exec(cme->screenPos());
997   m_selection->setPastePosition(TConst::nowhere);
998 }
999 
1000 //------------------------------------------------------------------
1001 
nearestPoint(const QPointF & point)1002 QPointF FxSchematicScene::nearestPoint(const QPointF &point) {
1003   QRectF rect(0, 0, 0.1, 0.1);
1004   rect.moveCenter(point);
1005   QList<QGraphicsItem *> itemList = items(rect);
1006   while (itemList.isEmpty()) {
1007     rect.adjust(-0.1, -0.1, 0.1, 0.1);
1008     itemList = items(rect);
1009   }
1010 #if QT_VERSION >= 0x050000
1011   /*
1012   FIXME: QTransform() のデフォルトは Qt4.8 の itemAt() と比べて equivant
1013   だろうか?
1014 */
1015   QGraphicsItem *item = itemAt(rect.bottomLeft(), QTransform());
1016   if (item) return rect.bottomLeft();
1017   item = itemAt(rect.bottomRight(), QTransform());
1018   if (item) return rect.bottomRight();
1019   item = itemAt(rect.topLeft(), QTransform());
1020   if (item) return rect.topLeft();
1021   item = itemAt(rect.topRight(), QTransform());
1022 #else
1023   QGraphicsItem *item = itemAt(rect.bottomLeft());
1024   if (item) return rect.bottomLeft();
1025   item = itemAt(rect.bottomRight());
1026   if (item) return rect.bottomRight();
1027   item = itemAt(rect.topLeft());
1028   if (item) return rect.topLeft();
1029   item                = itemAt(rect.topRight());
1030 #endif
1031   if (item) return rect.topRight();
1032   return QPointF();
1033 }
1034 
1035 //------------------------------------------------------------------
1036 
getFxNodeFromPosition(const QPointF & pos)1037 FxSchematicNode *FxSchematicScene::getFxNodeFromPosition(const QPointF &pos) {
1038   QList<QGraphicsItem *> pickedItems = items(pos);
1039   for (int i = 0; i < pickedItems.size(); i++) {
1040     FxSchematicNode *fxNode =
1041         dynamic_cast<FxSchematicNode *>(pickedItems.at(i));
1042     if (fxNode) return fxNode;
1043     FxSchematicPort *fxPort =
1044         dynamic_cast<FxSchematicPort *>(pickedItems.at(i));
1045     if (fxPort) return fxPort->getDock()->getNode();
1046   }
1047   return 0;
1048 }
1049 
1050 //------------------------------------------------------------------
1051 
updateDuplcatedNodesLink()1052 void FxSchematicScene::updateDuplcatedNodesLink() {
1053   QMap<TFx *, FxSchematicNode *>::iterator it;
1054 
1055   // fx2node contains only duplicated nodes
1056   // and zerary duplicated node s
1057   QMap<TFx *, FxSchematicNode *> fx2node;
1058   for (it = m_table.begin(); it != m_table.end(); ++it) {
1059     TFx *fx               = it.key();
1060     FxSchematicNode *node = it.value();
1061     if (TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx)) {
1062       fx = zcfx->getZeraryFx();
1063       if (!fx) return;
1064     }
1065     assert(fx2node.count(fx) == 0);
1066     if (fx->getLinkedFx() == fx) continue;
1067     fx2node[fx] = node;
1068   }
1069 
1070   // trovo i link
1071   std::set<TFx *> visited;
1072   for (it = fx2node.begin(); it != fx2node.end(); ++it) {
1073     TFx *fx               = it.key();
1074     FxSchematicNode *node = it.value();
1075     assert(fx->getLinkedFx() != fx);
1076     if (visited.count(fx) > 0) continue;
1077     visited.insert(fx);
1078     FxSchematicNode *lastNode = node;
1079     assert(lastNode);
1080     FxSchematicPort *lastPort = lastNode->getLinkPort();
1081     assert(lastPort);
1082     for (fx = fx->getLinkedFx(); fx != it.key(); fx = fx->getLinkedFx()) {
1083       assert(visited.count(fx) == 0);
1084       if (visited.count(fx) > 0) break;
1085       visited.insert(fx);
1086       QMap<TFx *, FxSchematicNode *>::iterator h;
1087       h = fx2node.find(fx);
1088       if (h == fx2node.end()) continue;
1089 
1090       assert(h != fx2node.end());
1091       FxSchematicNode *node = h.value();
1092       assert(node);
1093       FxSchematicPort *port = node->getLinkPort();
1094       assert(port);
1095       if (port && lastPort) port->makeLink(lastPort);
1096       lastNode = node;
1097       lastPort = port;
1098     }
1099   }
1100 }
1101 
1102 //------------------------------------------------------------------
1103 
getCurrentNode()1104 QGraphicsItem *FxSchematicScene::getCurrentNode() {
1105   QList<QGraphicsItem *> allItems = items();
1106 
1107   for (auto const item : allItems) {
1108     FxSchematicNode *node = dynamic_cast<FxSchematicNode *>(item);
1109     if (node && node->getFx() == m_fxHandle->getFx()) return node;
1110   }
1111   return 0;
1112 }
1113 
1114 //------------------------------------------------------------------
1115 
onSelectionSwitched(TSelection * oldSel,TSelection * newSel)1116 void FxSchematicScene::onSelectionSwitched(TSelection *oldSel,
1117                                            TSelection *newSel) {
1118   if (m_selection == oldSel && m_selection != newSel) clearSelection();
1119 }
1120 
1121 //------------------------------------------------------------------
1122 
onSelectionChanged()1123 void FxSchematicScene::onSelectionChanged() {
1124   m_selection->selectNone();
1125   int i, size = m_highlightedLinks.size();
1126   for (i = 0; i < size; i++) {
1127     SchematicLink *link = m_highlightedLinks[i];
1128     link->setHighlighted(false);
1129     link->update();
1130   }
1131   m_highlightedLinks.clear();
1132   QList<QGraphicsItem *> slcItems = selectedItems();
1133   QList<QGraphicsItem *>::iterator it;
1134   for (it = slcItems.begin(); it != slcItems.end(); it++) {
1135     FxSchematicNode *node = dynamic_cast<FxSchematicNode *>(*it);
1136     if (node) {
1137       if (!node->isA(eGroupedFx)) {
1138         if (node->isA(eXSheetFx)) continue;
1139         m_selection->select(node->getFx());
1140         if (node->isA(eColumnFx)) {
1141           FxSchematicColumnNode *columnNode =
1142               dynamic_cast<FxSchematicColumnNode *>(node);
1143           if (columnNode)
1144             m_selection->select(columnNode->getColumnIndex());
1145           else {
1146             FxSchematicPaletteNode *paletteNode =
1147                 dynamic_cast<FxSchematicPaletteNode *>(node);
1148             if (paletteNode) m_selection->select(paletteNode->getColumnIndex());
1149           }
1150         }
1151       } else {
1152         FxGroupNode *groupNode = dynamic_cast<FxGroupNode *>(node);
1153         assert(groupNode);
1154         QList<TFxP> fxs = groupNode->getGroupedFxs();
1155         for (i = 0; i < fxs.size(); i++) {
1156           m_selection->select(fxs[i].getPointer());
1157           TLevelColumnFx *colFx =
1158               dynamic_cast<TLevelColumnFx *>(fxs[i].getPointer());
1159           if (colFx) {
1160             if (TXshLevelColumn *column = colFx->getColumn()) {
1161               int colIndex = column->getIndex();
1162               m_selection->select(colIndex);
1163             }
1164           }
1165         }
1166       }
1167       highlightLinks(node, true);
1168     }
1169     SchematicLink *link = dynamic_cast<SchematicLink *>(*it);
1170     if (link) m_selection->select(link);
1171   }
1172   m_selection->makeCurrent();
1173   TSelectionHandle *selHandle = TSelectionHandle::getCurrent();
1174   selHandle->notifySelectionChanged();
1175 }
1176 
1177 //------------------------------------------------------------------
1178 
reorderScene()1179 void FxSchematicScene::reorderScene() {
1180   int step = m_gridDimension == eLarge ? 100 : 50;
1181   m_placedFxs.clear();
1182   QPointF sceneCenter = sceneRect().center();
1183   double minY         = sceneCenter.y();
1184   double maxX         = sceneCenter.x();
1185   double y            = minY;
1186   double x            = maxX;
1187 
1188   TXsheet *xsh = m_xshHandle->getXsheet();
1189   int i        = 0;
1190 
1191   FxDag *fxDag  = xsh->getFxDag();
1192   TFxSet *fxSet = fxDag->getInternalFxs();
1193 
1194   //  Let's reset every position to nowhere first
1195   fxDag->getXsheetFx()->getAttributes()->setDagNodePos(TConst::nowhere);
1196 
1197   for (i = 0; i < fxDag->getOutputFxCount(); i++) {
1198     TOutputFx *fx = fxDag->getOutputFx(i);
1199     if (!fx) continue;
1200     fx->getAttributes()->setDagNodePos(TConst::nowhere);
1201   }
1202 
1203   for (i = 0; i < xsh->getColumnCount(); i++) {
1204     TXshColumn *column = xsh->getColumn(i);
1205     TFx *fx            = column->getFx();
1206     if (!fx) continue;
1207     fx->getAttributes()->setDagNodePos(TConst::nowhere);
1208   }
1209 
1210   for (i = 0; i < fxSet->getFxCount(); i++) {
1211     TFx *fx = fxSet->getFx(i);
1212     fx->getAttributes()->setDagNodePos(TConst::nowhere);
1213     TMacroFx *macro = dynamic_cast<TMacroFx *>(fx);
1214     if (macro && macro->isEditing()) {
1215       std::vector<TFxP> fxs = macro->getFxs();
1216       int j;
1217       for (j = 0; j < (int)fxs.size(); j++) {
1218         fxs[j]->getAttributes()->setDagNodePos(TConst::nowhere);
1219       }
1220     }
1221   }
1222 
1223   // Let's start placing them now
1224   for (i = 0; i < xsh->getColumnCount(); i++) {
1225     TXshColumn *column = xsh->getColumn(i);
1226     TFx *fx            = column->getFx();
1227 
1228     if (column->isEmpty() || !fx) continue;
1229 
1230     TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx);
1231     if (zfx && (zfx->getZeraryFx()->getInputPortCount() > 0)) {
1232       TFxPort *port = zfx->getZeraryFx()->getInputPort(0);
1233       if (port && port->getFx()) continue;
1234     }
1235 
1236     if (zfx && m_placedFxs.contains(zfx->getZeraryFx())) continue;
1237 
1238     x = sceneCenter.x();
1239     placeNodeAndParents(fx, x, maxX, minY);
1240     y -= step;
1241     minY = std::min(y, minY);
1242   }
1243 
1244   // remove retrolink
1245   for (i = 0; i < xsh->getColumnCount(); i++) {
1246     TXshColumn *column = xsh->getColumn(i);
1247     TFx *fx            = column->getFx();
1248     if (column->isEmpty() || !fx) continue;
1249 
1250     TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx);
1251     if (zfx && m_placedFxs.contains(zfx->getZeraryFx())) continue;
1252 
1253     if (zfx && (zfx->getZeraryFx()->getInputPortCount() > 0)) {
1254       TFxPort *port = zfx->getZeraryFx()->getInputPort(0);
1255       if (port && port->getFx()) continue;
1256     }
1257 
1258     for (int j = 0; j < fx->getOutputConnectionCount(); j++) {
1259       TFx *outFx = fx->getOutputConnection(j)->getOwnerFx();
1260       removeRetroLinks(outFx, maxX);
1261     }
1262   }
1263 
1264   double middleY = (sceneCenter.y() + minY + step) * 0.5;
1265   placeNodeAndParents(xsh->getFxDag()->getXsheetFx(), maxX, maxX, middleY);
1266   y -= step;
1267   minY = std::min(y, minY);
1268 
1269   for (i = 0; i < fxSet->getFxCount(); i++) {
1270     TFx *fx = fxSet->getFx(i);
1271     if (m_placedFxs.contains(fx)) continue;
1272 
1273     placeNodeAndParents(fx, (sceneCenter.x() + 120), maxX, minY);
1274     y -= step;
1275     minY = std::min(y, minY);
1276   }
1277   updateScene();
1278 }
1279 
1280 //------------------------------------------------------------------
1281 
removeRetroLinks(TFx * fx,double & maxX)1282 void FxSchematicScene::removeRetroLinks(TFx *fx, double &maxX) {
1283   if (!fx) return;
1284   for (int i = 0; i < fx->getInputPortCount(); i++) {
1285     TFx *inFx = fx->getInputPort(i)->getFx();
1286     if (!inFx) continue;
1287     TPointD inFxPos = inFx->getAttributes()->getDagNodePos();
1288     TPointD fxPos   = fx->getAttributes()->getDagNodePos();
1289     if (inFxPos != TConst::nowhere && fxPos != TConst::nowhere &&
1290         fxPos.x <= inFxPos.x) {
1291       while (fxPos.x <= inFxPos.x) fxPos.x += 150;
1292       maxX = std::max(fxPos.x + 150, maxX);
1293       fx->getAttributes()->setDagNodePos(fxPos);
1294       for (int j = 0; j < fx->getOutputConnectionCount(); j++) {
1295         TFx *outFx = fx->getOutputConnection(j)->getOwnerFx();
1296         removeRetroLinks(outFx, maxX);
1297       }
1298     }
1299   }
1300 }
1301 
1302 //------------------------------------------------------------------
1303 
placeNodeAndParents(TFx * fx,double x,double & maxX,double & minY)1304 void FxSchematicScene::placeNodeAndParents(TFx *fx, double x, double &maxX,
1305                                            double &minY) {
1306   int step = m_gridDimension == eLarge ? 100 : 50;
1307   if (!fx) return;
1308   m_placedFxs.append(fx);
1309   if (fx->getFxType() == "STD_particlesFx" ||
1310       fx->getFxType() == "STD_Iwa_ParticlesFx") {
1311     TXsheet *xsh = m_xshHandle->getXsheet();
1312     int i        = 0;
1313     for (i = 0; i < xsh->getColumnCount(); i++) {
1314       TFx *columnFx        = xsh->getColumn(i)->getFx();
1315       TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(columnFx);
1316       if (zfx && zfx->getZeraryFx() == fx) {
1317         fx = zfx;
1318         break;
1319       }
1320     }
1321   }
1322   double y        = minY;
1323   TMacroFx *macro = dynamic_cast<TMacroFx *>(fx);
1324   if (macro) {
1325     int tmpY              = y;
1326     std::vector<TFxP> fxs = macro->getFxs();
1327     for (int j = 0; j < (int)fxs.size(); j++) {
1328       TFx *macroFx = fxs[j].getPointer();
1329       if (macroFx && !m_placedFxs.contains(macroFx)) {
1330         placeNodeAndParents(macroFx, x, maxX, minY);
1331         y -= step;
1332         minY = std::min(y, minY);
1333       }
1334     }
1335     tmpY = (minY + tmpY + step) * 0.5;
1336     fx->getAttributes()->setDagNodePos(TPointD(x, tmpY));
1337   } else
1338     fx->getAttributes()->setDagNodePos(TPointD(x, y));
1339   if (fx->getOutputConnectionCount() == 0) minY -= step;
1340   x += 120;
1341   maxX = std::max(maxX, x);
1342   int i;
1343   for (i = 0; i < fx->getOutputConnectionCount(); i++) {
1344     TFx *outputFx = fx->getOutputConnection(i)->getOwnerFx();
1345     // controllo se e' una porta sorgente
1346     TFxPort *port = outputFx->getInputPort(0);
1347     if (port && port->getFx() != fx) continue;
1348     if (!m_placedFxs.contains(outputFx) ||
1349         outputFx->getAttributes()->getDagNodePos().x < x) {
1350       placeNodeAndParents(outputFx, x, maxX, minY);
1351       y -= step;
1352       minY = std::min(y, minY);
1353     }
1354   }
1355 }
1356 
1357 //------------------------------------------------------------------
1358 
onDisconnectFromXSheet()1359 void FxSchematicScene::onDisconnectFromXSheet() {
1360   std::list<TFxP, std::allocator<TFxP>> list =
1361       m_selection->getFxs().toStdList();
1362   TFxCommand::disconnectNodesFromXsheet(list, m_xshHandle);
1363 }
1364 
1365 //------------------------------------------------------------------
1366 
onConnectToXSheet()1367 void FxSchematicScene::onConnectToXSheet() {
1368   std::list<TFxP, std::allocator<TFxP>> list =
1369       m_selection->getFxs().toStdList();
1370   TFxCommand::connectNodesToXsheet(list, m_xshHandle);
1371 }
1372 
1373 //------------------------------------------------------------------
1374 
onDeleteFx()1375 void FxSchematicScene::onDeleteFx() {
1376   std::list<TFxP, std::allocator<TFxP>> fxList =
1377       m_selection->getFxs().toStdList();
1378   std::list<TFxCommand::Link> linkList = m_selection->getLinks().toStdList();
1379   std::list<int> columnIndexList = m_selection->getColumnIndexes().toStdList();
1380   TFxCommand::deleteSelection(fxList, linkList, columnIndexList, m_xshHandle,
1381                               m_fxHandle);
1382 }
1383 
1384 //------------------------------------------------------------------
1385 
onDuplicateFx()1386 void FxSchematicScene::onDuplicateFx() {
1387   QList<TFxP> fxs = m_selection->getFxs();
1388   if (fxs.empty()) return;
1389 
1390   TUndoManager::manager()->beginBlock();
1391 
1392   int i, size = fxs.size();
1393   for (i = 0; i != size; ++i)
1394     TFxCommand::duplicateFx(fxs[i].getPointer(), m_xshHandle, m_fxHandle);
1395 
1396   TUndoManager::manager()->endBlock();
1397 }
1398 
1399 //------------------------------------------------------------------
1400 
onUnlinkFx()1401 void FxSchematicScene::onUnlinkFx() {
1402   QList<TFxP> fxs = m_selection->getFxs();
1403   if (fxs.empty()) return;
1404 
1405   TUndoManager::manager()->beginBlock();
1406 
1407   int i, size = fxs.size();
1408   for (i = 0; i != size; ++i)
1409     TFxCommand::unlinkFx(fxs[i].getPointer(), m_fxHandle, m_xshHandle);
1410 
1411   TUndoManager::manager()->endBlock();
1412 }
1413 
1414 //------------------------------------------------------------------
1415 
onMacroFx()1416 void FxSchematicScene::onMacroFx() {
1417   TFxCommand::makeMacroFx(m_selection->getFxs().toVector().toStdVector(),
1418                           m_app);
1419 }
1420 
1421 //------------------------------------------------------------------
1422 
onExplodeMacroFx()1423 void FxSchematicScene::onExplodeMacroFx() {
1424   if (TMacroFx *macroFx = dynamic_cast<TMacroFx *>(m_fxHandle->getFx()))
1425     TFxCommand::explodeMacroFx(macroFx, m_app);
1426 }
1427 
1428 //------------------------------------------------------------------
1429 
onOpenMacroFx()1430 void FxSchematicScene::onOpenMacroFx() {
1431   if (TMacroFx *macroFx = dynamic_cast<TMacroFx *>(m_fxHandle->getFx())) {
1432     macroFx->editMacro(true);
1433     updateScene();
1434   }
1435 }
1436 
1437 //------------------------------------------------------------------
1438 
onSavePresetFx()1439 void FxSchematicScene::onSavePresetFx() {
1440   CommandManager::instance()->getAction("MI_SavePreset")->trigger();
1441 }
1442 
1443 //------------------------------------------------------------------
1444 
onRemoveOutput()1445 void FxSchematicScene::onRemoveOutput() {
1446   TFxCommand::removeOutputFx(m_fxHandle->getFx(), m_xshHandle, m_fxHandle);
1447 }
1448 
1449 //------------------------------------------------------------------
1450 
onActivateOutput()1451 void FxSchematicScene::onActivateOutput() {
1452   TFxCommand::makeOutputFxCurrent(m_fxHandle->getFx(), m_xshHandle);
1453 }
1454 
1455 //------------------------------------------------------------------
1456 
onPreview()1457 void FxSchematicScene::onPreview() { emit showPreview(m_fxHandle->getFx()); }
1458 
1459 //------------------------------------------------------------------
1460 
onCacheFx()1461 void FxSchematicScene::onCacheFx() { setEnableCache(true); }
1462 
1463 //------------------------------------------------------------------
1464 
onUncacheFx()1465 void FxSchematicScene::onUncacheFx() { setEnableCache(false); }
1466 
1467 //------------------------------------------------------------------
1468 
setEnableCache(bool toggle)1469 void FxSchematicScene::setEnableCache(bool toggle) {
1470   QList<TFxP> selectedFxs = m_selection->getFxs();
1471   for (int i = 0; i < selectedFxs.size(); i++) {
1472     TFx *fx               = selectedFxs[i].getPointer();
1473     TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx);
1474     if (zcfx) fx = zcfx->getZeraryFx();
1475     TFxAttributes *attr = fx->getAttributes();
1476     if (!attr->isGrouped() || attr->isGroupEditing()) {
1477       if (toggle) {
1478         TPassiveCacheManager::instance()->enableCache(fx);
1479       } else {
1480         TPassiveCacheManager::instance()->disableCache(fx);
1481       }
1482     } else {
1483       QMap<int, FxGroupNode *>::iterator it;
1484       for (it = m_groupedTable.begin(); it != m_groupedTable.end(); it++) {
1485         FxGroupNode *group = it.value();
1486         QList<TFxP> roots  = group->getRootFxs();
1487         for (int j = 0; j < roots.size(); j++) {
1488           if (fx == roots[j].getPointer()) {
1489             if (toggle) {
1490               TPassiveCacheManager::instance()->enableCache(fx);
1491             } else {
1492               TPassiveCacheManager::instance()->disableCache(fx);
1493             }
1494           }
1495         }
1496         group->update();
1497       }
1498     }
1499   }
1500 }
1501 
1502 //------------------------------------------------------------------
1503 
onCollapse(const QList<TFxP> & fxs)1504 void FxSchematicScene::onCollapse(const QList<TFxP> &fxs) {
1505   emit doCollapse(fxs);
1506 }
1507 
1508 //------------------------------------------------------------------
1509 
getXsheet()1510 TXsheet *FxSchematicScene::getXsheet() { return m_xshHandle->getXsheet(); }
1511 
1512 //------------------------------------------------------------------
1513 
onXsheetChanged()1514 void FxSchematicScene::onXsheetChanged() { m_xshHandle->notifyXsheetChanged(); }
1515 
1516 //------------------------------------------------------------------
1517 
onSceneChanged()1518 void FxSchematicScene::onSceneChanged() {
1519   m_app->getCurrentScene()->notifySceneChanged();
1520 }
1521 
1522 //------------------------------------------------------------------
1523 
onSwitchCurrentFx(TFx * fx)1524 void FxSchematicScene::onSwitchCurrentFx(TFx *fx) {
1525   if (m_fxHandle->getFx() == fx) return;
1526   if (fx) {
1527     // Forbid update of the swatch upon column switch. This could generate
1528     // a further useless render...
1529     SwatchViewer::suspendRendering(true, false);
1530 
1531     int columnIndex = fx->getReferenceColumnIndex();
1532     if (columnIndex >= 0) {
1533       m_columnHandle->setColumnIndex(columnIndex);
1534       m_app->getCurrentObject()->setObjectId(
1535           TStageObjectId::ColumnId(columnIndex));
1536     }
1537 
1538     SwatchViewer::suspendRendering(false);
1539 
1540     m_fxHandle->setFx(fx, false);  // Setting the fx updates the swatch
1541 
1542     emit editObject();
1543   } else {
1544     m_fxHandle->setFx(0, false);
1545   }
1546 }
1547 
1548 //------------------------------------------------------------------
1549 
onFxNodeDoubleClicked()1550 void FxSchematicScene::onFxNodeDoubleClicked() {
1551   // emitting fxSettingsShouldBeSwitched
1552   m_fxHandle->onFxNodeDoubleClicked();
1553 }
1554 
1555 //------------------------------------------------------------------
1556 
onCurrentFxSwitched()1557 void FxSchematicScene::onCurrentFxSwitched() {
1558   if (m_currentFxNode) m_currentFxNode->setIsCurrentFxLinked(false, 0);
1559   if (m_table.contains(m_fxHandle->getFx())) {
1560     m_currentFxNode = m_table[m_fxHandle->getFx()];
1561     m_currentFxNode->setIsCurrentFxLinked(true, 0);
1562   } else
1563     m_currentFxNode = 0;
1564 }
1565 
1566 //------------------------------------------------------------------
1567 
onCurrentColumnChanged(int index)1568 void FxSchematicScene::onCurrentColumnChanged(int index) {
1569   m_app->getCurrentColumn()->setColumnIndex(index);
1570   m_app->getCurrentObject()->setObjectId(TStageObjectId::ColumnId(index));
1571 }
1572 
1573 //------------------------------------------------------------------
1574 
onIconifyNodesToggled(bool iconified)1575 void FxSchematicScene::onIconifyNodesToggled(bool iconified) {
1576   m_isNormalIconView      = !iconified;
1577   IconifyFxSchematicNodes = (iconified) ? 1 : 0;
1578   updateScene();
1579 }
1580 
1581 //------------------------------------------------------------------
1582 
getCurrentFx()1583 TFx *FxSchematicScene::getCurrentFx() { return m_fxHandle->getFx(); }
1584 
1585 //------------------------------------------------------------------
1586 
mousePressEvent(QGraphicsSceneMouseEvent * me)1587 void FxSchematicScene::mousePressEvent(QGraphicsSceneMouseEvent *me) {
1588   QList<QGraphicsItem *> items = selectedItems();
1589 #if QT_VERSION >= 0x050000
1590   QGraphicsItem *item = itemAt(me->scenePos(), QTransform());
1591 #else
1592   QGraphicsItem *item = itemAt(me->scenePos());
1593 #endif
1594   FxSchematicPort *port = dynamic_cast<FxSchematicPort *>(item);
1595   FxSchematicLink *link = dynamic_cast<FxSchematicLink *>(item);
1596   SchematicScene::mousePressEvent(me);
1597   onSelectionChanged();
1598   if (me->button() == Qt::MidButton) {
1599     int i;
1600     for (i = 0; i < items.size(); i++) items[i]->setSelected(true);
1601   }
1602   /*
1603   m_selection may not be updated here, so I use QGraphicsScene::selectedItems()
1604   instead of m_selection->isEmpty() to check whether any node is selected or
1605   not.
1606   */
1607   if (selectedItems().isEmpty()) {
1608     if (me->button() != Qt::MidButton && !item) m_fxHandle->setFx(0, false);
1609     return;
1610   }
1611   m_isConnected = false;
1612   if (!canDisconnectSelection(m_selection)) return;
1613   m_selectionOldPos.clear();
1614   QList<TFxP> selectedFxs = m_selection->getFxs();
1615   int i;
1616   for (i = 0; i < selectedFxs.size(); i++) {
1617     TFxP selectedFx = selectedFxs[i];
1618     TPointD pos     = selectedFx->getAttributes()->getDagNodePos();
1619     m_selectionOldPos.append(QPair<TFxP, TPointD>(selectedFx, pos));
1620   }
1621   FxsData fxsData;
1622   fxsData.setFxs(m_selection->getFxs(), m_selection->getLinks(),
1623                  m_selection->getColumnIndexes(), m_xshHandle->getXsheet());
1624   // m_isConnected indicates that the all selected nodes are connected
1625   if (fxsData.isConnected() && me->button() == Qt::LeftButton && !port && !link)
1626     m_isConnected = true;
1627 }
1628 
1629 //------------------------------------------------------------------
1630 
mouseMoveEvent(QGraphicsSceneMouseEvent * me)1631 void FxSchematicScene::mouseMoveEvent(QGraphicsSceneMouseEvent *me) {
1632   SchematicScene::mouseMoveEvent(me);
1633 
1634   m_lastPos = me->scenePos();
1635 
1636   bool leftButton = (QApplication::mouseButtons() == Qt::LeftButton);
1637   bool altButton  = (QApplication::keyboardModifiers() == Qt::AltModifier);
1638 
1639   if (leftButton && m_isConnected && altButton) {
1640     m_linkUnlinkSimulation = true;
1641 
1642     simulateDisconnectSelection(true);
1643     m_connectionLinks.showBridgeLinks();
1644 
1645 #if QT_VERSION >= 0x050000
1646     SchematicLink *link =
1647         dynamic_cast<SchematicLink *>(itemAt(m_lastPos, QTransform()));
1648 #else
1649     SchematicLink *link = dynamic_cast<SchematicLink *>(itemAt(m_lastPos));
1650 #endif
1651     if (link && (link->getEndPort() && link->getStartPort())) {
1652       TFxCommand::Link fxLink = m_selection->getBoundingFxs(link);
1653       if (fxLink == TFxCommand::Link()) return;
1654 
1655       TFx *inputFx  = fxLink.m_inputFx.getPointer();
1656       TFx *outputFx = fxLink.m_outputFx.getPointer();
1657 
1658       TFxSet *internalFxs = getXsheet()->getFxDag()->getInternalFxs();
1659       if (!internalFxs->containsFx(inputFx) &&
1660           !dynamic_cast<TColumnFx *>(inputFx) &&
1661           !dynamic_cast<TXsheetFx *>(inputFx) &&
1662           !dynamic_cast<TOutputFx *>(inputFx))
1663         return;
1664       if (!internalFxs->containsFx(outputFx) &&
1665           !dynamic_cast<TColumnFx *>(outputFx) &&
1666           !dynamic_cast<TXsheetFx *>(outputFx) &&
1667           !dynamic_cast<TOutputFx *>(outputFx))
1668         return;
1669     }
1670 
1671     m_connectionLinks.hideBridgeLinks();
1672     simulateInsertSelection(link, altButton && !!link);
1673   }
1674 }
1675 
1676 //------------------------------------------------------------------
1677 
mouseReleaseEvent(QGraphicsSceneMouseEvent * me)1678 void FxSchematicScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *me) {
1679   SchematicScene::mouseReleaseEvent(me);
1680 
1681   m_linkUnlinkSimulation = false;
1682 
1683   if ((m_disconnectionLinks.size() == 0) && (m_connectionLinks.size() == 0))
1684     return;
1685 
1686   TUndoManager::manager()->beginBlock();
1687 
1688   bool altButton = QApplication::keyboardModifiers() == Qt::AltModifier;
1689   if (altButton && m_isConnected) {
1690     if (m_connectionLinks.size() > 0) {
1691       const QList<SchematicLink *> &bridgeLinks =
1692           m_connectionLinks.getBridgeLinks();
1693       assert(bridgeLinks.size() <= 1);
1694 
1695       SchematicLink *link = bridgeLinks[0];
1696 
1697       if (link) {
1698         FxSchematicNode *outputNode =
1699             dynamic_cast<FxSchematicNode *>(link->getEndPort()->getNode());
1700         FxSchematicNode *inputNode =
1701             dynamic_cast<FxSchematicNode *>(link->getStartPort()->getNode());
1702 
1703         if (inputNode && outputNode) {
1704           SchematicPort *port = link->getStartPort();
1705           if (port->getType() == 200 || port->getType() == 204)
1706             port = link->getOtherPort(port);
1707 
1708           int i;
1709           for (i = 0; i < outputNode->getInputPortCount(); i++)
1710             if (port == outputNode->getInputPort(i)) break;
1711 
1712           TFxCommand::Link fxLink;
1713           fxLink.m_outputFx = outputNode->getFx();
1714           fxLink.m_inputFx  = inputNode->getFx();
1715           if (!outputNode->isA(eXSheetFx)) fxLink.m_index = i;
1716 
1717           TFxCommand::connectFxs(fxLink, m_selection->getFxs().toStdList(),
1718                                  m_xshHandle, m_selectionOldPos);
1719         }
1720       }
1721     } else if (m_disconnectionLinks.size() > 0) {
1722       QList<TFxP> fxs = m_selection->getFxs();
1723       TFxCommand::disconnectFxs(fxs.toStdList(), m_xshHandle,
1724                                 m_selectionOldPos);
1725       m_selectionOldPos.clear();
1726     }
1727   }
1728 
1729   TUndoManager::manager()->endBlock();
1730 
1731   m_isConnected = false;
1732 }
1733 
1734 //------------------------------------------------------------------
1735 
event(QEvent * e)1736 bool FxSchematicScene::event(QEvent *e) {
1737   bool ret        = SchematicScene::event(e);
1738   bool altPressed = QApplication::keyboardModifiers() == Qt::AltModifier;
1739   if (m_altPressed != altPressed) {
1740     // When Alt key is pressed, put the link lines on top of other items
1741     // in order to enable to pick them up with itemAt() function.
1742     double z                          = (altPressed) ? 5.0 : 0.0;
1743     QList<QGraphicsItem *> sceneItems = items();
1744     for (int i = 0; i < sceneItems.size(); i++) {
1745       SchematicLink *link = dynamic_cast<SchematicLink *>(sceneItems.at(i));
1746       if (link) link->setZValue(z);
1747     }
1748 
1749     if (m_linkUnlinkSimulation) onAltModifierChanged(altPressed);
1750     m_altPressed = altPressed;
1751   }
1752   return ret;
1753 }
1754 
1755 //------------------------------------------------------------------
1756 
onInsertPaste()1757 void FxSchematicScene::onInsertPaste() {
1758   if (!m_selection->insertPasteSelection())
1759     DVGui::error(
1760         tr("Cannot Paste Insert a selection of unconnected FX nodes.\nSelect "
1761            "FX nodes and related links before copying or cutting the selection "
1762            "you want to paste."));
1763 }
1764 
1765 //------------------------------------------------------------------
1766 
onAddPaste()1767 void FxSchematicScene::onAddPaste() {
1768   if (!m_selection->addPasteSelection())
1769     DVGui::error(
1770         tr("Cannot Paste Add a selection of unconnected FX nodes.\nSelect FX "
1771            "nodes and related links before copying or cutting the selection "
1772            "you want to paste."));
1773 }
1774 
1775 //------------------------------------------------------------------
1776 
onReplacePaste()1777 void FxSchematicScene::onReplacePaste() {
1778   if (!m_selection->replacePasteSelection())
1779     DVGui::error(
1780         tr("Cannot Paste Replace a selection of unconnected FX nodes.\nSelect "
1781            "FX nodes and related links before copying or cutting the selection "
1782            "you want to paste."));
1783 }
1784 
1785 //------------------------------------------------------------------
1786 
onAltModifierChanged(bool altPressed)1787 void FxSchematicScene::onAltModifierChanged(bool altPressed) {
1788   if (altPressed) {
1789     if (m_disconnectionLinks.size() == 0 && m_linkUnlinkSimulation)
1790       simulateDisconnectSelection(altPressed);
1791     if (m_connectionLinks.size() == 0 && m_linkUnlinkSimulation) {
1792 #if QT_VERSION >= 0x050000
1793       SchematicLink *link =
1794           dynamic_cast<SchematicLink *>(itemAt(m_lastPos, QTransform()));
1795 #else
1796       SchematicLink *link = dynamic_cast<SchematicLink *>(itemAt(m_lastPos));
1797 #endif
1798       if (link && (!link->getEndPort() || !link->getStartPort())) return;
1799       simulateInsertSelection(link, altPressed && !!link);
1800     }
1801   } else {
1802     if (m_disconnectionLinks.size() > 0 && m_linkUnlinkSimulation)
1803       simulateDisconnectSelection(altPressed);
1804     if (m_connectionLinks.size() > 0 && m_linkUnlinkSimulation) {
1805       m_connectionLinks.showBridgeLinks();
1806       simulateInsertSelection(0, false);
1807     }
1808   }
1809 }
1810 
1811 //------------------------------------------------------------------
1812 
onEditGroup()1813 void FxSchematicScene::onEditGroup() {
1814   if (m_selection->isEmpty()) return;
1815   QList<TFxP> fxs = m_selection->getFxs();
1816   int i;
1817   for (i = 0; i < fxs.size(); i++) {
1818     if (fxs[i]->getAttributes()->isGrouped() &&
1819         !fxs[i]->getAttributes()->isGroupEditing()) {
1820       fxs[i]->getAttributes()->editGroup();
1821       TMacroFx *macro = dynamic_cast<TMacroFx *>(fxs[i].getPointer());
1822       if (macro) {
1823         std::vector<TFxP> macroFxs = macro->getFxs();
1824         int j;
1825         for (j = 0; j < (int)macroFxs.size(); j++)
1826           macroFxs[j]->getAttributes()->editGroup();
1827       }
1828     }
1829   }
1830   updateScene();
1831 }
1832 
1833 //------------------------------------------------------------------
1834 
highlightLinks(FxSchematicNode * node,bool value)1835 void FxSchematicScene::highlightLinks(FxSchematicNode *node, bool value) {
1836   int i, portCount = node->getInputPortCount();
1837   // SchematicLink* ghostLink = m_supportLinks.getDisconnectionLink(eGhost);
1838   for (i = 0; i < portCount; i++) {
1839     FxSchematicPort *port = node->getInputPort(i);
1840     int j, linkCount = port->getLinkCount();
1841     for (j = 0; j < linkCount; j++) {
1842       SchematicLink *link = port->getLink(j);
1843       if (!link) continue;
1844       if (m_disconnectionLinks.isABridgeLink(link)) continue;
1845       link->setHighlighted(value);
1846       link->update();
1847       m_highlightedLinks.push_back(link);
1848     }
1849   }
1850 
1851   FxSchematicPort *port = node->getOutputPort();
1852   if (port) {
1853     int linkCount = port->getLinkCount();
1854     for (i = 0; i < linkCount; i++) {
1855       SchematicLink *link = port->getLink(i);
1856       if (!link) continue;
1857       if (m_disconnectionLinks.isABridgeLink(link)) continue;
1858       link->setHighlighted(value);
1859       link->update();
1860       m_highlightedLinks.push_back(link);
1861     }
1862   }
1863   port = node->getLinkPort();
1864   if (port) {
1865     SchematicLink *link = port->getLink(0);
1866     if (link && !m_disconnectionLinks.isABridgeLink(link)) {
1867       link->setHighlighted(value);
1868       link->update();
1869       m_highlightedLinks.push_back(link);
1870     }
1871   }
1872 }
1873 
1874 //------------------------------------------------------------------
1875 
simulateDisconnectSelection(bool disconnect)1876 void FxSchematicScene::simulateDisconnectSelection(bool disconnect) {
1877   if (disconnect) {
1878     if (m_selection->isEmpty()) return;
1879     QList<TFxP> selectedFxs = m_selection->getFxs();
1880     if (selectedFxs.isEmpty()) return;
1881     QMap<TFx *, bool> visitedFxs;
1882     int i;
1883     for (i = 0; i < selectedFxs.size(); i++)
1884       visitedFxs[selectedFxs[i].getPointer()] = false;
1885 
1886     TFx *inputFx = 0, *outputFx = 0;
1887     findBoundariesFxs(inputFx, outputFx, visitedFxs);
1888     FxSchematicNode *inputNode  = m_table[inputFx];
1889     FxSchematicNode *outputNode = m_table[outputFx];
1890     assert(inputNode && outputNode);
1891 
1892     FxSchematicPort *inputPort = 0, *outputPort = 0;
1893     SchematicPort *otherInputPort = 0;
1894     QList<SchematicPort *> otherOutputPorts;
1895     if (inputNode->getInputPortCount() > 0) {
1896       inputPort = inputNode->getInputPort(0);
1897       if (inputPort) {
1898         SchematicLink *inputLink = inputPort->getLink(0);
1899         if (inputLink && !m_connectionLinks.isAnInputLink(inputLink)) {
1900           if (!m_disconnectionLinks.isAnInputLink(inputLink))
1901             m_disconnectionLinks.addInputLink(inputLink);
1902           otherInputPort = inputLink->getOtherPort(inputPort);
1903         }
1904       }
1905     }
1906     outputPort = outputNode->getOutputPort();
1907     if (outputPort) {
1908       for (i = 0; i < outputPort->getLinkCount(); i++) {
1909         SchematicLink *outputLink = outputPort->getLink(i);
1910         if (outputLink && !m_connectionLinks.isAnOutputLink(outputLink)) {
1911           if (!m_disconnectionLinks.isAnOutputLink(outputLink))
1912             m_disconnectionLinks.addOutputLink(outputLink);
1913           otherOutputPorts.push_back(outputLink->getOtherPort(outputPort));
1914         }
1915       }
1916     }
1917     m_disconnectionLinks.hideInputLinks();
1918     m_disconnectionLinks.hideOutputLinks();
1919 
1920     if (otherInputPort) {
1921       for (i = 0; i < otherOutputPorts.size(); i++)
1922         m_disconnectionLinks.addBridgeLink(
1923             otherOutputPorts[i]->makeLink(otherInputPort));
1924     }
1925   } else {
1926     m_disconnectionLinks.showInputLinks();
1927     m_disconnectionLinks.showOutputLinks();
1928     m_disconnectionLinks.removeInputLinks();
1929     m_disconnectionLinks.removeOutputLinks();
1930     m_disconnectionLinks.removeBridgeLinks(true);
1931   }
1932 }
1933 
1934 //------------------------------------------------------------------
1935 
simulateInsertSelection(SchematicLink * link,bool connect)1936 void FxSchematicScene::simulateInsertSelection(SchematicLink *link,
1937                                                bool connect) {
1938   // first, remove all connected links
1939   m_connectionLinks.showBridgeLinks();
1940   m_connectionLinks.hideInputLinks();
1941   m_connectionLinks.hideOutputLinks();
1942   m_connectionLinks.removeBridgeLinks();
1943   m_connectionLinks.removeInputLinks(true);
1944   m_connectionLinks.removeOutputLinks(true);
1945   if (!link || !connect) return;
1946 
1947   if (m_disconnectionLinks.isABridgeLink(link) || m_selection->isEmpty())
1948     return;
1949 
1950   m_connectionLinks.addBridgeLink(link);
1951   m_connectionLinks.hideBridgeLinks();
1952 
1953   SchematicPort *inputPort = 0, *outputPort = 0;
1954   if (link) {
1955     if (link->getStartPort()->getType() == eFxInputPort) {
1956       inputPort  = link->getStartPort();
1957       outputPort = link->getEndPort();
1958     } else {
1959       inputPort  = link->getEndPort();
1960       outputPort = link->getStartPort();
1961     }
1962   }
1963 
1964   QMap<TFx *, bool> visitedFxs;
1965   QList<TFxP> selectedFxs = m_selection->getFxs();
1966   if (selectedFxs.isEmpty()) return;
1967   int i;
1968   for (i = 0; i < selectedFxs.size(); i++)
1969     visitedFxs[selectedFxs[i].getPointer()] = false;
1970 
1971   TFx *inputFx = 0, *outputFx = 0;
1972   findBoundariesFxs(inputFx, outputFx, visitedFxs);
1973   FxSchematicNode *inputNode  = m_table[inputFx];
1974   FxSchematicNode *outputNode = m_table[outputFx];
1975   assert(inputNode && outputNode);
1976 
1977   if (inputNode->getInputPortCount() > 0) {
1978     SchematicPort *inputNodePort = inputNode->getInputPort(0);
1979     if (inputNodePort && outputPort)
1980       m_connectionLinks.addInputLink(inputNodePort->makeLink(outputPort));
1981   }
1982 
1983   SchematicPort *outputNodePort = outputNode->getOutputPort();
1984   if (outputNodePort && inputPort)
1985     m_connectionLinks.addOutputLink(inputPort->makeLink(outputNodePort));
1986 
1987   m_connectionLinks.showInputLinks();
1988   m_connectionLinks.showOutputLinks();
1989 }
1990 
1991 //------------------------------------------------------------
1992 /*! in order to select nods after pasting the copied fx nodes from FxSelection
1993  */
selectNodes(QList<TFxP> & fxs)1994 void FxSchematicScene::selectNodes(QList<TFxP> &fxs) {
1995   clearSelection();
1996   for (int i = 0; i < (int)fxs.size(); i++) {
1997     TFx *tempFx = fxs[i].getPointer();
1998 
1999     QMap<TFx *, FxSchematicNode *>::iterator it;
2000     it = m_table.find(tempFx);
2001     if (it == m_table.end()) continue;
2002 
2003     it.value()->setSelected(true);
2004   }
2005   update();
2006 }
2007 
2008 //------------------------------------------------------------------
2009 
updateNestedGroupEditors(FxSchematicNode * node,const QPointF & newPos)2010 void FxSchematicScene::updateNestedGroupEditors(FxSchematicNode *node,
2011                                                 const QPointF &newPos) {
2012   if (!node) return;
2013   QStack<int> groupIdStack = node->getFx()->getAttributes()->getGroupIdStack();
2014   int i;
2015   QRectF rect;
2016   for (i = 0; i < groupIdStack.size(); i++) {
2017     if (m_groupEditorTable.contains(groupIdStack[i])) {
2018       QRectF app = m_groupEditorTable[groupIdStack[i]]->sceneBoundingRect();
2019       if (rect.isEmpty())
2020         rect = app;
2021       else
2022 #if QT_VERSION >= 0x050000
2023         rect = rect.united(app);
2024 #else
2025         rect = rect.unite(app);
2026 #endif
2027     }
2028   }
2029   QMap<TMacroFx *, FxSchematicMacroEditor *>::iterator it;
2030   for (it = m_macroEditorTable.begin(); it != m_macroEditorTable.end(); it++) {
2031     if (it.value()->contains(node)) {
2032       QRectF app = it.value()->sceneBoundingRect();
2033       if (rect.isEmpty())
2034         rect = app;
2035       else
2036 #if QT_VERSION >= 0x050000
2037         rect = rect.united(app);
2038 #else
2039         rect = rect.unite(app);
2040 #endif
2041     }
2042   }
2043   node->setPos(newPos);
2044   for (i = 0; i < groupIdStack.size(); i++) {
2045     if (!m_groupEditorTable.contains(groupIdStack[i])) continue;
2046 #if QT_VERSION >= 0x050000
2047     rect =
2048         rect.united(m_groupEditorTable[groupIdStack[i]]->sceneBoundingRect());
2049 #else
2050     rect = rect.unite(m_groupEditorTable[groupIdStack[i]]->sceneBoundingRect());
2051 #endif
2052     QRectF app = m_groupEditorTable[groupIdStack[i]]->boundingSceneRect();
2053     if (m_groupEditorTable[groupIdStack[i]]->scenePos() != app.topLeft())
2054       m_groupEditorTable[groupIdStack[i]]->setPos(app.topLeft());
2055   }
2056   for (it = m_macroEditorTable.begin(); it != m_macroEditorTable.end(); it++) {
2057     FxSchematicMacroEditor *editor = it.value();
2058     if (editor->contains(node)) {
2059       QRectF app = editor->sceneBoundingRect();
2060 #if QT_VERSION >= 0x050000
2061       rect = rect.united(app);
2062 #else
2063       rect = rect.unite(app);
2064 #endif
2065       app = editor->boundingSceneRect();
2066       if (editor->scenePos() != app.topLeft()) editor->setPos(app.topLeft());
2067     }
2068   }
2069   update(rect);
2070 }
2071 
2072 //------------------------------------------------------------------
2073 
closeInnerMacroEditor(int groupId)2074 void FxSchematicScene::closeInnerMacroEditor(int groupId) {
2075   assert(m_groupEditorTable.contains(groupId));
2076   QMap<TMacroFx *, FxSchematicMacroEditor *>::iterator it;
2077   for (it = m_macroEditorTable.begin(); it != m_macroEditorTable.end(); it++) {
2078     TMacroFx *macro = it.key();
2079     assert(macro);
2080     if (macro->getAttributes()->isContainedInGroup(groupId)) {
2081       macro->editMacro(false);
2082       macro->getAttributes()->closeEditingGroup(groupId);
2083     }
2084   }
2085 }
2086 
2087 //------------------------------------------------------------------
2088 
resizeNodes(bool maximizedNode)2089 void FxSchematicScene::resizeNodes(bool maximizedNode) {
2090   resizingNodes = true;
2091 
2092   // resize nodes
2093   m_gridDimension = maximizedNode ? eLarge : eSmall;
2094   m_xshHandle->getXsheet()->getFxDag()->setDagGridDimension(m_gridDimension);
2095   QMap<TFx *, FxSchematicNode *>::iterator it1;
2096   for (it1 = m_table.begin(); it1 != m_table.end(); it1++) {
2097     if (!it1.value()) continue;
2098     it1.value()->resize(maximizedNode);
2099     TFx *fx = it1.value()->getFx();
2100     updatePositionOnResize(fx, maximizedNode);
2101   }
2102   QMap<int, FxGroupNode *>::iterator it2;
2103   for (it2 = m_groupedTable.begin(); it2 != m_groupedTable.end(); it2++) {
2104     if (!it2.value()) continue;
2105     it2.value()->resize(maximizedNode);
2106     QList<TFxP> groupedFxs = it2.value()->getGroupedFxs();
2107     for (int i = 0; i < groupedFxs.size(); i++)
2108       updatePositionOnResize(groupedFxs[i].getPointer(), maximizedNode);
2109   }
2110 
2111   QMap<TMacroFx *, FxSchematicMacroEditor *>::iterator it3;
2112   for (it3 = m_macroEditorTable.begin(); it3 != m_macroEditorTable.end();
2113        it3++) {
2114     if (!it3.value()) continue;
2115     it3.value()->resizeNodes(maximizedNode);
2116   }
2117   updateScene();
2118 
2119   resizingNodes = false;
2120 }
2121 
2122 //------------------------------------------------------------------
2123 
updatePositionOnResize(TFx * fx,bool maximizedNode)2124 void FxSchematicScene::updatePositionOnResize(TFx *fx, bool maximizedNode) {
2125   TPointD oldPos = fx->getAttributes()->getDagNodePos();
2126   if (oldPos == TConst::nowhere) return;
2127   double oldPosY = oldPos.y - 25000;
2128   double newPosY = maximizedNode ? oldPosY * 2 : oldPosY * 0.5;
2129   fx->getAttributes()->setDagNodePos(TPointD(oldPos.x, newPosY + 25000));
2130 }
2131 
2132 //------------------------------------------------------------------
2133 
onNodeChangedSize()2134 void FxSchematicScene::onNodeChangedSize() {
2135   if (resizingNodes) return;
2136   updateScene();
2137 }
2138