8#include <QGraphicsView>
31 const QPointF delta = port->scenePos() - element->sceneBoundingRect().center();
32 if (qAbs(delta.x()) >= qAbs(delta.y())) {
43 if (i < element->inputSize()) {
57Port *decodePort(
Scene *scene,
const int elmId,
const int portNumber)
63 if (portNumber < element->inputSize()) {
84 connection->setStartPort(startPort);
85 connection->setEndPos(m_scene->mousePos());
87 m_scene->addItem(connection);
88 setEditedConnection(connection);
89 connection->updatePath();
95 connection->setEndPort(endPort);
96 connection->setStartPos(m_scene->mousePos());
98 m_scene->addItem(connection);
99 setEditedConnection(connection);
100 connection->updatePath();
108 auto *port = m_scene->portAt(scenePos);
110 if (!port || !connection) {
120 if (connection->startPort() !=
nullptr) {
121 startPort = connection->startPort();
122 endPort =
dynamic_cast<InputPort *
>(port);
123 }
else if (connection->endPort() !=
nullptr) {
125 endPort = connection->endPort();
128 if (!startPort || !endPort) {
134 if (rejection.isEmpty()) {
135 connection->setStartPort(startPort);
136 connection->setEndPort(endPort);
139 setEditedConnection(
nullptr);
142 m_scene->showStatusMessage(rejection);
143 deleteEditedConnection();
151 deleteEditedConnection();
159 if (connections.isEmpty()) {
164 auto *connection = connections.last();
166 if (
auto *startPort = connection->startPort()) {
183 return dynamic_cast<Connection *
>(m_scene->itemById(m_editedConnectionId));
193 if (connection->startPort()) {
195 connection->setEndPos(scenePos);
196 connection->updatePath();
200 if (connection->endPort()) {
202 connection->setStartPos(scenePos);
203 connection->updatePath();
208 deleteEditedConnection();
218 auto *port = m_scene->portAt(scenePos);
219 auto *hoverPort_ = hoverPort();
224 if (hoverPort_ != port) {
235 if (editedConn && editedConn->startPort() && (editedConn->startPort()->isOutput() == port->
isOutput())) {
236 auto *view = m_scene->view();
237 view->viewport()->setCursor(Qt::ForbiddenCursor);
256 if (!startPort || !endPort) {
257 return tr(
"This connection is not allowed.");
260 return tr(
"Can't connect an element to itself.");
263 return tr(
"These ports are already connected.");
268 return tr(
"This element receives wirelessly — no input wire needed.");
273 return tr(
"This element transmits wirelessly — no output wire needed.");
280void ConnectionManager::setEditedConnection(
Connection *connection)
283 connection->setFocus();
284 m_editedConnectionId = connection->
id();
286 m_editedConnectionId = 0;
290void ConnectionManager::deleteEditedConnection()
293 SimulationBlocker blocker(m_scene->simulation());
294 m_scene->removeItem(connection);
296 m_scene->setCircuitUpdateRequired();
299 setEditedConnection(
nullptr);
302void ConnectionManager::setHoverPort(
Port *port)
305 m_hoverPortElmId = 0;
306 m_hoverPortNumber = 0;
315 if (hoverElm && m_scene->contains(hoverElm->id())) {
316 m_hoverPortElmId = hoverElm->id();
317 m_hoverPortNumber = encodePortIndex(hoverElm, port);
326 m_highlightedPeers.clear();
327 for (
auto *peer : connectedPeers(port)) {
329 if (
auto *peerElm = peer->graphicElement(); peerElm && m_scene->contains(peerElm->id())) {
330 m_highlightedPeers.append(qMakePair(peerElm->id(), encodePortIndex(peerElm, peer)));
348 const auto addLabel = [
this](
Port *target) {
349 if (!target || target->name().isEmpty()) {
352 auto *label =
new PortHoverLabel(target->name(), sideFor(target));
353 label->setPos(target->scenePos());
354 m_scene->addItem(label);
355 m_peerLabels.append(label);
359 for (
auto *peer : connectedPeers(port)) {
364void ConnectionManager::releaseHoverPort()
368 const auto peerRefs = std::exchange(m_highlightedPeers, {});
369 for (
const auto &ref : peerRefs) {
370 if (
auto *peer = decodePort(m_scene, ref.first, ref.second)) {
375 if (
auto *hoverPort_ = hoverPort()) {
376 hoverPort_->hoverLeave();
377 setHoverPort(
nullptr);
378 auto *view = m_scene->view();
379 view->viewport()->unsetCursor();
383QList<Port *> ConnectionManager::connectedPeers(
Port *port)
391 peers.reserve(connections.size());
392 for (
auto *conn : connections) {
393 Port *peer = (conn->startPort() == port) ?
static_cast<Port *
>(conn->endPort())
394 :
static_cast<Port *
>(conn->startPort());
403void ConnectionManager::clearHoverLabels()
405 for (
const auto &label : std::as_const(m_peerLabels)) {
406 if (!label.isNull()) {
407 m_scene->removeItem(label);
412 m_peerLabels.clear();
415Port *ConnectionManager::hoverPort()
417 Port *hoverPort = decodePort(m_scene, m_hoverPortElmId, m_hoverPortNumber);
420 setHoverPort(
nullptr);
All QUndoCommand subclasses and the CommandUtils helper namespace.
ConnectionManager: manages wire creation, deletion, validation and hover feedback.
Connection: a wire that connects an output port to an input port in the circuit scene.
Abstract base class for all graphical circuit elements.
Extended QGraphicsView with zoom, pan, and fast-rendering modes.
PortHoverLabel: a transient tooltip-style chip showing a port's label on the canvas.
Port classes: Port (base), InputPort, and OutputPort.
Main circuit editing scene with undo/redo and user interaction.
Lightweight Sentry helpers gated behind HAVE_SENTRY.
void sentryBreadcrumb(const char *category, const QString &message)
RAII guard that temporarily stops the simulation while in scope.
Synchronous cycle-based simulation engine with event-driven clock support.
Undo command that adds a list of graphic elements to the scene.
void clearHover()
Clears the current hover state (unhighlights the port, resets cursor).
void detach(InputPort *endPort)
Detaches the existing wire on endPort and starts a new one from the same output.
bool hasEditedConnection() const
Returns true if a wire is currently being drawn.
void tryComplete(const QPointF &scenePos)
Attempts to complete the in-progress wire at the port under scenePos.
void startFromOutput(OutputPort *startPort)
Begins a new in-progress wire anchored at startPort (output port).
Connection * editedConnection() const
Returns the in-progress wire, or nullptr.
static bool isConnectionAllowed(OutputPort *startPort, InputPort *endPort)
Returns true if a wire from startPort to endPort is permitted.
void showHoverLabels(Port *port)
Shows in-situ label chips for port itself and every port connected to it.
void updateHover(const QPointF &scenePos)
Updates the hover state for the port under scenePos.
ConnectionManager(Scene *scene)
void updateEditedEnd(const QPointF &scenePos)
Updates the free end of the in-progress wire to follow scenePos.
void cancel()
Cancels and deletes the in-progress wire, if any.
static QString connectionRejectionReason(OutputPort *startPort, InputPort *endPort)
void startFromInput(InputPort *endPort)
Begins a new in-progress wire anchored at endPort (input port).
A bezier-curve wire connecting an output port to an input port in the scene.
Undo command that removes a list of items from the scene.
Abstract base class for all graphical circuit elements in wiRedPanda.
virtual WirelessMode wirelessMode() const
Returns the wireless routing mode for this element.
int inputSize() const
Returns the current number of input ports.
InputPort * inputPort(const int index=0) const
Returns the input port at index (default 0).
int outputSize() const
Returns the current number of output ports.
OutputPort * outputPort(const int index=0) const
Returns the output port at index (default 0).
int id() const
Returns the unique integer identifier of this item, or -1 if unassigned.
A port that drives a signal (the source end of a wire).
A small floating label drawn next to a port while a connected port is hovered.
Side
Which side of the port the chip is biased towards, away from the element body.
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 hoverEnter()
Applies hover-enter visual feedback.
GraphicElement * graphicElement()
Returns the graphic element that owns this port.
bool isConnected(Port *otherPort)
Returns true if this port is connected to otherPort via any wire.
const QList< Connection * > & connections() const
Returns the list of wires attached to this port.
Main circuit editing scene.
ItemWithId * itemById(int id) const
Returns the item registered under id, or nullptr if not found.