9#include <QAbstractItemView>
10#include <QApplication>
45 , m_externalScene(scene)
49 , m_askConnection(askConnection)
52 m_ui->retranslateUi(
this);
56 setAttribute(Qt::WA_DeleteOnClose);
58 setWindowModality(Qt::WindowModal);
59 setWindowTitle(tr(
"beWavedDolphin Simulator"));
67 m_signalTableView->setItemDelegate(m_delegate);
71 m_zoom = std::make_unique<DolphinZoom>(m_signalTableView);
74 m_signalTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
75 m_signalTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
76 m_ui->verticalLayout->addWidget(m_signalTableView);
79 m_signalTableView->viewport()->installEventFilter(
this);
83 connect(m_ui->actionAbout, &QAction::triggered,
this, &BewavedDolphin::on_actionAbout_triggered);
84 connect(m_ui->actionAboutQt, &QAction::triggered,
this, &BewavedDolphin::on_actionAboutQt_triggered);
85 connect(m_ui->actionClear, &QAction::triggered,
this, &BewavedDolphin::on_actionClear_triggered);
86 connect(m_ui->actionCombinational, &QAction::triggered,
this, &BewavedDolphin::on_actionCombinational_triggered);
87 connect(m_ui->actionCopy, &QAction::triggered,
this, &BewavedDolphin::on_actionCopy_triggered);
88 connect(m_ui->actionCut, &QAction::triggered,
this, &BewavedDolphin::on_actionCut_triggered);
89 connect(m_ui->actionExit, &QAction::triggered,
this, &BewavedDolphin::on_actionExit_triggered);
90 connect(m_ui->actionExportToPdf, &QAction::triggered,
this, &BewavedDolphin::on_actionExportToPdf_triggered);
91 connect(m_ui->actionExportToPng, &QAction::triggered,
this, &BewavedDolphin::on_actionExportToPng_triggered);
92 connect(m_ui->actionFitScreen, &QAction::triggered,
this, &BewavedDolphin::on_actionFitScreen_triggered);
93 connect(m_ui->actionInvert, &QAction::triggered,
this, &BewavedDolphin::on_actionInvert_triggered);
94 connect(m_ui->actionLoad, &QAction::triggered,
this, &BewavedDolphin::on_actionLoad_triggered);
95 connect(m_ui->actionPaste, &QAction::triggered,
this, &BewavedDolphin::on_actionPaste_triggered);
96 connect(m_ui->actionResetZoom, &QAction::triggered,
this, &BewavedDolphin::on_actionResetZoom_triggered);
97 connect(m_ui->actionSave, &QAction::triggered,
this, &BewavedDolphin::on_actionSave_triggered);
98 connect(m_ui->actionSaveAs, &QAction::triggered,
this, &BewavedDolphin::on_actionSaveAs_triggered);
99 connect(m_ui->actionSetClockWave, &QAction::triggered,
this, &BewavedDolphin::on_actionSetClockWave_triggered);
100 connect(m_ui->actionSetLength, &QAction::triggered,
this, &BewavedDolphin::on_actionSetLength_triggered);
101 connect(m_ui->actionSetTo0, &QAction::triggered,
this, &BewavedDolphin::on_actionSetTo0_triggered);
102 connect(m_ui->actionSetTo1, &QAction::triggered,
this, &BewavedDolphin::on_actionSetTo1_triggered);
103 connect(m_ui->actionShowNumbers, &QAction::triggered,
this, &BewavedDolphin::on_actionShowNumbers_triggered);
104 connect(m_ui->actionShowWaveforms, &QAction::triggered,
this, &BewavedDolphin::on_actionShowWaveforms_triggered);
105 connect(m_ui->actionZoomIn, &QAction::triggered,
this, &BewavedDolphin::on_actionZoomIn_triggered);
106 connect(m_ui->actionZoomOut, &QAction::triggered,
this, &BewavedDolphin::on_actionZoomOut_triggered);
107 connect(m_ui->actionAutoCrop, &QAction::triggered,
this, &BewavedDolphin::on_actionAutoCrop_triggered);
110 connect(&m_undoStack, &QUndoStack::canUndoChanged, m_ui->actionUndo, &QAction::setEnabled);
111 connect(&m_undoStack, &QUndoStack::canRedoChanged, m_ui->actionRedo, &QAction::setEnabled);
112 connect(m_ui->actionUndo, &QAction::triggered, &m_undoStack, &QUndoStack::undo);
113 connect(m_ui->actionRedo, &QAction::triggered, &m_undoStack, &QUndoStack::redo);
125 if (fileName.isEmpty()) {
127 setWindowTitle(tr(
"beWavedDolphin Simulator"));
133 QFileInfo fileInfo(fileName);
134 if (fileInfo.isRelative() || !fileInfo.exists()) {
135 fileInfo.setFile(m_host->currentDir(), QFileInfo(fileName).fileName());
138 if (!fileInfo.exists()) {
139 m_ui->statusbar->showMessage(tr(
"File \"%1\" does not exist!").arg(fileName), 4000);
143 load(fileInfo.absoluteFilePath());
146 qCDebug(zero) <<
"Resuming digital circuit main window after waveform simulation is finished.";
162void BewavedDolphin::loadFromTerminal()
166 QTextStream cin(stdin);
172 qCDebug(zero) <<
"Updating window name with current: " << fileName;
173 m_simulation = m_externalScene->simulation();
175 m_simDriver = std::make_unique<WaveformSimulator>(m_externalScene, m_simulation);
177 qCDebug(zero) <<
"Collecting and ordering the scene's input/output elements.";
179 m_inputs = tableSignals.inputs;
180 m_outputs = tableSignals.outputs;
181 m_inputPorts = tableSignals.inputPorts;
183 qCDebug(zero) <<
"Loading initial data into the table.";
184 loadNewTable(tableSignals.inputLabels, tableSignals.outputLabels);
187void BewavedDolphin::loadNewTable(
const QStringList &inputLabels,
const QStringList &outputLabels)
189 qCDebug(zero) <<
"Snapshotting current input values into oldvalues, to restore after simulation.";
194 qCDebug(zero) <<
"Num iter = " << m_length;
199 m_model =
new SignalModel(
static_cast<int>(inputLabels.size() + outputLabels.size()), m_length,
this);
200 m_signalTableView->setModel(m_model);
203 m_model->setVerticalHeaderLabels(inputLabels + outputLabels);
204 m_model->
setInputRows(
static_cast<int>(inputLabels.size()));
210 connect(m_model, &QAbstractItemModel::dataChanged,
this, [
this] {
211 m_signalTableView->viewport()->update();
214 m_signalTableView->setAlternatingRowColors(
true);
215 m_signalTableView->setShowGrid(
false);
219 m_signalTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Fixed);
220 m_signalTableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Fixed);
222 qCDebug(zero) <<
"Inputs: " << inputLabels.size() <<
", outputs: " << outputLabels.size();
225 on_actionClear_triggered();
227 connect(m_signalTableView, &QAbstractItemView::doubleClicked,
this, &BewavedDolphin::on_tableView_cellDoubleClicked);
228 connect(m_signalTableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &BewavedDolphin::on_tableView_selectionChanged);
235void BewavedDolphin::on_tableView_cellDoubleClicked()
239 applyToSelectedCells([](
int v) {
return (v + 1) % 2; });
242void BewavedDolphin::on_tableView_selectionChanged()
244 m_externalScene->clearSelection();
246 const auto indexes = m_signalTableView->selectionModel()->selectedIndexes();
248 m_ui->actionSetClockWave->setEnabled(!indexes.isEmpty());
253 for (
auto &index : indexes) {
254 if (index.row() < m_inputs.size()) {
255 m_inputs.at(index.row())->setSelected(
true);
259 m_externalScene->view()->update();
262bool BewavedDolphin::elementsStillLive()
const
264 const auto sceneElements = m_externalScene->elements();
265 for (
auto *elm : std::as_const(m_inputs)) {
266 if (!sceneElements.contains(elm)) {
270 for (
auto *elm : std::as_const(m_outputs)) {
271 if (!sceneElements.contains(elm)) {
283 if (!m_simDriver || !m_model) {
291 if (!elementsStillLive()) {
302 m_inputs, m_outputs, m_inputPorts, m_model->columnCount(),
303 [
this](
int row,
int col) { return m_model->value(row, col) != 0; },
304 [
this](
int row,
int col,
int value) { m_model->setValue(row, col, value); });
307 qCDebug(three) <<
"Setting inputs back to old values.";
316 if (watched == m_signalTableView->viewport() && event->type() == QEvent::Wheel) {
317 auto *wheel =
static_cast<QWheelEvent *
>(event);
318 if (wheel->angleDelta().y() > 0) {
319 on_actionZoomIn_triggered();
320 }
else if (wheel->angleDelta().y() < 0) {
321 on_actionZoomOut_triggered();
326 return QMainWindow::eventFilter(watched, event);
329void BewavedDolphin::applyZoom()
336void BewavedDolphin::on_actionExit_triggered()
347 if (m_askConnection && !checkSave()) {
357 QMainWindow::resizeEvent(event);
358 if (m_exerciseOverlay && m_exerciseOverlay->isVisible()) {
359 m_exerciseOverlay->repositionToParent();
365 m_exerciseOverlay = overlay;
370 return m_ui->mainToolBar;
375 return m_ui->actionCombinational;
380 on_actionCombinational_triggered();
383bool BewavedDolphin::checkSave()
390 QMessageBox::question(
392 tr(
"wiRedPanda - beWavedDolphin"),
393 tr(
"Save simulation before closing?"),
394 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
399 case QMessageBox::Save: on_actionSave_triggered();
return (!m_edited);
400 case QMessageBox::Discard:
return true;
401 case QMessageBox::Cancel:
return false;
402 default:
return true;
410 m_model->setValue(row, col, value);
415 for (
int row = 0; row < m_inputs.size(); ++row) {
416 if (m_inputs.at(row)->label() == label) {
431 for (
int row = 0; row < m_inputs.size(); ++row) {
433 signal.
label = m_inputs.at(row)->label();
434 for (
int col = 0; col < duration; ++col) {
435 signal.
values.append(m_model->value(row, col));
437 result.
inputs.append(signal);
440 for (
int row = 0; row < m_outputs.size(); ++row) {
442 signal.
label = m_outputs.at(row)->label();
443 const int outputRowIndex =
static_cast<int>(m_inputs.size()) + row;
444 for (
int col = 0; col < duration; ++col) {
445 signal.
values.append(m_model->value(outputRowIndex, col));
479 if (!elementsStillLive()) {
480 throw PANDACEPTION(
"Cannot export: the circuit this waveform was built from has changed.");
489 const int columns =
static_cast<int>((std::min)(
static_cast<double>(
SignalModel::kMaxColumns), std::pow(2, m_inputPorts)));
490 SignalModel truthTable(m_model->rowCount(), columns);
495 labels.reserve(m_model->rowCount());
496 for (
int row = 0; row < m_model->rowCount(); ++row) {
497 labels.append(m_model->verticalHeaderItem(row)->text());
499 truthTable.setVerticalHeaderLabels(labels);
508 m_inputs, m_outputs, m_inputPorts, columns,
509 [&truthTable](
int row,
int col) {
return truthTable.
value(row, col) != 0; },
510 [&truthTable](
int row,
int col,
int value) { truthTable.
setValue(row, col, value); });
527std::pair<QList<QPair<int, int>>, QList<int>> BewavedDolphin::snapshotCells(
const QModelIndexList &indexes)
const
529 QList<QPair<int, int>> cells;
530 QList<int> oldValues;
531 cells.reserve(indexes.size());
532 oldValues.reserve(indexes.size());
533 for (
const auto &idx : indexes) {
534 cells.append({idx.row(), idx.column()});
535 oldValues.append(m_model->value(idx.row(), idx.column()));
537 return {cells, oldValues};
540QModelIndexList BewavedDolphin::allCellIndexes(
int rows,
int cols)
const
542 QModelIndexList indexes;
543 indexes.reserve(rows * cols);
544 for (
int row = 0; row < rows; ++row) {
545 for (
int col = 0; col < cols; ++col) {
546 indexes.append(m_model->index(row, col));
552void BewavedDolphin::applyToSelectedCells(
const std::function<
int(
int)> &valueFn)
554 const auto indexes = m_signalTableView->selectionModel()->selectedIndexes();
555 const auto [cells, oldValues] = snapshotCells(indexes);
559 qCDebug(zero) <<
"Running simulation.";
560 m_undoStack.push(
new SetCellsCommand(m_model, cells, oldValues, [
this] {
566void BewavedDolphin::on_actionSetTo0_triggered()
571 applyToSelectedCells([](
int) {
return 0; });
575void BewavedDolphin::on_actionSetTo1_triggered()
580 applyToSelectedCells([](
int) {
return 1; });
584void BewavedDolphin::on_actionInvert_triggered()
588 qCDebug(zero) <<
"Pressed Not.";
589 applyToSelectedCells([](
int v) {
return (v + 1) % 2; });
593void BewavedDolphin::on_actionSetClockWave_triggered()
597 qCDebug(zero) <<
"Getting first column.";
598 const auto ranges = m_signalTableView->selectionModel()->selection();
600 if (ranges.isEmpty()) {
608 qCDebug(zero) <<
"Setting the signal according to its column and clock period.";
609 ClockDialog dialog(m_clockPeriod,
this);
611 if (dialog.exec() != QDialog::Accepted) {
615 const int clockPeriod = dialog.period();
616 m_clockPeriod = clockPeriod;
618 const auto indexes = m_signalTableView->selectionModel()->selectedIndexes();
619 const auto [cells, oldValues] = snapshotCells(indexes);
623 qCDebug(zero) <<
"Running simulation.";
624 m_undoStack.push(
new SetCellsCommand(m_model, cells, oldValues, [
this] {
631void BewavedDolphin::on_actionCombinational_triggered()
635 const int truthTableSize =
static_cast<int>((std::min)(
static_cast<double>(
SignalModel::kMaxColumns), std::pow(2, m_inputPorts)));
638 qCDebug(zero) <<
"Setting the signal according to its columns and clock period.";
639 const auto [cells, oldValues] = snapshotCells(allCellIndexes(m_inputPorts, m_model->columnCount()));
643 qCDebug(zero) <<
"Running simulation.";
644 m_undoStack.push(
new SetCellsCommand(m_model, cells, oldValues, [
this] {
651void BewavedDolphin::on_actionSetLength_triggered()
655 qCDebug(zero) <<
"Setting the simulation length.";
656 const int currentLength = m_length > 0 ? m_length : m_model->columnCount();
657 LengthDialog dialog(currentLength,
this);
659 if (dialog.exec() != QDialog::Accepted) {
669 if (m_length == simLength) {
673 m_length = simLength;
675 if (simLength <= m_model->columnCount()) {
678 qCDebug(zero) <<
"Reducing or keeping the simulation length.";
679 m_model->setColumnCount(simLength);
686 qCDebug(zero) <<
"Increasing the simulation length.";
687 const int oldLength = m_model->columnCount();
688 m_model->setColumnCount(simLength);
692 qCDebug(zero) <<
"Running simulation.";
699void BewavedDolphin::on_actionZoomOut_triggered()
708void BewavedDolphin::on_actionZoomIn_triggered()
717void BewavedDolphin::on_actionResetZoom_triggered()
726void BewavedDolphin::zoomChanged()
728 m_ui->actionZoomIn->setEnabled(m_zoom->canZoomIn());
729 m_ui->actionZoomOut->setEnabled(m_zoom->canZoomOut());
732void BewavedDolphin::on_actionFitScreen_triggered()
741void BewavedDolphin::on_actionClear_triggered()
745 const auto [cells, oldValues] = snapshotCells(allCellIndexes(m_inputPorts, m_model->columnCount()));
749 qCDebug(zero) <<
"Running simulation.";
750 m_undoStack.push(
new SetCellsCommand(m_model, cells, oldValues, [
this] {
757void BewavedDolphin::on_actionAutoCrop_triggered()
766void BewavedDolphin::on_actionCopy_triggered()
770 const auto ranges = m_signalTableView->selectionModel()->selection();
772 if (ranges.isEmpty()) {
773 QApplication::clipboard()->clear();
781void BewavedDolphin::on_actionCut_triggered()
785 const auto ranges = m_signalTableView->selectionModel()->selection();
787 if (ranges.isEmpty()) {
788 QApplication::clipboard()->clear();
794 on_actionSetTo0_triggered();
799void BewavedDolphin::on_actionPaste_triggered()
803 const auto ranges = m_signalTableView->selectionModel()->selection();
805 if (ranges.isEmpty()) {
816void BewavedDolphin::on_actionSave_triggered()
820 if (m_currentFile.fileName().isEmpty()) {
821 on_actionSaveAs_triggered();
826 m_ui->statusbar->showMessage(tr(
"Saved file successfully."), 4000);
831void BewavedDolphin::on_actionSaveAs_triggered()
837 const QString fileFilter = m_currentFile.fileName().endsWith(
".csv") ?
838 tr(
"CSV files") +
" (*.csv);;" + tr(
"Dolphin files") +
" (*.dolphin);;" + tr(
"All supported files") +
" (*.dolphin *.csv)"
839 : tr(
"Dolphin files") +
" (*.dolphin);;" + tr(
"CSV files") +
" (*.csv);;" + tr(
"All supported files") +
" (*.dolphin *.csv)";
841 const QString initialPath = m_currentFile.fileName().isEmpty()
842 ? m_host->currentFile().absolutePath()
843 : m_currentFile.absoluteFilePath();
848 if (fileName.isEmpty()) {
854 if (!fileName.endsWith(
".dolphin") && !fileName.endsWith(
".csv")) {
855 if (result.selectedFilter.contains(
"dolphin")) {
856 fileName.append(
".dolphin");
858 fileName.append(
".csv");
863 m_currentFile = QFileInfo(fileName);
864 associateToWiRedPanda(fileName);
865 setWindowTitle(tr(
"beWavedDolphin Simulator") +
" [" + m_currentFile.fileName() +
"]");
866 m_ui->statusbar->showMessage(tr(
"Saved file successfully."), 4000);
871void BewavedDolphin::associateToWiRedPanda(
const QString &fileName)
877 QMessageBox::question(
879 tr(
"wiRedPanda - beWavedDolphin"),
880 tr(
"Do you want to link this beWavedDolphin file to your current wiRedPanda file and save it?"),
881 QMessageBox::Yes | QMessageBox::No);
883 if (reply == QMessageBox::Yes) {
884 m_host->setDolphinFileName(fileName);
890void BewavedDolphin::on_actionLoad_triggered()
894 QDir defaultDirectory;
898 if (m_currentFile.exists()) {
899 defaultDirectory.setPath(m_currentFile.absolutePath());
901 if (m_host->currentFile().exists()) {
902 m_host->currentFile().dir();
904 defaultDirectory.setPath(QDir::homePath());
908 const QString homeDir(m_host->currentDir().absolutePath());
911 this, tr(
"Open File"), homeDir,
912 tr(
"All supported files") +
" (*.dolphin *.csv);;" + tr(
"Dolphin files") +
" (*.dolphin);;" + tr(
"CSV files") +
" (*.csv)");
914 if (fileName.isEmpty()) {
920 m_ui->statusbar->showMessage(tr(
"File loaded successfully."), 4000);
924void BewavedDolphin::load(
const QString &fileName)
929 m_currentFile = QFileInfo(fileName);
930 associateToWiRedPanda(fileName);
931 setWindowTitle(tr(
"beWavedDolphin Simulator") +
" [" + m_currentFile.fileName() +
"]");
937 qCDebug(zero) <<
"Update table.";
940 SignalModel::BulkEditGuard guard(*m_model);
941 for (
int row = 0; row < fileData.
inputPorts; ++row) {
942 for (
int col = 0; col < fileData.
columns; ++col) {
943 m_model->setValue(row, col, fileData.
values[row * fileData.
columns + col]);
951void BewavedDolphin::on_actionShowNumbers_triggered()
958 m_signalTableView->viewport()->update();
962void BewavedDolphin::on_actionShowWaveforms_triggered()
967 m_signalTableView->viewport()->update();
971void BewavedDolphin::on_actionExportToPng_triggered()
977 if (pngFile.isEmpty()) {
981 if (!pngFile.endsWith(
".png", Qt::CaseInsensitive)) {
982 pngFile.append(
".png");
989void BewavedDolphin::on_actionExportToPdf_triggered()
995 if (pdfFile.isEmpty()) {
999 if (!pdfFile.endsWith(
".pdf", Qt::CaseInsensitive)) {
1000 pdfFile.append(
".pdf");
1007void BewavedDolphin::on_actionAbout_triggered()
1010 QMessageBox::about(
this,
1012 tr(
"<p>beWavedDolphin is a waveform simulator for wiRedPanda, developed by the Federal University of São Paulo"
1013 " to help students learn about logic circuits.</p>"
1014 "<p>Software version: %1</p>"
1015 "<p><strong>Creators:</strong></p>"
1017 "<li> Prof. Fábio Cappabianco, Ph.D. </li>"
1019 "<p> beWavedDolphin is currently maintained by Prof. Fábio Cappabianco, Ph.D. and his students.</p>"
1020 "<p> Please file a report at our GitHub page if you find a bug or want to request a new feature.</p>"
1021 "<p><a href=\"http://gibis-unifesp.github.io/wiRedPanda/\">Visit our website!</a></p>")
1022 .arg(QApplication::applicationVersion()));
1026void BewavedDolphin::on_actionAboutQt_triggered()
1029 QMessageBox::aboutQt(
this);
Custom QApplication subclass with exception handling and main-window access.
BewavedDolphin waveform editor: digital signal creation, display, and export.
ClockDialog: dialog for selecting a clock wave's period (in time-step columns).
Common logging utilities, the Pandaception error type, and helper macros.
#define PANDACEPTION(msg,...)
#define qCDebug(category)
DolphinClipboard: copy/paste of waveform cell rectangles to/from a data stream.
DolphinCommands: undo/redo commands for the beWavedDolphin waveform editor.
DolphinEdits: pure value-grid mutations for the beWavedDolphin waveform table.
DolphinExporter: renders/serializes a SignalModel to images and text artifacts.
DolphinFile: reads/writes a SignalModel to .dolphin/.csv files on disk.
DolphinHost: the host-application context the beWavedDolphin editor depends on.
DolphinModelBuilder: maps a circuit scene's I/O elements to waveform signal rows.
DolphinZoom: zoom state and metrics for the beWavedDolphin waveform table.
Abstract file dialog interface for testability.
Abstract base class for all graphical circuit elements.
Extended QGraphicsView with zoom, pan, and fast-rendering modes.
LengthDialog: dialog for setting the BeWavedDolphin simulation length.
Lightweight Sentry helpers gated behind HAVE_SENTRY.
void sentryBreadcrumb(const char *category, const QString &message)
DolphinSerializer: encoding and decoding of .dolphin and .csv waveform files.
Typed wrappers around QSettings for all application preferences.
@ Line
Cells display a waveform-style rising/falling edge graphic.
@ Number
Cells display the numeric value (0/1).
static void guardedSlot(const QObject *context, Body &&body) noexcept
Wraps a slot body in try/catch and reports any exception synchronously, inside the slot's own stack f...
static bool interactiveMode
Hand-written UI descriptor for the BeWavedDolphin main window.
void print()
Prints the waveform table to the system printer.
int inputRow(const QString &label) const
Returns the input row index whose element label equals label, or -1 (MCP access).
void run()
Runs the simulation for all input combinations and fills output rows.
void createWaveform()
Initializes a blank waveform from the current scene's I/O elements.
~BewavedDolphin() override
void setExerciseOverlay(ExerciseOverlay *overlay)
void setCellValue(const int row, const int col, const int value)
Sets a single cell value in the waveform table.
QAction * actionCombinational() const
Returns the combinational action (for tour button spotlighting).
void prepare(const QString &fileName={})
Prepares the waveform from fileName (or blank if empty).
void saveToTxt(QTextStream &stream)
Exports the waveform data as plain text to stream.
WaveformSnapshot snapshot(int duration) const
Returns the input/output signals over the first duration columns (MCP access).
bool exportToPng(const QString &filename)
Exports the waveform scene to a PNG image file.
QToolBar * mainToolBar() const
Returns the main toolbar (for tour target resolution).
void show()
Shows the window and loads the initial waveform.
void resizeEvent(QResizeEvent *event) override
bool eventFilter(QObject *watched, QEvent *event) override
void triggerCombinational()
Triggers the combinational input-pattern generator (for tour automation).
void closeEvent(QCloseEvent *event) override
BewavedDolphin(Scene *scene, const bool askConnection=true, DolphinHost *host=nullptr, QWidget *parent=nullptr)
Constructs the waveform editor.
void setLength(const int simLength, const bool runSimulation=false)
Sets the number of time-step columns.
Interface the host application (MainWindow) provides to BewavedDolphin.
Semi-transparent overlay displayed at the bottom of the canvas during a circuit exercise.
virtual FileDialogResult getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter)=0
virtual QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter)=0
Main circuit editing scene.
static QByteArray dolphinGeometry()
static bool labelsUnderIcons()
static void setDolphinGeometry(const QByteArray &geometry)
Item delegate that draws digital waveform graphics inside table cells.
QStandardItemModel subclass that makes all cells non-editable.
void setValue(int row, int col, int value)
Sets the logic value (0/1) of the cell at (row, col).
int value(int row, int col) const
Returns the logic value (0/1) of the cell at (row, col).
void setInputRows(int inputRows)
Records how many leading rows are inputs (the rest are outputs).
static constexpr int kMaxColumns
bool pasteFromClipboard(SignalModel &model, const QItemSelection &ranges)
void copyToClipboard(const SignalModel &model, const QItemSelection &ranges)
int firstColumn(const SignalModel &model, const QItemSelection &ranges)
Returns the leftmost column index in ranges (clamped to the model's columns).
void combinational(SignalModel &model, const int inputPorts, const int columns)
void clearInputs(SignalModel &model, const int inputPorts)
Sets every input cell (the first inputPorts rows, over the model's columns) to 0.
void applyToCells(SignalModel &model, const QModelIndexList &cells, const std::function< int(int)> &valueFn)
Sets each cell in cells to valueFn(currentValue).
void growInputColumns(SignalModel &model, const int inputPorts, const int oldLength, const int newLength)
int lastNonZeroColumn(const SignalModel &model, const int inputPorts)
Returns the index of the last column with any non-zero input value, or 0 if none.
void clockWave(SignalModel &model, const QModelIndexList &cells, const int firstCol, const int period)
void exportToPdf(const SignalModel *model, const PlotType plotType, const QString &fileName)
void writeTruthTableText(QTextStream &out, const SignalModel *model, const int inputRowCount)
QString csvText(const SignalModel *model)
bool exportToPng(const SignalModel *model, const PlotType plotType, const QString &fileName)
DolphinSerializer::WaveformData parseTerminal(QTextStream &in, const int maxInputPorts)
DolphinSerializer::WaveformData load(const QString &fileName, const int maxInputPorts)
void save(const SignalModel &model, const QString &fileName, const int inputPorts)
Writes model to fileName atomically, choosing the format by extension.
Signals collect(Scene *scene)
FileDialogProvider * provider()
Returns the active provider. Never null.
A labelled waveform signal: a row label and its per-column 0/1 values.
QVector< int > values
Per-column logic values.
QString label
The signal's display label.
QString fileName
Selected file path, empty if cancelled.