9#include <QCoreApplication>
13#include <QGraphicsScene>
14#include <QGraphicsSceneMouseEvent>
18#include <QRegularExpression>
19#include <QStyleOptionGraphicsItem>
20#include <QSvgRenderer>
35 static const QFont font = [] {
36 QFont f(
"Sans Serif");
44 : QGraphicsObject(parent)
52 m_elementGroup = metadata.
group;
59 qCDebug(four) <<
"Setting flags of elements.";
62 setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
64 qCDebug(four) <<
"Setting attributes.";
76 qCDebug(four) <<
"Including input and output ports.";
85 setCacheMode(QGraphicsItem::DeviceCoordinateCache);
101 return m_elementGroup;
131 return m_ports.inputPort(index);
136 return m_ports.outputPort(index);
141 return WirelessMode::None;
177 const auto children = childItems();
179 for (
auto *child : children) {
180 if (
auto *port = qgraphicsitem_cast<Port *>(child)) {
181 rectChildren = rectChildren.united(mapRectFromItem(port, port->boundingRect()));
197 updateLabelOrientation();
208void GraphicElement::invalidateRenderCache()
213 setCacheMode(QGraphicsItem::NoCache);
214 setCacheMode(QGraphicsItem::DeviceCoordinateCache);
224 m_orientation.setRotation(angle);
229 m_orientation.rotatePorts();
234 return m_orientation.angle();
239 m_orientation.setFlippedX(flipped);
244 m_orientation.setFlippedY(flipped);
249 m_appearance.setAppearance(defaultAppearance, fileName);
260 return {{0, tr(
"Default")}};
270 qCDebug(five) <<
"Updating port positions that belong to the IC.";
276 if (!
m_ports.inputs().isEmpty()) {
279 int y = 32 - (
static_cast<int>(
m_ports.inputs().size()) * step) + step;
281 for (
auto *port :
m_ports.inputs()) {
282 qCDebug(five) <<
"Setting input at " << 0 <<
", " << y;
290 m_orientation.orientPort(port);
299 if (!
m_ports.outputs().isEmpty()) {
300 int y = 32 - (
static_cast<int>(
m_ports.outputs().size()) * step) + step;
302 for (
auto *port :
m_ports.outputs()) {
303 qCDebug(five) <<
"Setting output at " << 64 <<
", " << y;
311 m_orientation.orientPort(port);
330 return QGraphicsItem::itemChange(change, value);
333 if (change == ItemPositionChange) {
334 qCDebug(four) <<
"Align to grid.";
335 QPointF newPos = value.toPointF();
339 const int xV = qRound(newPos.x() / gridSize) * gridSize;
340 const int yV = qRound(newPos.y() / gridSize) * gridSize;
341 return QPoint(xV, yV);
345 if ((change == ItemScenePositionHasChanged) || (change == ItemRotationHasChanged) || (change == ItemTransformHasChanged)) {
346 qCDebug(four) <<
"Moves wires.";
348 port->updateConnections();
352 if (change == ItemSelectedHasChanged) {
353 m_selected = value.toBool();
356 highlight(m_selected);
359 return QGraphicsItem::itemChange(change, value);
366 if (event->type() == QEvent::GraphicsSceneMousePress || event->type() == QEvent::GraphicsSceneMouseRelease) {
367 if (
auto mouseEvent =
dynamic_cast<QGraphicsSceneMouseEvent *
>(event)) {
368 if (mouseEvent->modifiers().testFlag(Qt::ControlModifier)) {
374 return QGraphicsItem::sceneEvent(event);
385 QGraphicsItem::mouseDoubleClickEvent(event);
390 return m_metadata.hasAudio;
411 QString
label = m_labelText;
416 if (!
label.isEmpty()) {
430 updateLabelOrientation();
434void GraphicElement::updateLabelOrientation()
455 QTransform pivotRotate;
456 pivotRotate.translate(pivot.x(), pivot.y());
458 pivotRotate.translate(-pivot.x(), -pivot.y());
460 const QTransform elementRotateFlip = pivotRotate * transform();
490 return m_label->sceneBoundingRect();
498 if (
color() ==
"White")
return "Purple";
499 if (
color() ==
"Red")
return "White";
500 if (
color() ==
"Green")
return "Red";
501 if (
color() ==
"Blue")
return "Green";
502 if (
color() ==
"Purple")
return "Blue";
508 if (
color() ==
"White")
return "Red";
509 if (
color() ==
"Red")
return "Green";
510 if (
color() ==
"Green")
return "Blue";
511 if (
color() ==
"Blue")
return "Purple";
512 if (
color() ==
"Purple")
return "White";
523 for (
auto *input :
m_ports.inputs()) {
524 input->updateTheme();
527 for (
auto *output :
m_ports.outputs()) {
528 output->updateTheme();
536 qCDebug(four) <<
"Checking if the element has the required signals to compute its value.";
538 const bool valid = std::all_of(
m_ports.inputs().cbegin(),
m_ports.inputs().cend(),
539 [](
auto *input) { return input->isValid(); });
543 for (
auto *output :
m_ports.outputs()) {
544 for (
auto *conn : output->connections()) {
545 conn->setStatus(Status::Error);
547 if (
auto *port = conn->otherPort(output)) {
548 port->setStatus(Status::Error);
564 return m_metadata.hasTrigger;
584 if (
color ==
"White") {
return 0; }
585 if (
color ==
"Red") {
return 1; }
586 if (
color ==
"Green") {
return 2; }
587 if (
color ==
"Blue") {
return 3; }
588 if (
color ==
"Purple") {
return 4; }
604 return m_metadata.hasFrequency;
609 return m_metadata.hasDelay;
614 return m_metadata.hasLabel;
619 return m_metadata.hasTruthTable;
624 return m_metadata.hasAudioBox;
629 return m_metadata.hasVolume;
643 QList<PropertyDescriptor> props;
660 return m_metadata.canChangeAppearance;
665 return m_metadata.rotatesGraphic;
673void GraphicElement::setPortSize(
const int size,
const bool isInput)
678 if ((size < minSize) || (size > maxSize)) {
684 prepareGeometryChange();
697 setPortSize(size,
true);
707 setPortSize(size,
false);
737 m_sim.reset(
m_ports.outputs());
742 m_sim.connectPredecessor(inputIndex, source,
outputPort);
747 m_sim.initVectors(inputCount, outputCount,
m_ports.outputs());
752 return static_cast<int>(m_minOutputSize);
757 return static_cast<int>(m_minInputSize);
762 return static_cast<int>(m_maxOutputSize);
767 return static_cast<int>(m_maxInputSize);
790void GraphicElement::highlight(
const bool isSelected)
793 for (
auto *connection : port->connections()) {
796 if (connection->highLight() == isSelected) {
800 connection->setHighLight(isSelected);
Common logging utilities, the Pandaception error type, and helper macros.
#define qCDebug(category)
Connection: a wire that connects an output port to an input port in the circuit scene.
Shared numeric constants used across layers.
Singleton factory for all circuit element types.
Enums::ElementType ElementType
Enums::WirelessMode WirelessMode
Enums::ElementGroup ElementGroup
static const QFont & labelFont()
Shared label font — constructed once to avoid repeated QFont creation and fontconfig lookups.
Abstract base class for all graphical circuit elements.
Port classes: Port (base), InputPort, and OutputPort.
Deserialization/serialization context structs passed through load()/save() call chains.
Theme management types and singleton ThemeManager.
static QString translatedName(const ElementType type)
Returns the translated human-readable name for type.
virtual void updateLogic()
Computes this element's output values from its current inputs.
QPointF pixmapCenter() const
Returns the centre point of the element's pixmap in local coordinates.
GraphicElement(ElementType type, QGraphicsItem *parent=nullptr)
Constructs a graphic element of the given type, fetching all properties from the metadata registry.
virtual void updateTheme()
Updates the element's visual theme according to the current dark/light palette.
void setFlippedY(bool flipped)
Sets the vertical mirror state and updates the item transform.
QPixmap appearancePreviewPixmap(const int index, const QSize &size) const
Returns a small preview pixmap for the appearance at index (see appearanceStates()).
QString m_translatedName
Translated element name used as tooltip and port object name.
virtual WirelessMode wirelessMode() const
Returns the wireless routing mode for this element.
virtual void setFrequency(const double freq)
Sets the clock frequency to freq (overridden by clock elements).
ElementType elementType() const
Returns the type identifier for this element.
void setHasColors(const bool hasColors)
Sets whether this element type supports color selection.
void setFlippedX(bool flipped)
Sets the horizontal mirror state and updates the item transform.
bool hasDelay() const
Returns true if this element type exposes a configurable clock phase delay.
virtual void setColor(const QString &color)
Sets the element color to color and refreshes the pixmap.
virtual QStringList externalFiles() const
ElementAppearance m_appearance
bool hasVolume() const
Returns true if this element type supports volume control.
virtual void setAudio(const QString &audio)
Sets the audio file associated with this element to audio.
int inputSize() const
Returns the current number of input ports.
QList< PropertyDescriptor > editableProperties() const
Returns the list of editable properties this element exposes in the ElementEditor.
bool hasTruthTable() const
Returns true if this element type has an editable truth table.
bool hasAudioBox() const
Returns true if this element type shows an audio selection box.
void retranslate()
Updates the translated display name, tooltip, and port object name after a locale change.
qreal rotation() const
Returns the current rotation angle of this element in degrees.
void setRotation(const qreal angle)
Rotates the element to angle degrees and updates port positions.
bool isFlippedY() const
Returns true if this element is mirrored along the Y axis (vertical flip).
QRectF portsBoundingRect() const
Returns the bounding rectangle that encompasses all child ports.
QVector< Port * > allPorts() const
Returns a combined list of all input and output ports as Port pointers.
void setLabelAnchor(const QPointF &pos)
void inlineEditRequested(GraphicElement *element)
QPixmap pixmap() const
Returns the pixmap currently displayed by this element.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
Paints the element onto the scene.
QRectF renderBodyBounds() const
Footprint of a "procedural render body" (IC/Mux/Demux/TruthTable): the nominal 64x64 body unioned wit...
QString label() const
Returns the user-visible label text for this element.
int maxOutputSize() const
Returns the maximum allowed number of output ports.
virtual QList< std::pair< int, QString > > appearanceStates() const
Returns the list of editable appearance states for this element. Each pair is (appearance list index,...
void setTrigger(const QKeySequence &trigger)
Sets the keyboard shortcut to trigger and updates the label.
InputPort * inputPort(const int index=0) const
Returns the input port at index (default 0).
virtual void loadFromDrop(const QString &fileName, const QString &contextDir)
Polymorphic interface for drag-drop initialization (replaces elementType() == IC checks).
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override
Requests inline label editing on double-click.
void setAppearanceAt(const int index, const QString &fileName)
Sets a custom appearance at a specific index in the appearance list.
int minInputSize() const
Returns the minimum allowed number of input ports.
void setInputs(const QVector< InputPort * > &inputs)
Replaces the input port vector with inputs.
virtual QString audio() const
Returns the name of the audio file currently associated with this element.
bool hasLabel() const
Returns true if this element type supports a user-editable label.
virtual double delay() const
Returns the clock phase delay in seconds (overridden by Clock; returns 0 for other elements).
virtual void setInputSize(const int size)
Adjusts the number of input ports to size, adding or removing ports as needed.
virtual double frequency() const
Returns the clock frequency in Hz (overridden by Clock; returns 0 for other elements).
~GraphicElement() override
Out-of-line so the unique_ptr to the forward-declared QSvgRenderer can be destroyed.
QKeySequence trigger() const
Returns the keyboard shortcut that activates this element.
void setLabel(const QString &label)
Sets the label text to label and refreshes the display.
void updateLabel()
Repositions and updates the label child item to reflect current state.
virtual QString color() const
Returns the name of the color currently applied to this element.
int outputSize() const
Returns the current number of output ports.
void initSimulationVectors(const int inputCount, const int outputCount)
Allocates simulation I/O vectors with inputs inputs and outputs outputs.
QGraphicsSimpleTextItem * m_label
Child text item that displays the label and optional trigger shortcut.
QRectF labelSceneBoundingRect() const
void setPortName(const QString &name)
Sets the object name of all ports to name for identification.
OutputPort * outputPort(const int index=0) const
Returns the output port at index (default 0).
QString m_titleText
Translated title text shown in UI panels (from metadata).
bool hasFrequency() const
Returns true if this element type exposes a configurable clock frequency.
QString nextColor() const
Returns the name of the next color in the element's color list.
static int colorNameToIndex(const QString &color)
Maps a color name ("White","Red","Green","Blue","Purple") to indices 0–4.
bool hasColors() const
Returns true if this element type supports color selection.
ElementGroup elementGroup() const
Returns the group this element belongs to.
int maxInputSize() const
Returns the maximum allowed number of input ports.
void setMaxInputSize(const int maxInputSize)
Sets the maximum number of input ports to maxInputSize.
QPointF m_labelAnchor
The label's intended anchor point in the element's un-rotated local frame; see setLabelAnchor().
virtual void setDelay(const double delay)
Sets the clock phase delay to delay (overridden by clock elements).
void setMaxOutputSize(const int maxOutputSize)
Sets the maximum number of output ports to maxOutputSize.
void setPixmap(const QString &pixmapPath)
Loads and applies the pixmap located at pixmapPath.
bool canChangeAppearance() const
Returns true if the user is allowed to choose a custom appearance for this element.
virtual void setAppearance(const bool defaultAppearance, const QString &fileName)
Switches the element's appearance.
int minOutputSize() const
Returns the minimum allowed number of output ports.
void connectPredecessor(const int inputIndex, GraphicElement *source, const int outputPort)
Connects simulation input inputIndex to output outputPort of source element.
bool isFlippedX() const
Returns true if this element is mirrored along the X axis (horizontal flip).
virtual void resetSimState()
Resets all simulation-visible state to power-on defaults.
virtual QString genericProperties()
Returns a string encoding element-specific properties for serialization or display.
bool isValid()
Returns true if the element is fully initialised and connected correctly.
int type() const override
Returns the custom type identifier for this item.
virtual void setVolume(float vol)
Sets the audio playback volume to vol (0.0–1.0).
void setMinInputSize(const int minInputSize)
Sets the minimum number of input ports to minInputSize.
QRectF boundingRect() const override
Returns the bounding rectangle of this element in local coordinates.
const QVector< OutputPort * > & outputs() const
Returns a const reference to the vector of all output ports.
virtual void labelContentChanged()
virtual bool hasWirelessMode() const
Returns true if this element supports a configurable wireless routing mode.
virtual float volume() const
Returns the audio playback volume (0.0–1.0).
virtual void setOutputSize(const int size)
Adjusts the number of output ports to size, adding or removing ports as needed.
void setMinOutputSize(const int minOutputSize)
Sets the minimum number of output ports to minOutputSize.
QString previousColor() const
Returns the name of the previous color in the element's color list.
bool hasAudio() const
Returns true if this element type supports audio output.
bool sceneEvent(QEvent *event) override
Intercepts mouse-press and mouse-release events to handle Ctrl+click.
bool rotatesGraphic() const
virtual void updatePortsProperties()
Repositions and reconfigures all ports after the port count changes.
virtual void refresh()
Forces a visual refresh of the element's pixmap and ports.
bool hasTrigger() const
Returns true if this element type supports a keyboard trigger.
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override
Handles item state changes such as position, rotation, and selection.
const QVector< InputPort * > & inputs() const
Returns a const reference to the vector of all input ports.
A port that drives a signal (the source end of a wire).
Contains all color attributes for a theme.
QColor m_graphicElementLabelColor
static const ThemeAttributes & attributes()
Returns the current ThemeAttributes color set.
constexpr int gridSize
Scene grid unit in pixels (elements snap to gridSize/2).
@ Frequency
Clock oscillation frequency in Hz.
@ Delay
Phase delay as fraction of the clock period.
@ Appearance
Custom pixmap appearance selection.
@ Label
User-visible text label.
@ Audio
Audio note selection (buzzer tone).
@ WirelessModeSelector
Wireless routing mode (None / Tx / Rx) — Node elements only.
@ Volume
Audio playback volume (AudioBox, Buzzer).
@ Color
Color selection (LEDs, displays).
@ AudioBox
AudioBox file selection dialog.
@ Trigger
Keyboard trigger shortcut.
@ TruthTable
Editable truth table dialog.