wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
InputSwitch.cpp
Go to the documentation of this file.
1// Copyright 2015 - 2026, GIBIS-UNIFESP and the wiRedPanda contributors
2// SPDX-License-Identifier: GPL-3.0-or-later
3
5
6#include <QGraphicsSceneMouseEvent>
7
12#include "App/IO/VersionInfo.h"
13#include "App/Scene/Commands.h"
14#include "App/Scene/Scene.h"
15
16template<>
19 .type = ElementType::InputSwitch,
20 .group = ElementGroup::Input,
21 .minOutputSize = 1,
22 .maxOutputSize = 1,
23 .canChangeAppearance = true,
24 .hasTrigger = true,
25 .hasLabel = true,
26 .rotatesGraphic = false,
27 };
28 static_assert(validate(constraints));
29
31 {
33 meta.pixmapPath = []{ return QStringLiteral(":/Components/Input/switchOn.svg"); };
34 meta.titleText = QT_TRANSLATE_NOOP("InputSwitch", "INPUT SWITCH");
35 meta.translatedName = QT_TRANSLATE_NOOP("InputSwitch", "Input Switch");
36 meta.trContext = "InputSwitch";
37 meta.defaultAppearances = QStringList({
38 ":/Components/Input/switchOff.svg",
39 ":/Components/Input/switchOn.svg",
40 });
41 return meta;
42 }
43
44 static inline const bool registered = []() {
46 ElementFactory::registerCreator(constraints.type, [] { return new InputSwitch(); });
47 return true;
48 }();
49};
50
51InputSwitch::InputSwitch(QGraphicsItem *parent)
53{
54 // A switch drives a definite level from birth: push the OFF state to the
55 // output port, which otherwise stays at the undriven Unknown default.
56 // Base-qualified because the unqualified setOn()/setOff() toggle.
58}
59
60bool InputSwitch::isOn(const int port) const
61{
62 Q_UNUSED(port)
63 return m_isOn;
64}
65
67{
68 // Unlike a button, a switch toggles its latched state rather than forcing a specific value.
69 // Both setOff() and setOn() implement toggle so external callers (e.g. scripts, tests)
70 // get consistent behavior regardless of which variant they call.
72}
73
78
79void InputSwitch::mousePressEvent(QGraphicsSceneMouseEvent *event)
80{
81 if (!m_locked && (event->button() == Qt::LeftButton)) {
82 // Snapshot the pre-toggle state and push it through the same UpdateCommand path
83 // every other property edit uses, so the toggle is undoable and marks the file
84 // modified (previously it called setOn() directly, so a mouse-clicked switch was
85 // silently lost on undo and never made the tab show as unsaved).
86 QByteArray oldData;
87 auto *scene_ = qobject_cast<Scene *>(scene());
88 if (scene_) {
89 QDataStream stream(&oldData, QIODevice::WriteOnly);
91 save(stream, {.purpose = SerializationPurpose::InMemorySnapshot});
92 }
93
94 setOn(!m_isOn);
95 event->accept();
96
97 if (scene_) {
98 scene_->receiveCommand(new UpdateCommand({this}, oldData, scene_));
99 }
100 }
101
102 QGraphicsItem::mousePressEvent(event);
103}
104
105void InputSwitch::save(QDataStream &stream, SerializationOptions options) const
106{
107 GraphicElement::save(stream, options);
108
109 const bool slim = (options.purpose == SerializationPurpose::PortableFile);
110
111 QMap<QString, QVariant> map;
112 // PortableFile streams omit defaults; fresh-loaded elements start there
113 // anyway. Snapshots write unconditionally (reloaded into live elements).
114 if (!slim || m_isOn) {
115 map.insert("isOn", m_isOn);
116 }
117 if (!slim || m_locked) {
118 map.insert("locked", m_locked);
119 }
120
121 stream << map;
122}
123
124void InputSwitch::load(QDataStream &stream, SerializationContext &context)
125{
126 GraphicElement::load(stream, context);
127
128 if (!VersionInfo::hasQMapFormat(context.version)) {
129 // v1.x–4.0 stored isOn as a bare bool; locked flag added in v3.1
130 stream >> m_isOn;
131
132 if (VersionInfo::hasLockState(context.version)) {
133 stream >> m_locked;
134 }
135 }
136
137 if (VersionInfo::hasQMapFormat(context.version)) {
138 // v4.1+ uses a key-value map
139 QMap<QString, QVariant> map = Serialization::readBoundedMetadata(stream);
140
141 if (map.contains("isOn")) {
142 m_isOn = map.value("isOn").toBool();
143 }
144
145 if (map.contains("locked")) {
146 m_locked = map.value("locked").toBool();
147 }
148 }
149
150 // Apply the loaded on/off state to port and pixmap
151 setOn(m_isOn);
152}
153
154QList<std::pair<int, QString>> InputSwitch::appearanceStates() const
155{
156 return {{0, tr("Off")}, {1, tr("On")}};
157}
All QUndoCommand subclasses and the CommandUtils helper namespace.
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.
Definition ElementInfo.h:80
constexpr bool validate(const ElementConstraints &c)
Validates element constraints at compile time.
Definition ElementInfo.h:48
Enums::ElementType ElementType
Definition Enums.h:107
Graphic element for a bistable toggle switch input.
Main circuit editing scene with undo/redo and user interaction.
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().
static void registerMetadata(const ElementMetadata &meta)
Registers meta in the global map (called once per element type at startup).
virtual void setOn()=0
Sets all outputs to active (logic-1).
GraphicElementInput(ElementType type, QGraphicsItem *parent=nullptr)
virtual void load(QDataStream &stream, SerializationContext &context)
Loads the graphic element through a binary data stream.
virtual void save(QDataStream &stream, SerializationOptions options) const
Toggle switch input element that maintains its on/off state between clicks.
Definition InputSwitch.h:20
void setOn() override
Sets the switch to the on (logic-1) state (toggles; see implementation).
InputSwitch(QGraphicsItem *parent=nullptr)
Constructs the element with optional parent.
void load(QDataStream &stream, SerializationContext &context) override
void save(QDataStream &stream, SerializationOptions options) const override
bool isOn(const int port=0) const override
Returns true if output port port is driven logic-high.
void mousePressEvent(QGraphicsSceneMouseEvent *event) override
QList< std::pair< int, QString > > appearanceStates() const override
void setOff() override
Drives all output ports logic-low (toggles; see implementation).
static void writePandaHeader(QDataStream &stream)
Writes the .panda circuit file header to stream.
static QMap< QString, QVariant > readBoundedMetadata(QDataStream &stream)
Reads the file-level metadata QMap<QString,QVariant> from stream without calling QList::reserve() wit...
Undo command for property changes (label, color, frequency, appearance, etc.).
Definition Commands.h:193
bool hasLockState(const QVersionNumber &v)
V3.1: Lock state for input elements; color for some display/button types.
Definition VersionInfo.h:51
bool hasQMapFormat(const QVersionNumber &v)
V4.1: Format changed from flat binary to keyed QMap; port serial IDs; rotation fix.
Definition VersionInfo.h:60
Compile-time-validatable subset of ElementMetadata.
Definition ElementInfo.h:21
static ElementMetadata metadata()
static constexpr ElementConstraints constraints
static const bool registered
Self-registering element information trait.
Compile-time-registered properties for one element type.
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.
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.