1
/*******************************************************************
3
Part of the Fritzing project - http://fritzing.org
4
Copyright (c) 2007-2011 Fachhochschule Potsdam - http://fh-potsdam.de
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.
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.
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/>.
19
********************************************************************
22
$Author: cohen@irascible.com $:
23
$Date: 2011-07-05 11:33:03 +0200 (Tue, 05 Jul 2011) $
25
********************************************************************/
31
#include <QRadialGradient>
34
#include <QGraphicsScene>
36
#include <QGraphicsItem>
41
#include "../debugdialog.h"
42
#include "../sketch/infographicsview.h"
43
#include "../connectors/connectoritem.h"
44
#include "../connectors/svgidlayer.h"
45
#include "../fsvgrenderer.h"
46
#include "partlabel.h"
47
#include "../model/modelpart.h"
48
#include "../utils/graphicsutils.h"
52
QHash<QString, QString> Wire::colors;
53
QHash<QString, QString> Wire::shadowColors;
54
QHash<QString, QString> Wire::colorTrans;
55
QStringList Wire::colorNames;
56
QHash<int, QString> Wire::widthTrans;
57
QList<int> Wire::widths;
58
qreal Wire::STANDARD_TRACE_WIDTH;
59
qreal Wire::HALF_STANDARD_TRACE_WIDTH;
61
////////////////////////////////////////////////////////////
63
bool alphaLessThan(QColor * c1, QColor * c2)
65
return c1->alpha() < c2->alpha();
68
/////////////////////////////////////////////////////////////
71
WireMenu::WireMenu(const QString & title, QWidget * parent) : QMenu(title, parent)
76
void WireMenu::setWire(Wire * w) {
80
Wire * WireMenu::wire() {
84
/////////////////////////////////////////////////////////////
86
WireAction::WireAction(QAction * action) : QAction(action) {
88
this->setText(action->text());
89
this->setStatusTip(action->statusTip());
90
this->setCheckable(action->isCheckable());
93
WireAction::WireAction(const QString & title, QObject * parent) : QAction(title, parent) {
97
void WireAction::setWire(Wire * w) {
101
Wire * WireAction::wire() {
105
/////////////////////////////////////////////////////////////
107
Wire::Wire( ModelPart * modelPart, ViewIdentifierClass::ViewIdentifier viewIdentifier, const ViewGeometry & viewGeometry, long id, QMenu* itemMenu, bool initLabel)
108
: ItemBase(modelPart, viewIdentifier, viewGeometry, id, itemMenu)
110
m_connector0 = m_connector1 = NULL;
111
m_partLabel = initLabel ? new PartLabel(this, NULL) : NULL;
112
m_canChainMultiple = false;
113
setFlag(QGraphicsItem::ItemIsSelectable, true );
114
m_connectorHover = NULL;
116
m_ignoreSelectionChange = false;
118
//DebugDialog::debug(QString("aix line %1 %2 %3 %4").arg(this->viewGeometry().line().x1())
119
//.arg(this->viewGeometry().line().y1())
120
//.arg(this->viewGeometry().line().x2())
121
//.arg(this->viewGeometry().line().y2()) );
122
//DebugDialog::debug(QString("aix loc %1 %2").arg(this->viewGeometry().loc().x())
123
//.arg(this->viewGeometry().loc().y()) );
125
setPos(m_viewGeometry.loc());
133
FSvgRenderer * Wire::setUp(ViewLayer::ViewLayerID viewLayerID, const LayerHash & viewLayers, InfoGraphicsView * infoGraphicsView ) {
134
ItemBase::setViewLayerID(viewLayerID, viewLayers);
135
FSvgRenderer * svgRenderer = setUpConnectors(m_modelPart, m_viewIdentifier);
136
if (svgRenderer != NULL) {
137
initEnds(m_viewGeometry, svgRenderer->viewBox(), infoGraphicsView);
138
setConnectorTooltips();
140
setZValue(this->z());
145
void Wire::saveGeometry() {
146
m_viewGeometry.setSelected(this->isSelected());
147
m_viewGeometry.setLine(this->line());
148
m_viewGeometry.setLoc(this->pos());
149
m_viewGeometry.setZ(this->zValue());
153
bool Wire::itemMoved() {
154
if (m_viewGeometry.loc() != this->pos()) return true;
156
if (this->line().dx() != m_viewGeometry.line().dx()) return false;
157
if (this->line().dy() != m_viewGeometry.line().dy()) return false;
159
return (this->line() != m_viewGeometry.line());
162
void Wire::moveItem(ViewGeometry & viewGeometry) {
163
this->setPos(viewGeometry.loc());
164
this->setLine(viewGeometry.line());
167
void Wire::initEnds(const ViewGeometry & vg, QRectF defaultRect, InfoGraphicsView * infoGraphicsView) {
171
foreach (QGraphicsItem * childItem, childItems()) {
172
ConnectorItem * item = dynamic_cast<ConnectorItem *>(childItem);
173
if (item == NULL) continue;
175
// check the name or is order good enough?
183
penWidth = item->rect().width();
193
if ((vg.line().length() == 0) && (vg.line().x1() == -1)) {
194
this->setLine(defaultRect.left(), defaultRect.top(), defaultRect.right(), defaultRect.bottom());
197
this->setLine(vg.line());
202
m_viewGeometry.setLine(this->line());
204
QBrush brush(QColor(0, 0, 0));
205
QPen pen(brush, penWidth, Qt::SolidLine, Qt::RoundCap);
208
m_pen.setCapStyle(Qt::RoundCap);
209
m_shadowPen.setCapStyle(Qt::RoundCap);
210
if (infoGraphicsView != NULL) {
211
infoGraphicsView->initWire(this, penWidth);
214
prepareGeometryChange();
217
void Wire::paint (QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget ) {
218
if (m_hidden) return;
220
painter->setOpacity(m_inactive ? m_opacity / 2 : m_opacity);
221
if (!getRatsnest() && !getTrace()) {
223
painter->setPen(m_shadowPen);
224
QLineF line = this->line();
225
painter->drawLine(line);
228
ItemBase::paint(painter, option, widget);
231
void Wire::paintHover(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
236
if ((m_connectorHoverCount > 0 && !m_dragEnd) || m_connectorHoverCount2 > 0) {
237
painter->setOpacity(.50);
238
painter->fillPath(this->hoverShape(), QBrush(connectorHoverColor));
241
painter->setOpacity(hoverOpacity);
242
painter->fillPath(this->hoverShape(), QBrush(hoverColor));
247
void Wire::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
248
//DebugDialog::debug("checking press event");
249
emit wireSplitSignal(this, event->scenePos(), this->pos(), this->line());
252
void Wire::mousePressEvent(QGraphicsSceneMouseEvent *event)
254
WireMenu * wireMenu = qobject_cast<WireMenu *>(m_itemMenu);
256
wireMenu->setWire(this);
258
ItemBase::mousePressEvent(event);
261
void Wire::initDragEnd(ConnectorItem * connectorItem, QPointF scenePos) {
264
QLineF line = this->line();
265
m_drag0 = (connectorItem == m_connector0);
268
m_wireDragOrigin = line.p2();
269
//DebugDialog::debug(QString("drag near origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) );
272
m_wireDragOrigin = line.p1();
273
//DebugDialog::debug(QString("drag far origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) );
274
//DebugDialog::debug(QString("drag far other %1 %2").arg(line.p2().x()).arg(line.p2().y()) );
277
if (connectorItem->chained()) {
278
QList<Wire *> chained;
279
QList<ConnectorItem *> ends;
280
collectChained(chained, ends);
281
// already saved the first one
282
for (int i = 1; i < chained.count(); i++) {
283
chained[i]->saveGeometry();
289
void Wire::mouseReleaseConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
291
Q_UNUSED(connectorItem);
295
void Wire::mouseMoveConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
296
mouseMoveEventAux(this->mapFromItem(connectorItem, event->pos()), (event->modifiers() & Qt::ShiftModifier) != 0);
300
void Wire::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
301
mouseMoveEventAux(event->pos(), (event->modifiers() & Qt::ShiftModifier) != 0);
304
void Wire::mouseMoveEventAux(QPointF eventPos, bool shiftModifier) {
305
if (m_spaceBarWasPressed) {
309
if (m_dragEnd == false) {
313
ConnectorItem * whichConnectorItem;
314
ConnectorItem * otherConnectorItem;
316
whichConnectorItem = m_connector0;
317
otherConnectorItem = m_connector1;
320
whichConnectorItem = m_connector1;
321
otherConnectorItem = m_connector0;
325
QPointF initialPos = mapFromScene(otherConnectorItem->sceneAdjustedTerminalPoint(NULL));
326
bool bendpoint = whichConnectorItem->connectionsCount() > 0;
328
foreach (ConnectorItem * ci, whichConnectorItem->connectedToItems()) {
329
if (ci->attachedToItemType() != ModelPart::Wire) {
337
foreach (ConnectorItem * ci, whichConnectorItem->connectedToItems()) {
338
Wire * w = dynamic_cast<Wire *>(ci->attachedTo());
339
ConnectorItem * oci = w->otherConnector(ci);
340
QPointF otherInitialPos = mapFromScene(oci->sceneAdjustedTerminalPoint(NULL));
341
QPointF p1(initialPos.x(), otherInitialPos.y());
342
qreal d = ((p1.x() - eventPos.x()) * (p1.x() - eventPos.x())) + ((p1.y() - eventPos.y()) * (p1.y() - eventPos.y()));
348
p1.setX(otherInitialPos.x());
349
p1.setY(initialPos.y());
350
d = ((p1.x() - eventPos.x()) * (p1.x() - eventPos.x())) + ((p1.y() - eventPos.y()) * (p1.y() - eventPos.y()));
361
eventPos = GraphicsUtils::calcConstraint(initialPos, eventPos);
366
QPointF temp = this->mapToScene(eventPos);
367
//DebugDialog::debug(QString("wire move event %1,%2 %3").arg(temp.x()).arg(temp.y()).arg(m_drag0));
371
QPointF r = this->mapToScene(eventPos);
372
QGraphicsSvgItem::setPos(r.x(), r.y());
373
this->setLine(0, 0, m_wireDragOrigin.x() - r.x() + m_viewGeometry.loc().x(),
374
m_wireDragOrigin.y() - r.y() + m_viewGeometry.loc().y() );
377
this->setLine(m_wireDragOrigin.x(), m_wireDragOrigin.y(), eventPos.x(), eventPos.y());
381
bool chained = false;
382
foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) {
383
Wire * chainedWire = dynamic_cast<Wire *>(toConnectorItem->attachedTo());
384
if (chainedWire == NULL) continue;
386
chainedWire->simpleConnectedMoved(whichConnectorItem, toConnectorItem);
391
// don't allow wire to connect back to something the other end is already directly connected to
393
QList<ConnectorItem *> ends;
394
collectChained(otherConnectorItem, wires, ends);
395
for (int i = 0; i < wires.count(); i++) {
397
collectChained(w->m_connector1, wires, ends);
398
collectChained(w->m_connector0, wires, ends);
400
ends.append(otherConnectorItem);
401
foreach (Wire * w, wires) {
402
ends.append(w->connector0());
403
ends.append(w->connector1());
405
foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) {
406
ends.removeOne(toConnectorItem);
409
ConnectorItem * originatingConnector = NULL;
410
if (otherConnectorItem && otherConnectorItem->connectionsCount() > 0) {
411
originatingConnector = otherConnectorItem->connectedToItems()[0];
413
whichConnectorItem->findConnectorUnder(false, true, ends, true, originatingConnector);
417
void Wire::setConnector0Rect() {
418
QRectF rect = m_connector0->rect();
419
rect.moveTo(0 - (rect.width() / 2.0) ,
420
0 - (rect.height() / 2.0) );
421
//DebugDialog::debug(QString("set connector rect %1 %2").arg(rect.width()).arg(rect.height()));
422
m_connector0->setRect(rect);
426
void Wire::setConnector1Rect() {
427
QRectF rect = m_connector1->rect();
428
rect.moveTo(this->line().dx() - (rect.width() / 2.0) ,
429
this->line().dy() - (rect.height() / 2.0) );
430
m_connector1->setRect(rect);
433
void Wire::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
434
if (m_spaceBarWasPressed) {
438
if (releaseDrag()) return;
440
ItemBase::mouseReleaseEvent(event);
443
bool Wire::releaseDrag() {
444
if (m_dragEnd == false) return false;
448
ConnectorItem * from = (m_drag0) ? m_connector0 : m_connector1;
449
ConnectorItem * to = from->releaseDrag();
451
QLineF newLine = this->line();
452
QLineF oldLine = m_viewGeometry.line();
453
QPointF oldPos = m_viewGeometry.loc();
454
QPointF newPos = this->pos();
455
if (newLine != oldLine || oldPos != newPos) {
456
emit wireChangedSignal(this, oldLine, newLine, oldPos, newPos, from, to);
463
void Wire::saveInstanceLocation(QXmlStreamWriter & streamWriter)
465
QLineF line = m_viewGeometry.line();
466
QPointF loc = m_viewGeometry.loc();
467
streamWriter.writeAttribute("x", QString::number(loc.x()));
468
streamWriter.writeAttribute("y", QString::number(loc.y()));
469
streamWriter.writeAttribute("x1", QString::number(line.x1()));
470
streamWriter.writeAttribute("y1", QString::number(line.y1()));
471
streamWriter.writeAttribute("x2", QString::number(line.x2()));
472
streamWriter.writeAttribute("y2", QString::number(line.y2()));
473
streamWriter.writeAttribute("wireFlags", QString::number(m_viewGeometry.flagsAsInt()));
476
void Wire::writeGeometry(QXmlStreamWriter & streamWriter) {
477
ItemBase::writeGeometry(streamWriter);
478
streamWriter.writeStartElement("wireExtras");
479
streamWriter.writeAttribute("mils", QString::number(mils()));
480
streamWriter.writeAttribute("color", m_pen.brush().color().name());
481
streamWriter.writeAttribute("opacity", QString::number(m_opacity));
482
streamWriter.writeEndElement();
485
void Wire::setExtras(QDomElement & element, InfoGraphicsView * infoGraphicsView)
487
if (element.isNull()) return;
490
qreal w = element.attribute("width").toDouble(&ok);
492
setWireWidth(w, infoGraphicsView);
495
w = element.attribute("mils").toDouble(&ok);
497
setWireWidth(GraphicsUtils::mils2pixels(w, FSvgRenderer::printerScale()), infoGraphicsView);
501
setColorFromElement(element);
504
void Wire::setColorFromElement(QDomElement & element) {
505
QString colorString = element.attribute("color");
506
if (colorString.isNull() || colorString.isEmpty()) return;
509
qreal op = element.attribute("opacity").toDouble(&ok);
514
setColorString(colorString, op);
517
void Wire::hoverEnterConnectorItem(QGraphicsSceneHoverEvent * event , ConnectorItem * item) {
518
m_connectorHover = item;
519
ItemBase::hoverEnterConnectorItem(event, item);
522
void Wire::hoverLeaveConnectorItem(QGraphicsSceneHoverEvent * event, ConnectorItem * item) {
523
m_connectorHover = NULL;
524
ItemBase::hoverLeaveConnectorItem(event, item);
527
void Wire::connectionChange(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) {
528
checkVisibility(onMe, onIt, connect);
531
foreach (ConnectorItem * connectedTo, m_connector0->connectedToItems()) {
532
if (connectedTo->attachedToItemType() != ModelPart::Wire) {
538
foreach (ConnectorItem * connectedTo, m_connector1->connectedToItems()) {
539
if (connectedTo->attachedToItemType() != ModelPart::Wire) {
547
void Wire::mouseDoubleClickConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
550
foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) {
551
if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
560
emit wireJoinSignal(this, connectorItem);
564
void Wire::mousePressConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
565
//DebugDialog::debug("checking press connector event");
567
if (m_canChainMultiple && event->modifiers() & altOrMetaModifier()) {
568
// dragging a wire out of a bendpoint
569
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
570
if (infoGraphicsView != NULL) {
571
infoGraphicsView->mousePressConnectorEvent(connectorItem, event);
578
connectorItem->setOverConnectorItem(NULL);
579
initDragEnd(connectorItem, event->scenePos());
583
void Wire::simpleConnectedMoved(ConnectorItem * to) {
584
// to is this wire, from is something else
585
simpleConnectedMoved(to->firstConnectedToIsh(), to);
588
void Wire::simpleConnectedMoved(ConnectorItem * from, ConnectorItem * to)
590
if (from == NULL) return;
592
// to is this wire, from is something else
594
calcNewLine(from, to, p1, p2);
597
QPointF oldPos = this->pos();
599
QLineF oldLine = this->line();
600
QLineF newLine(0, 0, p2.x() - p1.x(), p2.y() - p1.y());
601
if (qAbs(oldPos.x() - newPos.x()) > 1.75 ||
602
qAbs(oldPos.y() - newPos.y()) > 1.75 ||
603
qAbs(oldLine.x1() - newLine.x1()) > 1.75 ||
604
qAbs(oldLine.x2() - newLine.x2()) > 1.75 ||
605
qAbs(oldLine.y1() - newLine.y1()) > 1.75 ||
606
qAbs(oldLine.y2() - newLine.y2()) > 1.75
609
DebugDialog::debug("line changed");
610
calcNewLine(from,to,p1,p2);
615
this->setLine(0,0, p2.x() - p1.x(), p2.y() - p1.y() );
616
//DebugDialog::debug(QString("set line %5: %1 %2, %3 %4, vis:%6 lyr:%7").arg(p1.x()).arg(p1.y()).arg(p2.x()).arg(p2.y()).arg(id()).arg(isVisible()).arg(m_viewIdentifier) );
620
void Wire::calcNewLine(ConnectorItem * from, ConnectorItem * to, QPointF & p1, QPointF & p2) {
621
// to is this wire, from is something else
622
if (to == m_connector0) {
623
p1 = from->sceneAdjustedTerminalPoint(to);
624
ConnectorItem * otherFrom = m_connector1->firstConnectedToIsh();
625
if (otherFrom == NULL) {
626
p2 = m_connector1->mapToScene(m_connector1->rect().center());
629
p2 = otherFrom->sceneAdjustedTerminalPoint(m_connector1);
633
p2 = from->sceneAdjustedTerminalPoint(to);
634
ConnectorItem * otherFrom = m_connector0->firstConnectedToIsh();
635
if (otherFrom == NULL) {
636
p1 = m_connector0->mapToScene(m_connector0->rect().center());
639
p1 = otherFrom->sceneAdjustedTerminalPoint(m_connector0);
645
void Wire::connectedMoved(ConnectorItem * from, ConnectorItem * to) {
646
// "from" is the connector on the part
647
// "to" is the connector on the wire
649
simpleConnectedMoved(from, to);
653
DebugDialog::debug(QString("connected moved %1 %2, %3 %4")
654
.arg(from->attachedToID())
655
.arg(from->attachedToTitle())
656
.arg(to->attachedToID())
657
.arg(to->attachedToTitle())
661
ConnectorItem * otherEnd = otherConnector(to);
662
bool chained = otherEnd->chained();
666
if (to == m_connector0) {
667
p1 = from->sceneAdjustedTerminalPoint(m_connector0);
668
p2 = this->line().p2() + p1;
671
p2 = from->sceneAdjustedTerminalPoint(m_connector1);
672
p1 = p2 - this->line().p2();
676
calcNewLine(from, to, p1, p2);
679
this->setLine(0,0, p2.x() - p1.x(), p2.y() - p1.y() );
680
//DebugDialog::debug(QString("set line %5: %1 %2, %3 %4, vis:%6 lyr:%7").arg(p1.x()).arg(p1.y()).arg(p2.x()).arg(p2.y()).arg(id()).arg(isVisible()).arg(m_viewIdentifier) );
684
foreach (ConnectorItem * otherEndTo, otherEnd->connectedToItems()) {
685
if (otherEndTo->attachedToItemType() == ModelPart::Wire) {
686
otherEndTo->attachedTo()->connectedMoved(otherEnd, otherEndTo);
693
FSvgRenderer * Wire::setUpConnectors(ModelPart * modelPart, ViewIdentifierClass::ViewIdentifier viewIdentifier) {
696
FSvgRenderer * renderer = ItemBase::setUpImage(modelPart, viewIdentifier, m_viewLayerID, m_viewLayerSpec, error);
697
if (renderer == NULL) {
701
foreach (Connector * connector, m_modelPart->connectors().values()) {
702
if (connector == NULL) continue;
704
SvgIdLayer * svgIdLayer = connector->fullPinInfo(viewIdentifier, m_viewLayerID);
705
if (svgIdLayer == NULL) continue;
707
bool result = renderer->setUpConnector(svgIdLayer, false);
708
if (!result) continue;
710
ConnectorItem * connectorItem = newConnectorItem(connector);
711
connectorItem->setRect(svgIdLayer->m_rect);
712
connectorItem->setTerminalPoint(svgIdLayer->m_point);
714
connectorItem->setCircular(true);
715
//DebugDialog::debug(QString("terminal point %1 %2").arg(terminalPoint.x()).arg(terminalPoint.y()) );
722
void Wire::setPos(const QPointF & pos) {
723
GraphicsSvgLineItem::setPos(pos);
726
// helpful for debugging
727
void Wire::setLine(QLineF line) {
728
GraphicsSvgLineItem::setLine(line);
729
DebugDialog::debug(QString("set line %5 %6, %7 %8, %1 %2 %3 %4").arg(line.x1()).arg(line.y1()).arg(line.x2()).arg(line.y2())
730
.arg(id()).arg(m_viewIdentifier).arg(this->pos().x()).arg(this->pos().y()) );
733
void Wire::setLine(qreal x1, qreal y1, qreal x2, qreal y2) {
734
GraphicsSvgLineItem::setLine(x1, y1, x2, y2);
735
DebugDialog::debug(QString("set line %5 %6, %7 %8, %1 %2 %3 %4").arg(x1).arg(y1).arg(x2).arg(y2)
736
.arg(id()).arg(m_viewIdentifier).arg(this->pos().x()).arg(this->pos().y()) );
742
void Wire::setLineAnd(QLineF line, QPointF pos, bool useLine) {
744
if (useLine) this->setLine(line);
749
ConnectorItem * Wire::otherConnector(ConnectorItem * oneConnector) {
750
if (oneConnector == m_connector0) return m_connector1;
755
ConnectorItem * Wire::connector0() {
759
ConnectorItem * Wire::connector1() {
763
void Wire::findConnectorsUnder() {
764
for (int i = 0; i < childItems().count(); i++) {
765
ConnectorItem * connectorItem = dynamic_cast<ConnectorItem *>(childItems()[i]);
766
if (connectorItem == NULL) continue;
768
connectorItem->findConnectorUnder(true, false, ConnectorItem::emptyConnectorItemList, false, NULL);
772
void Wire::collectChained(QList<Wire *> & chained, QList<ConnectorItem *> & ends ) {
773
chained.append(this);
774
for (int i = 0; i < chained.count(); i++) {
775
Wire * wire = chained[i];
776
collectChained(wire->m_connector1, chained, ends);
777
collectChained(wire->m_connector0, chained, ends);
781
void Wire::collectChained(ConnectorItem * connectorItem, QList<Wire *> & chained, QList<ConnectorItem *> & ends) {
782
if (connectorItem == NULL) return;
784
foreach (ConnectorItem * connectedToItem, connectorItem->connectedToItems()) {
785
Wire * wire = dynamic_cast<Wire *>(connectedToItem->attachedTo());
787
if (!ends.contains(connectedToItem)) {
788
ends.append(connectedToItem);
793
if (chained.contains(wire)) continue;
794
chained.append(wire);
798
void Wire::collectWires(QList<Wire *> & wires) {
799
if (wires.contains(this)) return;
802
//DebugDialog::debug(QString("collecting wire %1").arg(this->id()) );
803
collectWiresAux(wires, m_connector0);
804
collectWiresAux(wires, m_connector1);
807
void Wire::collectWiresAux(QList<Wire *> & wires, ConnectorItem * start) {
808
foreach (ConnectorItem * toConnectorItem, start->connectedToItems()) {
809
if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
810
dynamic_cast<Wire *>(toConnectorItem->attachedTo())->collectWires(wires);
816
bool Wire::stickyEnabled()
818
return (connector0()->connectionsCount() <= 0) && (connector1()->connectionsCount() <= 0);
821
bool Wire::getTrace() {
822
return m_viewGeometry.getAnyTrace();
825
bool Wire::getRouted() {
826
return m_viewGeometry.getRouted();
829
void Wire::setRouted(bool routed) {
830
m_viewGeometry.setRouted(routed);
833
void Wire::setRatsnest(bool ratsnest) {
834
m_viewGeometry.setRatsnest(ratsnest);
837
bool Wire::getRatsnest() {
838
return m_viewGeometry.getRatsnest();
841
void Wire::setAutoroutable(bool ar) {
842
m_viewGeometry.setAutoroutable(ar);
845
bool Wire::getAutoroutable() {
846
return m_viewGeometry.getAutoroutable();
849
void Wire::setNormal(bool normal) {
850
m_viewGeometry.setNormal(normal);
853
bool Wire::getNormal() {
854
return m_viewGeometry.getNormal();
857
void Wire::setColor(const QColor & color, qreal op) {
858
m_pen.setBrush(QBrush(color));
860
m_colorName = color.name();
864
void Wire::setShadowColor(QColor & color) {
865
m_shadowBrush = QBrush(color);
866
m_shadowPen.setBrush(m_shadowBrush);
867
m_bendpointPen.setBrush(m_shadowBrush);
868
m_bendpoint2Pen.setBrush(m_shadowBrush);
869
if (m_connector0) m_connector0->restoreColor(false, 0, false);
870
if (m_connector0) m_connector1->restoreColor(false, 0, false);
874
const QColor & Wire::color() {
875
return m_pen.brush().color();
878
void Wire::setWireWidth(qreal width, InfoGraphicsView * infoGraphicsView) {
879
if (m_pen.widthF() == width) return;
881
prepareGeometryChange();
882
setPenWidth(width, infoGraphicsView);
883
if (m_connector0) m_connector0->restoreColor(false, 0, false);
884
if (m_connector1) m_connector1->restoreColor(false, 0, false);
888
qreal Wire::width() {
889
return m_pen.widthF();
893
return 1000 * m_pen.widthF() / FSvgRenderer::printerScale();
896
void Wire::setColorString(QString colorName, qreal op) {
897
// sets a color using the name (.e. "red")
898
// note: colorName is associated with a Fritzing color, not a Qt color
900
QString colorString = colors.value(colorName, "");
901
if (colorString.isEmpty()) {
902
colorString = colorName;
904
foreach (QString c, colors.keys()) {
905
if (colors.value(c).compare(colorName, Qt::CaseInsensitive) == 0) {
913
c.setNamedColor(colorString);
915
m_colorName = colorName;
917
colorString = shadowColors.value(colorName, "");
918
if (colorString.isEmpty()) {
919
colorString = colorName;
922
c.setNamedColor(colorString);
926
QString Wire::hexString() {
927
return m_pen.brush().color().name();
930
QString Wire::colorString() {
934
void Wire::initNames() {
935
if (colors.count() > 0) return;
937
widths << 16 << 24 << 32 << 48;
938
widthTrans.insert(widths[0], tr("thin (16 mil)"));
939
widthTrans.insert(widths[1], tr("standard (24 mil)"));
940
widthTrans.insert(widths[2], tr("thick (32 mil)"));
941
widthTrans.insert(widths[3], tr("extra thick (48 mil)"));
943
STANDARD_TRACE_WIDTH = GraphicsUtils::mils2pixels(widths[1], FSvgRenderer::printerScale());
944
HALF_STANDARD_TRACE_WIDTH = STANDARD_TRACE_WIDTH / 2.0;
946
// need a list because a hash table doesn't guarantee order
947
colorNames.append(tr("blue"));
948
colorNames.append(tr("red"));
949
colorNames.append(tr("black"));
950
colorNames.append(tr("yellow"));
951
colorNames.append(tr("green"));
952
colorNames.append(tr("grey"));
953
colorNames.append(tr("white"));
954
colorNames.append(tr("orange"));
955
colorNames.append(tr("brown"));
956
colorNames.append(tr("purple"));
957
colorNames.append(tr("schematic black"));
959
// need this hash table to translate from user's language to internal color name
960
colorTrans.insert(tr("blue"), "blue");
961
colorTrans.insert(tr("red"), "red");
962
colorTrans.insert(tr("black"), "black");
963
colorTrans.insert(tr("yellow"), "yellow");
964
colorTrans.insert(tr("green"), "green");
965
colorTrans.insert(tr("grey"), "grey");
966
colorTrans.insert(tr("white"), "white");
967
colorTrans.insert(tr("orange"), "orange");
968
colorTrans.insert(tr("brown"), "brown");
969
colorTrans.insert(tr("purple"), "purple");
970
colorTrans.insert(tr("schematic black"), "schematic black");
972
colors.insert("blue", "#418dd9");
973
colors.insert("red", "#cc1414");
974
colors.insert("black", "#404040");
975
colors.insert("yellow", "#ffe24d");
976
colors.insert("green", "#47cc79");
977
colors.insert("grey", "#999999");
978
colors.insert("white", "#ffffff");
979
colors.insert("orange", "#ff7033");
980
colors.insert("jumper", ViewLayer::JumperColor);
981
colors.insert("trace", ViewLayer::Copper0Color);
982
colors.insert("trace1", ViewLayer::Copper1Color);
983
//colors.insert("unrouted", "#000000");
984
//colors.insert("blackblack", "#000000");
985
colors.insert("schematicGrey", "#9d9d9d");
986
colors.insert("purple", "#ab58a2");
987
colors.insert("brown", "#8c3b00");
988
colors.insert("schematic black", "#000000");
990
shadowColors.insert("blue", "#1b5bb3");
991
shadowColors.insert("red", "#8c0000");
992
shadowColors.insert("black", "#000000");
993
shadowColors.insert("yellow", "#e6ab00");
994
shadowColors.insert("green", "#00a63d");
995
shadowColors.insert("grey", "#666666");
996
shadowColors.insert("white", "#999999");
997
shadowColors.insert("orange", "#d95821");
998
shadowColors.insert("jumper", "#2d6563");
999
shadowColors.insert("trace", "#d69b00");
1000
shadowColors.insert("trace1", "#d69b00");
1001
//shadowColors.insert("unrouted", "#000000");
1002
shadowColors.insert("purple", "#7a3a73");
1003
shadowColors.insert("brown", "#6c2710");
1004
shadowColors.insert("schematicGrey", "#1d1d1d");
1005
//shadowColors.insert("blackblack", "#000000");
1006
shadowColors.insert("schematic black", "#000000");
1009
bool Wire::hasFlag(ViewGeometry::WireFlag flag)
1011
return m_viewGeometry.hasFlag(flag);
1014
bool Wire::hasAnyFlag(ViewGeometry::WireFlags flags)
1016
return m_viewGeometry.hasAnyFlag(flags);
1019
Wire * Wire::findTraced(ViewGeometry::WireFlags flags, QList<ConnectorItem *> & ends) {
1020
QList<Wire *> chainedWires;
1021
this->collectChained(chainedWires, ends);
1022
if (ends.count() != 2) {
1023
DebugDialog::debug(QString("wire in jumper or trace must have two ends") );
1027
return ConnectorItem::directlyWiredTo(ends[0], ends[1], flags);
1030
QRgb Wire::getRgb(const QString & name) {
1031
QString str = colors.value(name);
1033
c.setNamedColor(str);
1037
ViewGeometry::WireFlags Wire::wireFlags() {
1038
return m_viewGeometry.wireFlags();
1041
void Wire::setWireFlags(ViewGeometry::WireFlags wireFlags) {
1042
m_viewGeometry.setWireFlags(wireFlags);
1045
qreal Wire::opacity() {
1049
void Wire::setOpacity(qreal opacity) {
1050
m_opacity = opacity;
1054
bool Wire::draggingEnd() {
1058
void Wire::setCanChainMultiple(bool can) {
1059
m_canChainMultiple = can;
1062
bool Wire::canChangeColor() {
1063
if (getRatsnest()) return false;
1064
if (!getTrace()) return true;
1066
return (this->m_viewIdentifier == ViewIdentifierClass::SchematicView);
1069
void Wire::collectDirectWires(QList<Wire *> & wires) {
1070
if (!wires.contains(this)) {
1074
collectDirectWires(m_connector0, wires);
1075
collectDirectWires(m_connector1, wires);
1078
void Wire::collectDirectWires(ConnectorItem * connectorItem, QList<Wire *> & wires) {
1079
if (connectorItem->connectionsCount() != 1) return;
1081
ConnectorItem * toConnectorItem = connectorItem->connectedToItems()[0];
1082
if (toConnectorItem->attachedToItemType() != ModelPart::Wire) return;
1084
Wire * nextWire = dynamic_cast<Wire *>(toConnectorItem->attachedTo());
1085
if (wires.contains(nextWire)) return;
1087
wires.append(nextWire);
1088
nextWire->collectDirectWires(nextWire->otherConnector(toConnectorItem), wires);
1091
QVariant Wire::itemChange(GraphicsItemChange change, const QVariant &value)
1093
if (change == ItemSelectedChange) {
1095
m_partLabel->update();
1098
if (!m_ignoreSelectionChange) {
1099
QList<Wire *> chained;
1100
QList<ConnectorItem *> ends;
1101
collectChained(chained, ends);
1102
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1103
if (infoGraphicsView) {
1104
infoGraphicsView->setIgnoreSelectionChangeEvents(true);
1106
// DebugDialog::debug(QString("original wire selected %1 %2").arg(value.toBool()).arg(this->id()));
1107
foreach (Wire * wire, chained) {
1108
if (wire != this ) {
1109
wire->setIgnoreSelectionChange(true);
1110
wire->setSelected(value.toBool());
1111
wire->setIgnoreSelectionChange(false);
1112
// DebugDialog::debug(QString("wire selected %1 %2").arg(value.toBool()).arg(wire->id()));
1115
if (infoGraphicsView) {
1116
infoGraphicsView->setIgnoreSelectionChangeEvents(false);
1120
return ItemBase::itemChange(change, value);
1123
void Wire::cleanup() {
1126
void Wire::getConnectedColor(ConnectorItem * connectorItem, QBrush * &brush, QPen * &pen, qreal & opacity, qreal & negativePenWidth, bool & negativeOffsetRect) {
1128
connectorItem->setBigDot(false);
1130
bool bendpoint = true;
1131
foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) {
1132
if (toConnectorItem->attachedToItemType() != ModelPart::Wire) {
1133
// 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
1135
if (toConnectorItem->connectionsCount() > 1) {
1136
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1137
if (infoGraphicsView != NULL && infoGraphicsView->hasBigDots()) {
1139
foreach (ConnectorItem * totoConnectorItem, toConnectorItem->connectedToItems()) {
1140
if (totoConnectorItem->attachedToItemType() == ModelPart::Wire) {
1141
Wire * w = dynamic_cast<Wire *>(totoConnectorItem->attachedTo());
1142
if (w && w->getTrace()) {
1154
ItemBase::getConnectedColor(connectorItem, brush, pen, opacity, negativePenWidth, negativeOffsetRect);
1162
ItemBase::getConnectedColor(connectorItem, brush, pen, opacity, negativePenWidth, negativeOffsetRect);
1166
// connectorItem is a bendpoint or connects to a multiply connected connector
1169
//DebugDialog::debug(QString("big dot %1 %2 %3").arg(this->id()).arg(connectorItem->connectorSharedID()).arg(count));
1172
brush = &m_shadowBrush;
1175
// only ever reach here when drawing a connector that is connected to more than one trace
1176
pen = &m_bendpoint2Pen;
1177
negativePenWidth = m_bendpoint2Width;
1178
negativeOffsetRect = m_negativeOffsetRect;
1179
connectorItem->setBigDot(true);
1182
negativeOffsetRect = m_negativeOffsetRect;
1183
negativePenWidth = m_bendpointWidth;
1184
pen = &m_bendpointPen;
1188
void Wire::setPenWidth(qreal w, InfoGraphicsView * infoGraphicsView) {
1190
infoGraphicsView->getBendpointWidths(this, w, m_bendpointWidth, m_bendpoint2Width, m_negativeOffsetRect);
1191
m_bendpointPen.setWidthF(qAbs(m_bendpointWidth));
1192
m_bendpoint2Pen.setWidthF(qAbs(m_bendpoint2Width));
1193
m_shadowPen.setWidthF(w + 2);
1196
bool Wire::connectionIsAllowed(ConnectorItem * to) {
1197
if (!ItemBase::connectionIsAllowed(to)) return false;
1199
Wire * w = dynamic_cast<Wire *>(to->attachedTo());
1200
if (w == NULL) return true;
1202
if (w->getRatsnest()) return false;
1204
return m_viewIdentifier != ViewIdentifierClass::BreadboardView;
1207
bool Wire::isGrounded() {
1208
return ConnectorItem::isGrounded(connector0(), connector1());
1211
bool Wire::acceptsMouseDoubleClickConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1215
bool Wire::acceptsMouseMoveConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1219
bool Wire::acceptsMouseReleaseConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1223
void Wire::setIgnoreSelectionChange(bool ignore) {
1224
m_ignoreSelectionChange = ignore;
1227
bool Wire::collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget)
1229
if (prop.compare("width", Qt::CaseInsensitive) == 0) {
1230
// don't display width property
1234
if (prop.compare("color", Qt::CaseInsensitive) == 0) {
1235
returnProp = tr("color");
1236
if (canChangeColor()) {
1237
QComboBox * comboBox = new QComboBox(parent);
1238
comboBox->setEditable(false);
1239
comboBox->setEnabled(swappingEnabled);
1240
comboBox->setObjectName("infoViewComboBox");
1243
QString englishCurrColor = colorString();
1244
foreach(QString transColorName, Wire::colorNames) {
1245
QString englishColorName = Wire::colorTrans.value(transColorName);
1246
comboBox->addItem(transColorName, QVariant(englishColorName));
1247
if (englishColorName.compare(englishCurrColor, Qt::CaseInsensitive) == 0) {
1248
comboBox->setCurrentIndex(ix);
1253
connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(colorEntry(const QString &)));
1254
returnWidget = comboBox;
1255
returnValue = comboBox->currentText();
1259
returnWidget = NULL;
1260
returnValue = colorString();
1265
return ItemBase::collectExtraInfo(parent, family, prop, value, swappingEnabled, returnProp, returnValue, returnWidget);
1268
void Wire::colorEntry(const QString & text) {
1271
QComboBox * comboBox = dynamic_cast<QComboBox *>(sender());
1272
if (comboBox == NULL) return;
1274
QString color = comboBox->itemData(comboBox->currentIndex()).toString();
1276
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1277
if (infoGraphicsView != NULL) {
1278
infoGraphicsView->changeWireColor(color);
1282
bool Wire::hasPartLabel() {
1287
ItemBase::PluralType Wire::isPlural() {
1291
void Wire::checkVisibility(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) {
1293
if (!onIt->attachedTo()->isVisible()) {
1294
this->setVisible(false);
1297
ConnectorItem * other = otherConnector(onMe);
1298
foreach (ConnectorItem * toConnectorItem, other->connectedToItems()) {
1299
if (toConnectorItem->attachedToItemType() == ModelPart::Wire) continue;
1301
if (!toConnectorItem->attachedTo()->isVisible()) {
1302
this->setVisible(false);
1310
bool Wire::canSwitchLayers() {
1314
bool Wire::hasPartNumberProperty()
1319
bool Wire::rotationAllowed() {
1323
bool Wire::rotation45Allowed() {
1327
void Wire::addedToScene(bool temporary) {
1328
ItemBase::addedToScene(temporary);
1330
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1331
if (infoGraphicsView == NULL) return;
1333
bool succeeded = connect(this, SIGNAL(wireChangedSignal(Wire*, QLineF, QLineF, QPointF, QPointF, ConnectorItem *, ConnectorItem *) ),
1334
infoGraphicsView, SLOT(wire_wireChanged(Wire*, QLineF, QLineF, QPointF, QPointF, ConnectorItem *, ConnectorItem *)),
1335
Qt::DirectConnection); // DirectConnection means call the slot directly like a subroutine, without waiting for a thread or queue
1336
succeeded = succeeded && connect(this, SIGNAL(wireSplitSignal(Wire*, QPointF, QPointF, QLineF)),
1337
infoGraphicsView, SLOT(wire_wireSplit(Wire*, QPointF, QPointF, QLineF)));
1338
succeeded = succeeded && connect(this, SIGNAL(wireJoinSignal(Wire*, ConnectorItem *)),
1339
infoGraphicsView, SLOT(wire_wireJoin(Wire*, ConnectorItem*)));
1341
DebugDialog::debug("wire signal connect failed");
1
/*******************************************************************
3
Part of the Fritzing project - http://fritzing.org
4
Copyright (c) 2007-2011 Fachhochschule Potsdam - http://fh-potsdam.de
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.
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.
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/>.
19
********************************************************************
22
$Author: cohen@irascible.com $:
23
$Date: 2011-08-18 12:47:41 +0200 (Thu, 18 Aug 2011) $
25
********************************************************************/
39
* make-straight function
43
curvy to begin with? would have to vary with some function of angle and distance
44
could convert control points to t values?
46
turn curvature on/off per view
48
---------------------------------------------------------
56
autorouter warning in PCB view
58
modify parameters (tension, unit area)?
62
/////////////////////////////////////////////////////////////////
68
#include <QRadialGradient>
71
#include <QGraphicsScene>
73
#include <QGraphicsItem>
77
#include <QApplication>
79
#include "../debugdialog.h"
80
#include "../sketch/infographicsview.h"
81
#include "../connectors/connectoritem.h"
82
#include "../connectors/svgidlayer.h"
83
#include "../fsvgrenderer.h"
84
#include "partlabel.h"
85
#include "../model/modelpart.h"
86
#include "../utils/graphicsutils.h"
87
#include "../utils/textutils.h"
88
#include "../utils/bezier.h"
89
#include "../utils/bezierdisplay.h"
90
#include "../layerattributes.h"
94
QHash<QString, QString> Wire::colors;
95
QHash<QString, QString> Wire::shadowColors;
96
QHash<QString, QString> Wire::colorTrans;
97
QStringList Wire::colorNames;
98
QHash<int, QString> Wire::widthTrans;
99
QList<int> Wire::widths;
100
double Wire::STANDARD_TRACE_WIDTH;
101
double Wire::HALF_STANDARD_TRACE_WIDTH;
102
double Wire::THIN_TRACE_WIDTH;
104
const double DefaultHoverStrokeWidth = 4;
106
static Bezier UndoBezier;
107
static BezierDisplay * TheBezierDisplay = NULL;
109
////////////////////////////////////////////////////////////
111
bool alphaLessThan(QColor * c1, QColor * c2)
113
return c1->alpha() < c2->alpha();
116
/////////////////////////////////////////////////////////////
119
WireMenu::WireMenu(const QString & title, QWidget * parent) : QMenu(title, parent)
124
void WireMenu::setWire(Wire * w) {
128
Wire * WireMenu::wire() {
132
/////////////////////////////////////////////////////////////
134
WireAction::WireAction(QAction * action) : QAction(action) {
136
this->setText(action->text());
137
this->setStatusTip(action->statusTip());
138
this->setCheckable(action->isCheckable());
141
WireAction::WireAction(const QString & title, QObject * parent) : QAction(title, parent) {
145
void WireAction::setWire(Wire * w) {
149
Wire * WireAction::wire() {
153
/////////////////////////////////////////////////////////////
155
Wire::Wire( ModelPart * modelPart, ViewIdentifierClass::ViewIdentifier viewIdentifier, const ViewGeometry & viewGeometry, long id, QMenu* itemMenu, bool initLabel)
156
: ItemBase(modelPart, viewIdentifier, viewGeometry, id, itemMenu)
159
m_canHaveCurve = true;
160
m_hoverStrokeWidth = DefaultHoverStrokeWidth;
161
m_connector0 = m_connector1 = NULL;
162
m_partLabel = initLabel ? new PartLabel(this, NULL) : NULL;
163
m_canChainMultiple = false;
164
setFlag(QGraphicsItem::ItemIsSelectable, true );
165
m_connectorHover = NULL;
167
m_ignoreSelectionChange = false;
169
//DebugDialog::debug(QString("aix line %1 %2 %3 %4").arg(this->viewGeometry().line().x1())
170
//.arg(this->viewGeometry().line().y1())
171
//.arg(this->viewGeometry().line().x2())
172
//.arg(this->viewGeometry().line().y2()) );
173
//DebugDialog::debug(QString("aix loc %1 %2").arg(this->viewGeometry().loc().x())
174
//.arg(this->viewGeometry().loc().y()) );
176
setPos(m_viewGeometry.loc());
178
m_dragCurve = m_dragEnd = false;
187
FSvgRenderer * Wire::setUp(ViewLayer::ViewLayerID viewLayerID, const LayerHash & viewLayers, InfoGraphicsView * infoGraphicsView) {
188
ItemBase::setViewLayerID(viewLayerID, viewLayers);
189
FSvgRenderer * svgRenderer = setUpConnectors(m_modelPart, m_viewIdentifier);
190
if (svgRenderer != NULL) {
191
initEnds(m_viewGeometry, svgRenderer->viewBox(), infoGraphicsView);
192
setConnectorTooltips();
194
setZValue(this->z());
199
void Wire::saveGeometry() {
200
m_viewGeometry.setSelected(this->isSelected());
201
m_viewGeometry.setLine(this->line());
202
m_viewGeometry.setLoc(this->pos());
203
m_viewGeometry.setZ(this->zValue());
207
bool Wire::itemMoved() {
208
if (m_viewGeometry.loc() != this->pos()) return true;
210
if (this->line().dx() != m_viewGeometry.line().dx()) return false;
211
if (this->line().dy() != m_viewGeometry.line().dy()) return false;
213
return (this->line() != m_viewGeometry.line());
216
void Wire::moveItem(ViewGeometry & viewGeometry) {
217
this->setPos(viewGeometry.loc());
218
this->setLine(viewGeometry.line());
221
void Wire::initEnds(const ViewGeometry & vg, QRectF defaultRect, InfoGraphicsView * infoGraphicsView) {
225
foreach (ConnectorItem * item, cachedConnectorItems()) {
226
// check the name or is order good enough?
234
penWidth = item->rect().width();
244
if ((vg.line().length() == 0) && (vg.line().x1() == -1)) {
245
this->setLine(defaultRect.left(), defaultRect.top(), defaultRect.right(), defaultRect.bottom());
248
this->setLine(vg.line());
253
m_viewGeometry.setLine(this->line());
255
QBrush brush(QColor(0, 0, 0));
256
QPen pen(brush, penWidth, Qt::SolidLine, Qt::RoundCap);
259
m_pen.setCapStyle(Qt::RoundCap);
260
m_shadowPen.setCapStyle(Qt::RoundCap);
261
if (infoGraphicsView != NULL) {
262
infoGraphicsView->initWire(this, penWidth);
265
prepareGeometryChange();
268
void Wire::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget ) {
269
if (m_hidden) return;
271
ItemBase::paint(painter, option, widget);
274
void Wire::paintBody(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget )
279
QPainterPath painterPath;
280
if (m_bezier && !m_bezier->isEmpty()) {
281
QLineF line = this->line();
282
painterPath.moveTo(line.p1());
283
painterPath.cubicTo(m_bezier->cp0(), m_bezier->cp1(), line.p2());
286
DebugDialog::debug(QString("c0x:%1,c0y:%2 c1x:%3,c1y:%4 p0x:%5,p0y:%6 p1x:%7,p1y:%8 px:%9,py:%10")
287
.arg(m_controlPoints.at(0).x())
288
.arg(m_controlPoints.at(0).y())
289
.arg(m_controlPoints.at(1).x())
290
.arg(m_controlPoints.at(1).y())
291
.arg(m_line.p1().x())
292
.arg(m_line.p1().y())
293
.arg(m_line.p2().x())
294
.arg(m_line.p2().y())
303
painter->setOpacity(m_inactive ? m_opacity / 2 : m_opacity);
306
painter->setPen(m_shadowPen);
307
if (painterPath.isEmpty()) {
308
QLineF line = this->line();
309
painter->drawLine(line);
312
painter->drawPath(painterPath);
317
painter->setPen(m_pen);
318
if (painterPath.isEmpty()) {
319
painter->drawLine(getPaintLine());
322
painter->drawPath(painterPath);
326
void Wire::paintHover(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
331
if ((m_connectorHoverCount > 0 && !(m_dragEnd || m_dragCurve)) || m_connectorHoverCount2 > 0) {
332
painter->setOpacity(.50);
333
painter->fillPath(this->hoverShape(), QBrush(connectorHoverColor));
336
painter->setOpacity(hoverOpacity);
337
painter->fillPath(this->hoverShape(), QBrush(hoverColor));
342
QPainterPath Wire::hoverShape() const
344
return shapeAux(m_hoverStrokeWidth);
347
QPainterPath Wire::shape() const
349
return shapeAux(m_pen.widthF());
352
QPainterPath Wire::shapeAux(double width) const
355
if (m_line == QLineF()) {
359
path.moveTo(m_line.p1());
360
if (m_bezier == NULL || m_bezier->isEmpty()) {
361
path.lineTo(m_line.p2());
364
path.cubicTo(m_bezier->cp0(), m_bezier->cp1(), m_line.p2());
366
//DebugDialog::debug(QString("using hoverstrokewidth %1 %2").arg(m_id).arg(m_hoverStrokeWidth));
367
return GraphicsUtils::shapeFromPath(path, m_pen, width, false);
370
QRectF Wire::boundingRect() const
372
if (m_pen.widthF() == 0.0) {
373
const double x1 = m_line.p1().x();
374
const double x2 = m_line.p2().x();
375
const double y1 = m_line.p1().y();
376
const double y2 = m_line.p2().y();
377
double lx = qMin(x1, x2);
378
double rx = qMax(x1, x2);
379
double ty = qMin(y1, y2);
380
double by = qMax(y1, y2);
381
return QRectF(lx, ty, rx - lx, by - ty);
383
return hoverShape().controlPointRect();
386
void Wire::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
387
//DebugDialog::debug("checking press event");
388
emit wireSplitSignal(this, event->scenePos(), this->pos(), this->line());
391
void Wire::mousePressEvent(QGraphicsSceneMouseEvent *event)
393
WireMenu * wireMenu = qobject_cast<WireMenu *>(m_itemMenu);
395
wireMenu->setWire(this);
397
ItemBase::mousePressEvent(event);
400
void Wire::initDragCurve(QPointF scenePos) {
401
if (m_bezier == NULL) {
402
m_bezier = new Bezier();
405
UndoBezier.copy(m_bezier);
410
QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL);
411
QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL);
412
if (m_bezier->isEmpty()) {
413
m_bezier->initToEnds(mapFromScene(p0), mapFromScene(p1));
416
m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1));
419
m_bezier->initControlIndex(mapFromScene(scenePos), m_pen.widthF());
420
TheBezierDisplay = new BezierDisplay;
421
TheBezierDisplay->initDisplay(this, m_bezier);
424
bool Wire::initNewBendpoint(QPointF scenePos, Bezier & left, Bezier & right) {
425
if (m_bezier == NULL || m_bezier->isEmpty()) {
430
QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL);
431
QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL);
432
m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1));
433
UndoBezier.copy(m_bezier);
435
double t = m_bezier->findSplit(mapFromScene(scenePos), m_pen.widthF());
436
m_bezier->split(t, left, right);
440
void Wire::initDragEnd(ConnectorItem * connectorItem, QPointF scenePos) {
443
QLineF line = this->line();
444
m_drag0 = (connectorItem == m_connector0);
448
m_wireDragOrigin = line.p2();
449
//DebugDialog::debug(QString("drag near origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) );
452
m_wireDragOrigin = line.p1();
453
//DebugDialog::debug(QString("drag far origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) );
454
//DebugDialog::debug(QString("drag far other %1 %2").arg(line.p2().x()).arg(line.p2().y()) );
457
if (connectorItem->chained()) {
458
QList<Wire *> chained;
459
QList<ConnectorItem *> ends;
460
collectChained(chained, ends);
461
// already saved the first one
462
for (int i = 1; i < chained.count(); i++) {
463
chained[i]->saveGeometry();
469
void Wire::mouseReleaseConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
471
Q_UNUSED(connectorItem);
475
void Wire::mouseMoveConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
476
mouseMoveEventAux(this->mapFromItem(connectorItem, event->pos()), event->modifiers());
480
void Wire::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
481
mouseMoveEventAux(event->pos(), event->modifiers());
484
void Wire::mouseMoveEventAux(QPointF eventPos, Qt::KeyboardModifiers modifiers) {
485
if (m_spaceBarWasPressed) {
490
prepareGeometryChange();
491
dragCurve(eventPos, modifiers);
493
if (TheBezierDisplay) TheBezierDisplay->updateDisplay(this, m_bezier);
497
if (m_dragEnd == false) {
501
ConnectorItem * whichConnectorItem;
502
ConnectorItem * otherConnectorItem;
504
whichConnectorItem = m_connector0;
505
otherConnectorItem = m_connector1;
508
whichConnectorItem = m_connector1;
509
otherConnectorItem = m_connector0;
512
if ((modifiers & Qt::ShiftModifier) != 0) {
513
QPointF initialPos = mapFromScene(otherConnectorItem->sceneAdjustedTerminalPoint(NULL));
514
bool bendpoint = isBendpoint(whichConnectorItem);
517
foreach (ConnectorItem * ci, whichConnectorItem->connectedToItems()) {
518
Wire * w = qobject_cast<Wire *>(ci->attachedTo());
519
ConnectorItem * oci = w->otherConnector(ci);
520
QPointF otherInitialPos = mapFromScene(oci->sceneAdjustedTerminalPoint(NULL));
521
QPointF p1(initialPos.x(), otherInitialPos.y());
522
double d = GraphicsUtils::distanceSqd(p1, eventPos);
528
p1.setX(otherInitialPos.x());
529
p1.setY(initialPos.y());
530
d = GraphicsUtils::distanceSqd(p1, eventPos);
540
eventPos = GraphicsUtils::calcConstraint(initialPos, eventPos);
546
QPointF p = this->mapToScene(eventPos);
547
QGraphicsSvgItem::setPos(p.x(), p.y());
548
this->setLine(0, 0, m_wireDragOrigin.x() - p.x() + m_viewGeometry.loc().x(),
549
m_wireDragOrigin.y() - p.y() + m_viewGeometry.loc().y() );
550
//DebugDialog::debug(QString("drag0 wdo:(%1,%2) p:(%3,%4) vg:(%5,%6) l:(%7,%8)")
551
// .arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y())
552
// .arg(p.x()).arg(p.y())
553
// .arg(m_viewGeometry.loc().x()).arg(m_viewGeometry.loc().y())
554
// .arg(line().p2().x()).arg(line().p2().y())
558
this->setLine(m_wireDragOrigin.x(), m_wireDragOrigin.y(), eventPos.x(), eventPos.y());
559
//DebugDialog::debug(QString("drag1 wdo:(%1,%2) ep:(%3,%4) p:(%5,%6) l:(%7,%8)")
560
// .arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y())
561
// .arg(eventPos.x()).arg(eventPos.y())
562
// .arg(pos().x()).arg(pos().y())
563
// .arg(line().p2().x()).arg(line().p2().y())
568
bool chained = false;
569
foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) {
570
Wire * chainedWire = qobject_cast<Wire *>(toConnectorItem->attachedTo());
571
if (chainedWire == NULL) continue;
573
chainedWire->simpleConnectedMoved(whichConnectorItem, toConnectorItem);
578
// don't allow wire to connect back to something the other end is already directly connected to
580
QList<ConnectorItem *> ends;
581
collectChained(otherConnectorItem, wires, ends);
582
for (int i = 0; i < wires.count(); i++) {
584
collectChained(w->m_connector1, wires, ends);
585
collectChained(w->m_connector0, wires, ends);
587
ends.append(otherConnectorItem);
588
foreach (Wire * w, wires) {
589
ends.append(w->connector0());
590
ends.append(w->connector1());
592
foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) {
593
ends.removeOne(toConnectorItem);
596
ConnectorItem * originatingConnector = NULL;
597
if (otherConnectorItem && otherConnectorItem->connectionsCount() > 0) {
598
originatingConnector = otherConnectorItem->connectedToItems()[0];
600
whichConnectorItem->findConnectorUnder(false, true, ends, true, originatingConnector);
604
void Wire::setConnector0Rect() {
605
QRectF rect = m_connector0->rect();
606
rect.moveTo(0 - (rect.width() / 2.0) ,
607
0 - (rect.height() / 2.0) );
608
//DebugDialog::debug(QString("set connector rect %1 %2").arg(rect.width()).arg(rect.height()));
609
m_connector0->setRect(rect);
613
void Wire::setConnector1Rect() {
614
QRectF rect = m_connector1->rect();
615
rect.moveTo(this->line().dx() - (rect.width() / 2.0) ,
616
this->line().dy() - (rect.height() / 2.0) );
617
m_connector1->setRect(rect);
620
void Wire::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
621
if (m_spaceBarWasPressed) {
625
if (releaseDrag()) return;
627
ItemBase::mouseReleaseEvent(event);
630
bool Wire::releaseDrag() {
631
if (m_dragEnd == false && m_dragCurve == false) return false;
634
delete TheBezierDisplay;
635
TheBezierDisplay = NULL;
638
if (UndoBezier != *m_bezier) {
639
emit wireChangedCurveSignal(this, &UndoBezier, m_bezier, false);
646
ConnectorItem * from = (m_drag0) ? m_connector0 : m_connector1;
647
ConnectorItem * to = from->releaseDrag();
649
QLineF newLine = this->line();
650
QLineF oldLine = m_viewGeometry.line();
651
QPointF oldPos = m_viewGeometry.loc();
652
QPointF newPos = this->pos();
653
if (newLine != oldLine || oldPos != newPos) {
654
emit wireChangedSignal(this, oldLine, newLine, oldPos, newPos, from, to);
661
void Wire::saveInstanceLocation(QXmlStreamWriter & streamWriter)
663
QLineF line = m_viewGeometry.line();
664
QPointF loc = m_viewGeometry.loc();
665
streamWriter.writeAttribute("x", QString::number(loc.x()));
666
streamWriter.writeAttribute("y", QString::number(loc.y()));
667
streamWriter.writeAttribute("x1", QString::number(line.x1()));
668
streamWriter.writeAttribute("y1", QString::number(line.y1()));
669
streamWriter.writeAttribute("x2", QString::number(line.x2()));
670
streamWriter.writeAttribute("y2", QString::number(line.y2()));
671
streamWriter.writeAttribute("wireFlags", QString::number(m_viewGeometry.flagsAsInt()));
674
void Wire::writeGeometry(QXmlStreamWriter & streamWriter) {
675
ItemBase::writeGeometry(streamWriter);
676
streamWriter.writeStartElement("wireExtras");
677
streamWriter.writeAttribute("mils", QString::number(mils()));
678
streamWriter.writeAttribute("color", m_pen.brush().color().name());
679
streamWriter.writeAttribute("opacity", QString::number(m_opacity));
680
if (m_bezier) m_bezier->write(streamWriter);
681
streamWriter.writeEndElement();
684
void Wire::setExtras(QDomElement & element, InfoGraphicsView * infoGraphicsView)
686
if (element.isNull()) return;
689
double w = element.attribute("width").toDouble(&ok);
691
setWireWidth(w, infoGraphicsView, infoGraphicsView->getWireStrokeWidth(this, w));
694
w = element.attribute("mils").toDouble(&ok);
696
double wpix = GraphicsUtils::mils2pixels(w, FSvgRenderer::printerScale());
697
setWireWidth(wpix, infoGraphicsView, infoGraphicsView->getWireStrokeWidth(this, wpix));
701
setColorFromElement(element);
702
QDomElement bElement = element.firstChildElement("bezier");
703
Bezier bezier = Bezier::fromElement(bElement);
704
if (!bezier.isEmpty()) {
705
prepareGeometryChange();
706
m_bezier = new Bezier;
707
m_bezier->copy(&bezier);
708
QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL);
709
QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL);
710
m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1));
715
void Wire::setColorFromElement(QDomElement & element) {
716
QString colorString = element.attribute("color");
717
if (colorString.isNull() || colorString.isEmpty()) return;
720
double op = element.attribute("opacity").toDouble(&ok);
725
setColorString(colorString, op);
728
void Wire::hoverEnterConnectorItem(QGraphicsSceneHoverEvent * event , ConnectorItem * item) {
729
m_connectorHover = item;
730
ItemBase::hoverEnterConnectorItem(event, item);
733
void Wire::hoverLeaveConnectorItem(QGraphicsSceneHoverEvent * event, ConnectorItem * item) {
734
m_connectorHover = NULL;
735
ItemBase::hoverLeaveConnectorItem(event, item);
738
void Wire::hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) {
739
ItemBase::hoverEnterEvent(event);
740
QApplication::instance()->installEventFilter(this);
741
QApplication::setOverrideCursor(cursor());
742
//DebugDialog::debug("---wire set override cursor");
743
updateCursor(event->modifiers());
746
void Wire::hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ) {
747
QApplication::instance()->removeEventFilter(this);
748
ItemBase::hoverLeaveEvent(event);
749
//DebugDialog::debug("------wire restore override cursor");
750
QApplication::restoreOverrideCursor();
754
void Wire::connectionChange(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) {
755
checkVisibility(onMe, onIt, connect);
758
foreach (ConnectorItem * connectedTo, m_connector0->connectedToItems()) {
759
if (connectedTo->attachedToItemType() != ModelPart::Wire) {
765
foreach (ConnectorItem * connectedTo, m_connector1->connectedToItems()) {
766
if (connectedTo->attachedToItemType() != ModelPart::Wire) {
774
void Wire::mouseDoubleClickConnectorEvent(ConnectorItem * connectorItem) {
776
foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) {
777
if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
787
// near as I can tell, this is to eliminate the overrides from the connectorItem and then from the wire itself
788
QApplication::restoreOverrideCursor();
789
QApplication::restoreOverrideCursor();
790
emit wireJoinSignal(this, connectorItem);
794
void Wire::mousePressConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
795
//DebugDialog::debug("checking press connector event");
797
if (m_canChainMultiple && event->modifiers() & altOrMetaModifier()) {
798
// dragging a wire out of a bendpoint
799
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
800
if (infoGraphicsView != NULL) {
801
infoGraphicsView->mousePressConnectorEvent(connectorItem, event);
808
connectorItem->setOverConnectorItem(NULL);
809
initDragEnd(connectorItem, event->scenePos());
813
void Wire::simpleConnectedMoved(ConnectorItem * to) {
814
// to is this wire, from is something else
815
simpleConnectedMoved(to->firstConnectedToIsh(), to);
818
void Wire::simpleConnectedMoved(ConnectorItem * from, ConnectorItem * to)
820
if (from == NULL) return;
822
// to is this wire, from is something else
824
calcNewLine(from, to, p1, p2);
827
QPointF oldPos = this->pos();
829
QLineF oldLine = this->line();
830
QLineF newLine(0, 0, p2.x() - p1.x(), p2.y() - p1.y());
831
if (qAbs(oldPos.x() - newPos.x()) > 1.75 ||
832
qAbs(oldPos.y() - newPos.y()) > 1.75 ||
833
qAbs(oldLine.x1() - newLine.x1()) > 1.75 ||
834
qAbs(oldLine.x2() - newLine.x2()) > 1.75 ||
835
qAbs(oldLine.y1() - newLine.y1()) > 1.75 ||
836
qAbs(oldLine.y2() - newLine.y2()) > 1.75
839
DebugDialog::debug("line changed");
840
calcNewLine(from,to,p1,p2);
845
this->setLine(0,0, p2.x() - p1.x(), p2.y() - p1.y() );
846
//DebugDialog::debug(QString("set line %5: %1 %2, %3 %4, vis:%6 lyr:%7").arg(p1.x()).arg(p1.y()).arg(p2.x()).arg(p2.y()).arg(id()).arg(isVisible()).arg(m_viewIdentifier) );
850
void Wire::calcNewLine(ConnectorItem * from, ConnectorItem * to, QPointF & p1, QPointF & p2) {
851
// to is this wire, from is something else
852
if (to == m_connector0) {
853
p1 = from->sceneAdjustedTerminalPoint(to);
854
ConnectorItem * otherFrom = m_connector1->firstConnectedToIsh();
855
if (otherFrom == NULL) {
856
p2 = m_connector1->mapToScene(m_connector1->rect().center());
859
p2 = otherFrom->sceneAdjustedTerminalPoint(m_connector1);
863
p2 = from->sceneAdjustedTerminalPoint(to);
864
ConnectorItem * otherFrom = m_connector0->firstConnectedToIsh();
865
if (otherFrom == NULL) {
866
p1 = m_connector0->mapToScene(m_connector0->rect().center());
869
p1 = otherFrom->sceneAdjustedTerminalPoint(m_connector0);
875
void Wire::connectedMoved(ConnectorItem * from, ConnectorItem * to) {
876
// "from" is the connector on the part
877
// "to" is the connector on the wire
879
simpleConnectedMoved(from, to);
883
DebugDialog::debug(QString("connected moved %1 %2, %3 %4")
884
.arg(from->attachedToID())
885
.arg(from->attachedToTitle())
886
.arg(to->attachedToID())
887
.arg(to->attachedToTitle())
891
ConnectorItem * otherEnd = otherConnector(to);
892
bool chained = otherEnd->chained();
896
if (to == m_connector0) {
897
p1 = from->sceneAdjustedTerminalPoint(m_connector0);
898
p2 = this->line().p2() + p1;
901
p2 = from->sceneAdjustedTerminalPoint(m_connector1);
902
p1 = p2 - this->line().p2();
906
calcNewLine(from, to, p1, p2);
909
this->setLine(0,0, p2.x() - p1.x(), p2.y() - p1.y() );
910
//DebugDialog::debug(QString("set line %5: %1 %2, %3 %4, vis:%6 lyr:%7").arg(p1.x()).arg(p1.y()).arg(p2.x()).arg(p2.y()).arg(id()).arg(isVisible()).arg(m_viewIdentifier) );
914
foreach (ConnectorItem * otherEndTo, otherEnd->connectedToItems()) {
915
if (otherEndTo->attachedToItemType() == ModelPart::Wire) {
916
otherEndTo->attachedTo()->connectedMoved(otherEnd, otherEndTo);
923
FSvgRenderer * Wire::setUpConnectors(ModelPart * modelPart, ViewIdentifierClass::ViewIdentifier viewIdentifier)
925
clearConnectorItemCache();
928
LayerAttributes layerAttributes;
929
FSvgRenderer * renderer = ItemBase::setUpImage(modelPart, viewIdentifier, m_viewLayerID, m_viewLayerSpec, layerAttributes, error);
930
if (renderer == NULL) {
934
foreach (Connector * connector, m_modelPart->connectors().values()) {
935
if (connector == NULL) continue;
937
SvgIdLayer * svgIdLayer = connector->fullPinInfo(viewIdentifier, m_viewLayerID);
938
if (svgIdLayer == NULL) continue;
940
bool result = renderer->setUpConnector(svgIdLayer, false);
941
if (!result) continue;
943
ConnectorItem * connectorItem = newConnectorItem(connector);
944
connectorItem->setRect(svgIdLayer->m_rect);
945
connectorItem->setTerminalPoint(svgIdLayer->m_point);
946
m_originalConnectorRect = svgIdLayer->m_rect;
948
connectorItem->setCircular(true);
949
//DebugDialog::debug(QString("terminal point %1 %2").arg(terminalPoint.x()).arg(terminalPoint.y()) );
956
void Wire::setPos(const QPointF & pos) {
957
ItemBase::setPos(pos);
962
void Wire::setLineAnd(QLineF line, QPointF pos, bool useLine) {
964
if (useLine) this->setLine(line);
969
ConnectorItem * Wire::otherConnector(ConnectorItem * oneConnector) {
970
if (oneConnector == m_connector0) return m_connector1;
975
ConnectorItem * Wire::connector0() {
979
ConnectorItem * Wire::connector1() {
983
void Wire::findConnectorsUnder() {
984
foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
985
connectorItem->findConnectorUnder(true, false, ConnectorItem::emptyConnectorItemList, false, NULL);
989
void Wire::collectChained(QList<Wire *> & chained, QList<ConnectorItem *> & ends ) {
990
chained.append(this);
991
for (int i = 0; i < chained.count(); i++) {
992
Wire * wire = chained[i];
993
collectChained(wire->m_connector1, chained, ends);
994
collectChained(wire->m_connector0, chained, ends);
998
void Wire::collectChained(ConnectorItem * connectorItem, QList<Wire *> & chained, QList<ConnectorItem *> & ends) {
999
if (connectorItem == NULL) return;
1001
foreach (ConnectorItem * connectedToItem, connectorItem->connectedToItems()) {
1002
Wire * wire = qobject_cast<Wire *>(connectedToItem->attachedTo());
1004
if (!ends.contains(connectedToItem)) {
1005
ends.append(connectedToItem);
1010
if (chained.contains(wire)) continue;
1011
chained.append(wire);
1015
void Wire::collectWires(QList<Wire *> & wires) {
1016
if (wires.contains(this)) return;
1019
//DebugDialog::debug(QString("collecting wire %1").arg(this->id()) );
1020
collectWiresAux(wires, m_connector0);
1021
collectWiresAux(wires, m_connector1);
1024
void Wire::collectWiresAux(QList<Wire *> & wires, ConnectorItem * start) {
1025
foreach (ConnectorItem * toConnectorItem, start->connectedToItems()) {
1026
if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
1027
qobject_cast<Wire *>(toConnectorItem->attachedTo())->collectWires(wires);
1033
bool Wire::stickyEnabled()
1035
return (connector0()->connectionsCount() <= 0) && (connector1()->connectionsCount() <= 0);
1038
bool Wire::getTrace() {
1039
return m_viewGeometry.getAnyTrace();
1042
bool Wire::getRouted() {
1043
return m_viewGeometry.getRouted();
1046
void Wire::setRouted(bool routed) {
1047
m_viewGeometry.setRouted(routed);
1050
void Wire::setRatsnest(bool ratsnest) {
1051
m_viewGeometry.setRatsnest(ratsnest);
1054
bool Wire::getRatsnest() {
1055
return m_viewGeometry.getRatsnest();
1058
void Wire::setAutoroutable(bool ar) {
1059
m_viewGeometry.setAutoroutable(ar);
1062
bool Wire::getAutoroutable() {
1063
return m_viewGeometry.getAutoroutable();
1066
void Wire::setNormal(bool normal) {
1067
m_viewGeometry.setNormal(normal);
1070
bool Wire::getNormal() {
1071
return m_viewGeometry.getNormal();
1074
void Wire::setColor(const QColor & color, double op) {
1075
m_pen.setBrush(QBrush(color));
1077
m_colorName = color.name();
1081
void Wire::setShadowColor(QColor & color) {
1082
m_shadowBrush = QBrush(color);
1083
m_shadowPen.setBrush(m_shadowBrush);
1084
m_bendpointPen.setBrush(m_shadowBrush);
1085
m_bendpoint2Pen.setBrush(m_shadowBrush);
1086
if (m_connector0) m_connector0->restoreColor(false, 0, false);
1087
if (m_connector0) m_connector1->restoreColor(false, 0, false);
1091
const QColor & Wire::color() {
1092
return m_pen.brush().color();
1095
void Wire::setWireWidth(double width, InfoGraphicsView * infoGraphicsView, double hoverStrokeWidth) {
1096
if (m_pen.widthF() == width) return;
1098
prepareGeometryChange();
1099
setPenWidth(width, infoGraphicsView, hoverStrokeWidth);
1100
if (m_connector0) m_connector0->restoreColor(false, 0, false);
1101
if (m_connector1) m_connector1->restoreColor(false, 0, false);
1105
double Wire::width() {
1106
return m_pen.widthF();
1109
double Wire::shadowWidth() {
1110
return m_shadowPen.widthF();
1113
double Wire::mils() {
1114
return 1000 * m_pen.widthF() / FSvgRenderer::printerScale();
1117
void Wire::setColorString(QString colorName, double op) {
1118
// sets a color using the name (.e. "red")
1119
// note: colorName is associated with a Fritzing color, not a Qt color
1121
QString colorString = colors.value(colorName, "");
1122
if (colorString.isEmpty()) {
1123
colorString = colorName;
1125
foreach (QString c, colors.keys()) {
1126
if (colors.value(c).compare(colorName, Qt::CaseInsensitive) == 0) {
1134
c.setNamedColor(colorString);
1136
m_colorName = colorName;
1138
colorString = shadowColors.value(colorName, "");
1139
if (colorString.isEmpty()) {
1140
colorString = colorName;
1143
c.setNamedColor(colorString);
1147
QString Wire::hexString() {
1148
return m_pen.brush().color().name();
1151
QString Wire::shadowHexString() {
1152
return m_shadowPen.brush().color().name();
1155
QString Wire::colorString() {
1159
void Wire::initNames() {
1160
if (colors.count() > 0) return;
1162
widths << 16 << 24 << 32 << 48;
1163
widthTrans.insert(widths[0], tr("thin (16 mil)"));
1164
widthTrans.insert(widths[1], tr("standard (24 mil)"));
1165
widthTrans.insert(widths[2], tr("thick (32 mil)"));
1166
widthTrans.insert(widths[3], tr("extra thick (48 mil)"));
1168
THIN_TRACE_WIDTH = GraphicsUtils::mils2pixels(widths[0], FSvgRenderer::printerScale());
1169
STANDARD_TRACE_WIDTH = GraphicsUtils::mils2pixels(widths[1], FSvgRenderer::printerScale());
1170
HALF_STANDARD_TRACE_WIDTH = STANDARD_TRACE_WIDTH / 2.0;
1172
// need a list because a hash table doesn't guarantee order
1173
colorNames.append(tr("blue"));
1174
colorNames.append(tr("red"));
1175
colorNames.append(tr("black"));
1176
colorNames.append(tr("yellow"));
1177
colorNames.append(tr("green"));
1178
colorNames.append(tr("grey"));
1179
colorNames.append(tr("white"));
1180
colorNames.append(tr("orange"));
1181
colorNames.append(tr("brown"));
1182
colorNames.append(tr("purple"));
1183
colorNames.append(tr("schematic black"));
1185
// need this hash table to translate from user's language to internal color name
1186
colorTrans.insert(tr("blue"), "blue");
1187
colorTrans.insert(tr("red"), "red");
1188
colorTrans.insert(tr("black"), "black");
1189
colorTrans.insert(tr("yellow"), "yellow");
1190
colorTrans.insert(tr("green"), "green");
1191
colorTrans.insert(tr("grey"), "grey");
1192
colorTrans.insert(tr("white"), "white");
1193
colorTrans.insert(tr("orange"), "orange");
1194
colorTrans.insert(tr("brown"), "brown");
1195
colorTrans.insert(tr("purple"), "purple");
1196
colorTrans.insert(tr("schematic black"), "schematic black");
1198
colors.insert("blue", "#418dd9");
1199
colors.insert("red", "#cc1414");
1200
colors.insert("black", "#404040");
1201
colors.insert("yellow", "#ffe24d");
1202
colors.insert("green", "#47cc79");
1203
colors.insert("grey", "#999999");
1204
colors.insert("white", "#ffffff");
1205
colors.insert("orange", "#ff7033");
1206
colors.insert("jumper", ViewLayer::JumperColor);
1207
colors.insert("trace", ViewLayer::Copper0Color);
1208
colors.insert("trace1", ViewLayer::Copper1Color);
1209
//colors.insert("unrouted", "#000000");
1210
//colors.insert("blackblack", "#000000");
1211
colors.insert("schematicGrey", "#9d9d9d");
1212
colors.insert("purple", "#ab58a2");
1213
colors.insert("brown", "#8c3b00");
1214
colors.insert("schematic black", "#000000");
1216
shadowColors.insert("blue", "#1b5bb3");
1217
shadowColors.insert("red", "#8c0000");
1218
shadowColors.insert("black", "#000000");
1219
shadowColors.insert("yellow", "#e6ab00");
1220
shadowColors.insert("green", "#00a63d");
1221
shadowColors.insert("grey", "#666666");
1222
shadowColors.insert("white", "#999999");
1223
shadowColors.insert("orange", "#d95821");
1224
shadowColors.insert("jumper", "#2d6563");
1225
shadowColors.insert("trace", "#d69b00");
1226
shadowColors.insert("trace1", "#d69b00");
1227
//shadowColors.insert("unrouted", "#000000");
1228
shadowColors.insert("purple", "#7a3a73");
1229
shadowColors.insert("brown", "#6c2710");
1230
shadowColors.insert("schematicGrey", "#1d1d1d");
1231
//shadowColors.insert("blackblack", "#000000");
1232
shadowColors.insert("schematic black", "#000000");
1235
bool Wire::hasFlag(ViewGeometry::WireFlag flag)
1237
return m_viewGeometry.hasFlag(flag);
1240
bool Wire::hasAnyFlag(ViewGeometry::WireFlags flags)
1242
return m_viewGeometry.hasAnyFlag(flags);
1245
Wire * Wire::findTraced(ViewGeometry::WireFlags flags, QList<ConnectorItem *> & ends) {
1246
QList<Wire *> chainedWires;
1247
this->collectChained(chainedWires, ends);
1248
if (ends.count() != 2) {
1249
DebugDialog::debug(QString("wire in jumper or trace must have two ends") );
1253
return ConnectorItem::directlyWiredTo(ends[0], ends[1], flags);
1256
QRgb Wire::getRgb(const QString & name) {
1257
QString str = colors.value(name);
1259
c.setNamedColor(str);
1263
void Wire::setWireFlags(ViewGeometry::WireFlags wireFlags) {
1264
m_viewGeometry.setWireFlags(wireFlags);
1267
double Wire::opacity() {
1271
void Wire::setOpacity(double opacity) {
1272
m_opacity = opacity;
1276
bool Wire::draggingEnd() {
1277
return m_dragEnd || m_dragCurve;
1280
void Wire::setCanChainMultiple(bool can) {
1281
m_canChainMultiple = can;
1284
bool Wire::canChangeColor() {
1285
if (getRatsnest()) return false;
1286
if (!getTrace()) return true;
1288
return (this->m_viewIdentifier == ViewIdentifierClass::SchematicView);
1291
void Wire::collectDirectWires(QList<Wire *> & wires) {
1292
if (!wires.contains(this)) {
1296
collectDirectWires(m_connector0, wires);
1297
collectDirectWires(m_connector1, wires);
1300
void Wire::collectDirectWires(ConnectorItem * connectorItem, QList<Wire *> & wires) {
1301
if (connectorItem->connectionsCount() != 1) return;
1303
ConnectorItem * toConnectorItem = connectorItem->connectedToItems()[0];
1304
if (toConnectorItem->attachedToItemType() != ModelPart::Wire) return;
1306
Wire * nextWire = qobject_cast<Wire *>(toConnectorItem->attachedTo());
1307
if (wires.contains(nextWire)) return;
1309
wires.append(nextWire);
1310
nextWire->collectDirectWires(nextWire->otherConnector(toConnectorItem), wires);
1313
QVariant Wire::itemChange(GraphicsItemChange change, const QVariant &value)
1315
if (change == ItemSelectedChange) {
1317
m_partLabel->update();
1320
if (!m_ignoreSelectionChange) {
1321
QList<Wire *> chained;
1322
QList<ConnectorItem *> ends;
1323
collectChained(chained, ends);
1324
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1325
if (infoGraphicsView) {
1326
infoGraphicsView->setIgnoreSelectionChangeEvents(true);
1328
// DebugDialog::debug(QString("original wire selected %1 %2").arg(value.toBool()).arg(this->id()));
1329
foreach (Wire * wire, chained) {
1330
if (wire != this ) {
1331
wire->setIgnoreSelectionChange(true);
1332
wire->setSelected(value.toBool());
1333
wire->setIgnoreSelectionChange(false);
1334
// DebugDialog::debug(QString("wire selected %1 %2").arg(value.toBool()).arg(wire->id()));
1337
if (infoGraphicsView) {
1338
infoGraphicsView->setIgnoreSelectionChangeEvents(false);
1342
return ItemBase::itemChange(change, value);
1345
void Wire::cleanup() {
1348
void Wire::getConnectedColor(ConnectorItem * connectorItem, QBrush * &brush, QPen * &pen, double & opacity, double & negativePenWidth, bool & negativeOffsetRect) {
1350
connectorItem->setBigDot(false);
1352
bool bendpoint = true;
1353
foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) {
1354
if (toConnectorItem->attachedToItemType() != ModelPart::Wire) {
1355
// 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
1357
if (toConnectorItem->connectionsCount() > 1) {
1358
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1359
if (infoGraphicsView != NULL && infoGraphicsView->hasBigDots()) {
1361
foreach (ConnectorItem * totoConnectorItem, toConnectorItem->connectedToItems()) {
1362
if (totoConnectorItem->attachedToItemType() == ModelPart::Wire) {
1363
Wire * w = qobject_cast<Wire *>(totoConnectorItem->attachedTo());
1364
if (w && w->getTrace()) {
1376
ItemBase::getConnectedColor(connectorItem, brush, pen, opacity, negativePenWidth, negativeOffsetRect);
1384
ItemBase::getConnectedColor(connectorItem, brush, pen, opacity, negativePenWidth, negativeOffsetRect);
1388
// connectorItem is a bendpoint or connects to a multiply connected connector
1391
//DebugDialog::debug(QString("big dot %1 %2 %3").arg(this->id()).arg(connectorItem->connectorSharedID()).arg(count));
1394
brush = &m_shadowBrush;
1397
// only ever reach here when drawing a connector that is connected to more than one trace
1398
pen = &m_bendpoint2Pen;
1399
negativePenWidth = m_bendpoint2Width;
1400
negativeOffsetRect = m_negativeOffsetRect;
1401
connectorItem->setBigDot(true);
1404
negativeOffsetRect = m_negativeOffsetRect;
1405
negativePenWidth = m_bendpointWidth;
1406
pen = &m_bendpointPen;
1410
void Wire::setPenWidth(double w, InfoGraphicsView * infoGraphicsView, double hoverStrokeWidth) {
1411
m_hoverStrokeWidth = hoverStrokeWidth;
1412
//DebugDialog::debug(QString("setting hoverstrokewidth %1 %2").arg(m_id).arg(m_hoverStrokeWidth));
1414
infoGraphicsView->getBendpointWidths(this, w, m_bendpointWidth, m_bendpoint2Width, m_negativeOffsetRect);
1415
m_bendpointPen.setWidthF(qAbs(m_bendpointWidth));
1416
m_bendpoint2Pen.setWidthF(qAbs(m_bendpoint2Width));
1417
m_shadowPen.setWidthF(w + 2);
1420
bool Wire::connectionIsAllowed(ConnectorItem * to) {
1421
if (!ItemBase::connectionIsAllowed(to)) return false;
1423
Wire * w = qobject_cast<Wire *>(to->attachedTo());
1424
if (w == NULL) return true;
1426
if (w->getRatsnest()) return false;
1428
return m_viewIdentifier != ViewIdentifierClass::BreadboardView;
1431
bool Wire::isGrounded() {
1432
return ConnectorItem::isGrounded(connector0(), connector1());
1435
bool Wire::acceptsMouseDoubleClickConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1439
bool Wire::acceptsMouseMoveConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1443
bool Wire::acceptsMouseReleaseConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1447
void Wire::setIgnoreSelectionChange(bool ignore) {
1448
m_ignoreSelectionChange = ignore;
1451
bool Wire::collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget)
1453
if (prop.compare("width", Qt::CaseInsensitive) == 0) {
1454
// don't display width property
1458
if (prop.compare("color", Qt::CaseInsensitive) == 0) {
1459
returnProp = tr("color");
1460
if (canChangeColor()) {
1461
QComboBox * comboBox = new QComboBox(parent);
1462
comboBox->setEditable(false);
1463
comboBox->setEnabled(swappingEnabled);
1464
comboBox->setObjectName("infoViewComboBox");
1467
QString englishCurrColor = colorString();
1468
foreach(QString transColorName, Wire::colorNames) {
1469
QString englishColorName = Wire::colorTrans.value(transColorName);
1470
comboBox->addItem(transColorName, QVariant(englishColorName));
1471
if (englishColorName.compare(englishCurrColor, Qt::CaseInsensitive) == 0) {
1472
comboBox->setCurrentIndex(ix);
1477
connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(colorEntry(const QString &)));
1478
returnWidget = comboBox;
1479
returnValue = comboBox->currentText();
1483
returnWidget = NULL;
1484
returnValue = colorString();
1489
return ItemBase::collectExtraInfo(parent, family, prop, value, swappingEnabled, returnProp, returnValue, returnWidget);
1492
void Wire::colorEntry(const QString & text) {
1495
QComboBox * comboBox = qobject_cast<QComboBox *>(sender());
1496
if (comboBox == NULL) return;
1498
QString color = comboBox->itemData(comboBox->currentIndex()).toString();
1500
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1501
if (infoGraphicsView != NULL) {
1502
infoGraphicsView->changeWireColor(color);
1506
bool Wire::hasPartLabel() {
1511
ItemBase::PluralType Wire::isPlural() {
1515
void Wire::checkVisibility(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) {
1517
if (!onIt->attachedTo()->isVisible()) {
1518
this->setVisible(false);
1521
ConnectorItem * other = otherConnector(onMe);
1522
foreach (ConnectorItem * toConnectorItem, other->connectedToItems()) {
1523
if (toConnectorItem->attachedToItemType() == ModelPart::Wire) continue;
1525
if (!toConnectorItem->attachedTo()->isVisible()) {
1526
this->setVisible(false);
1534
bool Wire::canSwitchLayers() {
1538
bool Wire::hasPartNumberProperty()
1543
bool Wire::rotationAllowed() {
1547
bool Wire::rotation45Allowed() {
1551
void Wire::addedToScene(bool temporary) {
1552
ItemBase::addedToScene(temporary);
1554
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1555
if (infoGraphicsView == NULL) return;
1557
bool succeeded = connect(this, SIGNAL(wireChangedSignal(Wire*, const QLineF & , const QLineF & , QPointF, QPointF, ConnectorItem *, ConnectorItem *) ),
1558
infoGraphicsView, SLOT(wireChangedSlot(Wire*, const QLineF & , const QLineF & , QPointF, QPointF, ConnectorItem *, ConnectorItem *)),
1559
Qt::DirectConnection); // DirectConnection means call the slot directly like a subroutine, without waiting for a thread or queue
1560
succeeded = connect(this, SIGNAL(wireChangedCurveSignal(Wire*, const Bezier *, const Bezier *, bool)),
1561
infoGraphicsView, SLOT(wireChangedCurveSlot(Wire*, const Bezier *, const Bezier *, bool)),
1562
Qt::DirectConnection); // DirectConnection means call the slot directly like a subroutine, without waiting for a thread or queue
1563
succeeded = succeeded && connect(this, SIGNAL(wireSplitSignal(Wire*, QPointF, QPointF, const QLineF & )),
1564
infoGraphicsView, SLOT(wireSplitSlot(Wire*, QPointF, QPointF, const QLineF & )));
1565
succeeded = succeeded && connect(this, SIGNAL(wireJoinSignal(Wire*, ConnectorItem *)),
1566
infoGraphicsView, SLOT(wireJoinSlot(Wire*, ConnectorItem*)));
1568
DebugDialog::debug("wire signal connect failed");
1572
void Wire::setConnectorDimensions(double width, double height)
1574
setConnectorDimensionsAux(connector0(), width, height);
1575
setConnectorDimensionsAux(connector1(), width, height);
1578
void Wire::setConnectorDimensionsAux(ConnectorItem * connectorItem, double width, double height)
1580
QPointF p = connectorItem->rect().center();
1581
QRectF r(p.x() - (width / 2), p.y() - (height / 2), width, height);
1582
connectorItem->setRect(r);
1583
connectorItem->setTerminalPoint(r.center() - r.topLeft());
1586
void Wire::originalConnectorDimensions(double & width, double & height)
1588
width = m_originalConnectorRect.width();
1589
height = m_originalConnectorRect.height();
1592
bool Wire::isBendpoint(ConnectorItem * connectorItem) {
1593
return connectorItem->isBendpoint();
1596
double Wire::hoverStrokeWidth() {
1597
return m_hoverStrokeWidth;
1600
const QLineF & Wire::getPaintLine() {
1605
Returns the item's line, or a null line if no line has been set.
1609
QLineF Wire::line() const
1615
Sets the item's line to be the given \a line.
1619
void Wire::setLine(const QLineF &line)
1623
prepareGeometryChange();
1628
void Wire::setLine(double x1, double y1, double x2, double y2)
1630
setLine(QLineF(x1, y1, x2, y2));
1634
Returns the item's pen, or a black solid 0-width pen if no pen has
1639
QPen Wire::pen() const
1645
Sets the item's pen to \a pen. If no pen is set, the line will be painted
1646
using a black solid 0-width pen.
1650
void Wire::setPen(const QPen &pen)
1652
if (pen.widthF() != m_pen.widthF()) {
1653
prepareGeometryChange();
1659
bool Wire::canHaveCurve() {
1660
return m_canHaveCurve && (m_viewIdentifier == ViewIdentifierClass::BreadboardView);
1663
void Wire::dragCurve(QPointF eventPos, Qt::KeyboardModifiers)
1665
m_bezier->recalc(eventPos);
1668
void Wire::changeCurve(const Bezier * bezier)
1670
prepareGeometryChange();
1671
if (m_bezier == NULL) m_bezier = new Bezier;
1672
m_bezier->copy(bezier);
1676
bool Wire::isCurved() {
1677
return (m_bezier != NULL) && !m_bezier->isEmpty();
1680
const Bezier * Wire::curve() {
1684
const Bezier * Wire::undoCurve() {
1688
QPolygonF Wire::sceneCurve(QPointF offset) {
1690
if (m_bezier == NULL) return poly;
1691
if (m_bezier->isEmpty()) return poly;
1693
poly.append(m_line.p1() + pos() - offset);
1694
poly.append(m_bezier->cp0() + pos() - offset);
1695
poly.append(m_bezier->cp1() + pos() - offset);
1696
poly.append(m_line.p2() + pos() - offset);
1700
bool Wire::hasShadow() {
1701
if (getRatsnest()) return false;
1702
if (getTrace()) return false;
1703
return m_pen.widthF() != m_shadowPen.widthF();
1706
bool Wire::eventFilter(QObject * object, QEvent * event)
1709
if (!(m_dragEnd || m_dragCurve)) {
1710
if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
1711
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);;
1712
if (infoGraphicsView) {
1713
QPoint p = infoGraphicsView->mapFromGlobal(QCursor::pos());
1714
QPointF r = infoGraphicsView->mapToScene(p);
1715
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
1716
// DebugDialog::debug(QString("got key event %1").arg(keyEvent->modifiers()));
1717
updateCursor(keyEvent->modifiers());
1725
void Wire::updateCursor(Qt::KeyboardModifiers modifiers)
1727
if (m_connectorHover) {
1731
InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1732
bool segment = false;
1733
int totalConnections = 0;
1734
foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1735
totalConnections += connectorItem->connectionsCount();
1737
if (totalConnections == 2 && modifiers & altOrMetaModifier()) {
1739
foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1740
if (connectorItem->connectionsCount() != 1) {
1745
ConnectorItem * toConnectorItem = connectorItem->connectedToItems().at(0);
1746
if (toConnectorItem->attachedToItemType() != ModelPart::Wire) {
1754
// dragging a segment of wire between bounded by two other wires
1755
QApplication::changeOverrideCursor(*ConnectorItem::RubberbandCursor);
1757
else if (totalConnections == 0) {
1758
// only in breadboard view
1759
QApplication::changeOverrideCursor(*ConnectorItem::MoveCursor);
1761
else if (infoGraphicsView != NULL && infoGraphicsView->curvyWiresIndicated(modifiers)) {
1762
QApplication::changeOverrideCursor(*ConnectorItem::MakeCurveCursor);
1765
QApplication::changeOverrideCursor(*ConnectorItem::NewBendpointCursor);
1769
bool Wire::canChainMultiple()
1771
return m_canChainMultiple;