wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
ElementEditorUI.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 <QtCore/QCoreApplication>
7#include <QtCore/QMetaObject>
8#include <QtGui/QIcon>
9
11
12// Constructs a nested section QGroupBox (with its own compact QGridLayout) inside \a parent
13// and appends it to \a sections so setupUi() can stack them without repeating boilerplate.
14static QGridLayout *addSection(QGroupBox *&sectionBox, QWidget *parent, QVBoxLayout *sections, const char *objectName)
15{
16 sectionBox = new QGroupBox(parent);
17 sectionBox->setObjectName(objectName);
18 auto *grid = new QGridLayout(sectionBox);
19 sections->addWidget(sectionBox);
20 return grid;
21}
22
24{
25 if (ElementEditor->objectName().isEmpty()) {
26 ElementEditor->setObjectName("ElementEditor");
27 }
28
29 // Design size — actual size is controlled by the parent splitter.
30 ElementEditor->resize(304, 395);
31
32 // Zero margins/spacing so the group box fills the widget edge-to-edge,
33 // keeping the panel compact inside the narrow left splitter pane.
34 gridLayout = new QGridLayout(ElementEditor);
35 gridLayout->setSpacing(0);
36 gridLayout->setObjectName("gridLayout");
37 gridLayout->setContentsMargins(0, 0, 0, 0);
38
39 // The group box title shows the element type name (set dynamically by
40 // ElementEditor::setCurrentElements). Bold font makes it stand out.
41 groupBox = new QGroupBox(ElementEditor);
42 groupBox->setObjectName("groupBox");
43 QFont font;
44 font.setBold(true);
45 groupBox->setFont(font);
46
47 // Properties are grouped into labeled sections (Identity/Ports/Timing/Sound/
48 // Interaction/Appearance) instead of one flat list, so the panel doesn't read
49 // as an undifferentiated wall of fields.
50 verticalLayoutSections = new QVBoxLayout(groupBox);
51 verticalLayoutSections->setObjectName("verticalLayoutSections");
52
59
60 // --- Identity: Label, Color ---
61
62 labelLabels = new QLabel(groupBoxIdentity);
63 labelLabels->setObjectName("labelLabels");
64 gridLayoutIdentity->addWidget(labelLabels, 0, 0, 1, 1);
65
67 lineEditElementLabel->setObjectName("lineEditElementLabel");
68 gridLayoutIdentity->addWidget(lineEditElementLabel, 0, 1, 1, 1);
69
70 labelColor = new QLabel(groupBoxIdentity);
71 labelColor->setObjectName("labelColor");
72 gridLayoutIdentity->addWidget(labelColor, 1, 0, 1, 1);
73
74 comboBoxColor = new QComboBox(groupBoxIdentity);
75 comboBoxColor->setObjectName("comboBoxColor");
76 gridLayoutIdentity->addWidget(comboBoxColor, 1, 1, 1, 1);
77
78 // --- Ports: Inputs, Outputs, Value, Locked ---
79
80 labelInputs = new QLabel(groupBoxPorts);
81 labelInputs->setObjectName("labelInputs");
82 gridLayoutPorts->addWidget(labelInputs, 0, 0, 1, 1);
83
84 comboBoxInputSize = new QComboBox(groupBoxPorts);
85 comboBoxInputSize->setObjectName("comboBoxInputSize");
86 gridLayoutPorts->addWidget(comboBoxInputSize, 0, 1, 1, 1);
87
88 labelOutputs = new QLabel(groupBoxPorts);
89 labelOutputs->setObjectName("labelOutputs");
90 gridLayoutPorts->addWidget(labelOutputs, 1, 0, 1, 1);
91
92 comboBoxOutputSize = new QComboBox(groupBoxPorts);
93 comboBoxOutputSize->setObjectName("comboBoxOutputSize");
94 gridLayoutPorts->addWidget(comboBoxOutputSize, 1, 1, 1, 1);
95
96 labelValue = new QLabel(groupBoxPorts);
97 labelValue->setObjectName("labelValue");
98 gridLayoutPorts->addWidget(labelValue, 2, 0, 1, 1);
99
100 comboBoxValue = new QComboBox(groupBoxPorts);
101 comboBoxValue->setObjectName("comboBoxValue");
102 gridLayoutPorts->addWidget(comboBoxValue, 2, 1, 1, 1);
103
104 labelLocked = new QLabel(groupBoxPorts);
105 labelLocked->setObjectName("labelLocked");
106 gridLayoutPorts->addWidget(labelLocked, 3, 0, 1, 1);
107
108 checkBoxLocked = new QCheckBox(groupBoxPorts);
109 checkBoxLocked->setObjectName("checkBoxLocked");
110 gridLayoutPorts->addWidget(checkBoxLocked, 3, 1, 1, 1);
111
112 // --- Timing: Frequency, Delay ---
113
114 labelFrequency = new QLabel(groupBoxTiming);
115 labelFrequency->setObjectName("labelFrequency");
116 gridLayoutTiming->addWidget(labelFrequency, 0, 0, 1, 1);
117
118 doubleSpinBoxFrequency = new QDoubleSpinBox(groupBoxTiming);
119 doubleSpinBoxFrequency->setObjectName("doubleSpinBoxFrequency");
120 doubleSpinBoxFrequency->setDecimals(1);
121 // Minimum 0.0 here; ElementEditor raises it to 0.1 when a real value is shown
122 // (0.0 is reserved as the sentinel for "many frequencies"). 50 Hz max matches
123 // the simulation's 1 ms tick rate (anything faster would be indistinguishable).
124 doubleSpinBoxFrequency->setMinimum(0.000000000000000);
125 doubleSpinBoxFrequency->setMaximum(50.000000000000000);
126 doubleSpinBoxFrequency->setSingleStep(0.100000000000000);
127 gridLayoutTiming->addWidget(doubleSpinBoxFrequency, 0, 1, 1, 1);
128
129 labelDelay = new QLabel(groupBoxTiming);
130 labelDelay->setObjectName("labelDelay");
131 gridLayoutTiming->addWidget(labelDelay, 1, 0, 1, 1);
132
133 // Delay slider range -4 to +4 in integer steps. Each step represents 1/8 of
134 // a clock period, giving a phase offset range of -0.5 to +0.5 periods.
135 // ElementEditor converts between slider integer and float delay on read/write.
137 sliderDelay->setObjectName("sliderDelay");
138 sliderDelay->setOrientation(Qt::Horizontal);
139 sliderDelay->setMinimum(-4);
140 sliderDelay->setMaximum(4);
141 sliderDelay->setValue(0);
142 sliderDelay->setSingleStep(1);
143 sliderDelay->setPageStep(1);
144 sliderDelay->setTickPosition(QSlider::TicksBelow);
145 sliderDelay->setTickInterval(1);
146 gridLayoutTiming->addWidget(sliderDelay, 1, 1, 1, 1);
147
148 // --- Sound: Tone (Buzzer), Sound file (AudioBox), Volume ---
149
150 labelAudio = new QLabel(groupBoxSound);
151 labelAudio->setObjectName("labelAudio");
152 gridLayoutSound->addWidget(labelAudio, 0, 0, 1, 1);
153
154 // Pre-populate with 8 empty items so retranslateUi() can fill them in
155 // without needing to know the count at construction time.
156 comboBoxAudio = new QComboBox(groupBoxSound);
157
158 for (int i = 0; i < 8; ++i) {
159 comboBoxAudio->addItem(QString());
160 }
161
162 comboBoxAudio->setObjectName("comboBoxAudio");
163 gridLayoutSound->addWidget(comboBoxAudio, 0, 1, 1, 1);
164
165 labelAudioBox = new QLabel(groupBoxSound);
166 labelAudioBox->setObjectName("labelAudioBox");
167 gridLayoutSound->addWidget(labelAudioBox, 1, 0, 1, 1);
168
169 horizontalLayout_2 = new QHBoxLayout();
170 horizontalLayout_2->setObjectName("horizontalLayout_2");
171
172 // Read-only line edit shows the currently selected audio file path.
173 // Editing is done via the "..." button which opens a file dialog.
174 lineCurrentAudioBox = new QLineEdit(groupBoxSound);
175 lineCurrentAudioBox->setObjectName("lineCurrentAudioBox");
176 lineCurrentAudioBox->setReadOnly(true);
178
179 // Narrow "..." button beside the audio path — constrained to 28 px wide so
180 // it doesn't steal space from the filename display.
181 pushButtonAudioBox = new QPushButton(groupBoxSound);
182 pushButtonAudioBox->setObjectName("pushButtonAudioBox");
183 QSizePolicy sizePolicy1(QSizePolicy::Fixed, QSizePolicy::Fixed);
184 sizePolicy1.setHorizontalStretch(0);
185 sizePolicy1.setVerticalStretch(0);
186 sizePolicy1.setHeightForWidth(pushButtonAudioBox->sizePolicy().hasHeightForWidth());
187 pushButtonAudioBox->setSizePolicy(sizePolicy1);
188 pushButtonAudioBox->setMaximumSize(QSize(28, 16777215));
190 gridLayoutSound->addLayout(horizontalLayout_2, 1, 1, 1, 1);
191
192 labelVolume = new QLabel(groupBoxSound);
193 labelVolume->setObjectName("labelVolume");
194 gridLayoutSound->addWidget(labelVolume, 2, 0, 1, 1);
195
196 sliderVolume = new QSlider(groupBoxSound);
197 sliderVolume->setObjectName("sliderVolume");
198 sliderVolume->setOrientation(Qt::Horizontal);
199 sliderVolume->setMinimum(0);
200 sliderVolume->setMaximum(100);
201 sliderVolume->setValue(50);
202 sliderVolume->setSingleStep(5);
203 sliderVolume->setPageStep(10);
204 sliderVolume->setTickPosition(QSlider::TicksBelow);
205 sliderVolume->setTickInterval(25);
206 gridLayoutSound->addWidget(sliderVolume, 2, 1, 1, 1);
207
208 // --- Interaction: Trigger, (shared row) Truth Table button / Wireless mode ---
209
210 labelTrigger = new QLabel(groupBoxInteraction);
211 labelTrigger->setObjectName("labelTrigger");
212 gridLayoutInteraction->addWidget(labelTrigger, 0, 0, 1, 1);
213
214 lineEditTrigger = new QLineEdit(groupBoxInteraction);
215 lineEditTrigger->setObjectName("lineEditTrigger");
216 gridLayoutInteraction->addWidget(lineEditTrigger, 0, 1, 1, 1);
217
218 // Row 1 is shared between the Truth Table button and Wireless mode — mutually
219 // exclusive by element type, toggled via setVisible() in ElementEditor, never
220 // both visible at once, so overlapping them here costs no real screen space.
221 pushButtonTruthTable = new QPushButton(groupBoxInteraction);
222 pushButtonTruthTable->setObjectName("pushButtonTruthTable");
223 pushButtonTruthTable->setEnabled(true);
224 gridLayoutInteraction->addWidget(pushButtonTruthTable, 1, 0, 1, 2);
225
227 labelWirelessMode->setObjectName("labelWirelessMode");
228 gridLayoutInteraction->addWidget(labelWirelessMode, 1, 0, 1, 1);
229
231 comboBoxWirelessMode->setObjectName("comboBoxWirelessMode");
232 for (int i = 0; i < 3; ++i) {
233 comboBoxWirelessMode->addItem(QString());
234 }
235 gridLayoutInteraction->addWidget(comboBoxWirelessMode, 1, 1, 1, 1);
236
237 // --- Appearance: state tile grid, (shared row) Change/Default buttons / IC Name ---
238
240 labelAppearanceState->setObjectName("labelAppearanceState");
242
243 // Container for the per-state icon swatch grid; tiles are (re)built by
244 // ElementEditor::rebuildAppearanceStateTiles() whenever the selection changes,
245 // since the states/icons depend on the currently selected element.
247 widgetAppearanceStates->setObjectName("widgetAppearanceStates");
249 gridLayoutAppearanceStates->setContentsMargins(0, 0, 0, 0);
250 gridLayoutAppearanceStates->setSpacing(2);
253
254 // Row 1 is shared between the appearance buttons and the IC-name field — mutually
255 // exclusive (an element either can change appearance or is an embedded IC).
256 horizontalLayout = new QHBoxLayout();
257 horizontalLayout->setSpacing(6);
258 horizontalLayout->setObjectName("horizontalLayout");
259 horizontalLayout->setSizeConstraint(QLayout::SetNoConstraint);
260
262 pushButtonChangeAppearance->setObjectName("pushButtonChangeAppearance");
264
266 pushButtonDefaultAppearance->setObjectName("pushButtonDefaultAppearance");
267 QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
268 sizePolicy.setHorizontalStretch(0);
269 sizePolicy.setVerticalStretch(0);
270 sizePolicy.setHeightForWidth(pushButtonDefaultAppearance->sizePolicy().hasHeightForWidth());
271 pushButtonDefaultAppearance->setSizePolicy(sizePolicy);
272 pushButtonDefaultAppearance->setIcon(QIcon(":/Interface/Locale/default.svg"));
273 pushButtonDefaultAppearance->setIconSize(QSize(16, 16));
275
276 gridLayoutAppearanceSection->addLayout(horizontalLayout, 1, 0, 1, 2);
277
279 labelBlobName->setObjectName("labelBlobName");
280 gridLayoutAppearanceSection->addWidget(labelBlobName, 1, 0, 1, 1);
281
283 lineEditBlobName->setObjectName("lineEditBlobName");
284 gridLayoutAppearanceSection->addWidget(lineEditBlobName, 1, 1, 1, 1);
285
286 gridLayout->addWidget(groupBox, 0, 0, 1, 1);
287
289
290 QMetaObject::connectSlotsByName(ElementEditor);
291}
292
294{
295 ElementEditor->setWindowTitle(QCoreApplication::translate("ElementEditor", "Element Editor"));
296 // Outer container: no visible heading (the inner sections carry their own labels), so
297 // don't ship a placeholder "Title" string to the catalog.
298 groupBox->setTitle(QString());
299 groupBoxIdentity->setTitle(QCoreApplication::translate("ElementEditor", "Identity"));
300 groupBoxPorts->setTitle(QCoreApplication::translate("ElementEditor", "Ports"));
301 groupBoxTiming->setTitle(QCoreApplication::translate("ElementEditor", "Timing"));
302 groupBoxSound->setTitle(QCoreApplication::translate("ElementEditor", "Sound"));
303 groupBoxInteraction->setTitle(QCoreApplication::translate("ElementEditor", "Interaction"));
304 groupBoxAppearanceSection->setTitle(QCoreApplication::translate("ElementEditor", "Appearance"));
305 comboBoxAudio->setItemText(0, QCoreApplication::translate("ElementEditor", "C6"));
306 comboBoxAudio->setItemText(1, QCoreApplication::translate("ElementEditor", "D6"));
307 comboBoxAudio->setItemText(2, QCoreApplication::translate("ElementEditor", "E6"));
308 comboBoxAudio->setItemText(3, QCoreApplication::translate("ElementEditor", "F6"));
309 comboBoxAudio->setItemText(4, QCoreApplication::translate("ElementEditor", "G6"));
310 comboBoxAudio->setItemText(5, QCoreApplication::translate("ElementEditor", "A6"));
311 comboBoxAudio->setItemText(6, QCoreApplication::translate("ElementEditor", "B6"));
312 comboBoxAudio->setItemText(7, QCoreApplication::translate("ElementEditor", "C7"));
313
314 checkBoxLocked->setText(QString());
315 labelLabels->setText(QCoreApplication::translate("ElementEditor", "Label:"));
316 labelTrigger->setText(QCoreApplication::translate("ElementEditor", "Trigger:"));
317 pushButtonTruthTable->setText(QCoreApplication::translate("ElementEditor", "Edit Truth Table"));
318 labelAppearanceState->setText(QCoreApplication::translate("ElementEditor", "Appearance for:"));
319 pushButtonChangeAppearance->setText(QCoreApplication::translate("ElementEditor", "Change appearance to ..."));
320 pushButtonDefaultAppearance->setToolTip(QCoreApplication::translate("ElementEditor", "Default"));
321 pushButtonDefaultAppearance->setText(QString());
322 labelValue->setText(QCoreApplication::translate("ElementEditor", "Value:"));
323 doubleSpinBoxFrequency->setSpecialValueText(QString());
324 doubleSpinBoxFrequency->setSuffix(QCoreApplication::translate("ElementEditor", " Hz"));
325 labelFrequency->setText(QCoreApplication::translate("ElementEditor", "Frequency:"));
326 labelColor->setText(QCoreApplication::translate("ElementEditor", "Color:"));
327 // The "..." glyph is a browse affordance, not translatable text; keep it out of the
328 // catalog and give the button a real accessible name / tooltip so its purpose is clear.
329 pushButtonAudioBox->setText(QStringLiteral("..."));
330 pushButtonAudioBox->setAccessibleName(QCoreApplication::translate("ElementEditor", "Choose audio file"));
331 pushButtonAudioBox->setToolTip(QCoreApplication::translate("ElementEditor", "Choose audio file"));
332 labelInputs->setText(QCoreApplication::translate("ElementEditor", "Inputs:"));
333 comboBoxColor->setCurrentText(QString());
334 labelAudioBox->setText(QCoreApplication::translate("ElementEditor", "Sound file:"));
335 labelOutputs->setText(QCoreApplication::translate("ElementEditor", "Outputs:"));
336 labelLocked->setText(QCoreApplication::translate("ElementEditor", "Locked:"));
337 labelAudio->setText(QCoreApplication::translate("ElementEditor", "Tone:"));
338 labelDelay->setText(QCoreApplication::translate("ElementEditor", "Delay:"));
339 labelWirelessMode->setText(QCoreApplication::translate("ElementEditor", "Wireless:"));
340 comboBoxWirelessMode->setItemText(0, QCoreApplication::translate("ElementEditor", "None"));
341 comboBoxWirelessMode->setItemText(1, QCoreApplication::translate("ElementEditor", "Transmit (Tx)"));
342 comboBoxWirelessMode->setItemText(2, QCoreApplication::translate("ElementEditor", "Receive (Rx)"));
343 labelBlobName->setText(QCoreApplication::translate("ElementEditor", "IC Name:"));
344 labelVolume->setText(QCoreApplication::translate("ElementEditor", "Volume:"));
345
346 // Tooltips for controls whose meaning isn't self-evident from the label alone.
347 const QString lockedTip = QCoreApplication::translate(
348 "ElementEditor", "Prevent this element from being toggled by clicking it during simulation.");
349 labelLocked->setToolTip(lockedTip);
350 checkBoxLocked->setToolTip(lockedTip);
351
352 const QString wirelessTip = QCoreApplication::translate(
353 "ElementEditor", "Nodes with the same label connect wirelessly — Transmit sends its input, Receive outputs it.");
354 labelWirelessMode->setToolTip(wirelessTip);
355 comboBoxWirelessMode->setToolTip(wirelessTip);
356
357 const QString valueTip = QCoreApplication::translate("ElementEditor", "The value this input element outputs.");
358 labelValue->setToolTip(valueTip);
359 comboBoxValue->setToolTip(valueTip);
360
361 const QString triggerTip = QCoreApplication::translate(
362 "ElementEditor", "Keyboard key that toggles this element during simulation.");
363 labelTrigger->setToolTip(triggerTip);
364 lineEditTrigger->setToolTip(triggerTip);
365
366 const QString delayTip = QCoreApplication::translate(
367 "ElementEditor", "Phase offset from the driving clock, as a fraction of its period.");
368 labelDelay->setToolTip(delayTip);
369 sliderDelay->setToolTip(delayTip);
370}
static QGridLayout * addSection(QGroupBox *&sectionBox, QWidget *parent, QVBoxLayout *sections, const char *objectName)
ElementEditorUi: hand-written UI class for the ElementEditor widget.
LabeledSlider: QSlider subclass that draws numeric labels beneath each tick mark.
QComboBox * comboBoxAudio
QGroupBox * groupBoxTiming
QGroupBox * groupBoxInteraction
QComboBox * comboBoxWirelessMode
QLabel * labelWirelessMode
QGroupBox * groupBoxIdentity
QGroupBox * groupBox
QComboBox * comboBoxOutputSize
QComboBox * comboBoxInputSize
QHBoxLayout * horizontalLayout
QGridLayout * gridLayoutPorts
QVBoxLayout * verticalLayoutSections
QLabel * labelFrequency
QGridLayout * gridLayout
QLineEdit * lineCurrentAudioBox
void retranslateUi(QWidget *ElementEditor)
Updates all translatable strings in the widget.
QHBoxLayout * horizontalLayout_2
QLineEdit * lineEditBlobName
QPushButton * pushButtonTruthTable
QGridLayout * gridLayoutTiming
QGroupBox * groupBoxPorts
QPushButton * pushButtonChangeAppearance
QGridLayout * gridLayoutIdentity
QComboBox * comboBoxColor
QPushButton * pushButtonAudioBox
QGroupBox * groupBoxAppearanceSection
QLineEdit * lineEditElementLabel
QButtonGroup * buttonGroupAppearanceStates
QGridLayout * gridLayoutAppearanceStates
QLineEdit * lineEditTrigger
QComboBox * comboBoxValue
QGridLayout * gridLayoutInteraction
QGridLayout * gridLayoutAppearanceSection
QLabel * labelAppearanceState
QWidget * widgetAppearanceStates
QCheckBox * checkBoxLocked
QGroupBox * groupBoxSound
void setupUi(QWidget *ElementEditor)
Creates and lays out all child widgets inside ElementEditor.
QDoubleSpinBox * doubleSpinBoxFrequency
QPushButton * pushButtonDefaultAppearance
LabeledSlider * sliderDelay
QGridLayout * gridLayoutSound
Widget for inspecting and editing the properties of selected circuit elements.
QSlider that draws numeric value labels beneath each tick mark.