wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
DolphinExporter.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 <QHeaderView>
7#include <QPainter>
8#include <QPixmap>
9#include <QPrinter>
10#include <QString>
11#include <QTableView>
12#include <QTextStream>
13
16#include "App/Core/Common.h"
17#include "App/Core/Enums.h"
18
19namespace {
20constexpr int kExportCellWidth = 50;
21constexpr int kExportCellHeight = 40;
22} // namespace
23
24namespace DolphinExporter {
25
26QPixmap renderToPixmap(const SignalModel *model, const PlotType plotType, const int cellW, const int cellH)
27{
28 // Render through a throwaway table bound to the same model, so the live view
29 // (its zoom, selection, scroll position) is never disturbed by an export.
30 QTableView view;
31 view.setModel(const_cast<SignalModel *>(model));
32 auto *delegate = new SignalDelegate(&view);
33 delegate->setPlotType(plotType);
34 view.setItemDelegate(delegate);
35 view.setShowGrid(false);
36 view.setAlternatingRowColors(true);
37 view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
38 view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
39 view.horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
40 view.verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
41 view.horizontalHeader()->setDefaultSectionSize(cellW);
42 view.verticalHeader()->setDefaultSectionSize(cellH);
43
44 // Size the view to its full content so grab() captures every row/column with
45 // no scrollbars and no blank padding.
46 const int contentW = view.horizontalHeader()->length() + view.verticalHeader()->width();
47 const int contentH = view.verticalHeader()->length() + view.horizontalHeader()->height();
48 view.resize(contentW, contentH);
49
50 return view.grab();
51}
52
53bool exportToPng(const SignalModel *model, const PlotType plotType, const QString &fileName)
54{
55 return renderToPixmap(model, plotType, kExportCellWidth, kExportCellHeight).save(fileName);
56}
57
58void exportToPdf(const SignalModel *model, const PlotType plotType, const QString &fileName)
59{
60 // Landscape A4 fits a reasonably long waveform without excessive scaling.
61 QPrinter printer(QPrinter::HighResolution);
62 printer.setPageSize(QPageSize(QPageSize::A4));
63 printer.setPageOrientation(QPageLayout::Orientation::Landscape);
64 printer.setOutputFormat(QPrinter::PdfFormat);
65 printer.setOutputFileName(fileName);
66
67 QPainter painter;
68
69 if (!painter.begin(&printer)) {
70 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Could not print this circuit to PDF.");
71 }
72
73 // Render the waveform offscreen, then scale it to fit the page preserving aspect.
74 const QPixmap pixmap = renderToPixmap(model, plotType, kExportCellWidth, kExportCellHeight);
75 const QSize target = pixmap.size().scaled(painter.viewport().size(), Qt::KeepAspectRatio);
76 painter.drawPixmap(QRect(QPoint(0, 0), target), pixmap);
77 painter.end();
78}
79
84static QChar cellChar(const int value)
85{
86 if (value == static_cast<int>(Status::Unknown)) { return QLatin1Char('x'); }
87 if (value == static_cast<int>(Status::Error)) { return QLatin1Char('E'); }
88 return (value == 0) ? QLatin1Char('0') : QLatin1Char('1');
89}
90
91void writeTruthTableText(QTextStream &out, const SignalModel *model, const int inputRowCount)
92{
93 // Write input rows first, then output rows, each followed by its signal label.
94 for (int row = 0; row < inputRowCount; ++row) {
95 for (int col = 0; col < model->columnCount(); ++col) {
96 out << cellChar(model->value(row, col));
97 }
98
99 const auto *header = model->verticalHeaderItem(row);
100 out << " : \"" << (header ? header->text() : QString()) << "\"\n";
101 }
102
103 out << "\n";
104
105 for (int row = inputRowCount; row < model->rowCount(); ++row) {
106 for (int col = 0; col < model->columnCount(); ++col) {
107 out << cellChar(model->value(row, col));
108 }
109
110 const auto *header = model->verticalHeaderItem(row);
111 out << " : \"" << (header ? header->text() : QString()) << "\"\n";
112 }
113}
114
115QString csvText(const SignalModel *model)
116{
117 // CSV-ish format: "rows,cols," header line, then one comma-separated line per row.
118 QString text;
119 QTextStream out(&text);
120
121 out << model->rowCount() << "," << model->columnCount() << ",\n";
122
123 for (int row = 0; row < model->rowCount(); ++row) {
124 for (int col = 0; col < model->columnCount(); ++col) {
125 out << model->value(row, col) << ",";
126 }
127
128 out << "\n";
129 }
130
131 return text;
132}
133
134} // namespace DolphinExporter
Common logging utilities, the Pandaception error type, and helper macros.
#define PANDACEPTION_WITH_CONTEXT(context, msg,...)
Definition Common.h:102
DolphinExporter: renders/serializes a SignalModel to images and text artifacts.
Central enumeration types for element types, groups, and signal status.
SignalDelegate: paints digital waveform graphics into table cells.
PlotType
Controls how signal cells are rendered in the waveform table.
SignalModel for the beWavedDolphin waveform table.
Item delegate that draws digital waveform graphics inside table cells.
QStandardItemModel subclass that makes all cells non-editable.
Definition SignalModel.h:21
int value(int row, int col) const
Returns the logic value (0/1) of the cell at (row, col).
Model → artifact conversions for the beWavedDolphin export paths.
void exportToPdf(const SignalModel *model, const PlotType plotType, const QString &fileName)
QPixmap renderToPixmap(const SignalModel *model, const PlotType plotType, const int cellW, const int cellH)
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)
static QChar cellChar(const int value)