9#include <QGraphicsSceneMouseEvent>
11#include <QStyleOptionGraphicsItem>
29 .type = ElementType::IC,
30 .group = ElementGroup::IC,
33 static_assert(
validate(constraints));
38 meta.pixmapPath = []{
return QString(); };
39 meta.titleText = QT_TRANSLATE_NOOP(
"IC",
"INTEGRATED CIRCUIT");
40 meta.translatedName = QT_TRANSLATE_NOOP(
"IC",
"IC");
41 meta.trContext =
"IC";
42 meta.defaultAppearances = QStringList();
61 setAcceptHoverEvents(
true);
70 qDeleteAll(m_internalConnections);
71 qDeleteAll(m_internalElements);
78 result.append(m_file);
87 QMap<QString, QVariant> map;
90 map.insert(
"name", m_blobName);
91 }
else if (!m_file.isEmpty()) {
108 QHash<Port *, quint64> reversePortMap;
109 reversePortMap.reserve(context.
portMap.size());
110 for (
auto it = context.
portMap.constBegin(); it != context.
portMap.constEnd(); ++it) {
111 reversePortMap[it.value()] = it.key();
114 QVector<quint64> savedInputKeys, savedOutputKeys;
115 for (
auto *port :
inputs()) {
116 if (
auto it = reversePortMap.constFind(port); it != reversePortMap.constEnd()) {
117 savedInputKeys.append(it.value());
121 if (
auto it = reversePortMap.constFind(port); it != reversePortMap.constEnd()) {
122 savedOutputKeys.append(it.value());
134 m_file = QFileInfo(QString(m_file).replace(
'\\',
'/')).fileName();
143 const QString name = map.contains(
"name") ? map.value(
"name").toString()
144 : map.contains(
"fileName") ? map.value(
"fileName").toString()
145 : map.contains(
"blobName") ? map.value(
"blobName").toString()
148 if (name.isEmpty()) {
149 throw PANDACEPTION(
"IC load: no IC name present in serialized data");
154 const QString baseName = QFileInfo(name).baseName();
159 const QByteArray blobBytes = context.
blobRegistry->value(name);
170 const bool blobUnchanged = (m_blobName == name) && !m_internalElements.isEmpty()
171 && (m_loadedBlobSnapshot == blobBytes);
174 if (!blobUnchanged) {
177 }
else if (baseMatch) {
178 m_blobName = baseName;
198 for (
int i = 0; i < savedInputKeys.size(); ++i) {
199 if (i <
inputs().size()) {
202 context.
portMap.remove(savedInputKeys[i]);
205 for (
int i = 0; i < savedOutputKeys.size(); ++i) {
209 context.
portMap.remove(savedOutputKeys[i]);
214void IC::resetInternalState()
216 m_internalInputs.clear();
217 m_internalOutputs.clear();
225 m_sortedInternalElements.clear();
226 m_boundaryInputElements.clear();
227 m_internalHasFeedback =
false;
228 qDeleteAll(m_internalConnections);
229 m_internalConnections.clear();
230 qDeleteAll(m_internalElements);
231 m_internalElements.clear();
235 Q_ASSERT(m_internalElements.isEmpty());
236 Q_ASSERT(m_sortedInternalElements.isEmpty());
237 Q_ASSERT(m_internalConnections.isEmpty());
238 Q_ASSERT(m_internalInputs.isEmpty());
239 Q_ASSERT(m_internalOutputs.isEmpty());
240 Q_ASSERT(m_boundaryInputElements.isEmpty());
251 m_loadedBlobSnapshot = blob;
276 if (!m_blobName.isEmpty()) {
279 return m_file.isEmpty() ? QString() : QFileInfo(m_file).fileName();
282bool IC::isCursorOverPort(
const QPointF &localPos)
const
285 return std::any_of(ports.cbegin(), ports.cend(), [&](
const Port *port) {
286 return port->contains(mapToItem(port, localPos));
294 if (isCursorOverPort(event->pos())) {
304 if (isCursorOverPort(event->pos())) {
327void IC::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget)
335 painter->setPen(QPen(
m_appearance.selectionPen(), 0.5, Qt::SolidLine));
Common logging utilities, the Pandaception error type, and helper macros.
#define PANDACEPTION(msg,...)
Connection: a wire that connects an output port to an input port in the circuit scene.
Singleton factory for all circuit element types.
Self-registering element trait template and compile-time constraint validation.
ElementMetadata metadataFromConstraints(const ElementConstraints &c)
Converts ElementConstraints to an ElementMetadata with all constraint-derived fields set.
constexpr bool validate(const ElementConstraints &c)
Validates element constraints at compile time.
Enums::ElementType ElementType
Single, shared implementation of how an element's external-file reference (an appearance image,...
ICLoader: loads an IC's sub-circuit from file or embedded blob.
ICRenderer: draws an IC's body and builds its cached pixmaps.
ICSimulation: builds and runs an IC's internal simulation graph.
Integrated Circuit (IC) graphic element that encapsulates a sub-circuit file.
Port classes: Port (base), InputPort, and OutputPort.
Deserialization/serialization context structs passed through load()/save() call chains.
Circuit and waveform file serialization/deserialization utilities.
Named version predicates for file-format compatibility checks.
static void registerCreator(ElementType type, std::function< GraphicElement *()> creator)
Registers a creator lambda for type, used by buildElement().
GraphicElement(ElementType type, QGraphicsItem *parent=nullptr)
Constructs a graphic element of the given type, fetching all properties from the metadata registry.
ElementAppearance m_appearance
QVector< Port * > allPorts() const
Returns a combined list of all input and output ports as Port pointers.
QRectF renderBodyBounds() const
Footprint of a "procedural render body" (IC/Mux/Demux/TruthTable): the nominal 64x64 body unioned wit...
virtual void load(QDataStream &stream, SerializationContext &context)
Loads the graphic element through a binary data stream.
QGraphicsSimpleTextItem * m_label
Child text item that displays the label and optional trigger shortcut.
virtual void save(QDataStream &stream, SerializationOptions options) const
const QVector< OutputPort * > & outputs() const
Returns a const reference to the vector of all output ports.
const QVector< InputPort * > & inputs() const
Returns a const reference to the vector of all input ports.
static IC::PortMetadata buildPortMetadata(const QVector< GraphicElement * > &elements)
Scans elements for Input/Output groups, sorts by Y/X position, and builds labels.
static void loadFromBlob(IC &ic, const QByteArray &blob, const QString &contextDir)
Loads ic from in-memory blob bytes (full .panda file format).
static void loadFile(IC &ic, const QString &fileName, const QString &contextDir={})
Loads ic's circuit from fileName and rebuilds the logic mapping.
static void drawBody(IC &ic, QPainter *painter)
static void update(IC &ic)
Simulates ic's internal circuit and propagates results to its boundary.
static void resettle(IC &ic)
static void initialize(IC &ic)
Builds the internal simulation graph (connection graph + topological sort) for ic.
Graphic element representing an Integrated Circuit (sub-circuit) box.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
void resettleCombinational() override
void previewHideRequested()
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override
void initializeSimulation()
Builds the internal simulation graph (connection graph + sort) for direct simulation.
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override
QString displayName() const
void loadFromBlob(const QByteArray &blob, const QString &contextDir)
Loads the IC from in-memory blob bytes (full .panda file format).
bool isEmbedded() const override
Returns true if this element is an embedded IC (not file-backed). Base returns false.
void previewRequested(IC *ic, const QPoint &screenPos)
void load(QDataStream &stream, SerializationContext &context) override
void save(QDataStream &stream, SerializationOptions options) const override
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override
QStringList externalFiles() const override
void loadFromDrop(const QString &fileName, const QString &contextDir) override
Polymorphic interface for drag-drop initialization (replaces elementType() == IC checks).
void previewMoved(IC *ic, const QPoint &screenPos)
static PortMetadata buildPortMetadata(const QVector< GraphicElement * > &elements)
Scans elements for Input/Output groups, sorts by Y/X position, and builds labels.
void requestOpenSubCircuit(int elementId, const QString &blobName, const QString &filePath)
Emitted on double-click to request opening the sub-circuit in a new tab.
void updateLogic() override
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override
void previewCancelRequested(IC *ic)
QRectF boundingRect() const override
IC(QGraphicsItem *parent=nullptr)
Constructs an IC element without loading a file.
void loadFile(const QString &fileName, const QString &contextDir={})
Loads the IC circuit from fileName and rebuilds the logic mapping.
Abstract base class for circuit element ports (connection endpoints).
static QString readBoundedString(QDataStream &stream)
Reads a QString from stream, refusing to allocate more bytes than remain in the stream (prevents OOM ...
static QMap< QString, QVariant > readBoundedMetadata(QDataStream &stream)
Reads the file-level metadata QMap<QString,QVariant> from stream without calling QList::reserve() wit...
QString forWriting(const QString &path, SerializationPurpose purpose)
bool hasQMapFormat(const QVersionNumber &v)
V4.1: Format changed from flat binary to keyed QMap; port serial IDs; rotation fix.
bool hasLabels(const QVersionNumber &v)
V1.2: Labels added to elements; IC filename field.
Compile-time-validatable subset of ElementMetadata.
static ElementMetadata metadata()
static constexpr ElementConstraints constraints
static const bool registered
Self-registering element information trait.
Bundles all per-deserialization state so that load() overrides receive it through one explicit parame...
QVersionNumber version
File-format version read from the stream header.
QHash< quint64, Port * > & portMap
Accumulated port-pointer map built during deserialization.
QMap< QString, QByteArray > * blobRegistry
Blob registry for resolving embedded IC blobNames during deserialization.
QString contextDir
Directory of the .panda file (for relative path resolution).
Options passed to GraphicElement::save() (and friends); the save-side counterpart of SerializationCon...
SerializationPurpose purpose
What this serialization is for; see SerializationPurpose. Mandatory, no default.