9#include <QGraphicsSceneMouseEvent>
11#include <QPainterPath>
14#include <QStyleOptionGraphicsItem>
23 : QGraphicsPathItem(parent)
25 setFlag(QGraphicsItem::ItemIsSelectable);
41 m_startPort->detachConnection(
this);
45 m_endPort->detachConnection(
this);
59void Connection::changePortAttachment(
Port *oldPort,
Port *newPort)
63 if (oldPort && (oldPort != newPort)) {
73 auto *oldPort = m_startPort;
75 changePortAttachment(oldPort, port);
85 auto *oldPort = m_endPort;
87 changePortAttachment(oldPort, port);
98 const QPointF newStartPos = m_startPort ? m_startPort->scenePos() : m_startPos;
99 const QPointF newEndPos = m_endPort ? m_endPort->scenePos() : m_endPos;
106 if (newStartPos == m_startPos && newEndPos == m_endPos) {
110 m_startPos = newStartPos;
111 m_endPos = newEndPos;
129 path.moveTo(m_startPos);
131 qreal dx = m_endPos.x() - m_startPos.x();
132 qreal dy = m_endPos.y() - m_startPos.y();
137 QPointF ctr1(m_startPos.x() + dx * 0.25, m_startPos.y() + dy * 0.1);
138 QPointF ctr2(m_startPos.x() + dx * 0.75, m_startPos.y() + dy * 0.9);
140 path.cubicTo(ctr1, ctr2, m_endPos);
158 Port *port1 = m_startPort;
159 Port *port2 = m_endPort;
161 if (port1 && port2) {
168 std::swap(port1, port2);
171 return QLineF(port1->scenePos(), port2->scenePos()).angle();
189 if (port == m_startPort) {
211 if (
auto *scene_ = qobject_cast<Scene *>(scene())) {
212 scene_->noteWireActivity();
223void Connection::applyStatusPen()
229 case Status::Unknown: m_statusPen = QPen(m_unknownColor, 3);
break;
230 case Status::Inactive: m_statusPen = QPen(m_inactiveColor, 3);
break;
231 case Status::Active: m_statusPen = QPen(m_activeColor, 3);
break;
232 case Status::Error: m_statusPen = QPen(m_errorColor, 5);
break;
242 if (!qFuzzyCompare(m_statusPen.widthF(), pen().widthF())) {
254 m_unknownColor = theme.m_connectionUnknown;
255 m_inactiveColor = theme.m_connectionInactive;
256 m_activeColor = theme.m_connectionActive;
257 m_errorColor = theme.m_connectionError;
258 m_selectedColor = theme.m_connectionSelected;
267void Connection::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget)
277 if (
auto *scene_ = qobject_cast<Scene *>(scene()); scene_ && !scene_->wireAntialiasingEnabled()) {
278 painter->setRenderHint(QPainter::Antialiasing,
false);
285 painter->setPen(QPen(Qt::blue, 10));
286 painter->drawPath(path());
292 painter->setPen(isSelected() ? QPen(m_selectedColor, 5) : m_statusPen);
293 painter->drawPath(path());
300 if (change == ItemSelectedChange) {
301 if (value.toBool()) {
310 return QGraphicsPathItem::itemChange(change, value);
328 return path().boundingRect().adjusted(-10, -10, 10, 10);
340 QPainterPathStroker stroker;
341 stroker.setWidth(qMax(pen().widthF(), 0.00000001));
342 stroker.setCapStyle(pen().capStyle());
343 stroker.setJoinStyle(pen().joinStyle());
344 stroker.setMiterLimit(pen().miterLimit());
348 QPainterPath flattened;
349 for (
const QPolygonF &polygon : path().toSubpathPolygons()) {
350 flattened.addPolygon(polygon);
353 m_cachedShape = stroker.createStroke(flattened);
354 m_shapeDirty =
false;
357 return m_cachedShape;
364 if (
auto mouseEvent =
dynamic_cast<QGraphicsSceneMouseEvent *
>(event)) {
365 if (mouseEvent->modifiers().testFlag(Qt::ControlModifier)) {
370 return QGraphicsPathItem::sceneEvent(event);
Custom QApplication subclass with exception handling and main-window access.
ConnectionSerializer: reads/writes a Connection to a versioned QDataStream.
Connection: a wire that connects an output port to an input port in the circuit scene.
Port classes: Port (base), InputPort, and OutputPort.
Main circuit editing scene with undo/redo and user interaction.
Theme management types and singleton ThemeManager.
static bool renderingEnabled
static void save(const Connection &connection, QDataStream &stream)
Writes connection's endpoint port serial IDs to stream.
static void load(Connection &connection, QDataStream &stream, SerializationContext &context)
Reads connection's endpoints from stream, resolving ports via context.
Connection(QGraphicsItem *parent=nullptr)
Constructs an unconnected wire.
OutputPort * startPort() const
Returns the output port this connection originates from.
void updateTheme()
Refreshes wire colours from the current ThemeManager palette.
void setHighLight(const bool highLight)
Enables or disables connection highlighting.
Status status() const
Returns the current four-state signal status (Active/Inactive/Unknown/Error).
void setEndPos(const QPointF point)
Sets the visual end position to point (used when dragging).
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
void updatePath()
Recomputes the bezier control points from the current start/end positions.
InputPort * endPort() const
Returns the input port this connection leads to.
QRectF boundingRect() const override
bool highLight()
Returns true if this connection is highlighted.
void setStatus(const Status status)
Sets the connection status and triggers a visual refresh.
double angle()
Returns the current angle of the bezier midpoint in radians.
void save(QDataStream &stream) const
Serializes the connection endpoints to stream.
QPainterPath shape() const override
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override
void updatePosFromPorts()
Moves the wire endpoints to match the current port positions.
void load(QDataStream &stream, SerializationContext &context)
Deserializes the connection from stream, resolving ports via context.
void setEndPort(InputPort *port)
Sets the input port this connection leads to.
Port * otherPort(const Port *port) const
Returns the port at the other end of this connection from port.
void setStartPort(OutputPort *port)
Sets the output port this connection originates from.
bool sceneEvent(QEvent *event) override
void setStartPos(const QPointF point)
Sets the visual start position to point (used when dragging).
A port that drives a signal (the source end of a wire).
Abstract base class for circuit element ports (connection endpoints).
virtual bool isOutput() const =0
Returns true if this is an output port. Pure virtual.
void attachConnection(Connection *conn)
Registers conn as a connection attached to this port.
void hoverEnter()
Applies hover-enter visual feedback.
void detachConnection(Connection *conn)
Removes conn from this port's connection list.
Status status() const
Returns the current logical status (Active/Inactive/Unknown/Error).
void hoverLeave()
Reverts hover-enter visual feedback.
static const ThemeAttributes & attributes()
Returns the current ThemeAttributes color set.
Bundles all per-deserialization state so that load() overrides receive it through one explicit parame...