1
2
3 #include "toonzqt/schematicnode.h"
4 #include "toonzqt/stageschematicscene.h"
5 #include "toonzqt/fxschematicscene.h"
6
7 #include <QGraphicsSceneMouseEvent>
8 #include <QStyleOptionGraphicsItem>
9 #include <QKeyEvent>
10 #include <algorithm>
11 #include <QApplication>
12 #include <QTextDocument>
13 #include <QTextCursor>
14 #include <QTextBlock>
15 #include <QMenuBar>
16 #include <QPolygonF>
17 #include <QDesktopWidget>
18 #include "tundo.h"
19 #include "toonzqt/menubarcommand.h"
20 #include "toonzqt/gutil.h"
21
22 //========================================================
23 //
24 // StageSchematicName
25 //
26 //========================================================
27
SchematicName(QGraphicsItem * parent,double width,double height)28 SchematicName::SchematicName(QGraphicsItem *parent, double width, double height)
29 : QGraphicsTextItem("", parent), m_width(width), m_height(height) {
30 setFlag(QGraphicsItem::ItemIsSelectable, true);
31 setFlag(QGraphicsItem::ItemIsFocusable, true);
32 setTextInteractionFlags(Qt::TextEditorInteraction);
33
34 connect(document(), SIGNAL(contentsChanged()), this,
35 SLOT(onContentsChanged()));
36 }
37
38 //--------------------------------------------------------
39
~SchematicName()40 SchematicName::~SchematicName() {}
41
42 //--------------------------------------------------------
43
setName(const QString & name)44 void SchematicName::setName(const QString &name) { setPlainText(name); }
45
46 //--------------------------------------------------------
47
onContentsChanged()48 void SchematicName::onContentsChanged() {
49 QString text = document()->toPlainText();
50 QTextCursor cursor = textCursor();
51 int position = cursor.position();
52 if (position > 0 && text.at(position - 1) == '\n') {
53 text.remove("\n");
54 setPlainText(text);
55 ;
56 emit focusOut();
57 }
58 }
59
60 //--------------------------------------------------------
61
focusOutEvent(QFocusEvent * fe)62 void SchematicName::focusOutEvent(QFocusEvent *fe) {
63 qApp->removeEventFilter(this);
64 if (fe->reason() == Qt::MouseFocusReason) emit focusOut();
65 }
66
67 //--------------------------------------------------------
68
keyPressEvent(QKeyEvent * ke)69 void SchematicName::keyPressEvent(QKeyEvent *ke) {
70 if (ke->key() == Qt::Key_Left || ke->key() == Qt::Key_Right) {
71 QTextCursor cursor = textCursor();
72 int currentPos = cursor.position();
73 if (ke->key() == Qt::Key_Left)
74 cursor.setPosition(currentPos - 1);
75 else
76 cursor.setPosition(currentPos + 1);
77 setTextCursor(cursor);
78 } else
79 QGraphicsTextItem::keyPressEvent(ke);
80 }
81
82 //--------------------------------------------------------
83
eventFilter(QObject * object,QEvent * event)84 bool SchematicName::eventFilter(QObject *object, QEvent *event) {
85 if (event->type() == QEvent::Shortcut ||
86 event->type() == QEvent::ShortcutOverride) {
87 if (!object->inherits("QGraphicsView")) {
88 event->accept();
89 return true;
90 }
91 }
92 return false;
93 }
94
95 //--------------------------------------------------------
96
focusInEvent(QFocusEvent * fe)97 void SchematicName::focusInEvent(QFocusEvent *fe) {
98 QGraphicsTextItem::focusInEvent(fe);
99 qApp->installEventFilter(this);
100 QTextDocument *doc = document();
101 QTextCursor cursor(doc->begin());
102 cursor.select(QTextCursor::Document);
103 setTextCursor(cursor);
104 }
105
106 //========================================================
107 //
108 // class SchematicThumbnailToggle
109 //
110 //========================================================
111
SchematicThumbnailToggle(SchematicNode * parent,bool isOpened)112 SchematicThumbnailToggle::SchematicThumbnailToggle(SchematicNode *parent,
113 bool isOpened)
114 : QGraphicsItem(parent), m_isDown(!isOpened) {}
115
116 //--------------------------------------------------------
117
~SchematicThumbnailToggle()118 SchematicThumbnailToggle::~SchematicThumbnailToggle() {}
119
120 //--------------------------------------------------------
121
boundingRect() const122 QRectF SchematicThumbnailToggle::boundingRect() const {
123 return QRectF(0, 0, 14, 14);
124 }
125
126 //--------------------------------------------------------
127
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)128 void SchematicThumbnailToggle::paint(QPainter *painter,
129 const QStyleOptionGraphicsItem *option,
130 QWidget *widget) {
131 QRect rect(3, 3, 8, 8);
132 QRect sourceRect = scene()->views()[0]->matrix().mapRect(rect);
133 static QIcon onIcon(":Resources/schematic_thumbtoggle_on.svg");
134 static QIcon offIcon(":Resources/schematic_thumbtoggle_off.svg");
135 QPixmap pixmap;
136 if (m_isDown)
137 pixmap = offIcon.pixmap(sourceRect.size());
138 else
139 pixmap = onIcon.pixmap(sourceRect.size());
140 sourceRect = QRect(0, 0, sourceRect.width() * getDevPixRatio(),
141 sourceRect.height() * getDevPixRatio());
142 painter->drawPixmap(rect, pixmap, sourceRect);
143 }
144
145 //--------------------------------------------------------
146
setIsDown(bool value)147 void SchematicThumbnailToggle::setIsDown(bool value) {
148 m_isDown = value;
149 emit(toggled(!m_isDown));
150 }
151
152 //--------------------------------------------------------
153
mousePressEvent(QGraphicsSceneMouseEvent * me)154 void SchematicThumbnailToggle::mousePressEvent(QGraphicsSceneMouseEvent *me) {
155 m_isDown = !m_isDown;
156 emit(toggled(!m_isDown));
157 }
158
159 //========================================================
160 //
161 // SchematicToggle
162 //
163 //========================================================
164
SchematicToggle(SchematicNode * parent,const QIcon & imageOn,QColor colorOn,int flags,bool isNormalIconView)165 SchematicToggle::SchematicToggle(SchematicNode *parent, const QIcon &imageOn,
166 QColor colorOn, int flags,
167 bool isNormalIconView)
168 : QGraphicsItem(parent)
169 , m_imageOn(imageOn)
170 , m_imageOn2()
171 , m_imageOff()
172 , m_state(0)
173 , m_flags(flags)
174 , m_width(isNormalIconView ? 18 : 30)
175 , m_height(isNormalIconView ? 7 : 5)
176 , m_colorOn(colorOn)
177 , m_colorOff(QColor(0, 0, 0, 0)) {}
178
179 //--------------------------------------------------------
180
SchematicToggle(SchematicNode * parent,const QIcon & imageOn,QColor colorOn,const QIcon & imageOff,QColor colorOff,int flags,bool isNormalIconView)181 SchematicToggle::SchematicToggle(SchematicNode *parent, const QIcon &imageOn,
182 QColor colorOn, const QIcon &imageOff,
183 QColor colorOff, int flags,
184 bool isNormalIconView)
185 : QGraphicsItem(parent)
186 , m_imageOn(imageOn)
187 , m_imageOn2()
188 , m_imageOff(imageOff)
189 , m_state(0)
190 , m_flags(flags)
191 , m_width(isNormalIconView ? 18 : 30)
192 , m_height(isNormalIconView ? 7 : 5)
193 , m_colorOn(colorOn)
194 , m_colorOff(colorOff) {}
195
196 //--------------------------------------------------------
197
SchematicToggle(SchematicNode * parent,const QIcon & imageOn,const QIcon & imageOn2,QColor colorOn,int flags,bool isNormalIconView)198 SchematicToggle::SchematicToggle(SchematicNode *parent, const QIcon &imageOn,
199 const QIcon &imageOn2, QColor colorOn,
200 int flags, bool isNormalIconView)
201 : QGraphicsItem(parent)
202 , m_imageOn(imageOn)
203 , m_imageOn2(imageOn2)
204 , m_imageOff()
205 , m_state(0)
206 , m_flags(flags)
207 , m_width(isNormalIconView ? 18 : 30)
208 , m_height(isNormalIconView ? 7 : 5)
209 , m_colorOn(colorOn)
210 , m_colorOff(QColor(0, 0, 0, 0)) {}
211
212 //--------------------------------------------------------
213
SchematicToggle(SchematicNode * parent,const QIcon & imageOn,const QIcon & imageOn2,QColor colorOn,const QIcon & imageOff,QColor colorOff,int flags,bool isNormalIconView)214 SchematicToggle::SchematicToggle(SchematicNode *parent, const QIcon &imageOn,
215 const QIcon &imageOn2, QColor colorOn,
216 const QIcon &imageOff, QColor colorOff,
217 int flags, bool isNormalIconView)
218 : QGraphicsItem(parent)
219 , m_imageOn(imageOn)
220 , m_imageOn2(imageOn2)
221 , m_imageOff(imageOff)
222 , m_state(0)
223 , m_flags(flags)
224 , m_width(isNormalIconView ? 18 : 30)
225 , m_height(isNormalIconView ? 7 : 5)
226 , m_colorOn(colorOn)
227 , m_colorOff(colorOff) {}
228
229 //--------------------------------------------------------
230
~SchematicToggle()231 SchematicToggle::~SchematicToggle() {}
232
233 //--------------------------------------------------------
234
boundingRect() const235 QRectF SchematicToggle::boundingRect() const {
236 return QRectF(0, 0, m_width, m_height);
237 }
238
239 //--------------------------------------------------------
240
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)241 void SchematicToggle::paint(QPainter *painter,
242 const QStyleOptionGraphicsItem *option,
243 QWidget *widget) {
244 int rectHeight = boundingRect().height();
245 int rectWidth = boundingRect().width();
246 int rectX = boundingRect().left();
247 int rectY = boundingRect().top();
248
249 QRect rect =
250 QRect(0, 0, rectHeight, rectHeight)
251 .translated(rectX + (rectWidth / 2) - (rectHeight / 2), rectY);
252
253 if (m_state != 0) {
254 QIcon &pix =
255 (m_state == 2 && !m_imageOn2.isNull()) ? m_imageOn2 : m_imageOn;
256 painter->fillRect(boundingRect().toRect(), m_colorOn);
257 QRect sourceRect =
258 scene()->views()[0]->matrix().mapRect(QRect(0, 0, 18, 17));
259 QPixmap redPm = pix.pixmap(sourceRect.size());
260 QRect newRect = QRect(0, 0, sourceRect.width() * getDevPixRatio(),
261 sourceRect.height() * getDevPixRatio());
262 painter->drawPixmap(rect, redPm, newRect);
263 } else if (!m_imageOff.isNull()) {
264 QPen pen(m_colorOn);
265 pen.setWidthF(0.5);
266 painter->setPen(pen);
267 painter->setBrush(m_colorOff);
268 double d = pen.widthF() / 2.0;
269 painter->drawRect(boundingRect().adjusted(d, d, -d, -d));
270 QRect sourceRect =
271 scene()->views()[0]->matrix().mapRect(QRect(0, 0, 18, 17));
272 QPixmap redPm = m_imageOff.pixmap(sourceRect.size());
273 QRect newRect = QRect(0, 0, sourceRect.width() * getDevPixRatio(),
274 sourceRect.height() * getDevPixRatio());
275 painter->drawPixmap(rect, redPm, newRect);
276 }
277 }
278
279 //--------------------------------------------------------
280
mousePressEvent(QGraphicsSceneMouseEvent * me)281 void SchematicToggle::mousePressEvent(QGraphicsSceneMouseEvent *me) {
282 if (me->button() == Qt::LeftButton) {
283 if (m_imageOn2.isNull()) {
284 m_state = 1 - m_state;
285 emit(toggled(m_state != 0));
286 } else if (m_flags & eEnableNullState) {
287 m_state = (m_state + 1) % 3;
288 emit(stateChanged(m_state));
289 } else {
290 m_state = 3 - m_state;
291 emit(stateChanged(m_state));
292 }
293 }
294 if (me->button() == Qt::RightButton) {
295 SchematicNode *parent = dynamic_cast<SchematicNode *>(this->parentItem());
296 if (parent) parent->onClicked();
297 }
298 }
299 //--------------------------------------------------------
300
contextMenuEvent(QGraphicsSceneContextMenuEvent * cme)301 void SchematicToggle::contextMenuEvent(QGraphicsSceneContextMenuEvent *cme) {
302 if (!(m_flags & eIsParentColumn)) return;
303 if (m_imageOn2.isNull()) {
304 QMenu *menu = new QMenu(0);
305 CommandManager *cmdManager = CommandManager::instance();
306 menu->addAction(cmdManager->getAction("MI_EnableThisColumnOnly"));
307 menu->addAction(cmdManager->getAction("MI_EnableSelectedColumns"));
308 menu->addAction(cmdManager->getAction("MI_EnableAllColumns"));
309 menu->addAction(cmdManager->getAction("MI_DisableAllColumns"));
310 menu->addAction(cmdManager->getAction("MI_DisableSelectedColumns"));
311 menu->addAction(cmdManager->getAction("MI_SwapEnabledColumns"));
312 QAction *action = menu->exec(cme->screenPos());
313 } else {
314 QMenu *menu = new QMenu(0);
315 CommandManager *cmdManager = CommandManager::instance();
316 menu->addAction(cmdManager->getAction("MI_ActivateThisColumnOnly"));
317 menu->addAction(cmdManager->getAction("MI_ActivateSelectedColumns"));
318 menu->addAction(cmdManager->getAction("MI_ActivateAllColumns"));
319 menu->addAction(cmdManager->getAction("MI_DeactivateAllColumns"));
320 menu->addAction(cmdManager->getAction("MI_DeactivateSelectedColumns"));
321 menu->addAction(cmdManager->getAction("MI_ToggleColumnsActivation"));
322 QAction *action = menu->exec(cme->screenPos());
323 }
324 }
325 //========================================================
326
327 //--------------------------------------------------------
328 /*! for Spline Aim and CP toggles
329 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)330 void SchematicToggle_SplineOptions::paint(
331 QPainter *painter, const QStyleOptionGraphicsItem *option,
332 QWidget *widget) {
333 QRectF rect = boundingRect();
334 painter->fillRect(rect, Qt::white);
335 if (m_state != 0) {
336 QIcon &pix =
337 (m_state == 2 && !m_imageOn2.isNull()) ? m_imageOn2 : m_imageOn;
338 QRect sourceRect = scene()->views()[0]->matrix().mapRect(rect.toRect());
339 QPixmap redPm = pix.pixmap(sourceRect.size());
340 QRect newRect = QRect(0, 0, sourceRect.width() * getDevPixRatio(),
341 sourceRect.height() * getDevPixRatio());
342 painter->drawPixmap(rect, redPm, newRect);
343 }
344 painter->setBrush(Qt::NoBrush);
345 painter->setPen(QColor(180, 180, 180, 255));
346 painter->drawRect(rect);
347 }
348
349 //--------------------------------------------------------
350 /*! for Spline Aim and CP toggles
351 */
mousePressEvent(QGraphicsSceneMouseEvent * me)352 void SchematicToggle_SplineOptions::mousePressEvent(
353 QGraphicsSceneMouseEvent *me) {
354 SchematicToggle::mousePressEvent(me);
355 update();
356 }
357
358 //========================================================
359 //
360 // SchematicHandleSpinBox
361 //
362 //========================================================
363
SchematicHandleSpinBox(QGraphicsItem * parent)364 SchematicHandleSpinBox::SchematicHandleSpinBox(QGraphicsItem *parent)
365 : QGraphicsItem(parent), m_buttonState(Qt::NoButton), m_delta(0) {
366 setFlag(QGraphicsItem::ItemIsSelectable, false);
367 setFlag(QGraphicsItem::ItemIsFocusable, false);
368 m_pixmap = QPixmap(":Resources/schematic_spin_arrows.svg");
369 }
370
371 //--------------------------------------------------------
372
~SchematicHandleSpinBox()373 SchematicHandleSpinBox::~SchematicHandleSpinBox() {}
374
375 //--------------------------------------------------------
376
boundingRect() const377 QRectF SchematicHandleSpinBox::boundingRect() const {
378 return QRectF(0, 0, 10, 10);
379 }
380
381 //--------------------------------------------------------
382
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)383 void SchematicHandleSpinBox::paint(QPainter *painter,
384 const QStyleOptionGraphicsItem *option,
385 QWidget *widget) {
386 QRectF rect = boundingRect();
387 painter->drawPixmap(rect.toRect(), m_pixmap);
388 painter->setBrush(QColor(0, 0, 0, 0));
389 painter->setPen(QColor(128, 128, 128, 255));
390 painter->drawRect(rect);
391 }
392
393 //--------------------------------------------------------
394
mouseMoveEvent(QGraphicsSceneMouseEvent * me)395 void SchematicHandleSpinBox::mouseMoveEvent(QGraphicsSceneMouseEvent *me) {
396 if (m_buttonState == Qt::LeftButton) {
397 bool increase = false;
398 int delta = me->screenPos().y() - me->lastScreenPos().y();
399 if (delta < 0) increase = true;
400 m_delta += abs(delta);
401 if (m_delta > 5) {
402 if (increase)
403 emit(modifyHandle(1));
404 else
405 emit(modifyHandle(-1));
406 m_delta = 0;
407 emit sceneChanged();
408 }
409 }
410 }
411
412 //--------------------------------------------------------
413
mousePressEvent(QGraphicsSceneMouseEvent * me)414 void SchematicHandleSpinBox::mousePressEvent(QGraphicsSceneMouseEvent *me) {
415 m_buttonState = me->button();
416 TUndoManager::manager()->beginBlock();
417 }
418
419 //--------------------------------------------------------
420
mouseReleaseEvent(QGraphicsSceneMouseEvent * me)421 void SchematicHandleSpinBox::mouseReleaseEvent(QGraphicsSceneMouseEvent *me) {
422 m_buttonState = Qt::NoButton;
423 m_delta = 0;
424 TUndoManager::manager()->endBlock();
425 emit handleReleased();
426 }
427
428 //========================================================
429 //
430 // class SchematicLink
431 //
432 //========================================================
433
SchematicLink(QGraphicsItem * parent,QGraphicsScene * scene)434 SchematicLink::SchematicLink(QGraphicsItem *parent, QGraphicsScene *scene)
435 #if QT_VERSION >= 0x050000
436 : QGraphicsItem(parent)
437 #else
438 : QGraphicsItem(parent, scene)
439 #endif
440 , m_startPort(0)
441 , m_endPort(0)
442 , m_path()
443 , m_hitPath()
444 , m_lineShaped(false)
445 , m_highlighted(false) {
446 #if QT_VERSION >= 0x050000
447 scene->addItem(this);
448 #endif
449 setFlag(QGraphicsItem::ItemIsMovable, false);
450 setFlag(QGraphicsItem::ItemIsSelectable, true);
451 setFlag(QGraphicsItem::ItemIsFocusable, false);
452 setZValue(0.0);
453 }
454
455 //--------------------------------------------------------
456
~SchematicLink()457 SchematicLink::~SchematicLink() { m_startPort = m_endPort = 0; }
458
459 //--------------------------------------------------------
460
boundingRect() const461 QRectF SchematicLink::boundingRect() const {
462 return m_hitPath.boundingRect().adjusted(-5, -5, 5, 5);
463 }
464
465 //--------------------------------------------------------
466
shape() const467 QPainterPath SchematicLink::shape() const { return m_hitPath; }
468
469 //--------------------------------------------------------
470
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)471 void SchematicLink::paint(QPainter *painter,
472 const QStyleOptionGraphicsItem *option,
473 QWidget *widget) {
474 SchematicViewer *viewer;
475 FxSchematicScene *fxScene = dynamic_cast<FxSchematicScene *>(scene());
476 StageSchematicScene *stageScene =
477 dynamic_cast<StageSchematicScene *>(scene());
478 if (fxScene) {
479 viewer = fxScene->getSchematicViewer();
480 } else if (stageScene) {
481 viewer = stageScene->getSchematicViewer();
482 } else {
483 return;
484 }
485
486 if (getStartPort() && (getStartPort()->getType() == 100 // eStageSplinePort
487 || getStartPort()->getType() == 202)) { // eFxLinkPort
488 if (isSelected() || isHighlighted())
489 painter->setPen(QPen(viewer->getMotionPathSelectedLinkColor()));
490 else
491 painter->setPen(QColor(viewer->getMotionPathLinkColor()));
492 } else if (isSelected() || isHighlighted())
493 painter->setPen(QPen(viewer->getSelectedLinkColor()));
494
495 else if (!m_lineShaped)
496 painter->setPen(QPen(viewer->getLinkColor()));
497 else
498 painter->setPen(QPen(QColor(170, 170, 10), 0, Qt::DashLine));
499
500 painter->setRenderHint(QPainter::Antialiasing, true);
501 painter->drawPath(m_path);
502 }
503
504 //--------------------------------------------------------
505
updatePath(const QPointF & startPos,const QPointF & endPos)506 void SchematicLink::updatePath(const QPointF &startPos, const QPointF &endPos) {
507 prepareGeometryChange();
508 setPos(startPos);
509 if (!m_lineShaped) {
510 QPointF p0((endPos.x() - startPos.x()) * 0.5, 0);
511 QPointF p1(p0.x(), endPos.y() - startPos.y());
512 QPointF p2(endPos - startPos);
513
514 m_path = QPainterPath(QPointF(0, 0));
515 m_path.cubicTo(p0, p1, p2);
516
517 QPointF h(0, 5);
518 QPointF p = h;
519 if (p2.y() > 0)
520 p.setX(p2.x() > 0 ? -5 : 5);
521 else
522 p.setX(p2.x() > 0 ? 5 : -5);
523 m_hitPath = QPainterPath(QPointF(0, 0));
524 m_hitPath.lineTo(h);
525 m_hitPath.cubicTo(p0 + p, p1 + p, p2 + h);
526 m_hitPath.lineTo(p2 - h);
527 m_hitPath.cubicTo(p1 - p, p0 - p, -h);
528 m_hitPath.lineTo(0, 0);
529 } else {
530 m_path = QPainterPath(QPointF(0, 0));
531 m_path.lineTo(endPos - startPos);
532
533 m_hitPath = QPainterPath(QPointF(0, 0));
534 m_hitPath.lineTo(endPos - startPos);
535 }
536 }
537
538 //--------------------------------------------------------
539
updatePath(SchematicPort * startPort,SchematicPort * endPort)540 void SchematicLink::updatePath(SchematicPort *startPort,
541 SchematicPort *endPort) {
542 updatePath(startPort->getLinkEndPoint(), endPort->getLinkEndPoint());
543 }
544
545 //--------------------------------------------------------
546
updateEndPos(const QPointF & endPos)547 void SchematicLink::updateEndPos(const QPointF &endPos) {
548 if (m_startPort) updatePath(m_startPort->getLinkEndPoint(), endPos);
549 }
550
551 //--------------------------------------------------------
552
getOtherPort(const SchematicPort * port) const553 SchematicPort *SchematicLink::getOtherPort(const SchematicPort *port) const {
554 if (port == m_startPort)
555 return m_endPort;
556 else if (port == m_endPort)
557 return m_startPort;
558 else
559 return 0;
560 }
561
562 //--------------------------------------------------------
563
getOtherNode(const SchematicNode * node) const564 SchematicNode *SchematicLink::getOtherNode(const SchematicNode *node) const {
565 if (node == m_startPort->getNode())
566 return m_endPort->getNode();
567 else if (node == m_endPort->getNode())
568 return m_startPort->getNode();
569 else
570 return 0;
571 }
572
573 //--------------------------------------------------------
574
mousePressEvent(QGraphicsSceneMouseEvent * me)575 void SchematicLink::mousePressEvent(QGraphicsSceneMouseEvent *me) {
576 QPointF pos = me->scenePos();
577 SchematicPort *startPort = getStartPort();
578 SchematicPort *endPort = getEndPort();
579
580 if (!startPort || !endPort) {
581 me->ignore();
582 return;
583 }
584
585 if (startPort && endPort) {
586 QRectF startRect = startPort->boundingRect();
587 startRect.moveTopLeft(startPort->scenePos());
588 QRectF endRect = endPort->boundingRect();
589 endRect.moveTopLeft(endPort->scenePos());
590 if (startRect.contains(pos) || endRect.contains(pos)) {
591 me->ignore();
592 return;
593 }
594 }
595
596 QMatrix matrix = scene()->views()[0]->matrix();
597 #if QT_VERSION >= 0x050000
598 double scaleFactor = sqrt(matrix.determinant());
599 #else
600 double scaleFactor = sqrt(matrix.det());
601 #endif
602
603 QPointF startPos = getStartPort()->getLinkEndPoint();
604 QPointF endPos = getEndPort()->getLinkEndPoint();
605 QPointF p0((endPos.x() - startPos.x()) * 0.5, 0);
606 QPointF p1(p0.x(), endPos.y() - startPos.y());
607 QPointF p2(endPos - startPos);
608 double sensitivity = 5 / scaleFactor;
609 QPointF h(0, sensitivity);
610 QPointF p = h;
611 if (p2.y() > 0)
612 p.setX(p2.x() > 0 ? -sensitivity : sensitivity);
613 else
614 p.setX(p2.x() > 0 ? sensitivity : -sensitivity);
615 QPainterPath path(QPointF(0, 0));
616 path.lineTo(h);
617 path.cubicTo(p0 + p, p1 + p, p2 + h);
618 path.lineTo(p2 - h);
619 path.cubicTo(p1 - p, p0 - p, -h);
620 path.lineTo(0, 0);
621 if (!path.contains(me->scenePos() - scenePos())) {
622 me->ignore();
623 return;
624 }
625
626 if (!isSelected()) {
627 if (me->modifiers() != Qt::ControlModifier) scene()->clearSelection();
628 if (me->button() == Qt::LeftButton || me->button() == Qt::RightButton)
629 setSelected(true);
630 } else {
631 if (me->modifiers() == Qt::ControlModifier &&
632 me->button() == Qt::LeftButton)
633 setSelected(false);
634 }
635 }
636
637 //--------------------------------------------------------
638
mouseReleaseEvent(QGraphicsSceneMouseEvent * me)639 void SchematicLink::mouseReleaseEvent(QGraphicsSceneMouseEvent *me) {
640 if (me->modifiers() != Qt::ControlModifier && me->button() != Qt::RightButton)
641 QGraphicsItem::mouseReleaseEvent(me);
642 }
643
644 //========================================================
645 //
646 // class SchematicPort
647 //
648 //========================================================
649
SchematicPort(QGraphicsItem * parent,SchematicNode * node,int type)650 SchematicPort::SchematicPort(QGraphicsItem *parent, SchematicNode *node,
651 int type)
652 : QGraphicsItem(parent)
653 , m_node(node)
654 , m_buttonState(Qt::NoButton)
655 , m_highlighted(false)
656 , m_linkingTo(0)
657 , m_hook(0, 0)
658 , m_type(type) {
659 #if QT_VERSION >= 0x050000
660 setAcceptHoverEvents(false);
661 #else
662 setAcceptsHoverEvents(false);
663 #endif
664 setFlag(QGraphicsItem::ItemIsSelectable, false);
665 setFlag(QGraphicsItem::ItemIsFocusable, false);
666 }
667
668 //--------------------------------------------------------
669
~SchematicPort()670 SchematicPort::~SchematicPort() { m_links.clear(); }
671
672 //--------------------------------------------------------
673
mouseMoveEvent(QGraphicsSceneMouseEvent * me)674 void SchematicPort::mouseMoveEvent(QGraphicsSceneMouseEvent *me) {
675 if (m_buttonState != Qt::LeftButton) return;
676 if (m_ghostLinks.isEmpty()) return;
677
678 // Snapping
679 SchematicPort *linkingTo = searchPort(me->scenePos());
680 if (!linkingTo) {
681 for (SchematicLink *ghostLink : m_ghostLinks) {
682 ghostLink->updateEndPos(me->scenePos());
683 ghostLink->getStartPort()->showSnappedLinks(m_linkingTo);
684 }
685 if (m_linkingTo) {
686 m_linkingTo->highLight(false);
687 m_linkingTo->update();
688 m_linkingTo = nullptr;
689 }
690 }
691 // if to be connected something
692 else if (linkingTo != this) {
693 m_linkingTo = linkingTo;
694 for (SchematicLink *ghostLink : m_ghostLinks) {
695 ghostLink->updatePath(ghostLink->getStartPort(), linkingTo);
696 ghostLink->getStartPort()->hideSnappedLinks(m_linkingTo);
697 }
698 }
699 // autopan
700 QGraphicsView *viewer = scene()->views()[0];
701 viewer->setInteractive(false);
702 viewer->ensureVisible(QRectF(me->scenePos(), QSizeF(1, 1)), 5, 5);
703 viewer->setInteractive(true);
704 }
705
706 //--------------------------------------------------------
707
mousePressEvent(QGraphicsSceneMouseEvent * me)708 void SchematicPort::mousePressEvent(QGraphicsSceneMouseEvent *me) {
709 if (!isSelected()) {
710 if (me->modifiers() != Qt::ControlModifier) scene()->clearSelection();
711 if (me->button() == Qt::LeftButton || me->button() == Qt::RightButton)
712 getNode()->setSelected(true);
713 } else {
714 if (me->modifiers() == Qt::ControlModifier &&
715 me->button() == Qt::LeftButton)
716 getNode()->setSelected(false);
717 }
718 getNode()->onClicked();
719 if (me->button() == Qt::LeftButton && getType() != 202 // eFxLinkPort
720 && getType() != 203 // eFxGroupedInPort
721 && getType() != 204 // eFxGroupedOutPort
722 && getType() != 103 // eStageSplineGroupPort
723 && getType() != 104 // eStageParentGroupPort
724 && getType() != 105) // eStageChildGroupPort
725 {
726 m_buttonState = Qt::LeftButton;
727 QPointF endPos(me->pos());
728
729 // Enable to connect multiple links from all selected nodes
730 // only when ( Ctrl + ) dragging from the eStageParentPort.
731 if (getType() == 101) { // eStageParentPort
732 QList<QGraphicsItem *> items = scene()->selectedItems();
733 if (items.empty()) return;
734 for (auto const &item : items) {
735 SchematicNode *node = dynamic_cast<SchematicNode *>(item);
736 if (node) {
737 SchematicPort *parentPort =
738 node->getPort(0); // id 0 is for parent port.
739 if (parentPort) {
740 SchematicLink *ghostLink = new SchematicLink(0, scene());
741 ghostLink->setStartPort(parentPort);
742 ghostLink->setZValue(3.0);
743 ghostLink->updateEndPos(me->scenePos());
744 m_ghostLinks.push_back(ghostLink);
745 }
746 }
747 }
748 } else {
749 SchematicLink *ghostLink = new SchematicLink(0, scene());
750 ghostLink->setStartPort(this);
751 ghostLink->setZValue(3.0);
752 ghostLink->updateEndPos(me->scenePos());
753 m_ghostLinks.push_back(ghostLink);
754 }
755 emit(isClicked());
756 }
757 }
758
759 //--------------------------------------------------------
760
mouseReleaseEvent(QGraphicsSceneMouseEvent * me)761 void SchematicPort::mouseReleaseEvent(QGraphicsSceneMouseEvent *me) {
762 if (me->modifiers() != Qt::ControlModifier && me->button() != Qt::RightButton)
763 QGraphicsItem::mouseReleaseEvent(me);
764
765 if (m_buttonState == Qt::LeftButton) emit(isReleased(me->scenePos()));
766
767 // The link is added to the scene only if the user released the left mouse
768 // button over
769 // a SchematicPort different from SchematicPort of the parent node.
770 bool somethingChanged = false;
771 if (m_buttonState == Qt::LeftButton && m_linkingTo) {
772 TUndoManager::manager()->beginBlock();
773 for (SchematicLink *ghostLink : m_ghostLinks) {
774 SchematicPort *port = ghostLink->getStartPort();
775 if (!port) continue;
776 if (!port->isLinkedTo(m_linkingTo) && port->linkTo(m_linkingTo, true)) {
777 port->linkTo(m_linkingTo);
778 somethingChanged = true;
779 } else
780 port->showSnappedLinks(m_linkingTo);
781 }
782 m_buttonState = Qt::NoButton;
783 m_linkingTo = 0;
784 TUndoManager::manager()->endBlock();
785 }
786
787 if (!m_ghostLinks.isEmpty()) {
788 for (SchematicLink *ghostLink : m_ghostLinks)
789 scene()->removeItem(ghostLink);
790 qDeleteAll(m_ghostLinks.begin(), m_ghostLinks.end());
791 m_ghostLinks.clear();
792 }
793
794 if (somethingChanged) {
795 emit sceneChanged();
796 emit xsheetChanged();
797 }
798 }
799
800 //--------------------------------------------------------
801
removeLink(SchematicLink * link)802 void SchematicPort::removeLink(SchematicLink *link) { m_links.removeAll(link); }
803
804 //--------------------------------------------------------
805
eraseLink(SchematicLink * link)806 void SchematicPort::eraseLink(SchematicLink *link) {
807 SchematicPort *otherPort = link->getOtherPort(this);
808 if (otherPort) otherPort->removeLink(link);
809 removeLink(link);
810 if (link->scene()) link->scene()->removeItem(link);
811 delete link;
812 }
813
814 //--------------------------------------------------------
815
eraseAllLinks()816 void SchematicPort::eraseAllLinks() {
817 while (!m_links.empty()) eraseLink(m_links[0]);
818 }
819
820 //--------------------------------------------------------
821
makeLink(SchematicPort * port)822 SchematicLink *SchematicPort::makeLink(SchematicPort *port) {
823 if (isLinkedTo(port) || !port) return 0;
824 SchematicLink *link = new SchematicLink(0, scene());
825 if (getType() == 202 && port->getType() == 202) link->setLineShaped(true);
826
827 link->setStartPort(this);
828 link->setEndPort(port);
829 addLink(link);
830 port->addLink(link);
831 link->updatePath();
832 return link;
833 }
834
835 //--------------------------------------------------------
836
isLinkedTo(SchematicPort * port) const837 bool SchematicPort::isLinkedTo(SchematicPort *port) const {
838 if (m_links.size() == 0) return false;
839 int i;
840 for (i = 0; i < m_links.size(); i++) {
841 SchematicLink *link = m_links[i];
842 if (((link->getStartPort() == this && link->getEndPort() == port) ||
843 (link->getEndPort() == this && link->getStartPort() == port)) &&
844 link->isVisible())
845 return true;
846 }
847 return false;
848 }
849
850 //--------------------------------------------------------
851
updateLinksGeometry()852 void SchematicPort::updateLinksGeometry() {
853 int linkCount = getLinkCount();
854 int i;
855 for (i = 0; i < linkCount; i++) {
856 SchematicLink *link = getLink(i);
857 SchematicPort *startPort = link->getStartPort();
858 SchematicPort *endPort = link->getEndPort();
859 if (startPort && endPort) {
860 link->updatePath(startPort, endPort);
861 link->setPos(startPort->getLinkEndPoint());
862 }
863 }
864 }
865
866 //--------------------------------------------------------
867
getLinkEndPoint() const868 QPointF SchematicPort::getLinkEndPoint() const { return scenePos() + m_hook; }
869
870 //========================================================
871 //
872 // class SchematicNode
873 //
874 //========================================================
875
876 /*! \class SchematicNode schematicnode.h "../inlcude/toonzqt/schematicnode.h"
877 \brief The class provides methods to draw and handle a node item in the
878 SchematicScene.
879 */
880
881 /*! \fn SchematicPort *SchematicNode::getInputPort() const
882 Returns the input SchematicPort of the node.
883 */
884
885 /*! \fn SchematicPort *SchematicNode::getOutputPort() const
886 Returns the output SchematicPort of the node.
887 */
888
889 /*! \fn SchematicScene* SchematicNode::getScene() const
890 Returns the scene where the node is placed.
891 */
892
SchematicNode(SchematicScene * scene)893 SchematicNode::SchematicNode(SchematicScene *scene)
894 #if QT_VERSION >= 0x050000
895 : QGraphicsItem(0)
896 #else
897 : QGraphicsItem(0, scene)
898 #endif
899 , m_scene(scene)
900 , m_width(0)
901 , m_height(0)
902 , m_buttonState(Qt::NoButton) {
903 #if QT_VERSION >= 0x050000
904 scene->addItem(this);
905 #endif
906 setFlag(QGraphicsItem::ItemIsMovable, false);
907 setFlag(QGraphicsItem::ItemIsSelectable, true);
908 setFlag(QGraphicsItem::ItemIsFocusable, false);
909 setZValue(1.0);
910 }
911
912 //--------------------------------------------------------
913
~SchematicNode()914 SchematicNode::~SchematicNode() {}
915
916 //--------------------------------------------------------
917
918 /*!Reimplements the pure virtual QGraphicsItem::boundingRect() method.
919 */
boundingRect() const920 QRectF SchematicNode::boundingRect() const { return QRectF(0, 0, 1, 1); }
921
922 //--------------------------------------------------------
923
924 /*! Reimplements the pure virtual QGraphicsItem::paint() method.
925 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)926 void SchematicNode::paint(QPainter *painter,
927 const QStyleOptionGraphicsItem *option,
928 QWidget *widget) {
929 SchematicViewer *viewer;
930 FxSchematicScene *fxScene = dynamic_cast<FxSchematicScene *>(scene());
931 StageSchematicScene *stageScene =
932 dynamic_cast<StageSchematicScene *>(scene());
933 if (fxScene) {
934 viewer = fxScene->getSchematicViewer();
935 } else if (stageScene) {
936 viewer = stageScene->getSchematicViewer();
937 } else {
938 return;
939 }
940
941 QPen pen;
942 if (isSelected()) {
943 painter->setBrush(QColor(0, 0, 0, 0));
944 pen.setColor(QColor(viewer->getSelectedBorderColor()));
945
946 pen.setWidth(4.0);
947 pen.setJoinStyle(Qt::RoundJoin);
948 painter->setPen(pen);
949 painter->drawRect(-2, -2, m_width + 4, m_height + 4);
950 }
951 pen.setColor(QColor(0, 0, 0, 255));
952 pen.setWidth(0);
953 painter->setPen(pen);
954 }
955
956 //--------------------------------------------------------
957
958 /*! Reimplements the QGraphicsItem::mouseMoveEvent() method.
959 */
mouseMoveEvent(QGraphicsSceneMouseEvent * me)960 void SchematicNode::mouseMoveEvent(QGraphicsSceneMouseEvent *me) {
961 QList<QGraphicsItem *> items = scene()->selectedItems();
962 if (items.empty()) return;
963 QPointF delta = me->scenePos() - me->lastScenePos();
964 QGraphicsView *viewer = scene()->views()[0];
965 for (auto const &item : items) {
966 SchematicNode *node = dynamic_cast<SchematicNode *>(item);
967 if (node) {
968 node->setPosition(node->scenePos() + delta);
969 node->setSchematicNodePos(node->scenePos());
970 node->updateLinksGeometry();
971 }
972 }
973 viewer->setInteractive(false);
974 viewer->ensureVisible(QRectF(me->scenePos(), QSizeF(1, 1)), 5, 5);
975 viewer->setInteractive(true);
976 }
977
978 //--------------------------------------------------------
979
mousePressEvent(QGraphicsSceneMouseEvent * me)980 void SchematicNode::mousePressEvent(QGraphicsSceneMouseEvent *me) {
981 if (!isSelected()) {
982 if (me->modifiers() != Qt::ControlModifier) scene()->clearSelection();
983 if (me->button() == Qt::LeftButton || me->button() == Qt::RightButton)
984 setSelected(true);
985 } else {
986 if (me->modifiers() == Qt::ControlModifier &&
987 me->button() == Qt::LeftButton)
988 setSelected(false);
989 }
990 onClicked();
991 }
992
993 //--------------------------------------------------------
994
mouseReleaseEvent(QGraphicsSceneMouseEvent * me)995 void SchematicNode::mouseReleaseEvent(QGraphicsSceneMouseEvent *me) {
996 if (me->modifiers() != Qt::ControlModifier && me->button() != Qt::RightButton)
997 QGraphicsItem::mouseReleaseEvent(me);
998 }
999
1000 //--------------------------------------------------------
1001 /* Add a pair (portId, SchematicPort*port) in the mapping
1002 */
addPort(int portId,SchematicPort * port)1003 SchematicPort *SchematicNode::addPort(int portId, SchematicPort *port) {
1004 QMap<int, SchematicPort *>::iterator it;
1005 it = m_ports.find(portId);
1006 if (it != m_ports.end() && m_ports[portId] != port) {
1007 SchematicPort *oldPort = m_ports[portId];
1008 m_ports.erase(it);
1009 scene()->removeItem(oldPort);
1010 delete oldPort;
1011 }
1012 m_ports[portId] = port;
1013 return port;
1014 }
1015
1016 //--------------------------------------------------------
1017
1018 /*!Erase the pair (portId, SchematicPort*port) from the mapping*/
erasePort(int portId)1019 void SchematicNode::erasePort(int portId) {
1020 QMap<int, SchematicPort *>::iterator it = m_ports.find(portId);
1021 if (it != m_ports.end()) {
1022 delete it.value();
1023 m_ports.erase(it);
1024 }
1025 }
1026
1027 //--------------------------------------------------------
1028
1029 /*! Returns a pointer to the SchematicPort mapped from \b portId.\n
1030 Returns 0 if \b portId doesn't map no SchematicPort.
1031 */
getPort(int portId) const1032 SchematicPort *SchematicNode::getPort(int portId) const {
1033 QMap<int, SchematicPort *>::const_iterator it = m_ports.find(portId);
1034 if (it != m_ports.end()) return it.value();
1035 return 0;
1036 }
1037
1038 //--------------------------------------------------------
1039
1040 /*! Returns a list of all node connected by links to a SchematicPort identified
1041 * by \b portId.
1042 */
getLinkedNodes(int portId) const1043 QList<SchematicNode *> SchematicNode::getLinkedNodes(int portId) const {
1044 QList<SchematicNode *> list;
1045 SchematicPort *port = getPort(portId);
1046 if (port) {
1047 int linkCount = port->getLinkCount();
1048 int i;
1049 for (i = 0; i < linkCount; i++) list.push_back(port->getLinkedNode(i));
1050 }
1051 return list;
1052 }
1053
1054 //--------------------------------------------------------
1055
updateLinksGeometry()1056 void SchematicNode::updateLinksGeometry() {
1057 QMap<int, SchematicPort *>::iterator it;
1058 for (it = m_ports.begin(); it != m_ports.end(); ++it)
1059 it.value()->updateLinksGeometry();
1060 }
1061