1 /*******************************************************************
2
3 Part of the Fritzing project - http://fritzing.org
4 Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de
5
6 Fritzing is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Fritzing is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Fritzing. If not, see <http://www.gnu.org/licenses/>.
18
19 ********************************************************************
20
21 $Revision: 7000 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-29 07:24:08 +0200 (Mo, 29. Apr 2013) $
24
25 ********************************************************************/
26
27 /*
28
29 curvy To Do
30
31 curvy to begin with? would have to vary with some function of angle and distance
32 could convert control points to t values?
33
34 turn curvature on/off per view
35
36 ---------------------------------------------------------
37
38 later:
39
40 clippable wire
41
42 gerber
43
44 autorouter warning in PCB view
45
46 modify parameters (tension, unit area)?
47
48 */
49
50 /////////////////////////////////////////////////////////////////
51
52 #include "wire.h"
53
54 #include <QLineF>
55 #include <QPen>
56 #include <QRadialGradient>
57 #include <QBrush>
58 #include <QPen>
59 #include <QGraphicsScene>
60 #include <QList>
61 #include <QGraphicsItem>
62 #include <QSet>
63 #include <QComboBox>
64 #include <QToolTip>
65 #include <QApplication>
66 #include <QCheckBox>
67 #include <QHBoxLayout>
68
69 #include "../debugdialog.h"
70 #include "../sketch/infographicsview.h"
71 #include "../connectors/connectoritem.h"
72 #include "../connectors/svgidlayer.h"
73 #include "../fsvgrenderer.h"
74 #include "partlabel.h"
75 #include "../model/modelpart.h"
76 #include "../utils/graphicsutils.h"
77 #include "../utils/textutils.h"
78 #include "../utils/bezier.h"
79 #include "../utils/bezierdisplay.h"
80 #include "../utils/cursormaster.h"
81 #include "../utils/ratsnestcolors.h"
82 #include "../layerattributes.h"
83
84 #include <stdlib.h>
85
86 QVector<qreal> Wire::TheDash;
87 QVector<qreal> RatDash;
88 QBrush BandedBrush(QColor(255, 255, 255));
89
90
91 QHash<QString, QString> Wire::colorTrans;
92 QStringList Wire::colorNames;
93 QHash<int, QString> Wire::widthTrans;
94 QList<int> Wire::widths;
95 double Wire::STANDARD_TRACE_WIDTH;
96 double Wire::HALF_STANDARD_TRACE_WIDTH;
97 double Wire::THIN_TRACE_WIDTH;
98
99 const double DefaultHoverStrokeWidth = 4;
100
101 static Bezier UndoBezier;
102 static BezierDisplay * TheBezierDisplay = NULL;
103
104 ////////////////////////////////////////////////////////////
105
alphaLessThan(QColor * c1,QColor * c2)106 bool alphaLessThan(QColor * c1, QColor * c2)
107 {
108 return c1->alpha() < c2->alpha();
109 }
110
debugCompare(ItemBase * it)111 void debugCompare(ItemBase * it) {
112 Wire * wire = dynamic_cast<Wire *>(it);
113 if (wire) {
114 QRectF r0 = wire->connector0()->rect();
115 QRectF r1 = wire->connector1()->rect();
116 if (qAbs(r0.left() - r1.left()) < 0.1 &&
117 qAbs(r0.right() - r1.right()) < 0.1 &&
118 qAbs(r0.top() - r1.top()) < 0.1 &&
119 qAbs(r0.bottom() - r1.bottom()) < 0.1)
120 {
121 wire->debugInfo("zero wire");
122 if (wire->viewID() == ViewLayer::PCBView) {
123 DebugDialog::debug("in pcb");
124 }
125 }
126 }
127 }
128
129 /////////////////////////////////////////////////////////////
130
WireAction(QAction * action)131 WireAction::WireAction(QAction * action) : QAction(action) {
132 m_wire = NULL;
133 this->setText(action->text());
134 this->setStatusTip(action->statusTip());
135 this->setCheckable(action->isCheckable());
136 }
137
WireAction(const QString & title,QObject * parent)138 WireAction::WireAction(const QString & title, QObject * parent) : QAction(title, parent) {
139 m_wire = NULL;
140 }
141
setWire(Wire * w)142 void WireAction::setWire(Wire * w) {
143 m_wire = w;
144 }
145
wire()146 Wire * WireAction::wire() {
147 return m_wire;
148 }
149
150 /////////////////////////////////////////////////////////////
151
Wire(ModelPart * modelPart,ViewLayer::ViewID viewID,const ViewGeometry & viewGeometry,long id,QMenu * itemMenu,bool initLabel)152 Wire::Wire( ModelPart * modelPart, ViewLayer::ViewID viewID, const ViewGeometry & viewGeometry, long id, QMenu* itemMenu, bool initLabel)
153 : ItemBase(modelPart, viewID, viewGeometry, id, itemMenu)
154 {
155 m_banded = false;
156 m_bezier = NULL;
157 m_displayBendpointCursor = m_canHaveCurve = true;
158 m_hoverStrokeWidth = DefaultHoverStrokeWidth;
159 m_connector0 = m_connector1 = NULL;
160 m_partLabel = initLabel ? new PartLabel(this, NULL) : NULL;
161 m_canChainMultiple = false;
162 setFlag(QGraphicsItem::ItemIsSelectable, true );
163 m_connectorHover = NULL;
164 m_opacity = 1.0;
165 m_ignoreSelectionChange = false;
166
167 //DebugDialog::debug(QString("aix line %1 %2 %3 %4").arg(this->viewGeometry().line().x1())
168 //.arg(this->viewGeometry().line().y1())
169 //.arg(this->viewGeometry().line().x2())
170 //.arg(this->viewGeometry().line().y2()) );
171 //DebugDialog::debug(QString("aix loc %1 %2").arg(this->viewGeometry().loc().x())
172 //.arg(this->viewGeometry().loc().y()) );
173
174 setPos(m_viewGeometry.loc());
175
176 m_dragCurve = m_dragEnd = false;
177 }
178
~Wire()179 Wire::~Wire() {
180 if (m_bezier) {
181 delete m_bezier;
182 }
183 }
184
setUp(ViewLayer::ViewLayerID viewLayerID,const LayerHash & viewLayers,InfoGraphicsView * infoGraphicsView)185 FSvgRenderer * Wire::setUp(ViewLayer::ViewLayerID viewLayerID, const LayerHash & viewLayers, InfoGraphicsView * infoGraphicsView) {
186 ItemBase::setViewLayerID(viewLayerID, viewLayers);
187 FSvgRenderer * svgRenderer = setUpConnectors(m_modelPart, m_viewID);
188 if (svgRenderer != NULL) {
189 initEnds(m_viewGeometry, svgRenderer->viewBox(), infoGraphicsView);
190 //debugCompare(this);
191 }
192 setZValue(this->z());
193
194 return svgRenderer;
195 }
196
saveGeometry()197 void Wire::saveGeometry() {
198 m_viewGeometry.setSelected(this->isSelected());
199 m_viewGeometry.setLine(this->line());
200 m_viewGeometry.setLoc(this->pos());
201 m_viewGeometry.setZ(this->zValue());
202 }
203
204
itemMoved()205 bool Wire::itemMoved() {
206 if (m_viewGeometry.loc() != this->pos()) return true;
207
208 if (this->line().dx() != m_viewGeometry.line().dx()) return false;
209 if (this->line().dy() != m_viewGeometry.line().dy()) return false;
210
211 return (this->line() != m_viewGeometry.line());
212 }
213
moveItem(ViewGeometry & viewGeometry)214 void Wire::moveItem(ViewGeometry & viewGeometry) {
215 this->setPos(viewGeometry.loc());
216 this->setLine(viewGeometry.line());
217 }
218
initEnds(const ViewGeometry & vg,QRectF defaultRect,InfoGraphicsView * infoGraphicsView)219 void Wire::initEnds(const ViewGeometry & vg, QRectF defaultRect, InfoGraphicsView * infoGraphicsView) {
220 bool gotOne = false;
221 bool gotTwo = false;
222 double penWidth = 1;
223 foreach (ConnectorItem * item, cachedConnectorItems()) {
224 // check the name or is order good enough?
225
226 if (gotOne) {
227 gotTwo = true;
228 m_connector1 = item;
229 break;
230 }
231 else {
232 penWidth = item->rect().width();
233 m_connector0 = item;
234 gotOne = true;
235 }
236 }
237
238 if (!gotTwo) {
239 return;
240 }
241
242 if ((vg.line().length() == 0) && (vg.line().x1() == -1)) {
243 this->setLine(defaultRect.left(), defaultRect.top(), defaultRect.right(), defaultRect.bottom());
244 }
245 else {
246 this->setLine(vg.line());
247 }
248
249 setConnector0Rect();
250 setConnector1Rect();
251 m_viewGeometry.setLine(this->line());
252
253 QBrush brush(QColor(0, 0, 0));
254 QPen pen(brush, penWidth, Qt::SolidLine, Qt::RoundCap);
255 this->setPen(pen);
256
257 m_pen.setCapStyle(Qt::RoundCap);
258 m_shadowPen.setCapStyle(Qt::RoundCap);
259 if (infoGraphicsView != NULL) {
260 infoGraphicsView->initWire(this, penWidth);
261 }
262
263 prepareGeometryChange();
264 }
265
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)266 void Wire::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget ) {
267 if (m_hidden) return;
268
269 ItemBase::paint(painter, option, widget);
270 }
271
paintBody(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)272 void Wire::paintBody(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget )
273 {
274 Q_UNUSED(option);
275 Q_UNUSED(widget);
276
277 QPainterPath painterPath;
278 if (m_bezier && !m_bezier->isEmpty()) {
279 QLineF line = this->line();
280 painterPath.moveTo(line.p1());
281 painterPath.cubicTo(m_bezier->cp0(), m_bezier->cp1(), line.p2());
282
283 /*
284 DebugDialog::debug(QString("c0x:%1,c0y:%2 c1x:%3,c1y:%4 p0x:%5,p0y:%6 p1x:%7,p1y:%8 px:%9,py:%10")
285 .arg(m_controlPoints.at(0).x())
286 .arg(m_controlPoints.at(0).y())
287 .arg(m_controlPoints.at(1).x())
288 .arg(m_controlPoints.at(1).y())
289 .arg(m_line.p1().x())
290 .arg(m_line.p1().y())
291 .arg(m_line.p2().x())
292 .arg(m_line.p2().y())
293 .arg(pos().x())
294 .arg(pos().y())
295
296 );
297 */
298 }
299
300
301 painter->setOpacity(m_inactive ? m_opacity / 2 : m_opacity);
302 if (hasShadow()) {
303 painter->save();
304 painter->setPen(m_shadowPen);
305 if (painterPath.isEmpty()) {
306 QLineF line = this->line();
307 painter->drawLine(line);
308 }
309 else {
310 painter->drawPath(painterPath);
311 }
312 painter->restore();
313 }
314
315 // DebugDialog::debug(QString("pen width %1 %2").arg(m_pen.widthF()).arg(m_viewID));
316
317 if (m_banded) {
318 QBrush brush = m_pen.brush();
319 m_pen.setStyle(Qt::SolidLine);
320 m_pen.setBrush(BandedBrush);
321 painter->setPen(m_pen);
322 if (painterPath.isEmpty()) {
323 painter->drawLine(getPaintLine());
324 }
325 else {
326 painter->drawPath(painterPath);
327 }
328 m_pen.setBrush(brush);
329 m_pen.setDashPattern(TheDash);
330 m_pen.setCapStyle(Qt::FlatCap);
331 }
332
333 if (getRatsnest()) {
334 m_pen.setDashPattern(RatDash);
335 }
336 painter->setPen(m_pen);
337 if (painterPath.isEmpty()) {
338 painter->drawLine(getPaintLine());
339 }
340 else {
341 painter->drawPath(painterPath);
342 }
343
344 if (m_banded) {
345 m_pen.setStyle(Qt::SolidLine);
346 m_pen.setCapStyle(Qt::RoundCap);
347 }
348 }
349
paintHover(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)350 void Wire::paintHover(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
351 {
352 Q_UNUSED(widget);
353 Q_UNUSED(option);
354 painter->save();
355 if ((m_connectorHoverCount > 0 && !(m_dragEnd || m_dragCurve)) || m_connectorHoverCount2 > 0) {
356 painter->setOpacity(.50);
357 painter->fillPath(this->hoverShape(), QBrush(ConnectorHoverColor));
358 }
359 else {
360 painter->setOpacity(HoverOpacity);
361 painter->fillPath(this->hoverShape(), QBrush(HoverColor));
362 }
363 painter->restore();
364 }
365
hoverShape() const366 QPainterPath Wire::hoverShape() const
367 {
368 return shapeAux(m_hoverStrokeWidth);
369 }
370
shape() const371 QPainterPath Wire::shape() const
372 {
373 return shapeAux(m_pen.widthF());
374 }
375
shapeAux(double width) const376 QPainterPath Wire::shapeAux(double width) const
377 {
378 QPainterPath path;
379 if (m_line == QLineF()) {
380 return path;
381 }
382
383 path.moveTo(m_line.p1());
384 if (m_bezier == NULL || m_bezier->isEmpty()) {
385 path.lineTo(m_line.p2());
386 }
387 else {
388 path.cubicTo(m_bezier->cp0(), m_bezier->cp1(), m_line.p2());
389 }
390 //DebugDialog::debug(QString("using hoverstrokewidth %1 %2").arg(m_id).arg(m_hoverStrokeWidth));
391 return GraphicsUtils::shapeFromPath(path, m_pen, width, false);
392 }
393
boundingRect() const394 QRectF Wire::boundingRect() const
395 {
396 if (m_pen.widthF() == 0.0) {
397 const double x1 = m_line.p1().x();
398 const double x2 = m_line.p2().x();
399 const double y1 = m_line.p1().y();
400 const double y2 = m_line.p2().y();
401 double lx = qMin(x1, x2);
402 double rx = qMax(x1, x2);
403 double ty = qMin(y1, y2);
404 double by = qMax(y1, y2);
405 return QRectF(lx, ty, rx - lx, by - ty);
406 }
407 return hoverShape().controlPointRect();
408 }
409
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)410 void Wire::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
411 //DebugDialog::debug("checking press event");
412 emit wireSplitSignal(this, event->scenePos(), this->pos(), this->line());
413 }
414
contextMenuEvent(QGraphicsSceneContextMenuEvent * event)415 void Wire::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
416 {
417 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
418 if (infoGraphicsView != NULL) {
419 infoGraphicsView->setActiveWire(this);
420 }
421
422 ItemBase::contextMenuEvent(event);
423 }
424
mousePressEvent(QGraphicsSceneMouseEvent * event)425 void Wire::mousePressEvent(QGraphicsSceneMouseEvent *event)
426 {
427 ItemBase::mousePressEvent(event);
428 }
429
initDragCurve(QPointF scenePos)430 void Wire::initDragCurve(QPointF scenePos) {
431 if (m_bezier == NULL) {
432 m_bezier = new Bezier();
433 }
434
435 UndoBezier.copy(m_bezier);
436
437 m_dragCurve = true;
438 m_dragEnd = false;
439
440 QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL);
441 QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL);
442 if (m_bezier->isEmpty()) {
443 m_bezier->initToEnds(mapFromScene(p0), mapFromScene(p1));
444 }
445 else {
446 m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1));
447 }
448
449 m_bezier->initControlIndex(mapFromScene(scenePos), m_pen.widthF());
450 TheBezierDisplay = new BezierDisplay;
451 TheBezierDisplay->initDisplay(this, m_bezier);
452 }
453
initNewBendpoint(QPointF scenePos,Bezier & left,Bezier & right)454 bool Wire::initNewBendpoint(QPointF scenePos, Bezier & left, Bezier & right) {
455 if (m_bezier == NULL || m_bezier->isEmpty()) {
456 UndoBezier.clear();
457 return false;
458 }
459
460 QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL);
461 QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL);
462 m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1));
463 UndoBezier.copy(m_bezier);
464
465 double t = m_bezier->findSplit(mapFromScene(scenePos), m_pen.widthF());
466 m_bezier->split(t, left, right);
467 return true;
468 }
469
initDragEnd(ConnectorItem * connectorItem,QPointF scenePos)470 void Wire::initDragEnd(ConnectorItem * connectorItem, QPointF scenePos) {
471 Q_UNUSED(scenePos);
472 saveGeometry();
473 QLineF line = this->line();
474 m_drag0 = (connectorItem == m_connector0);
475 //debugInfo("setting drag end to true");
476 m_dragEnd = true;
477 m_dragCurve = false;
478 if (m_drag0) {
479 m_wireDragOrigin = line.p2();
480 //DebugDialog::debug(QString("drag near origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) );
481 }
482 else {
483 m_wireDragOrigin = line.p1();
484 //DebugDialog::debug(QString("drag far origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) );
485 //DebugDialog::debug(QString("drag far other %1 %2").arg(line.p2().x()).arg(line.p2().y()) );
486 }
487
488 if (connectorItem->chained()) {
489 QList<Wire *> chained;
490 QList<ConnectorItem *> ends;
491 collectChained(chained, ends);
492 // already saved the first one
493 for (int i = 1; i < chained.count(); i++) {
494 chained[i]->saveGeometry();
495 }
496 }
497 }
498
499
mouseReleaseConnectorEvent(ConnectorItem * connectorItem,QGraphicsSceneMouseEvent * event)500 void Wire::mouseReleaseConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
501 Q_UNUSED(event);
502 Q_UNUSED(connectorItem);
503 releaseDrag();
504 }
505
mouseMoveConnectorEvent(ConnectorItem * connectorItem,QGraphicsSceneMouseEvent * event)506 void Wire::mouseMoveConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
507 mouseMoveEventAux(this->mapFromItem(connectorItem, event->pos()), event->modifiers());
508 }
509
mouseMoveEvent(QGraphicsSceneMouseEvent * event)510 void Wire::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
511 mouseMoveEventAux(event->pos(), event->modifiers());
512 }
513
mouseMoveEventAux(QPointF eventPos,Qt::KeyboardModifiers modifiers)514 void Wire::mouseMoveEventAux(QPointF eventPos, Qt::KeyboardModifiers modifiers) {
515 if (m_spaceBarWasPressed) {
516 return;
517 }
518
519 if (m_dragCurve) {
520 prepareGeometryChange();
521 dragCurve(eventPos, modifiers);
522 update();
523 if (TheBezierDisplay) TheBezierDisplay->updateDisplay(this, m_bezier);
524 return;
525 }
526
527 if (m_dragEnd == false) {
528 return;
529 }
530
531 //debugInfo("dragging wire");
532
533 ConnectorItem * whichConnectorItem;
534 ConnectorItem * otherConnectorItem;
535 if (m_drag0) {
536 whichConnectorItem = m_connector0;
537 otherConnectorItem = m_connector1;
538 }
539 else {
540 whichConnectorItem = m_connector1;
541 otherConnectorItem = m_connector0;
542 }
543
544 if ((modifiers & Qt::ShiftModifier) != 0) {
545 QPointF initialPos = mapFromScene(otherConnectorItem->sceneAdjustedTerminalPoint(NULL));
546 bool bendpoint = isBendpoint(whichConnectorItem);
547 if (bendpoint) {
548 bendpoint = false;
549 foreach (ConnectorItem * ci, whichConnectorItem->connectedToItems()) {
550 Wire * w = qobject_cast<Wire *>(ci->attachedTo());
551 ConnectorItem * oci = w->otherConnector(ci);
552 QPointF otherInitialPos = mapFromScene(oci->sceneAdjustedTerminalPoint(NULL));
553 QPointF p1(initialPos.x(), otherInitialPos.y());
554 double d = GraphicsUtils::distanceSqd(p1, eventPos);
555 if (d <= 144) {
556 bendpoint = true;
557 eventPos = p1;
558 break;
559 }
560 p1.setX(otherInitialPos.x());
561 p1.setY(initialPos.y());
562 d = GraphicsUtils::distanceSqd(p1, eventPos);
563 if (d <= 144) {
564 bendpoint = true;
565 eventPos = p1;
566 break;
567 }
568 }
569 }
570
571 if (!bendpoint) {
572 eventPos = GraphicsUtils::calcConstraint(initialPos, eventPos);
573 }
574
575 }
576
577 if (m_drag0) {
578 QPointF p = this->mapToScene(eventPos);
579 QGraphicsSvgItem::setPos(p.x(), p.y());
580 this->setLine(0, 0, m_wireDragOrigin.x() - p.x() + m_viewGeometry.loc().x(),
581 m_wireDragOrigin.y() - p.y() + m_viewGeometry.loc().y() );
582 //DebugDialog::debug(QString("drag0 wdo:(%1,%2) p:(%3,%4) vg:(%5,%6) l:(%7,%8)")
583 // .arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y())
584 // .arg(p.x()).arg(p.y())
585 // .arg(m_viewGeometry.loc().x()).arg(m_viewGeometry.loc().y())
586 // .arg(line().p2().x()).arg(line().p2().y())
587 // );
588 }
589 else {
590 this->setLine(m_wireDragOrigin.x(), m_wireDragOrigin.y(), eventPos.x(), eventPos.y());
591 //DebugDialog::debug(QString("drag1 wdo:(%1,%2) ep:(%3,%4) p:(%5,%6) l:(%7,%8)")
592 // .arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y())
593 // .arg(eventPos.x()).arg(eventPos.y())
594 // .arg(pos().x()).arg(pos().y())
595 // .arg(line().p2().x()).arg(line().p2().y())
596 // );
597 }
598 setConnector1Rect();
599
600
601 QSet<ConnectorItem *> allTo;
602 allTo.insert(whichConnectorItem);
603 foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) {
604 Wire * chainedWire = qobject_cast<Wire *>(toConnectorItem->attachedTo());
605 if (chainedWire == NULL) continue;
606
607 allTo.insert(toConnectorItem);
608 foreach (ConnectorItem * subTo, toConnectorItem->connectedToItems()) {
609 allTo.insert(subTo);
610 }
611 }
612 allTo.remove(whichConnectorItem);
613
614 // TODO: this could all be determined once at mouse press time
615
616 if (allTo.count() == 0) {
617 // dragging one end of the wire
618
619 // don't allow wire to connect back to something the other end is already directly connected to
620 // an alternative would be to exclude all connectors in the net connected by the same kind of trace
621 QList<Wire *> wires;
622 QList<ConnectorItem *> ends;
623 collectChained(wires, ends);
624
625 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
626 //DebugDialog::debug("------------------------");
627
628 QList<ConnectorItem *> exclude;
629 foreach (ConnectorItem * end, ends) {
630 exclude << end;
631 foreach (ConnectorItem * ci, end->connectedToItems()) {
632 // if there is a wire growing out of one of the excluded ends, exclude the attached end
633 exclude << ci;
634 }
635 foreach (ConnectorItem * toConnectorItem, end->connectedToItems()) {
636 if (toConnectorItem->attachedToItemType() != ModelPart::Wire) continue;
637
638 Wire * w = qobject_cast<Wire *>(toConnectorItem->attachedTo());
639 if (w->getRatsnest()) continue;
640 if (!w->isTraceType(infoGraphicsView->getTraceFlag())) continue;
641
642 //w->debugInfo("what wire");
643
644 QList<ConnectorItem *> ends2;
645 QList<Wire *> wires2;
646 w->collectChained(wires2, ends2);
647 exclude.append(ends2);
648 foreach (ConnectorItem * e2, ends2) {
649 foreach (ConnectorItem * ci, e2->connectedToItems()) {
650 // if there is a wire growing out of one of the excluded ends, exclude that end of the wire
651 exclude << ci;
652 }
653 }
654 foreach (Wire * w2, wires2) {
655 exclude.append(w2->cachedConnectorItems());
656 }
657 }
658 }
659
660
661 // but allow to restore connections at this end (collect chained above got both ends of this wire)
662 foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) {
663 if (ends.contains(toConnectorItem)) exclude.removeAll(toConnectorItem);
664 }
665
666 //DebugDialog::debug("");
667 //DebugDialog::debug("__________________");
668 //foreach (ConnectorItem * end, exclude) end->debugInfo("exclude");
669
670 ConnectorItem * originatingConnector = NULL;
671 if (otherConnectorItem) {
672 foreach (ConnectorItem * toConnectorItem, otherConnectorItem->connectedToItems()) {
673 if (ends.contains(toConnectorItem)) {
674 originatingConnector = toConnectorItem;
675 break;
676 }
677 }
678 }
679
680 whichConnectorItem->findConnectorUnder(false, true, exclude, true, originatingConnector);
681 }
682 else {
683 // dragging a bendpoint
684 foreach (ConnectorItem * toConnectorItem, allTo) {
685 Wire * chained = qobject_cast<Wire *>(toConnectorItem->attachedTo());
686 if (chained) {
687 chained->simpleConnectedMoved(whichConnectorItem, toConnectorItem);
688 }
689 }
690 }
691 }
692
setConnector0Rect()693 void Wire::setConnector0Rect() {
694 QRectF rect = m_connector0->rect();
695 rect.moveTo(0 - (rect.width() / 2.0),
696 0 - (rect.height() / 2.0) );
697 m_connector0->setRect(rect);
698
699 //debugCompare(this);
700
701 // QPointF p = m_connector0->mapToScene(m_connector0->rect().center());
702 // m_connector0->debugInfo(QString("c0:%1 %2").arg(p.x()).arg(p.y()));
703 // p = m_connector1->mapToScene(m_connector1->rect().center());
704 // m_connector1->debugInfo(QString("c1:%1 %2").arg(p.x()).arg(p.y()));
705
706 }
707
708
setConnector1Rect()709 void Wire::setConnector1Rect() {
710 QRectF rect = m_connector1->rect();
711 rect.moveTo(this->line().dx() - (rect.width() / 2.0),
712 this->line().dy() - (rect.height() / 2.0) );
713 m_connector1->setRect(rect);
714
715 //debugCompare(this);
716
717 // QPointF p = m_connector0->mapToScene(m_connector0->rect().center());
718 // m_connector0->debugInfo(QString("c0:%1 %2").arg(p.x()).arg(p.y()));
719 // p = m_connector1->mapToScene(m_connector1->rect().center());
720 // m_connector1->debugInfo(QString("c1:%1 %2").arg(p.x()).arg(p.y()));
721 }
722
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)723 void Wire::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
724 if (m_spaceBarWasPressed) {
725 return;
726 }
727
728 //debugInfo("wire release drag");
729 if (releaseDrag()) return;
730
731 ItemBase::mouseReleaseEvent(event);
732 }
733
releaseDrag()734 bool Wire::releaseDrag() {
735 if (m_dragEnd == false && m_dragCurve == false) return false;
736
737 if (m_dragCurve) {
738 delete TheBezierDisplay;
739 TheBezierDisplay = NULL;
740 m_dragCurve = false;
741 ungrabMouse();
742 if (UndoBezier != *m_bezier) {
743 emit wireChangedCurveSignal(this, &UndoBezier, m_bezier, false);
744 }
745 return true;
746 }
747
748 //debugInfo("clearing drag end");
749 m_dragEnd = false;
750
751 ConnectorItem * from = (m_drag0) ? m_connector0 : m_connector1;
752 ConnectorItem * to = from->releaseDrag();
753
754 QLineF newLine = this->line();
755 QLineF oldLine = m_viewGeometry.line();
756 QPointF oldPos = m_viewGeometry.loc();
757 QPointF newPos = this->pos();
758 if (newLine != oldLine || oldPos != newPos) {
759 emit wireChangedSignal(this, oldLine, newLine, oldPos, newPos, from, to);
760 }
761
762 return true;
763 }
764
765
saveInstanceLocation(QXmlStreamWriter & streamWriter)766 void Wire::saveInstanceLocation(QXmlStreamWriter & streamWriter)
767 {
768 QLineF line = m_viewGeometry.line();
769 QPointF loc = m_viewGeometry.loc();
770 streamWriter.writeAttribute("x", QString::number(loc.x()));
771 streamWriter.writeAttribute("y", QString::number(loc.y()));
772 streamWriter.writeAttribute("x1", QString::number(line.x1()));
773 streamWriter.writeAttribute("y1", QString::number(line.y1()));
774 streamWriter.writeAttribute("x2", QString::number(line.x2()));
775 streamWriter.writeAttribute("y2", QString::number(line.y2()));
776 streamWriter.writeAttribute("wireFlags", QString::number(m_viewGeometry.flagsAsInt()));
777 }
778
writeGeometry(QXmlStreamWriter & streamWriter)779 void Wire::writeGeometry(QXmlStreamWriter & streamWriter) {
780 ItemBase::writeGeometry(streamWriter);
781 streamWriter.writeStartElement("wireExtras");
782 streamWriter.writeAttribute("mils", QString::number(mils()));
783 streamWriter.writeAttribute("color", m_pen.brush().color().name());
784 streamWriter.writeAttribute("opacity", QString::number(m_opacity));
785 streamWriter.writeAttribute("banded", m_banded ? "1" : "0");
786 if (m_bezier) m_bezier->write(streamWriter);
787 streamWriter.writeEndElement();
788 }
789
setExtras(QDomElement & element,InfoGraphicsView * infoGraphicsView)790 void Wire::setExtras(QDomElement & element, InfoGraphicsView * infoGraphicsView)
791 {
792 if (element.isNull()) return;
793
794 bool ok;
795 double w = element.attribute("width").toDouble(&ok);
796 if (ok) {
797 setWireWidth(w, infoGraphicsView, infoGraphicsView->getWireStrokeWidth(this, w));
798 }
799 else {
800 w = element.attribute("mils").toDouble(&ok);
801 if (ok) {
802 double wpix = GraphicsUtils::mils2pixels(w, GraphicsUtils::SVGDPI);
803 setWireWidth(wpix, infoGraphicsView, infoGraphicsView->getWireStrokeWidth(this, wpix));
804 }
805 }
806
807 m_banded = (element.attribute("banded", "") == "1");
808
809 setColorFromElement(element);
810 QDomElement bElement = element.firstChildElement("bezier");
811 Bezier bezier = Bezier::fromElement(bElement);
812 if (!bezier.isEmpty()) {
813 prepareGeometryChange();
814 m_bezier = new Bezier;
815 m_bezier->copy(&bezier);
816 QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL);
817 QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL);
818 m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1));
819 }
820
821 }
822
setColorFromElement(QDomElement & element)823 void Wire::setColorFromElement(QDomElement & element) {
824 QString colorString = element.attribute("color");
825 if (colorString.isNull() || colorString.isEmpty()) return;
826
827 bool ok;
828 double op = element.attribute("opacity").toDouble(&ok);
829 if (!ok) {
830 op = 1.0;
831 }
832
833 setColorString(colorString, op, false);
834 }
835
hoverEnterConnectorItem(QGraphicsSceneHoverEvent * event,ConnectorItem * item)836 void Wire::hoverEnterConnectorItem(QGraphicsSceneHoverEvent * event , ConnectorItem * item) {
837 m_connectorHover = item;
838 ItemBase::hoverEnterConnectorItem(event, item);
839 }
840
hoverLeaveConnectorItem(QGraphicsSceneHoverEvent * event,ConnectorItem * item)841 void Wire::hoverLeaveConnectorItem(QGraphicsSceneHoverEvent * event, ConnectorItem * item) {
842 m_connectorHover = NULL;
843 ItemBase::hoverLeaveConnectorItem(event, item);
844 }
845
hoverEnterEvent(QGraphicsSceneHoverEvent * event)846 void Wire::hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) {
847 ItemBase::hoverEnterEvent(event);
848 CursorMaster::instance()->addCursor(this, cursor());
849 //DebugDialog::debug("---wire set override cursor");
850 updateCursor(event->modifiers());
851 }
852
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)853 void Wire::hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ) {
854 ItemBase::hoverLeaveEvent(event);
855 //DebugDialog::debug("------wire restore override cursor");
856 CursorMaster::instance()->removeCursor(this);
857 }
858
859
connectionChange(ConnectorItem * onMe,ConnectorItem * onIt,bool connect)860 void Wire::connectionChange(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) {
861 checkVisibility(onMe, onIt, connect);
862
863 bool movable = true;
864 foreach (ConnectorItem * connectedTo, m_connector0->connectedToItems()) {
865 if (connectedTo->attachedToItemType() != ModelPart::Wire) {
866 movable = false;
867 break;
868 }
869 }
870 if (movable) {
871 foreach (ConnectorItem * connectedTo, m_connector1->connectedToItems()) {
872 if (connectedTo->attachedToItemType() != ModelPart::Wire) {
873 movable = false;
874 break;
875 }
876 }
877 }
878 }
879
mouseDoubleClickConnectorEvent(ConnectorItem * connectorItem)880 void Wire::mouseDoubleClickConnectorEvent(ConnectorItem * connectorItem) {
881 int chained = 0;
882 foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) {
883 if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
884 chained++;
885 }
886 else {
887 return;
888 }
889 }
890
891
892 if (chained == 1) {
893 // near as I can tell, this is to eliminate the overrides from the connectorItem and then from the wire itself
894 emit wireJoinSignal(this, connectorItem);
895 }
896 }
897
mousePressConnectorEvent(ConnectorItem * connectorItem,QGraphicsSceneMouseEvent * event)898 void Wire::mousePressConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
899 //DebugDialog::debug("checking press connector event");
900
901 if (m_canChainMultiple && event->modifiers() & altOrMetaModifier()) {
902 // dragging a wire out of a bendpoint
903 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
904 if (infoGraphicsView != NULL) {
905 infoGraphicsView->mousePressConnectorEvent(connectorItem, event);
906 }
907
908 return;
909 }
910
911
912 connectorItem->setOverConnectorItem(NULL);
913 initDragEnd(connectorItem, event->scenePos());
914
915 }
916
simpleConnectedMoved(ConnectorItem * to)917 void Wire::simpleConnectedMoved(ConnectorItem * to) {
918 // to is this wire, from is something else
919 simpleConnectedMoved(to->firstConnectedToIsh(), to);
920 }
921
simpleConnectedMoved(ConnectorItem * from,ConnectorItem * to)922 void Wire::simpleConnectedMoved(ConnectorItem * from, ConnectorItem * to)
923 {
924 if (from == NULL) return;
925
926 //if (from) from->debugInfo("connected moved from");
927 //if (to) to->debugInfo("\tto");
928
929 // to is this wire, from is something else
930 QPointF p1, p2;
931 calcNewLine(from, to, p1, p2);
932
933 /*
934 QPointF oldPos = this->pos();
935 QPointF newPos = p1;
936 QLineF oldLine = this->line();
937 QLineF newLine(0, 0, p2.x() - p1.x(), p2.y() - p1.y());
938 if (qAbs(oldPos.x() - newPos.x()) > 1.75 ||
939 qAbs(oldPos.y() - newPos.y()) > 1.75 ||
940 qAbs(oldLine.x1() - newLine.x1()) > 1.75 ||
941 qAbs(oldLine.x2() - newLine.x2()) > 1.75 ||
942 qAbs(oldLine.y1() - newLine.y1()) > 1.75 ||
943 qAbs(oldLine.y2() - newLine.y2()) > 1.75
944 )
945 {
946 DebugDialog::debug("line changed");
947 calcNewLine(from,to,p1,p2);
948 }
949 */
950
951 this->setPos(p1);
952 this->setLine(0,0, p2.x() - p1.x(), p2.y() - p1.y() );
953 //debugInfo(QString("set line %1 %2, %3 %4, vis:%5").arg(p1.x()).arg(p1.y()).arg(p2.x()).arg(p2.y()).arg(isVisible()) );
954 setConnector1Rect();
955 }
956
calcNewLine(ConnectorItem * from,ConnectorItem * to,QPointF & p1,QPointF & p2)957 void Wire::calcNewLine(ConnectorItem * from, ConnectorItem * to, QPointF & p1, QPointF & p2) {
958 // to is this wire, from is something else
959 if (to == m_connector0) {
960 p1 = from->sceneAdjustedTerminalPoint(to);
961 ConnectorItem * otherFrom = m_connector1->firstConnectedToIsh();
962 if (otherFrom == NULL) {
963 p2 = m_connector1->mapToScene(m_connector1->rect().center());
964 }
965 else {
966 p2 = otherFrom->sceneAdjustedTerminalPoint(m_connector1);
967 }
968 }
969 else {
970 p2 = from->sceneAdjustedTerminalPoint(to);
971 ConnectorItem * otherFrom = m_connector0->firstConnectedToIsh();
972 if (otherFrom == NULL) {
973 p1 = m_connector0->mapToScene(m_connector0->rect().center());
974 }
975 else {
976 p1 = otherFrom->sceneAdjustedTerminalPoint(m_connector0);
977 }
978
979 }
980 }
981
connectedMoved(ConnectorItem * from,ConnectorItem * to,QList<ConnectorItem * > & already)982 void Wire::connectedMoved(ConnectorItem * from, ConnectorItem * to, QList<ConnectorItem *> & already) {
983 Q_UNUSED(already);
984
985 // "from" is the connector on the part
986 // "to" is the connector on the wire
987
988 //from->debugInfo("connected moved");
989 //to->debugInfo("\tconnected moved");
990
991 if (from->connectedToItems().contains(to) || to->connectedToItems().contains(from)) {
992 simpleConnectedMoved(from, to);
993 }
994 else {
995 //from->debugInfo("not connected");
996 //to->debugInfo("\t");
997 }
998 }
999
1000
setUpConnectors(ModelPart * modelPart,ViewLayer::ViewID viewID)1001 FSvgRenderer * Wire::setUpConnectors(ModelPart * modelPart, ViewLayer::ViewID viewID)
1002 {
1003 clearConnectorItemCache();
1004
1005 LayerAttributes layerAttributes;
1006 this->initLayerAttributes(layerAttributes, viewID, m_viewLayerID, m_viewLayerPlacement, false, false);
1007 FSvgRenderer * renderer = ItemBase::setUpImage(modelPart, layerAttributes);
1008 if (renderer == NULL) {
1009 return NULL;
1010 }
1011
1012 foreach (Connector * connector, modelPart->connectors().values()) {
1013 if (connector == NULL) continue;
1014
1015 SvgIdLayer * svgIdLayer = connector->fullPinInfo(viewID, m_viewLayerID);
1016 if (svgIdLayer == NULL) continue;
1017
1018 bool result = renderer->setUpConnector(svgIdLayer, false, viewLayerPlacement());
1019 if (!result) continue;
1020
1021 ConnectorItem * connectorItem = newConnectorItem(connector);
1022 connectorItem->setRect(svgIdLayer->rect(viewLayerPlacement()));
1023 connectorItem->setTerminalPoint(svgIdLayer->point(viewLayerPlacement()));
1024 m_originalConnectorRect = svgIdLayer->rect(viewLayerPlacement());
1025
1026 connectorItem->setCircular(true);
1027 //DebugDialog::debug(QString("terminal point %1 %2").arg(terminalPoint.x()).arg(terminalPoint.y()) );
1028 }
1029
1030 return renderer;
1031 }
1032
1033 /*
1034 void Wire::setPos(const QPointF & pos) {
1035 ItemBase::setPos(pos);
1036 }
1037 */
1038
1039
setLineAnd(QLineF line,QPointF pos,bool useLine)1040 void Wire::setLineAnd(QLineF line, QPointF pos, bool useLine) {
1041 this->setPos(pos);
1042 if (useLine) this->setLine(line);
1043
1044 setConnector1Rect();
1045 }
1046
otherConnector(ConnectorItem * oneConnector)1047 ConnectorItem * Wire::otherConnector(ConnectorItem * oneConnector) {
1048 if (oneConnector == m_connector0) return m_connector1;
1049
1050 return m_connector0;
1051 }
1052
connector0()1053 ConnectorItem * Wire::connector0() {
1054 return m_connector0;
1055 }
1056
connector1()1057 ConnectorItem * Wire::connector1() {
1058 return m_connector1;
1059 }
1060
findConnectorsUnder()1061 void Wire::findConnectorsUnder() {
1062 foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1063 if (connectorItem->connectionsCount() > 0) continue; // only check free ends
1064 connectorItem->findConnectorUnder(true, false, ConnectorItem::emptyConnectorItemList, false, NULL);
1065 }
1066 }
1067
collectChained(QList<Wire * > & chained,QList<ConnectorItem * > & ends)1068 void Wire::collectChained(QList<Wire *> & chained, QList<ConnectorItem *> & ends ) {
1069 chained.append(this);
1070 for (int i = 0; i < chained.count(); i++) {
1071 Wire * wire = chained[i];
1072 collectChained(wire->m_connector1, chained, ends);
1073 collectChained(wire->m_connector0, chained, ends);
1074 }
1075 }
1076
collectChained(ConnectorItem * connectorItem,QList<Wire * > & chained,QList<ConnectorItem * > & ends)1077 void Wire::collectChained(ConnectorItem * connectorItem, QList<Wire *> & chained, QList<ConnectorItem *> & ends) {
1078 if (connectorItem == NULL) return;
1079
1080 foreach (ConnectorItem * connectedToItem, connectorItem->connectedToItems()) {
1081 Wire * wire = qobject_cast<Wire *>(connectedToItem->attachedTo());
1082 if (wire == NULL) {
1083 if (!ends.contains(connectedToItem)) {
1084 ends.append(connectedToItem);
1085 }
1086 continue;
1087 }
1088
1089 if (chained.contains(wire)) continue;
1090 chained.append(wire);
1091 }
1092 }
1093
collectWires(QList<Wire * > & wires)1094 void Wire::collectWires(QList<Wire *> & wires) {
1095 if (wires.contains(this)) return;
1096
1097 wires.append(this);
1098 //DebugDialog::debug(QString("collecting wire %1").arg(this->id()) );
1099 collectWiresAux(wires, m_connector0);
1100 collectWiresAux(wires, m_connector1);
1101 }
1102
collectWiresAux(QList<Wire * > & wires,ConnectorItem * start)1103 void Wire::collectWiresAux(QList<Wire *> & wires, ConnectorItem * start) {
1104 foreach (ConnectorItem * toConnectorItem, start->connectedToItems()) {
1105 if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
1106 qobject_cast<Wire *>(toConnectorItem->attachedTo())->collectWires(wires);
1107 }
1108 }
1109
1110 }
1111
stickyEnabled()1112 bool Wire::stickyEnabled()
1113 {
1114 QList<Wire *> wires;
1115 QList<ConnectorItem *> ends;
1116 this->collectChained(wires, ends);
1117 foreach (ConnectorItem * connector, ends) {
1118 if (connector->connectionsCount() > 0) {
1119 return false;
1120 }
1121 }
1122
1123 return true;
1124 }
1125
getTrace()1126 bool Wire::getTrace() {
1127 return m_viewGeometry.getAnyTrace();
1128 }
1129
getRouted()1130 bool Wire::getRouted() {
1131 return m_viewGeometry.getRouted();
1132 }
1133
setRouted(bool routed)1134 void Wire::setRouted(bool routed) {
1135 m_viewGeometry.setRouted(routed);
1136 }
1137
setRatsnest(bool ratsnest)1138 void Wire::setRatsnest(bool ratsnest) {
1139 m_viewGeometry.setRatsnest(ratsnest);
1140 }
1141
setAutoroutable(bool ar)1142 void Wire::setAutoroutable(bool ar) {
1143 m_viewGeometry.setAutoroutable(ar);
1144 }
1145
getAutoroutable()1146 bool Wire::getAutoroutable() {
1147 return m_viewGeometry.getAutoroutable();
1148 }
1149
setNormal(bool normal)1150 void Wire::setNormal(bool normal) {
1151 m_viewGeometry.setNormal(normal);
1152 }
1153
getNormal()1154 bool Wire::getNormal() {
1155 return m_viewGeometry.getNormal();
1156 }
1157
setColor(const QColor & color,double op)1158 void Wire::setColor(const QColor & color, double op) {
1159 m_pen.setBrush(QBrush(color));
1160 m_opacity = op;
1161 m_colorName = color.name();
1162 this->update();
1163 }
1164
setShadowColor(QColor & color,bool restore)1165 void Wire::setShadowColor(QColor & color, bool restore) {
1166 m_shadowBrush = QBrush(color);
1167 m_shadowPen.setBrush(m_shadowBrush);
1168 m_bendpointPen.setBrush(m_shadowBrush);
1169 m_bendpoint2Pen.setBrush(m_shadowBrush);
1170 QList<ConnectorItem *> visited;
1171 if (restore) {
1172 if (m_connector0) m_connector0->restoreColor(visited);
1173 if (m_connector1) m_connector1->restoreColor(visited);
1174 }
1175 this->update();
1176 }
1177
color()1178 const QColor & Wire::color() {
1179 return m_pen.brush().color();
1180 }
1181
setWireWidth(double width,InfoGraphicsView * infoGraphicsView,double hoverStrokeWidth)1182 void Wire::setWireWidth(double width, InfoGraphicsView * infoGraphicsView, double hoverStrokeWidth) {
1183 if (m_pen.widthF() == width) return;
1184
1185 prepareGeometryChange();
1186 setPenWidth(width, infoGraphicsView, hoverStrokeWidth);
1187 QList<ConnectorItem *> visited;
1188 if (m_connector0) m_connector0->restoreColor(visited);
1189 if (m_connector1) m_connector1->restoreColor(visited);
1190 update();
1191 }
1192
width()1193 double Wire::width() {
1194 return m_pen.widthF();
1195 }
1196
shadowWidth()1197 double Wire::shadowWidth() {
1198 return m_shadowPen.widthF();
1199 }
1200
mils()1201 double Wire::mils() {
1202 return 1000 * m_pen.widthF() / GraphicsUtils::SVGDPI;
1203 }
1204
setColorString(QString colorName,double op,bool restore)1205 void Wire::setColorString(QString colorName, double op, bool restore) {
1206 // sets a color using the name (.e. "red")
1207 // note: colorName is associated with a Fritzing color, not a Qt color
1208
1209 QString colorString = RatsnestColors::wireColor(m_viewID, colorName);
1210 if (colorString.isEmpty()) {
1211 colorString = colorName;
1212 }
1213
1214 QColor c;
1215 c.setNamedColor(colorString);
1216 setColor(c, op);
1217 m_colorName = colorName;
1218
1219 QString shadowColorString = RatsnestColors::shadowColor(m_viewID, colorName);
1220 if (shadowColorString.isEmpty()) {
1221 shadowColorString = colorString;
1222 }
1223
1224 c.setNamedColor(shadowColorString);
1225 setShadowColor(c, restore);
1226 }
1227
hexString()1228 QString Wire::hexString() {
1229 return m_pen.brush().color().name();
1230 }
1231
shadowHexString()1232 QString Wire::shadowHexString() {
1233 return m_shadowPen.brush().color().name();
1234 }
1235
colorString()1236 QString Wire::colorString() {
1237 return m_colorName;
1238 }
1239
initNames()1240 void Wire::initNames() {
1241 if (colorNames.count() > 0) return;
1242
1243 TheDash.clear();
1244 TheDash << 10 << 8;
1245 RatDash.clear();
1246 RatDash << 2 << 2;
1247
1248 widths << 8 << 12 << 16 << 24 << 32 << 48;
1249 int i = 0;
1250 widthTrans.insert(widths[i++], tr("super fine (8 mil)"));
1251 widthTrans.insert(widths[i++], tr("extra thin (12 mil)"));
1252
1253 THIN_TRACE_WIDTH = GraphicsUtils::mils2pixels(widths[i], GraphicsUtils::SVGDPI);
1254 widthTrans.insert(widths[i++], tr("thin (16 mil)"));
1255
1256 STANDARD_TRACE_WIDTH = GraphicsUtils::mils2pixels(widths[i], GraphicsUtils::SVGDPI);
1257 widthTrans.insert(widths[i++], tr("standard (24 mil)"));
1258
1259 widthTrans.insert(widths[i++], tr("thick (32 mil)"));
1260 widthTrans.insert(widths[i++], tr("extra thick (48 mil)"));
1261
1262 HALF_STANDARD_TRACE_WIDTH = STANDARD_TRACE_WIDTH / 2.0;
1263
1264 // need a list because a hash table doesn't guarantee order
1265 colorNames.append(tr("blue"));
1266 colorNames.append(tr("red"));
1267 colorNames.append(tr("black"));
1268 colorNames.append(tr("yellow"));
1269 colorNames.append(tr("green"));
1270 colorNames.append(tr("grey"));
1271 colorNames.append(tr("white"));
1272 colorNames.append(tr("orange"));
1273 colorNames.append(tr("ochre"));
1274 colorNames.append(tr("cyan"));
1275 colorNames.append(tr("brown"));
1276 colorNames.append(tr("purple"));
1277 colorNames.append(tr("pink"));
1278
1279 // need this hash table to translate from user's language to internal color name
1280 colorTrans.insert(tr("blue"), "blue");
1281 colorTrans.insert(tr("red"), "red");
1282 colorTrans.insert(tr("black"), "black");
1283 colorTrans.insert(tr("yellow"), "yellow");
1284 colorTrans.insert(tr("green"), "green");
1285 colorTrans.insert(tr("grey"), "grey");
1286 colorTrans.insert(tr("white"), "white");
1287 colorTrans.insert(tr("orange"), "orange");
1288 colorTrans.insert(tr("ochre"), "ochre");
1289 colorTrans.insert(tr("cyan"), "cyan");
1290 colorTrans.insert(tr("brown"), "brown");
1291 colorTrans.insert(tr("purple"), "purple");
1292 colorTrans.insert(tr("pink"), "pink");
1293 }
1294
hasFlag(ViewGeometry::WireFlag flag)1295 bool Wire::hasFlag(ViewGeometry::WireFlag flag)
1296 {
1297 return m_viewGeometry.hasFlag(flag);
1298 }
1299
isTraceType(ViewGeometry::WireFlag flag)1300 bool Wire::isTraceType(ViewGeometry::WireFlag flag) {
1301 return hasFlag(flag);
1302 }
1303
hasAnyFlag(ViewGeometry::WireFlags flags)1304 bool Wire::hasAnyFlag(ViewGeometry::WireFlags flags)
1305 {
1306 return m_viewGeometry.hasAnyFlag(flags);
1307 }
1308
findTraced(ViewGeometry::WireFlags flags,QList<ConnectorItem * > & ends)1309 Wire * Wire::findTraced(ViewGeometry::WireFlags flags, QList<ConnectorItem *> & ends) {
1310 QList<Wire *> chainedWires;
1311 this->collectChained(chainedWires, ends);
1312 if (ends.count() != 2) {
1313 DebugDialog::debug(QString("wire in jumper or trace must have two ends") );
1314 return NULL;
1315 }
1316
1317 return ConnectorItem::directlyWiredTo(ends[0], ends[1], flags);
1318 }
1319
setWireFlags(ViewGeometry::WireFlags wireFlags)1320 void Wire::setWireFlags(ViewGeometry::WireFlags wireFlags) {
1321 m_viewGeometry.setWireFlags(wireFlags);
1322 }
1323
opacity()1324 double Wire::opacity() {
1325 return m_opacity;
1326 }
1327
setOpacity(double opacity)1328 void Wire::setOpacity(double opacity) {
1329 m_opacity = opacity;
1330 this->update();
1331 }
1332
draggingEnd()1333 bool Wire::draggingEnd() {
1334 return m_dragEnd || m_dragCurve;
1335 }
1336
setCanChainMultiple(bool can)1337 void Wire::setCanChainMultiple(bool can) {
1338 m_canChainMultiple = can;
1339 }
1340
canChangeColor()1341 bool Wire::canChangeColor() {
1342 if (getRatsnest()) return false;
1343 if (!getTrace()) return true;
1344
1345 return (this->m_viewID == ViewLayer::SchematicView);
1346 }
1347
collectDirectWires(QList<Wire * > & wires)1348 void Wire::collectDirectWires(QList<Wire *> & wires) {
1349 bool firstRound = false;
1350 if (!wires.contains(this)) {
1351 wires.append(this);
1352 firstRound = true;
1353 }
1354
1355 QList<ConnectorItem *> junctions;
1356 if (firstRound) {
1357 // collect up to any junction
1358 collectDirectWires(m_connector0, wires, junctions);
1359 collectDirectWires(m_connector1, wires, junctions);
1360 return;
1361 }
1362
1363 // second round: deal with junctions
1364 foreach (Wire * wire, wires) {
1365 junctions << wire->connector0() << wire->connector1();
1366 }
1367
1368 int ix = 0;
1369 while (ix < junctions.count()) {
1370 ConnectorItem * junction = junctions.at(ix++);
1371
1372 QSet<Wire *> jwires;
1373 foreach (ConnectorItem * toConnectorItem, junction->connectedToItems()) {
1374 if (toConnectorItem->attachedToItemType() != ModelPart::Wire) break;
1375
1376 Wire * w = qobject_cast<Wire *>(toConnectorItem->attachedTo());
1377 if (!wires.contains(w)) jwires << w;
1378
1379 bool onlyWiresConnected = true;
1380 foreach (ConnectorItem * toToConnectorItem, toConnectorItem->connectedToItems()) {
1381 if (toToConnectorItem->attachedToItemType() != ModelPart::Wire) {
1382 onlyWiresConnected = false;
1383 break;
1384 }
1385
1386 w = qobject_cast<Wire *>(toToConnectorItem->attachedTo());
1387 if (!wires.contains(w)) jwires << w;
1388 }
1389 if (!onlyWiresConnected) break;
1390 }
1391
1392 if (jwires.count() == 1) {
1393 // there is a junction of > 2 wires and all wires leading to it except one are already on the delete list
1394 Wire * w = jwires.values().at(0);
1395 wires << w;
1396 w->collectDirectWires(w->connector0(), wires, junctions);
1397 w->collectDirectWires(w->connector1(), wires, junctions);
1398 }
1399 }
1400 }
1401
1402
collectDirectWires(ConnectorItem * connectorItem,QList<Wire * > & wires,QList<ConnectorItem * > & junctions)1403 void Wire::collectDirectWires(ConnectorItem * connectorItem, QList<Wire *> & wires, QList<ConnectorItem *> & junctions) {
1404 if (connectorItem->connectionsCount() == 0) return;
1405 if (connectorItem->connectionsCount() > 1) {
1406 if (!junctions.contains(connectorItem)) junctions.append(connectorItem);
1407 return;
1408 }
1409
1410 ConnectorItem * toConnectorItem = connectorItem->connectedToItems().at(0);
1411 if (toConnectorItem->attachedToItemType() != ModelPart::Wire) return;
1412
1413 if (toConnectorItem->connectionsCount() != 1) {
1414 if (!junctions.contains(connectorItem)) junctions.append(connectorItem);
1415 return;
1416 }
1417
1418 Wire * nextWire = qobject_cast<Wire *>(toConnectorItem->attachedTo());
1419 if (wires.contains(nextWire)) return;
1420
1421 wires.append(nextWire);
1422 nextWire->collectDirectWires(nextWire->otherConnector(toConnectorItem), wires, junctions);
1423 }
1424
itemChange(GraphicsItemChange change,const QVariant & value)1425 QVariant Wire::itemChange(GraphicsItemChange change, const QVariant &value)
1426 {
1427 if (change == ItemSelectedChange) {
1428 if (m_partLabel) {
1429 m_partLabel->update();
1430 }
1431
1432 if (!m_ignoreSelectionChange) {
1433 QList<Wire *> chained;
1434 QList<ConnectorItem *> ends;
1435 collectChained(chained, ends);
1436 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1437 if (infoGraphicsView) {
1438 infoGraphicsView->setIgnoreSelectionChangeEvents(true);
1439 }
1440 // DebugDialog::debug(QString("original wire selected %1 %2").arg(value.toBool()).arg(this->id()));
1441 foreach (Wire * wire, chained) {
1442 if (wire != this ) {
1443 wire->setIgnoreSelectionChange(true);
1444 wire->setSelected(value.toBool());
1445 wire->setIgnoreSelectionChange(false);
1446 // DebugDialog::debug(QString("wire selected %1 %2").arg(value.toBool()).arg(wire->id()));
1447 }
1448 }
1449 if (infoGraphicsView) {
1450 infoGraphicsView->setIgnoreSelectionChangeEvents(false);
1451 }
1452 }
1453 }
1454 return ItemBase::itemChange(change, value);
1455 }
1456
cleanup()1457 void Wire::cleanup() {
1458 }
1459
getConnectedColor(ConnectorItem * connectorItem,QBrush & brush,QPen & pen,double & opacity,double & negativePenWidth,bool & negativeOffsetRect)1460 void Wire::getConnectedColor(ConnectorItem * connectorItem, QBrush &brush, QPen &pen, double & opacity, double & negativePenWidth, bool & negativeOffsetRect)
1461 {
1462 connectorItem->setBigDot(false);
1463 ItemBase::getConnectedColor(connectorItem, brush, pen, opacity, negativePenWidth, negativeOffsetRect);
1464 int count = 0;
1465 bool bendpoint = true;
1466 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1467 if (infoGraphicsView == NULL) {
1468 return;
1469 }
1470
1471 foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) {
1472 if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
1473 Wire * w = qobject_cast<Wire *>(toConnectorItem->attachedTo());
1474 if (w->isTraceType(infoGraphicsView->getTraceFlag())) {
1475 count++;
1476 }
1477 }
1478 else {
1479 // for drawing a big dot on the end of a part connector in schematic view if the part is connected to more than one trace
1480 bendpoint = false;
1481 if (toConnectorItem->connectionsCount() > 1) {
1482 if (infoGraphicsView->hasBigDots()) {
1483 int c = 0;
1484 foreach (ConnectorItem * totoConnectorItem, toConnectorItem->connectedToItems()) {
1485 if (totoConnectorItem->attachedToItemType() == ModelPart::Wire) {
1486 Wire * w = qobject_cast<Wire *>(totoConnectorItem->attachedTo());
1487 if (w && w->isTraceType(ViewGeometry::SchematicTraceFlag) && w->isTraceType(infoGraphicsView->getTraceFlag())) {
1488 c++;
1489 }
1490 }
1491 }
1492 if (c > 1) {
1493 count = 2;
1494 break;
1495 }
1496 }
1497 }
1498
1499 count = 0;
1500 break;
1501 }
1502 }
1503
1504 if (count == 0) {
1505 return;
1506 }
1507
1508 // connectorItem is a bendpoint or connects to a multiply connected connector
1509
1510 //if (!bendpoint) {
1511 //DebugDialog::debug(QString("big dot %1 %2 %3").arg(this->id()).arg(connectorItem->connectorSharedID()).arg(count));
1512 //}
1513
1514 brush = m_shadowBrush;
1515 opacity = 1.0;
1516 if (count > 1) {
1517 // only ever reach here when drawing a connector that is connected to more than one trace
1518 pen = m_bendpoint2Pen;
1519 negativePenWidth = m_bendpoint2Width;
1520 negativeOffsetRect = m_negativeOffsetRect;
1521 connectorItem->setBigDot(true);
1522 }
1523 else {
1524 negativeOffsetRect = m_negativeOffsetRect;
1525 negativePenWidth = m_bendpointWidth;
1526 pen = m_bendpointPen;
1527 }
1528 }
1529
setPenWidth(double w,InfoGraphicsView * infoGraphicsView,double hoverStrokeWidth)1530 void Wire::setPenWidth(double w, InfoGraphicsView * infoGraphicsView, double hoverStrokeWidth) {
1531 m_hoverStrokeWidth = hoverStrokeWidth;
1532 //DebugDialog::debug(QString("setting hoverstrokewidth %1 %2").arg(m_id).arg(m_hoverStrokeWidth));
1533 m_pen.setWidthF(w);
1534 infoGraphicsView->getBendpointWidths(this, w, m_bendpointWidth, m_bendpoint2Width, m_negativeOffsetRect);
1535 m_bendpointPen.setWidthF(qAbs(m_bendpointWidth));
1536 m_bendpoint2Pen.setWidthF(qAbs(m_bendpoint2Width));
1537 m_shadowPen.setWidthF(w + 2);
1538 }
1539
connectionIsAllowed(ConnectorItem * to)1540 bool Wire::connectionIsAllowed(ConnectorItem * to) {
1541 if (!ItemBase::connectionIsAllowed(to)) return false;
1542
1543 Wire * w = qobject_cast<Wire *>(to->attachedTo());
1544 if (w == NULL) return true;
1545
1546 if (w->getRatsnest()) return false;
1547
1548 return m_viewID != ViewLayer::BreadboardView;
1549 }
1550
isGrounded()1551 bool Wire::isGrounded() {
1552 return ConnectorItem::isGrounded(connector0(), connector1());
1553 }
1554
acceptsMouseDoubleClickConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)1555 bool Wire::acceptsMouseDoubleClickConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1556 return true;
1557 }
1558
acceptsMouseMoveConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)1559 bool Wire::acceptsMouseMoveConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1560 return true;
1561 }
1562
acceptsMouseReleaseConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)1563 bool Wire::acceptsMouseReleaseConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1564 return true;
1565 }
1566
setIgnoreSelectionChange(bool ignore)1567 void Wire::setIgnoreSelectionChange(bool ignore) {
1568 m_ignoreSelectionChange = ignore;
1569 }
1570
collectExtraInfo(QWidget * parent,const QString & family,const QString & prop,const QString & value,bool swappingEnabled,QString & returnProp,QString & returnValue,QWidget * & returnWidget,bool & hide)1571 bool Wire::collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget, bool & hide)
1572 {
1573 if (prop.compare("width", Qt::CaseInsensitive) == 0) {
1574 // don't display width property
1575 hide = true;
1576 return false;
1577 }
1578
1579 if (prop.compare("color", Qt::CaseInsensitive) == 0) {
1580 returnProp = tr("color");
1581 if (canChangeColor()) {
1582 QComboBox * comboBox = new QComboBox(parent);
1583 comboBox->setEditable(false);
1584 comboBox->setEnabled(swappingEnabled);
1585 comboBox->setObjectName("infoViewComboBox");
1586
1587 int ix = 0;
1588 QString englishCurrColor = colorString();
1589 foreach(QString transColorName, Wire::colorNames) {
1590 QString englishColorName = Wire::colorTrans.value(transColorName);
1591 bool ok = (this->m_viewID != ViewLayer::SchematicView || englishColorName.compare("white", Qt::CaseInsensitive) != 0);
1592 if (ok) {
1593 comboBox->addItem(transColorName, QVariant(englishColorName));
1594 if (englishColorName.compare(englishCurrColor, Qt::CaseInsensitive) == 0) {
1595 comboBox->setCurrentIndex(ix);
1596 }
1597 ix++;
1598 }
1599 }
1600
1601 connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(colorEntry(const QString &)));
1602
1603 if (this->hasShadow()) {
1604 QCheckBox * checkBox = new QCheckBox(tr("Banded"));
1605 checkBox->setChecked(m_banded);
1606 checkBox->setObjectName("infoViewCheckBox");
1607 connect(checkBox, SIGNAL(clicked(bool)), this, SLOT(setBandedProp(bool)));
1608
1609 QFrame * frame = new QFrame(parent);
1610 QHBoxLayout * hboxLayout = new QHBoxLayout;
1611 hboxLayout->addWidget(comboBox);
1612 hboxLayout->addWidget(checkBox);
1613 frame->setLayout(hboxLayout);
1614
1615 returnWidget = frame;
1616 }
1617 else {
1618 returnWidget = comboBox;
1619 }
1620
1621 returnValue = comboBox->currentText();
1622 return true;
1623 }
1624 else {
1625 returnWidget = NULL;
1626 returnValue = colorString();
1627 return true;
1628 }
1629 }
1630
1631 return ItemBase::collectExtraInfo(parent, family, prop, value, swappingEnabled, returnProp, returnValue, returnWidget, hide);
1632 }
1633
colorEntry(const QString & text)1634 void Wire::colorEntry(const QString & text) {
1635 Q_UNUSED(text);
1636
1637 QComboBox * comboBox = qobject_cast<QComboBox *>(sender());
1638 if (comboBox == NULL) return;
1639
1640 QString color = comboBox->itemData(comboBox->currentIndex()).toString();
1641
1642 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1643 if (infoGraphicsView != NULL) {
1644 infoGraphicsView->changeWireColor(color);
1645 }
1646 }
1647
hasPartLabel()1648 bool Wire::hasPartLabel() {
1649
1650 return false;
1651 }
1652
isPlural()1653 ItemBase::PluralType Wire::isPlural() {
1654 return Plural;
1655 }
1656
checkVisibility(ConnectorItem * onMe,ConnectorItem * onIt,bool connect)1657 void Wire::checkVisibility(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) {
1658 if (connect) {
1659 if (!onIt->attachedTo()->isVisible()) {
1660 this->setVisible(false);
1661 }
1662 else {
1663 ConnectorItem * other = otherConnector(onMe);
1664 foreach (ConnectorItem * toConnectorItem, other->connectedToItems()) {
1665 if (toConnectorItem->attachedToItemType() == ModelPart::Wire) continue;
1666
1667 if (!toConnectorItem->attachedTo()->isVisible()) {
1668 this->setVisible(false);
1669 break;
1670 }
1671 }
1672 }
1673 }
1674 }
1675
canSwitchLayers()1676 bool Wire::canSwitchLayers() {
1677 return false;
1678 }
1679
hasPartNumberProperty()1680 bool Wire::hasPartNumberProperty()
1681 {
1682 return false;
1683 }
1684
rotationAllowed()1685 bool Wire::rotationAllowed() {
1686 return false;
1687 }
1688
rotation45Allowed()1689 bool Wire::rotation45Allowed() {
1690 return false;
1691 }
1692
addedToScene(bool temporary)1693 void Wire::addedToScene(bool temporary) {
1694 ItemBase::addedToScene(temporary);
1695
1696 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1697 if (infoGraphicsView == NULL) return;
1698
1699 infoGraphicsView->newWire(this);
1700 }
1701
setConnectorDimensions(double width,double height)1702 void Wire::setConnectorDimensions(double width, double height)
1703 {
1704 setConnectorDimensionsAux(connector0(), width, height);
1705 setConnectorDimensionsAux(connector1(), width, height);
1706 }
1707
setConnectorDimensionsAux(ConnectorItem * connectorItem,double width,double height)1708 void Wire::setConnectorDimensionsAux(ConnectorItem * connectorItem, double width, double height)
1709 {
1710 QPointF p = connectorItem->rect().center();
1711 QRectF r(p.x() - (width / 2), p.y() - (height / 2), width, height);
1712 connectorItem->setRect(r);
1713 connectorItem->setTerminalPoint(r.center() - r.topLeft());
1714 //debugCompare(connectorItem->attachedTo());
1715 }
1716
originalConnectorDimensions(double & width,double & height)1717 void Wire::originalConnectorDimensions(double & width, double & height)
1718 {
1719 width = m_originalConnectorRect.width();
1720 height = m_originalConnectorRect.height();
1721 }
1722
isBendpoint(ConnectorItem * connectorItem)1723 bool Wire::isBendpoint(ConnectorItem * connectorItem) {
1724 return connectorItem->isBendpoint();
1725 }
1726
hoverStrokeWidth()1727 double Wire::hoverStrokeWidth() {
1728 return m_hoverStrokeWidth;
1729 }
1730
getPaintLine()1731 const QLineF & Wire::getPaintLine() {
1732 return m_line;
1733 }
1734
1735 /*!
1736 Returns the item's line, or a null line if no line has been set.
1737
1738 \sa setLine()
1739 */
line() const1740 QLineF Wire::line() const
1741 {
1742 return m_line;
1743 }
1744
1745 /*!
1746 Sets the item's line to be the given \a line.
1747
1748 \sa line()
1749 */
setLine(const QLineF & line)1750 void Wire::setLine(const QLineF &line)
1751 {
1752
1753 //if (line.length() < 0.5) {
1754 // debugInfo("zero line");
1755 //}
1756
1757 if (m_line == line)
1758 return;
1759 prepareGeometryChange();
1760 m_line = line;
1761 update();
1762 }
1763
setLine(double x1,double y1,double x2,double y2)1764 void Wire::setLine(double x1, double y1, double x2, double y2)
1765 {
1766 setLine(QLineF(x1, y1, x2, y2));
1767 }
1768
1769 /*!
1770 Returns the item's pen, or a black solid 0-width pen if no pen has
1771 been set.
1772
1773 \sa setPen()
1774 */
pen() const1775 QPen Wire::pen() const
1776 {
1777 return m_pen;
1778 }
1779
1780 /*!
1781 Sets the item's pen to \a pen. If no pen is set, the line will be painted
1782 using a black solid 0-width pen.
1783
1784 \sa pen()
1785 */
setPen(const QPen & pen)1786 void Wire::setPen(const QPen &pen)
1787 {
1788 if (pen.widthF() != m_pen.widthF()) {
1789 prepareGeometryChange();
1790 }
1791 m_pen = pen;
1792 update();
1793 }
1794
canHaveCurve()1795 bool Wire::canHaveCurve() {
1796 return m_canHaveCurve && !getRatsnest();
1797 }
1798
dragCurve(QPointF eventPos,Qt::KeyboardModifiers)1799 void Wire::dragCurve(QPointF eventPos, Qt::KeyboardModifiers)
1800 {
1801 m_bezier->recalc(eventPos);
1802 }
1803
changeCurve(const Bezier * bezier)1804 void Wire::changeCurve(const Bezier * bezier)
1805 {
1806 prepareGeometryChange();
1807 if (m_bezier == NULL) m_bezier = new Bezier;
1808 m_bezier->copy(bezier);
1809 update();
1810 }
1811
isCurved()1812 bool Wire::isCurved() {
1813 return (m_bezier != NULL) && !m_bezier->isEmpty();
1814 }
1815
curve()1816 const Bezier * Wire::curve() {
1817 return m_bezier;
1818 }
1819
undoCurve()1820 const Bezier * Wire::undoCurve() {
1821 return &UndoBezier;
1822 }
1823
sceneCurve(QPointF offset)1824 QPolygonF Wire::sceneCurve(QPointF offset) {
1825 QPolygonF poly;
1826 if (m_bezier == NULL) return poly;
1827 if (m_bezier->isEmpty()) return poly;
1828
1829 poly.append(m_line.p1() + pos() - offset);
1830 poly.append(m_bezier->cp0() + pos() - offset);
1831 poly.append(m_bezier->cp1() + pos() - offset);
1832 poly.append(m_line.p2() + pos() - offset);
1833 return poly;
1834 }
1835
hasShadow()1836 bool Wire::hasShadow() {
1837 if (getRatsnest()) return false;
1838 if (getTrace()) return false;
1839 return m_pen.widthF() != m_shadowPen.widthF();
1840 }
1841
cursorKeyEvent(Qt::KeyboardModifiers modifiers)1842 void Wire::cursorKeyEvent(Qt::KeyboardModifiers modifiers)
1843 {
1844 if (m_dragEnd || m_dragCurve) return;
1845
1846 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);;
1847 if (infoGraphicsView) {
1848 QPoint p = infoGraphicsView->mapFromGlobal(QCursor::pos());
1849 QPointF r = infoGraphicsView->mapToScene(p);
1850 // DebugDialog::debug(QString("got key event %1").arg(keyEvent->modifiers()));
1851 updateCursor(modifiers);
1852 }
1853 }
1854
updateCursor(Qt::KeyboardModifiers modifiers)1855 void Wire::updateCursor(Qt::KeyboardModifiers modifiers)
1856 {
1857 if (m_connectorHover) {
1858 return;
1859 }
1860
1861 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1862 bool segment = false;
1863 int totalConnections = 0;
1864 foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1865 totalConnections += connectorItem->connectionsCount();
1866 }
1867 if (totalConnections == 2 && modifiers & altOrMetaModifier()) {
1868 segment = true;
1869 foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1870 if (connectorItem->connectionsCount() != 1) {
1871 segment = false;
1872 break;
1873 }
1874
1875 ConnectorItem * toConnectorItem = connectorItem->connectedToItems().at(0);
1876 if (toConnectorItem->attachedToItemType() != ModelPart::Wire) {
1877 segment = false;
1878 break;
1879 }
1880 }
1881 }
1882
1883 if (segment) {
1884 // dragging a segment of wire between bounded by two other wires
1885 CursorMaster::instance()->addCursor(this, *CursorMaster::RubberbandCursor);
1886 }
1887 else if (totalConnections == 0) {
1888 // only in breadboard view
1889 CursorMaster::instance()->addCursor(this, *CursorMaster::MoveCursor);
1890 }
1891 else if (infoGraphicsView != NULL && infoGraphicsView->curvyWiresIndicated(modifiers)) {
1892 CursorMaster::instance()->addCursor(this, *CursorMaster::MakeCurveCursor);
1893 }
1894 else if (m_displayBendpointCursor) {
1895 CursorMaster::instance()->addCursor(this, *CursorMaster::NewBendpointCursor);
1896 }
1897 }
1898
canChainMultiple()1899 bool Wire::canChainMultiple()
1900 {
1901 return m_canChainMultiple;
1902 }
1903
useViewIDForPixmap(ViewLayer::ViewID vid,bool)1904 ViewLayer::ViewID Wire::useViewIDForPixmap(ViewLayer::ViewID vid, bool)
1905 {
1906 if (vid == ViewLayer::BreadboardView) {
1907 return ViewLayer::IconView;
1908 }
1909
1910 return ViewLayer::UnknownView;
1911 }
1912
setDisplayBendpointCursor(bool dbc)1913 void Wire::setDisplayBendpointCursor(bool dbc) {
1914 m_displayBendpointCursor = dbc;
1915 }
1916
banded()1917 bool Wire::banded() {
1918 return m_banded;
1919 }
1920
setBanded(bool banded)1921 void Wire::setBanded(bool banded) {
1922 m_banded = banded;
1923 QList<Wire *> chained;
1924 QList<ConnectorItem *> ends;
1925 collectChained(chained, ends);
1926 foreach (Wire * w, chained) {
1927 w->m_banded = banded;
1928 w->update();
1929 }
1930 }
1931
setBandedProp(bool banded)1932 void Wire::setBandedProp(bool banded) {
1933 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1934 if (infoGraphicsView != NULL) {
1935 infoGraphicsView->setProp(this, "banded", ItemBase::TranslatedPropertyNames.value("banded"), m_banded ? "Yes" : "No", banded ? "Yes" : "No", true);
1936 }
1937 }
1938
setProp(const QString & prop,const QString & value)1939 void Wire::setProp(const QString & prop, const QString & value) {
1940 if (prop.compare("banded", Qt::CaseInsensitive) == 0) {
1941 setBanded(value == "Yes");
1942 return;
1943 }
1944
1945 ItemBase::setProp(prop, value);
1946 }
1947
1948