/******************************************************************* Part of the Fritzing project - http://fritzing.org Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de Fritzing is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fritzing is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fritzing. If not, see . ******************************************************************** $Revision: 7000 $: $Author: irascibl@gmail.com $: $Date: 2013-04-29 07:24:08 +0200 (Mo, 29. Apr 2013) $ ********************************************************************/ /* curvy To Do curvy to begin with? would have to vary with some function of angle and distance could convert control points to t values? turn curvature on/off per view --------------------------------------------------------- later: clippable wire gerber autorouter warning in PCB view modify parameters (tension, unit area)? */ ///////////////////////////////////////////////////////////////// #include "wire.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../debugdialog.h" #include "../sketch/infographicsview.h" #include "../connectors/connectoritem.h" #include "../connectors/svgidlayer.h" #include "../fsvgrenderer.h" #include "partlabel.h" #include "../model/modelpart.h" #include "../utils/graphicsutils.h" #include "../utils/textutils.h" #include "../utils/bezier.h" #include "../utils/bezierdisplay.h" #include "../utils/cursormaster.h" #include "../utils/ratsnestcolors.h" #include "../layerattributes.h" #include QVector Wire::TheDash; QVector RatDash; QBrush BandedBrush(QColor(255, 255, 255)); QHash Wire::colorTrans; QStringList Wire::colorNames; QHash Wire::widthTrans; QList Wire::widths; double Wire::STANDARD_TRACE_WIDTH; double Wire::HALF_STANDARD_TRACE_WIDTH; double Wire::THIN_TRACE_WIDTH; const double DefaultHoverStrokeWidth = 4; static Bezier UndoBezier; static BezierDisplay * TheBezierDisplay = NULL; //////////////////////////////////////////////////////////// bool alphaLessThan(QColor * c1, QColor * c2) { return c1->alpha() < c2->alpha(); } void debugCompare(ItemBase * it) { Wire * wire = dynamic_cast(it); if (wire) { QRectF r0 = wire->connector0()->rect(); QRectF r1 = wire->connector1()->rect(); if (qAbs(r0.left() - r1.left()) < 0.1 && qAbs(r0.right() - r1.right()) < 0.1 && qAbs(r0.top() - r1.top()) < 0.1 && qAbs(r0.bottom() - r1.bottom()) < 0.1) { wire->debugInfo("zero wire"); if (wire->viewID() == ViewLayer::PCBView) { DebugDialog::debug("in pcb"); } } } } ///////////////////////////////////////////////////////////// WireAction::WireAction(QAction * action) : QAction(action) { m_wire = NULL; this->setText(action->text()); this->setStatusTip(action->statusTip()); this->setCheckable(action->isCheckable()); } WireAction::WireAction(const QString & title, QObject * parent) : QAction(title, parent) { m_wire = NULL; } void WireAction::setWire(Wire * w) { m_wire = w; } Wire * WireAction::wire() { return m_wire; } ///////////////////////////////////////////////////////////// Wire::Wire( ModelPart * modelPart, ViewLayer::ViewID viewID, const ViewGeometry & viewGeometry, long id, QMenu* itemMenu, bool initLabel) : ItemBase(modelPart, viewID, viewGeometry, id, itemMenu) { m_banded = false; m_bezier = NULL; m_displayBendpointCursor = m_canHaveCurve = true; m_hoverStrokeWidth = DefaultHoverStrokeWidth; m_connector0 = m_connector1 = NULL; m_partLabel = initLabel ? new PartLabel(this, NULL) : NULL; m_canChainMultiple = false; setFlag(QGraphicsItem::ItemIsSelectable, true ); m_connectorHover = NULL; m_opacity = 1.0; m_ignoreSelectionChange = false; //DebugDialog::debug(QString("aix line %1 %2 %3 %4").arg(this->viewGeometry().line().x1()) //.arg(this->viewGeometry().line().y1()) //.arg(this->viewGeometry().line().x2()) //.arg(this->viewGeometry().line().y2()) ); //DebugDialog::debug(QString("aix loc %1 %2").arg(this->viewGeometry().loc().x()) //.arg(this->viewGeometry().loc().y()) ); setPos(m_viewGeometry.loc()); m_dragCurve = m_dragEnd = false; } Wire::~Wire() { if (m_bezier) { delete m_bezier; } } FSvgRenderer * Wire::setUp(ViewLayer::ViewLayerID viewLayerID, const LayerHash & viewLayers, InfoGraphicsView * infoGraphicsView) { ItemBase::setViewLayerID(viewLayerID, viewLayers); FSvgRenderer * svgRenderer = setUpConnectors(m_modelPart, m_viewID); if (svgRenderer != NULL) { initEnds(m_viewGeometry, svgRenderer->viewBox(), infoGraphicsView); //debugCompare(this); } setZValue(this->z()); return svgRenderer; } void Wire::saveGeometry() { m_viewGeometry.setSelected(this->isSelected()); m_viewGeometry.setLine(this->line()); m_viewGeometry.setLoc(this->pos()); m_viewGeometry.setZ(this->zValue()); } bool Wire::itemMoved() { if (m_viewGeometry.loc() != this->pos()) return true; if (this->line().dx() != m_viewGeometry.line().dx()) return false; if (this->line().dy() != m_viewGeometry.line().dy()) return false; return (this->line() != m_viewGeometry.line()); } void Wire::moveItem(ViewGeometry & viewGeometry) { this->setPos(viewGeometry.loc()); this->setLine(viewGeometry.line()); } void Wire::initEnds(const ViewGeometry & vg, QRectF defaultRect, InfoGraphicsView * infoGraphicsView) { bool gotOne = false; bool gotTwo = false; double penWidth = 1; foreach (ConnectorItem * item, cachedConnectorItems()) { // check the name or is order good enough? if (gotOne) { gotTwo = true; m_connector1 = item; break; } else { penWidth = item->rect().width(); m_connector0 = item; gotOne = true; } } if (!gotTwo) { return; } if ((vg.line().length() == 0) && (vg.line().x1() == -1)) { this->setLine(defaultRect.left(), defaultRect.top(), defaultRect.right(), defaultRect.bottom()); } else { this->setLine(vg.line()); } setConnector0Rect(); setConnector1Rect(); m_viewGeometry.setLine(this->line()); QBrush brush(QColor(0, 0, 0)); QPen pen(brush, penWidth, Qt::SolidLine, Qt::RoundCap); this->setPen(pen); m_pen.setCapStyle(Qt::RoundCap); m_shadowPen.setCapStyle(Qt::RoundCap); if (infoGraphicsView != NULL) { infoGraphicsView->initWire(this, penWidth); } prepareGeometryChange(); } void Wire::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget ) { if (m_hidden) return; ItemBase::paint(painter, option, widget); } void Wire::paintBody(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget ) { Q_UNUSED(option); Q_UNUSED(widget); QPainterPath painterPath; if (m_bezier && !m_bezier->isEmpty()) { QLineF line = this->line(); painterPath.moveTo(line.p1()); painterPath.cubicTo(m_bezier->cp0(), m_bezier->cp1(), line.p2()); /* DebugDialog::debug(QString("c0x:%1,c0y:%2 c1x:%3,c1y:%4 p0x:%5,p0y:%6 p1x:%7,p1y:%8 px:%9,py:%10") .arg(m_controlPoints.at(0).x()) .arg(m_controlPoints.at(0).y()) .arg(m_controlPoints.at(1).x()) .arg(m_controlPoints.at(1).y()) .arg(m_line.p1().x()) .arg(m_line.p1().y()) .arg(m_line.p2().x()) .arg(m_line.p2().y()) .arg(pos().x()) .arg(pos().y()) ); */ } painter->setOpacity(m_inactive ? m_opacity / 2 : m_opacity); if (hasShadow()) { painter->save(); painter->setPen(m_shadowPen); if (painterPath.isEmpty()) { QLineF line = this->line(); painter->drawLine(line); } else { painter->drawPath(painterPath); } painter->restore(); } // DebugDialog::debug(QString("pen width %1 %2").arg(m_pen.widthF()).arg(m_viewID)); if (m_banded) { QBrush brush = m_pen.brush(); m_pen.setStyle(Qt::SolidLine); m_pen.setBrush(BandedBrush); painter->setPen(m_pen); if (painterPath.isEmpty()) { painter->drawLine(getPaintLine()); } else { painter->drawPath(painterPath); } m_pen.setBrush(brush); m_pen.setDashPattern(TheDash); m_pen.setCapStyle(Qt::FlatCap); } if (getRatsnest()) { m_pen.setDashPattern(RatDash); } painter->setPen(m_pen); if (painterPath.isEmpty()) { painter->drawLine(getPaintLine()); } else { painter->drawPath(painterPath); } if (m_banded) { m_pen.setStyle(Qt::SolidLine); m_pen.setCapStyle(Qt::RoundCap); } } void Wire::paintHover(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(widget); Q_UNUSED(option); painter->save(); if ((m_connectorHoverCount > 0 && !(m_dragEnd || m_dragCurve)) || m_connectorHoverCount2 > 0) { painter->setOpacity(.50); painter->fillPath(this->hoverShape(), QBrush(ConnectorHoverColor)); } else { painter->setOpacity(HoverOpacity); painter->fillPath(this->hoverShape(), QBrush(HoverColor)); } painter->restore(); } QPainterPath Wire::hoverShape() const { return shapeAux(m_hoverStrokeWidth); } QPainterPath Wire::shape() const { return shapeAux(m_pen.widthF()); } QPainterPath Wire::shapeAux(double width) const { QPainterPath path; if (m_line == QLineF()) { return path; } path.moveTo(m_line.p1()); if (m_bezier == NULL || m_bezier->isEmpty()) { path.lineTo(m_line.p2()); } else { path.cubicTo(m_bezier->cp0(), m_bezier->cp1(), m_line.p2()); } //DebugDialog::debug(QString("using hoverstrokewidth %1 %2").arg(m_id).arg(m_hoverStrokeWidth)); return GraphicsUtils::shapeFromPath(path, m_pen, width, false); } QRectF Wire::boundingRect() const { if (m_pen.widthF() == 0.0) { const double x1 = m_line.p1().x(); const double x2 = m_line.p2().x(); const double y1 = m_line.p1().y(); const double y2 = m_line.p2().y(); double lx = qMin(x1, x2); double rx = qMax(x1, x2); double ty = qMin(y1, y2); double by = qMax(y1, y2); return QRectF(lx, ty, rx - lx, by - ty); } return hoverShape().controlPointRect(); } void Wire::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { //DebugDialog::debug("checking press event"); emit wireSplitSignal(this, event->scenePos(), this->pos(), this->line()); } void Wire::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this); if (infoGraphicsView != NULL) { infoGraphicsView->setActiveWire(this); } ItemBase::contextMenuEvent(event); } void Wire::mousePressEvent(QGraphicsSceneMouseEvent *event) { ItemBase::mousePressEvent(event); } void Wire::initDragCurve(QPointF scenePos) { if (m_bezier == NULL) { m_bezier = new Bezier(); } UndoBezier.copy(m_bezier); m_dragCurve = true; m_dragEnd = false; QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL); QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL); if (m_bezier->isEmpty()) { m_bezier->initToEnds(mapFromScene(p0), mapFromScene(p1)); } else { m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1)); } m_bezier->initControlIndex(mapFromScene(scenePos), m_pen.widthF()); TheBezierDisplay = new BezierDisplay; TheBezierDisplay->initDisplay(this, m_bezier); } bool Wire::initNewBendpoint(QPointF scenePos, Bezier & left, Bezier & right) { if (m_bezier == NULL || m_bezier->isEmpty()) { UndoBezier.clear(); return false; } QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL); QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL); m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1)); UndoBezier.copy(m_bezier); double t = m_bezier->findSplit(mapFromScene(scenePos), m_pen.widthF()); m_bezier->split(t, left, right); return true; } void Wire::initDragEnd(ConnectorItem * connectorItem, QPointF scenePos) { Q_UNUSED(scenePos); saveGeometry(); QLineF line = this->line(); m_drag0 = (connectorItem == m_connector0); //debugInfo("setting drag end to true"); m_dragEnd = true; m_dragCurve = false; if (m_drag0) { m_wireDragOrigin = line.p2(); //DebugDialog::debug(QString("drag near origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) ); } else { m_wireDragOrigin = line.p1(); //DebugDialog::debug(QString("drag far origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) ); //DebugDialog::debug(QString("drag far other %1 %2").arg(line.p2().x()).arg(line.p2().y()) ); } if (connectorItem->chained()) { QList chained; QList ends; collectChained(chained, ends); // already saved the first one for (int i = 1; i < chained.count(); i++) { chained[i]->saveGeometry(); } } } void Wire::mouseReleaseConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) { Q_UNUSED(event); Q_UNUSED(connectorItem); releaseDrag(); } void Wire::mouseMoveConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) { mouseMoveEventAux(this->mapFromItem(connectorItem, event->pos()), event->modifiers()); } void Wire::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { mouseMoveEventAux(event->pos(), event->modifiers()); } void Wire::mouseMoveEventAux(QPointF eventPos, Qt::KeyboardModifiers modifiers) { if (m_spaceBarWasPressed) { return; } if (m_dragCurve) { prepareGeometryChange(); dragCurve(eventPos, modifiers); update(); if (TheBezierDisplay) TheBezierDisplay->updateDisplay(this, m_bezier); return; } if (m_dragEnd == false) { return; } //debugInfo("dragging wire"); ConnectorItem * whichConnectorItem; ConnectorItem * otherConnectorItem; if (m_drag0) { whichConnectorItem = m_connector0; otherConnectorItem = m_connector1; } else { whichConnectorItem = m_connector1; otherConnectorItem = m_connector0; } if ((modifiers & Qt::ShiftModifier) != 0) { QPointF initialPos = mapFromScene(otherConnectorItem->sceneAdjustedTerminalPoint(NULL)); bool bendpoint = isBendpoint(whichConnectorItem); if (bendpoint) { bendpoint = false; foreach (ConnectorItem * ci, whichConnectorItem->connectedToItems()) { Wire * w = qobject_cast(ci->attachedTo()); ConnectorItem * oci = w->otherConnector(ci); QPointF otherInitialPos = mapFromScene(oci->sceneAdjustedTerminalPoint(NULL)); QPointF p1(initialPos.x(), otherInitialPos.y()); double d = GraphicsUtils::distanceSqd(p1, eventPos); if (d <= 144) { bendpoint = true; eventPos = p1; break; } p1.setX(otherInitialPos.x()); p1.setY(initialPos.y()); d = GraphicsUtils::distanceSqd(p1, eventPos); if (d <= 144) { bendpoint = true; eventPos = p1; break; } } } if (!bendpoint) { eventPos = GraphicsUtils::calcConstraint(initialPos, eventPos); } } if (m_drag0) { QPointF p = this->mapToScene(eventPos); QGraphicsSvgItem::setPos(p.x(), p.y()); this->setLine(0, 0, m_wireDragOrigin.x() - p.x() + m_viewGeometry.loc().x(), m_wireDragOrigin.y() - p.y() + m_viewGeometry.loc().y() ); //DebugDialog::debug(QString("drag0 wdo:(%1,%2) p:(%3,%4) vg:(%5,%6) l:(%7,%8)") // .arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) // .arg(p.x()).arg(p.y()) // .arg(m_viewGeometry.loc().x()).arg(m_viewGeometry.loc().y()) // .arg(line().p2().x()).arg(line().p2().y()) // ); } else { this->setLine(m_wireDragOrigin.x(), m_wireDragOrigin.y(), eventPos.x(), eventPos.y()); //DebugDialog::debug(QString("drag1 wdo:(%1,%2) ep:(%3,%4) p:(%5,%6) l:(%7,%8)") // .arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) // .arg(eventPos.x()).arg(eventPos.y()) // .arg(pos().x()).arg(pos().y()) // .arg(line().p2().x()).arg(line().p2().y()) // ); } setConnector1Rect(); QSet allTo; allTo.insert(whichConnectorItem); foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) { Wire * chainedWire = qobject_cast(toConnectorItem->attachedTo()); if (chainedWire == NULL) continue; allTo.insert(toConnectorItem); foreach (ConnectorItem * subTo, toConnectorItem->connectedToItems()) { allTo.insert(subTo); } } allTo.remove(whichConnectorItem); // TODO: this could all be determined once at mouse press time if (allTo.count() == 0) { // dragging one end of the wire // don't allow wire to connect back to something the other end is already directly connected to // an alternative would be to exclude all connectors in the net connected by the same kind of trace QList wires; QList ends; collectChained(wires, ends); InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this); //DebugDialog::debug("------------------------"); QList exclude; foreach (ConnectorItem * end, ends) { exclude << end; foreach (ConnectorItem * ci, end->connectedToItems()) { // if there is a wire growing out of one of the excluded ends, exclude the attached end exclude << ci; } foreach (ConnectorItem * toConnectorItem, end->connectedToItems()) { if (toConnectorItem->attachedToItemType() != ModelPart::Wire) continue; Wire * w = qobject_cast(toConnectorItem->attachedTo()); if (w->getRatsnest()) continue; if (!w->isTraceType(infoGraphicsView->getTraceFlag())) continue; //w->debugInfo("what wire"); QList ends2; QList wires2; w->collectChained(wires2, ends2); exclude.append(ends2); foreach (ConnectorItem * e2, ends2) { foreach (ConnectorItem * ci, e2->connectedToItems()) { // if there is a wire growing out of one of the excluded ends, exclude that end of the wire exclude << ci; } } foreach (Wire * w2, wires2) { exclude.append(w2->cachedConnectorItems()); } } } // but allow to restore connections at this end (collect chained above got both ends of this wire) foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) { if (ends.contains(toConnectorItem)) exclude.removeAll(toConnectorItem); } //DebugDialog::debug(""); //DebugDialog::debug("__________________"); //foreach (ConnectorItem * end, exclude) end->debugInfo("exclude"); ConnectorItem * originatingConnector = NULL; if (otherConnectorItem) { foreach (ConnectorItem * toConnectorItem, otherConnectorItem->connectedToItems()) { if (ends.contains(toConnectorItem)) { originatingConnector = toConnectorItem; break; } } } whichConnectorItem->findConnectorUnder(false, true, exclude, true, originatingConnector); } else { // dragging a bendpoint foreach (ConnectorItem * toConnectorItem, allTo) { Wire * chained = qobject_cast(toConnectorItem->attachedTo()); if (chained) { chained->simpleConnectedMoved(whichConnectorItem, toConnectorItem); } } } } void Wire::setConnector0Rect() { QRectF rect = m_connector0->rect(); rect.moveTo(0 - (rect.width() / 2.0), 0 - (rect.height() / 2.0) ); m_connector0->setRect(rect); //debugCompare(this); // QPointF p = m_connector0->mapToScene(m_connector0->rect().center()); // m_connector0->debugInfo(QString("c0:%1 %2").arg(p.x()).arg(p.y())); // p = m_connector1->mapToScene(m_connector1->rect().center()); // m_connector1->debugInfo(QString("c1:%1 %2").arg(p.x()).arg(p.y())); } void Wire::setConnector1Rect() { QRectF rect = m_connector1->rect(); rect.moveTo(this->line().dx() - (rect.width() / 2.0), this->line().dy() - (rect.height() / 2.0) ); m_connector1->setRect(rect); //debugCompare(this); // QPointF p = m_connector0->mapToScene(m_connector0->rect().center()); // m_connector0->debugInfo(QString("c0:%1 %2").arg(p.x()).arg(p.y())); // p = m_connector1->mapToScene(m_connector1->rect().center()); // m_connector1->debugInfo(QString("c1:%1 %2").arg(p.x()).arg(p.y())); } void Wire::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (m_spaceBarWasPressed) { return; } //debugInfo("wire release drag"); if (releaseDrag()) return; ItemBase::mouseReleaseEvent(event); } bool Wire::releaseDrag() { if (m_dragEnd == false && m_dragCurve == false) return false; if (m_dragCurve) { delete TheBezierDisplay; TheBezierDisplay = NULL; m_dragCurve = false; ungrabMouse(); if (UndoBezier != *m_bezier) { emit wireChangedCurveSignal(this, &UndoBezier, m_bezier, false); } return true; } //debugInfo("clearing drag end"); m_dragEnd = false; ConnectorItem * from = (m_drag0) ? m_connector0 : m_connector1; ConnectorItem * to = from->releaseDrag(); QLineF newLine = this->line(); QLineF oldLine = m_viewGeometry.line(); QPointF oldPos = m_viewGeometry.loc(); QPointF newPos = this->pos(); if (newLine != oldLine || oldPos != newPos) { emit wireChangedSignal(this, oldLine, newLine, oldPos, newPos, from, to); } return true; } void Wire::saveInstanceLocation(QXmlStreamWriter & streamWriter) { QLineF line = m_viewGeometry.line(); QPointF loc = m_viewGeometry.loc(); streamWriter.writeAttribute("x", QString::number(loc.x())); streamWriter.writeAttribute("y", QString::number(loc.y())); streamWriter.writeAttribute("x1", QString::number(line.x1())); streamWriter.writeAttribute("y1", QString::number(line.y1())); streamWriter.writeAttribute("x2", QString::number(line.x2())); streamWriter.writeAttribute("y2", QString::number(line.y2())); streamWriter.writeAttribute("wireFlags", QString::number(m_viewGeometry.flagsAsInt())); } void Wire::writeGeometry(QXmlStreamWriter & streamWriter) { ItemBase::writeGeometry(streamWriter); streamWriter.writeStartElement("wireExtras"); streamWriter.writeAttribute("mils", QString::number(mils())); streamWriter.writeAttribute("color", m_pen.brush().color().name()); streamWriter.writeAttribute("opacity", QString::number(m_opacity)); streamWriter.writeAttribute("banded", m_banded ? "1" : "0"); if (m_bezier) m_bezier->write(streamWriter); streamWriter.writeEndElement(); } void Wire::setExtras(QDomElement & element, InfoGraphicsView * infoGraphicsView) { if (element.isNull()) return; bool ok; double w = element.attribute("width").toDouble(&ok); if (ok) { setWireWidth(w, infoGraphicsView, infoGraphicsView->getWireStrokeWidth(this, w)); } else { w = element.attribute("mils").toDouble(&ok); if (ok) { double wpix = GraphicsUtils::mils2pixels(w, GraphicsUtils::SVGDPI); setWireWidth(wpix, infoGraphicsView, infoGraphicsView->getWireStrokeWidth(this, wpix)); } } m_banded = (element.attribute("banded", "") == "1"); setColorFromElement(element); QDomElement bElement = element.firstChildElement("bezier"); Bezier bezier = Bezier::fromElement(bElement); if (!bezier.isEmpty()) { prepareGeometryChange(); m_bezier = new Bezier; m_bezier->copy(&bezier); QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL); QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL); m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1)); } } void Wire::setColorFromElement(QDomElement & element) { QString colorString = element.attribute("color"); if (colorString.isNull() || colorString.isEmpty()) return; bool ok; double op = element.attribute("opacity").toDouble(&ok); if (!ok) { op = 1.0; } setColorString(colorString, op, false); } void Wire::hoverEnterConnectorItem(QGraphicsSceneHoverEvent * event , ConnectorItem * item) { m_connectorHover = item; ItemBase::hoverEnterConnectorItem(event, item); } void Wire::hoverLeaveConnectorItem(QGraphicsSceneHoverEvent * event, ConnectorItem * item) { m_connectorHover = NULL; ItemBase::hoverLeaveConnectorItem(event, item); } void Wire::hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) { ItemBase::hoverEnterEvent(event); CursorMaster::instance()->addCursor(this, cursor()); //DebugDialog::debug("---wire set override cursor"); updateCursor(event->modifiers()); } void Wire::hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ) { ItemBase::hoverLeaveEvent(event); //DebugDialog::debug("------wire restore override cursor"); CursorMaster::instance()->removeCursor(this); } void Wire::connectionChange(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) { checkVisibility(onMe, onIt, connect); bool movable = true; foreach (ConnectorItem * connectedTo, m_connector0->connectedToItems()) { if (connectedTo->attachedToItemType() != ModelPart::Wire) { movable = false; break; } } if (movable) { foreach (ConnectorItem * connectedTo, m_connector1->connectedToItems()) { if (connectedTo->attachedToItemType() != ModelPart::Wire) { movable = false; break; } } } } void Wire::mouseDoubleClickConnectorEvent(ConnectorItem * connectorItem) { int chained = 0; foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) { if (toConnectorItem->attachedToItemType() == ModelPart::Wire) { chained++; } else { return; } } if (chained == 1) { // near as I can tell, this is to eliminate the overrides from the connectorItem and then from the wire itself emit wireJoinSignal(this, connectorItem); } } void Wire::mousePressConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) { //DebugDialog::debug("checking press connector event"); if (m_canChainMultiple && event->modifiers() & altOrMetaModifier()) { // dragging a wire out of a bendpoint InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this); if (infoGraphicsView != NULL) { infoGraphicsView->mousePressConnectorEvent(connectorItem, event); } return; } connectorItem->setOverConnectorItem(NULL); initDragEnd(connectorItem, event->scenePos()); } void Wire::simpleConnectedMoved(ConnectorItem * to) { // to is this wire, from is something else simpleConnectedMoved(to->firstConnectedToIsh(), to); } void Wire::simpleConnectedMoved(ConnectorItem * from, ConnectorItem * to) { if (from == NULL) return; //if (from) from->debugInfo("connected moved from"); //if (to) to->debugInfo("\tto"); // to is this wire, from is something else QPointF p1, p2; calcNewLine(from, to, p1, p2); /* QPointF oldPos = this->pos(); QPointF newPos = p1; QLineF oldLine = this->line(); QLineF newLine(0, 0, p2.x() - p1.x(), p2.y() - p1.y()); if (qAbs(oldPos.x() - newPos.x()) > 1.75 || qAbs(oldPos.y() - newPos.y()) > 1.75 || qAbs(oldLine.x1() - newLine.x1()) > 1.75 || qAbs(oldLine.x2() - newLine.x2()) > 1.75 || qAbs(oldLine.y1() - newLine.y1()) > 1.75 || qAbs(oldLine.y2() - newLine.y2()) > 1.75 ) { DebugDialog::debug("line changed"); calcNewLine(from,to,p1,p2); } */ this->setPos(p1); this->setLine(0,0, p2.x() - p1.x(), p2.y() - p1.y() ); //debugInfo(QString("set line %1 %2, %3 %4, vis:%5").arg(p1.x()).arg(p1.y()).arg(p2.x()).arg(p2.y()).arg(isVisible()) ); setConnector1Rect(); } void Wire::calcNewLine(ConnectorItem * from, ConnectorItem * to, QPointF & p1, QPointF & p2) { // to is this wire, from is something else if (to == m_connector0) { p1 = from->sceneAdjustedTerminalPoint(to); ConnectorItem * otherFrom = m_connector1->firstConnectedToIsh(); if (otherFrom == NULL) { p2 = m_connector1->mapToScene(m_connector1->rect().center()); } else { p2 = otherFrom->sceneAdjustedTerminalPoint(m_connector1); } } else { p2 = from->sceneAdjustedTerminalPoint(to); ConnectorItem * otherFrom = m_connector0->firstConnectedToIsh(); if (otherFrom == NULL) { p1 = m_connector0->mapToScene(m_connector0->rect().center()); } else { p1 = otherFrom->sceneAdjustedTerminalPoint(m_connector0); } } } void Wire::connectedMoved(ConnectorItem * from, ConnectorItem * to, QList & already) { Q_UNUSED(already); // "from" is the connector on the part // "to" is the connector on the wire //from->debugInfo("connected moved"); //to->debugInfo("\tconnected moved"); if (from->connectedToItems().contains(to) || to->connectedToItems().contains(from)) { simpleConnectedMoved(from, to); } else { //from->debugInfo("not connected"); //to->debugInfo("\t"); } } FSvgRenderer * Wire::setUpConnectors(ModelPart * modelPart, ViewLayer::ViewID viewID) { clearConnectorItemCache(); LayerAttributes layerAttributes; this->initLayerAttributes(layerAttributes, viewID, m_viewLayerID, m_viewLayerPlacement, false, false); FSvgRenderer * renderer = ItemBase::setUpImage(modelPart, layerAttributes); if (renderer == NULL) { return NULL; } foreach (Connector * connector, modelPart->connectors().values()) { if (connector == NULL) continue; SvgIdLayer * svgIdLayer = connector->fullPinInfo(viewID, m_viewLayerID); if (svgIdLayer == NULL) continue; bool result = renderer->setUpConnector(svgIdLayer, false, viewLayerPlacement()); if (!result) continue; ConnectorItem * connectorItem = newConnectorItem(connector); connectorItem->setRect(svgIdLayer->rect(viewLayerPlacement())); connectorItem->setTerminalPoint(svgIdLayer->point(viewLayerPlacement())); m_originalConnectorRect = svgIdLayer->rect(viewLayerPlacement()); connectorItem->setCircular(true); //DebugDialog::debug(QString("terminal point %1 %2").arg(terminalPoint.x()).arg(terminalPoint.y()) ); } return renderer; } /* void Wire::setPos(const QPointF & pos) { ItemBase::setPos(pos); } */ void Wire::setLineAnd(QLineF line, QPointF pos, bool useLine) { this->setPos(pos); if (useLine) this->setLine(line); setConnector1Rect(); } ConnectorItem * Wire::otherConnector(ConnectorItem * oneConnector) { if (oneConnector == m_connector0) return m_connector1; return m_connector0; } ConnectorItem * Wire::connector0() { return m_connector0; } ConnectorItem * Wire::connector1() { return m_connector1; } void Wire::findConnectorsUnder() { foreach (ConnectorItem * connectorItem, cachedConnectorItems()) { if (connectorItem->connectionsCount() > 0) continue; // only check free ends connectorItem->findConnectorUnder(true, false, ConnectorItem::emptyConnectorItemList, false, NULL); } } void Wire::collectChained(QList & chained, QList & ends ) { chained.append(this); for (int i = 0; i < chained.count(); i++) { Wire * wire = chained[i]; collectChained(wire->m_connector1, chained, ends); collectChained(wire->m_connector0, chained, ends); } } void Wire::collectChained(ConnectorItem * connectorItem, QList & chained, QList & ends) { if (connectorItem == NULL) return; foreach (ConnectorItem * connectedToItem, connectorItem->connectedToItems()) { Wire * wire = qobject_cast(connectedToItem->attachedTo()); if (wire == NULL) { if (!ends.contains(connectedToItem)) { ends.append(connectedToItem); } continue; } if (chained.contains(wire)) continue; chained.append(wire); } } void Wire::collectWires(QList & wires) { if (wires.contains(this)) return; wires.append(this); //DebugDialog::debug(QString("collecting wire %1").arg(this->id()) ); collectWiresAux(wires, m_connector0); collectWiresAux(wires, m_connector1); } void Wire::collectWiresAux(QList & wires, ConnectorItem * start) { foreach (ConnectorItem * toConnectorItem, start->connectedToItems()) { if (toConnectorItem->attachedToItemType() == ModelPart::Wire) { qobject_cast(toConnectorItem->attachedTo())->collectWires(wires); } } } bool Wire::stickyEnabled() { QList wires; QList ends; this->collectChained(wires, ends); foreach (ConnectorItem * connector, ends) { if (connector->connectionsCount() > 0) { return false; } } return true; } bool Wire::getTrace() { return m_viewGeometry.getAnyTrace(); } bool Wire::getRouted() { return m_viewGeometry.getRouted(); } void Wire::setRouted(bool routed) { m_viewGeometry.setRouted(routed); } void Wire::setRatsnest(bool ratsnest) { m_viewGeometry.setRatsnest(ratsnest); } void Wire::setAutoroutable(bool ar) { m_viewGeometry.setAutoroutable(ar); } bool Wire::getAutoroutable() { return m_viewGeometry.getAutoroutable(); } void Wire::setNormal(bool normal) { m_viewGeometry.setNormal(normal); } bool Wire::getNormal() { return m_viewGeometry.getNormal(); } void Wire::setColor(const QColor & color, double op) { m_pen.setBrush(QBrush(color)); m_opacity = op; m_colorName = color.name(); this->update(); } void Wire::setShadowColor(QColor & color, bool restore) { m_shadowBrush = QBrush(color); m_shadowPen.setBrush(m_shadowBrush); m_bendpointPen.setBrush(m_shadowBrush); m_bendpoint2Pen.setBrush(m_shadowBrush); QList visited; if (restore) { if (m_connector0) m_connector0->restoreColor(visited); if (m_connector1) m_connector1->restoreColor(visited); } this->update(); } const QColor & Wire::color() { return m_pen.brush().color(); } void Wire::setWireWidth(double width, InfoGraphicsView * infoGraphicsView, double hoverStrokeWidth) { if (m_pen.widthF() == width) return; prepareGeometryChange(); setPenWidth(width, infoGraphicsView, hoverStrokeWidth); QList visited; if (m_connector0) m_connector0->restoreColor(visited); if (m_connector1) m_connector1->restoreColor(visited); update(); } double Wire::width() { return m_pen.widthF(); } double Wire::shadowWidth() { return m_shadowPen.widthF(); } double Wire::mils() { return 1000 * m_pen.widthF() / GraphicsUtils::SVGDPI; } void Wire::setColorString(QString colorName, double op, bool restore) { // sets a color using the name (.e. "red") // note: colorName is associated with a Fritzing color, not a Qt color QString colorString = RatsnestColors::wireColor(m_viewID, colorName); if (colorString.isEmpty()) { colorString = colorName; } QColor c; c.setNamedColor(colorString); setColor(c, op); m_colorName = colorName; QString shadowColorString = RatsnestColors::shadowColor(m_viewID, colorName); if (shadowColorString.isEmpty()) { shadowColorString = colorString; } c.setNamedColor(shadowColorString); setShadowColor(c, restore); } QString Wire::hexString() { return m_pen.brush().color().name(); } QString Wire::shadowHexString() { return m_shadowPen.brush().color().name(); } QString Wire::colorString() { return m_colorName; } void Wire::initNames() { if (colorNames.count() > 0) return; TheDash.clear(); TheDash << 10 << 8; RatDash.clear(); RatDash << 2 << 2; widths << 8 << 12 << 16 << 24 << 32 << 48; int i = 0; widthTrans.insert(widths[i++], tr("super fine (8 mil)")); widthTrans.insert(widths[i++], tr("extra thin (12 mil)")); THIN_TRACE_WIDTH = GraphicsUtils::mils2pixels(widths[i], GraphicsUtils::SVGDPI); widthTrans.insert(widths[i++], tr("thin (16 mil)")); STANDARD_TRACE_WIDTH = GraphicsUtils::mils2pixels(widths[i], GraphicsUtils::SVGDPI); widthTrans.insert(widths[i++], tr("standard (24 mil)")); widthTrans.insert(widths[i++], tr("thick (32 mil)")); widthTrans.insert(widths[i++], tr("extra thick (48 mil)")); HALF_STANDARD_TRACE_WIDTH = STANDARD_TRACE_WIDTH / 2.0; // need a list because a hash table doesn't guarantee order colorNames.append(tr("blue")); colorNames.append(tr("red")); colorNames.append(tr("black")); colorNames.append(tr("yellow")); colorNames.append(tr("green")); colorNames.append(tr("grey")); colorNames.append(tr("white")); colorNames.append(tr("orange")); colorNames.append(tr("ochre")); colorNames.append(tr("cyan")); colorNames.append(tr("brown")); colorNames.append(tr("purple")); colorNames.append(tr("pink")); // need this hash table to translate from user's language to internal color name colorTrans.insert(tr("blue"), "blue"); colorTrans.insert(tr("red"), "red"); colorTrans.insert(tr("black"), "black"); colorTrans.insert(tr("yellow"), "yellow"); colorTrans.insert(tr("green"), "green"); colorTrans.insert(tr("grey"), "grey"); colorTrans.insert(tr("white"), "white"); colorTrans.insert(tr("orange"), "orange"); colorTrans.insert(tr("ochre"), "ochre"); colorTrans.insert(tr("cyan"), "cyan"); colorTrans.insert(tr("brown"), "brown"); colorTrans.insert(tr("purple"), "purple"); colorTrans.insert(tr("pink"), "pink"); } bool Wire::hasFlag(ViewGeometry::WireFlag flag) { return m_viewGeometry.hasFlag(flag); } bool Wire::isTraceType(ViewGeometry::WireFlag flag) { return hasFlag(flag); } bool Wire::hasAnyFlag(ViewGeometry::WireFlags flags) { return m_viewGeometry.hasAnyFlag(flags); } Wire * Wire::findTraced(ViewGeometry::WireFlags flags, QList & ends) { QList chainedWires; this->collectChained(chainedWires, ends); if (ends.count() != 2) { DebugDialog::debug(QString("wire in jumper or trace must have two ends") ); return NULL; } return ConnectorItem::directlyWiredTo(ends[0], ends[1], flags); } void Wire::setWireFlags(ViewGeometry::WireFlags wireFlags) { m_viewGeometry.setWireFlags(wireFlags); } double Wire::opacity() { return m_opacity; } void Wire::setOpacity(double opacity) { m_opacity = opacity; this->update(); } bool Wire::draggingEnd() { return m_dragEnd || m_dragCurve; } void Wire::setCanChainMultiple(bool can) { m_canChainMultiple = can; } bool Wire::canChangeColor() { if (getRatsnest()) return false; if (!getTrace()) return true; return (this->m_viewID == ViewLayer::SchematicView); } void Wire::collectDirectWires(QList & wires) { bool firstRound = false; if (!wires.contains(this)) { wires.append(this); firstRound = true; } QList junctions; if (firstRound) { // collect up to any junction collectDirectWires(m_connector0, wires, junctions); collectDirectWires(m_connector1, wires, junctions); return; } // second round: deal with junctions foreach (Wire * wire, wires) { junctions << wire->connector0() << wire->connector1(); } int ix = 0; while (ix < junctions.count()) { ConnectorItem * junction = junctions.at(ix++); QSet jwires; foreach (ConnectorItem * toConnectorItem, junction->connectedToItems()) { if (toConnectorItem->attachedToItemType() != ModelPart::Wire) break; Wire * w = qobject_cast(toConnectorItem->attachedTo()); if (!wires.contains(w)) jwires << w; bool onlyWiresConnected = true; foreach (ConnectorItem * toToConnectorItem, toConnectorItem->connectedToItems()) { if (toToConnectorItem->attachedToItemType() != ModelPart::Wire) { onlyWiresConnected = false; break; } w = qobject_cast(toToConnectorItem->attachedTo()); if (!wires.contains(w)) jwires << w; } if (!onlyWiresConnected) break; } if (jwires.count() == 1) { // there is a junction of > 2 wires and all wires leading to it except one are already on the delete list Wire * w = jwires.values().at(0); wires << w; w->collectDirectWires(w->connector0(), wires, junctions); w->collectDirectWires(w->connector1(), wires, junctions); } } } void Wire::collectDirectWires(ConnectorItem * connectorItem, QList & wires, QList & junctions) { if (connectorItem->connectionsCount() == 0) return; if (connectorItem->connectionsCount() > 1) { if (!junctions.contains(connectorItem)) junctions.append(connectorItem); return; } ConnectorItem * toConnectorItem = connectorItem->connectedToItems().at(0); if (toConnectorItem->attachedToItemType() != ModelPart::Wire) return; if (toConnectorItem->connectionsCount() != 1) { if (!junctions.contains(connectorItem)) junctions.append(connectorItem); return; } Wire * nextWire = qobject_cast(toConnectorItem->attachedTo()); if (wires.contains(nextWire)) return; wires.append(nextWire); nextWire->collectDirectWires(nextWire->otherConnector(toConnectorItem), wires, junctions); } QVariant Wire::itemChange(GraphicsItemChange change, const QVariant &value) { if (change == ItemSelectedChange) { if (m_partLabel) { m_partLabel->update(); } if (!m_ignoreSelectionChange) { QList chained; QList ends; collectChained(chained, ends); InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this); if (infoGraphicsView) { infoGraphicsView->setIgnoreSelectionChangeEvents(true); } // DebugDialog::debug(QString("original wire selected %1 %2").arg(value.toBool()).arg(this->id())); foreach (Wire * wire, chained) { if (wire != this ) { wire->setIgnoreSelectionChange(true); wire->setSelected(value.toBool()); wire->setIgnoreSelectionChange(false); // DebugDialog::debug(QString("wire selected %1 %2").arg(value.toBool()).arg(wire->id())); } } if (infoGraphicsView) { infoGraphicsView->setIgnoreSelectionChangeEvents(false); } } } return ItemBase::itemChange(change, value); } void Wire::cleanup() { } void Wire::getConnectedColor(ConnectorItem * connectorItem, QBrush &brush, QPen &pen, double & opacity, double & negativePenWidth, bool & negativeOffsetRect) { connectorItem->setBigDot(false); ItemBase::getConnectedColor(connectorItem, brush, pen, opacity, negativePenWidth, negativeOffsetRect); int count = 0; bool bendpoint = true; InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this); if (infoGraphicsView == NULL) { return; } foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) { if (toConnectorItem->attachedToItemType() == ModelPart::Wire) { Wire * w = qobject_cast(toConnectorItem->attachedTo()); if (w->isTraceType(infoGraphicsView->getTraceFlag())) { count++; } } else { // 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 bendpoint = false; if (toConnectorItem->connectionsCount() > 1) { if (infoGraphicsView->hasBigDots()) { int c = 0; foreach (ConnectorItem * totoConnectorItem, toConnectorItem->connectedToItems()) { if (totoConnectorItem->attachedToItemType() == ModelPart::Wire) { Wire * w = qobject_cast(totoConnectorItem->attachedTo()); if (w && w->isTraceType(ViewGeometry::SchematicTraceFlag) && w->isTraceType(infoGraphicsView->getTraceFlag())) { c++; } } } if (c > 1) { count = 2; break; } } } count = 0; break; } } if (count == 0) { return; } // connectorItem is a bendpoint or connects to a multiply connected connector //if (!bendpoint) { //DebugDialog::debug(QString("big dot %1 %2 %3").arg(this->id()).arg(connectorItem->connectorSharedID()).arg(count)); //} brush = m_shadowBrush; opacity = 1.0; if (count > 1) { // only ever reach here when drawing a connector that is connected to more than one trace pen = m_bendpoint2Pen; negativePenWidth = m_bendpoint2Width; negativeOffsetRect = m_negativeOffsetRect; connectorItem->setBigDot(true); } else { negativeOffsetRect = m_negativeOffsetRect; negativePenWidth = m_bendpointWidth; pen = m_bendpointPen; } } void Wire::setPenWidth(double w, InfoGraphicsView * infoGraphicsView, double hoverStrokeWidth) { m_hoverStrokeWidth = hoverStrokeWidth; //DebugDialog::debug(QString("setting hoverstrokewidth %1 %2").arg(m_id).arg(m_hoverStrokeWidth)); m_pen.setWidthF(w); infoGraphicsView->getBendpointWidths(this, w, m_bendpointWidth, m_bendpoint2Width, m_negativeOffsetRect); m_bendpointPen.setWidthF(qAbs(m_bendpointWidth)); m_bendpoint2Pen.setWidthF(qAbs(m_bendpoint2Width)); m_shadowPen.setWidthF(w + 2); } bool Wire::connectionIsAllowed(ConnectorItem * to) { if (!ItemBase::connectionIsAllowed(to)) return false; Wire * w = qobject_cast(to->attachedTo()); if (w == NULL) return true; if (w->getRatsnest()) return false; return m_viewID != ViewLayer::BreadboardView; } bool Wire::isGrounded() { return ConnectorItem::isGrounded(connector0(), connector1()); } bool Wire::acceptsMouseDoubleClickConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) { return true; } bool Wire::acceptsMouseMoveConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) { return true; } bool Wire::acceptsMouseReleaseConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) { return true; } void Wire::setIgnoreSelectionChange(bool ignore) { m_ignoreSelectionChange = ignore; } bool Wire::collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget, bool & hide) { if (prop.compare("width", Qt::CaseInsensitive) == 0) { // don't display width property hide = true; return false; } if (prop.compare("color", Qt::CaseInsensitive) == 0) { returnProp = tr("color"); if (canChangeColor()) { QComboBox * comboBox = new QComboBox(parent); comboBox->setEditable(false); comboBox->setEnabled(swappingEnabled); comboBox->setObjectName("infoViewComboBox"); int ix = 0; QString englishCurrColor = colorString(); foreach(QString transColorName, Wire::colorNames) { QString englishColorName = Wire::colorTrans.value(transColorName); bool ok = (this->m_viewID != ViewLayer::SchematicView || englishColorName.compare("white", Qt::CaseInsensitive) != 0); if (ok) { comboBox->addItem(transColorName, QVariant(englishColorName)); if (englishColorName.compare(englishCurrColor, Qt::CaseInsensitive) == 0) { comboBox->setCurrentIndex(ix); } ix++; } } connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(colorEntry(const QString &))); if (this->hasShadow()) { QCheckBox * checkBox = new QCheckBox(tr("Banded")); checkBox->setChecked(m_banded); checkBox->setObjectName("infoViewCheckBox"); connect(checkBox, SIGNAL(clicked(bool)), this, SLOT(setBandedProp(bool))); QFrame * frame = new QFrame(parent); QHBoxLayout * hboxLayout = new QHBoxLayout; hboxLayout->addWidget(comboBox); hboxLayout->addWidget(checkBox); frame->setLayout(hboxLayout); returnWidget = frame; } else { returnWidget = comboBox; } returnValue = comboBox->currentText(); return true; } else { returnWidget = NULL; returnValue = colorString(); return true; } } return ItemBase::collectExtraInfo(parent, family, prop, value, swappingEnabled, returnProp, returnValue, returnWidget, hide); } void Wire::colorEntry(const QString & text) { Q_UNUSED(text); QComboBox * comboBox = qobject_cast(sender()); if (comboBox == NULL) return; QString color = comboBox->itemData(comboBox->currentIndex()).toString(); InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this); if (infoGraphicsView != NULL) { infoGraphicsView->changeWireColor(color); } } bool Wire::hasPartLabel() { return false; } ItemBase::PluralType Wire::isPlural() { return Plural; } void Wire::checkVisibility(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) { if (connect) { if (!onIt->attachedTo()->isVisible()) { this->setVisible(false); } else { ConnectorItem * other = otherConnector(onMe); foreach (ConnectorItem * toConnectorItem, other->connectedToItems()) { if (toConnectorItem->attachedToItemType() == ModelPart::Wire) continue; if (!toConnectorItem->attachedTo()->isVisible()) { this->setVisible(false); break; } } } } } bool Wire::canSwitchLayers() { return false; } bool Wire::hasPartNumberProperty() { return false; } bool Wire::rotationAllowed() { return false; } bool Wire::rotation45Allowed() { return false; } void Wire::addedToScene(bool temporary) { ItemBase::addedToScene(temporary); InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this); if (infoGraphicsView == NULL) return; infoGraphicsView->newWire(this); } void Wire::setConnectorDimensions(double width, double height) { setConnectorDimensionsAux(connector0(), width, height); setConnectorDimensionsAux(connector1(), width, height); } void Wire::setConnectorDimensionsAux(ConnectorItem * connectorItem, double width, double height) { QPointF p = connectorItem->rect().center(); QRectF r(p.x() - (width / 2), p.y() - (height / 2), width, height); connectorItem->setRect(r); connectorItem->setTerminalPoint(r.center() - r.topLeft()); //debugCompare(connectorItem->attachedTo()); } void Wire::originalConnectorDimensions(double & width, double & height) { width = m_originalConnectorRect.width(); height = m_originalConnectorRect.height(); } bool Wire::isBendpoint(ConnectorItem * connectorItem) { return connectorItem->isBendpoint(); } double Wire::hoverStrokeWidth() { return m_hoverStrokeWidth; } const QLineF & Wire::getPaintLine() { return m_line; } /*! Returns the item's line, or a null line if no line has been set. \sa setLine() */ QLineF Wire::line() const { return m_line; } /*! Sets the item's line to be the given \a line. \sa line() */ void Wire::setLine(const QLineF &line) { //if (line.length() < 0.5) { // debugInfo("zero line"); //} if (m_line == line) return; prepareGeometryChange(); m_line = line; update(); } void Wire::setLine(double x1, double y1, double x2, double y2) { setLine(QLineF(x1, y1, x2, y2)); } /*! Returns the item's pen, or a black solid 0-width pen if no pen has been set. \sa setPen() */ QPen Wire::pen() const { return m_pen; } /*! Sets the item's pen to \a pen. If no pen is set, the line will be painted using a black solid 0-width pen. \sa pen() */ void Wire::setPen(const QPen &pen) { if (pen.widthF() != m_pen.widthF()) { prepareGeometryChange(); } m_pen = pen; update(); } bool Wire::canHaveCurve() { return m_canHaveCurve && !getRatsnest(); } void Wire::dragCurve(QPointF eventPos, Qt::KeyboardModifiers) { m_bezier->recalc(eventPos); } void Wire::changeCurve(const Bezier * bezier) { prepareGeometryChange(); if (m_bezier == NULL) m_bezier = new Bezier; m_bezier->copy(bezier); update(); } bool Wire::isCurved() { return (m_bezier != NULL) && !m_bezier->isEmpty(); } const Bezier * Wire::curve() { return m_bezier; } const Bezier * Wire::undoCurve() { return &UndoBezier; } QPolygonF Wire::sceneCurve(QPointF offset) { QPolygonF poly; if (m_bezier == NULL) return poly; if (m_bezier->isEmpty()) return poly; poly.append(m_line.p1() + pos() - offset); poly.append(m_bezier->cp0() + pos() - offset); poly.append(m_bezier->cp1() + pos() - offset); poly.append(m_line.p2() + pos() - offset); return poly; } bool Wire::hasShadow() { if (getRatsnest()) return false; if (getTrace()) return false; return m_pen.widthF() != m_shadowPen.widthF(); } void Wire::cursorKeyEvent(Qt::KeyboardModifiers modifiers) { if (m_dragEnd || m_dragCurve) return; InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);; if (infoGraphicsView) { QPoint p = infoGraphicsView->mapFromGlobal(QCursor::pos()); QPointF r = infoGraphicsView->mapToScene(p); // DebugDialog::debug(QString("got key event %1").arg(keyEvent->modifiers())); updateCursor(modifiers); } } void Wire::updateCursor(Qt::KeyboardModifiers modifiers) { if (m_connectorHover) { return; } InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this); bool segment = false; int totalConnections = 0; foreach (ConnectorItem * connectorItem, cachedConnectorItems()) { totalConnections += connectorItem->connectionsCount(); } if (totalConnections == 2 && modifiers & altOrMetaModifier()) { segment = true; foreach (ConnectorItem * connectorItem, cachedConnectorItems()) { if (connectorItem->connectionsCount() != 1) { segment = false; break; } ConnectorItem * toConnectorItem = connectorItem->connectedToItems().at(0); if (toConnectorItem->attachedToItemType() != ModelPart::Wire) { segment = false; break; } } } if (segment) { // dragging a segment of wire between bounded by two other wires CursorMaster::instance()->addCursor(this, *CursorMaster::RubberbandCursor); } else if (totalConnections == 0) { // only in breadboard view CursorMaster::instance()->addCursor(this, *CursorMaster::MoveCursor); } else if (infoGraphicsView != NULL && infoGraphicsView->curvyWiresIndicated(modifiers)) { CursorMaster::instance()->addCursor(this, *CursorMaster::MakeCurveCursor); } else if (m_displayBendpointCursor) { CursorMaster::instance()->addCursor(this, *CursorMaster::NewBendpointCursor); } } bool Wire::canChainMultiple() { return m_canChainMultiple; } ViewLayer::ViewID Wire::useViewIDForPixmap(ViewLayer::ViewID vid, bool) { if (vid == ViewLayer::BreadboardView) { return ViewLayer::IconView; } return ViewLayer::UnknownView; } void Wire::setDisplayBendpointCursor(bool dbc) { m_displayBendpointCursor = dbc; } bool Wire::banded() { return m_banded; } void Wire::setBanded(bool banded) { m_banded = banded; QList chained; QList ends; collectChained(chained, ends); foreach (Wire * w, chained) { w->m_banded = banded; w->update(); } } void Wire::setBandedProp(bool banded) { InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this); if (infoGraphicsView != NULL) { infoGraphicsView->setProp(this, "banded", ItemBase::TranslatedPropertyNames.value("banded"), m_banded ? "Yes" : "No", banded ? "Yes" : "No", true); } } void Wire::setProp(const QString & prop, const QString & value) { if (prop.compare("banded", Qt::CaseInsensitive) == 0) { setBanded(value == "Yes"); return; } ItemBase::setProp(prop, value); }