15#include <QSvgGenerator>
28constexpr int kMaxExportPadding = 2000;
39 if (command ==
"load_circuit") {
40 return handleLoadCircuit(params, requestId);
41 }
else if (command ==
"save_circuit") {
42 return handleSaveCircuit(params, requestId);
43 }
else if (command ==
"new_circuit") {
44 return handleNewCircuit(params, requestId);
45 }
else if (command ==
"close_circuit") {
46 return handleCloseCircuit(params, requestId);
47 }
else if (command ==
"get_tab_count") {
48 return handleGetTabCount(params, requestId);
49 }
else if (command ==
"export_image") {
50 return handleExportImage(params, requestId);
51 }
else if (command ==
"export_arduino") {
52 return handleExportArduino(params, requestId);
53 }
else if (command ==
"export_systemverilog") {
54 return handleExportSystemVerilog(params, requestId);
61QJsonObject FileHandler::handleLoadCircuit(
const QJsonObject ¶ms,
const QJsonValue &requestId)
72 QString filename = params.value(
"filename").toString();
81 },
"load circuit", requestId);
84QJsonObject FileHandler::handleSaveCircuit(
const QJsonObject ¶ms,
const QJsonValue &requestId)
95 QString filename = params.value(
"filename").toString();
97 if (!filename.endsWith(
".panda", Qt::CaseInsensitive)) {
108 },
"save circuit", requestId);
111QJsonObject FileHandler::handleNewCircuit(
const QJsonObject &,
const QJsonValue &requestId)
126 },
"create new circuit", requestId);
129QJsonObject FileHandler::handleCloseCircuit(
const QJsonObject &,
const QJsonValue &requestId)
136 QTabWidget *tabWidget =
m_mainWindow->findChild<QTabWidget *>(
"tab");
141 if (tabWidget->count() == 0) {
150 int currentIndex = tabWidget->currentIndex();
152 QWidget *tabWidget_widget = tabWidget->widget(currentIndex);
153 tabWidget->removeTab(currentIndex);
154 if (tabWidget_widget) {
155 tabWidget_widget->deleteLater();
159 },
"close circuit", requestId);
162QJsonObject FileHandler::handleGetTabCount(
const QJsonObject &,
const QJsonValue &requestId)
169 QTabWidget *tabWidget =
m_mainWindow->findChild<QTabWidget *>(
"tab");
175 result[
"tab_count"] = tabWidget->count();
178 },
"get tab count", requestId);
181QJsonObject FileHandler::handleExportImage(
const QJsonObject ¶ms,
const QJsonValue &requestId)
196 QString filename = params.value(
"filename").toString();
197 QString format = params.value(
"format").toString().toLower();
198 const int padding = std::clamp(params.value(
"padding").toInt(20), 0, kMaxExportPadding);
205 if (format !=
"png" && format !=
"svg" && format !=
"pdf") {
210 QRectF sceneRect = scene->itemsBoundingRect();
211 if (sceneRect.isEmpty()) {
215 sceneRect.adjust(-padding, -padding, padding, padding);
217 if (format ==
"svg") {
218 QSvgGenerator generator;
219 generator.setFileName(filename);
220 generator.setSize(sceneRect.size().toSize());
221 generator.setViewBox(sceneRect);
222 generator.setTitle(
"wiRedPanda Circuit");
223 generator.setDescription(
"Circuit exported from wiRedPanda");
225 QPainter painter(&generator);
226 if (!painter.isActive()) {
227 return createErrorResponse(QString(
"Failed to open SVG file for writing: %1").arg(filename),
230 scene->render(&painter, QRectF(), sceneRect);
233 const QFileInfo svgInfo(filename);
234 if (!svgInfo.exists() || svgInfo.size() == 0) {
237 }
else if (format ==
"pdf") {
238 QPdfWriter pdfWriter(filename);
239 pdfWriter.setTitle(
"wiRedPanda Circuit");
240 pdfWriter.setCreator(
"wiRedPanda");
242 pdfWriter.setResolution(72);
243 pdfWriter.setPageSize(QPageSize(sceneRect.size(), QPageSize::Point));
244 pdfWriter.setPageMargins(QMarginsF(0, 0, 0, 0));
246 QPainter painter(&pdfWriter);
247 if (!painter.isActive()) {
248 return createErrorResponse(QString(
"Failed to open PDF file for writing: %1").arg(filename),
251 painter.setRenderHint(QPainter::Antialiasing);
252 scene->render(&painter, QRectF(), sceneRect);
261 if (!image.save(filename,
"PNG")) {
266 result[
"exported_file"] = filename;
267 result[
"format"] = format;
268 result[
"size"] = QString(
"%1x%2").arg(image.width()).arg(image.height());
274 result[
"exported_file"] = filename;
275 result[
"format"] = format;
276 result[
"size"] = QString(
"%1x%2").arg(sceneRect.width()).arg(sceneRect.height());
279 },
"export image", requestId);
282QJsonObject FileHandler::handleExportArduino(
const QJsonObject ¶ms,
const QJsonValue &requestId)
293 QString filename = params.value(
"filename").toString();
303 result[
"exported_file"] = filename;
304 result[
"format"] =
"arduino";
307 },
"export Arduino code", requestId);
310QJsonObject FileHandler::handleExportSystemVerilog(
const QJsonObject ¶ms,
const QJsonValue &requestId)
321 QString filename = params.value(
"filename").toString();
331 result[
"exported_file"] = filename;
332 result[
"format"] =
"systemverilog";
335 },
"export SystemVerilog code", requestId);
CircuitExporter: render a Scene to PDF or PNG image.
Main application window providing menus, toolbars, and tab management.
Main circuit editing scene with undo/redo and user interaction.
WorkSpace widget: the complete circuit editing environment for one tab.
QJsonObject createSuccessResponse(const QJsonObject &result={}, const QJsonValue &requestId=QJsonValue()) const
QJsonObject tryCommand(Fn &&fn, const QString &action, const QJsonValue &requestId=QJsonValue())
Wraps fn in a try/catch, returning an error response on exception.
BaseHandler(MainWindow *mainWindow, const MCPValidator *validator)
QJsonObject createErrorResponse(const QString &error, const QJsonValue &requestId=QJsonValue(), int code=JsonRpcError::InternalError) const
MainWindow * m_mainWindow
bool validateParameters(const QJsonObject ¶ms, const QStringList &required) const
bool validateNonEmptyString(const QJsonValue &value, const QString ¶mName, QString &errorMsg) const
FileHandler(MainWindow *mainWindow, const MCPValidator *validator)
QJsonObject handleCommand(const QString &command, const QJsonObject ¶ms, const QJsonValue &requestId) override
JSON Schema validator for MCP commands and responses using native json-schema-validator.
The top-level application window hosting the tab bar, menus, element palette, and editor.
Simulation * simulation()
Returns the simulation engine associated with this scene.
void stop()
Stops the simulation timer.
QImage renderScaledImage(Scene *scene, const QRectF &paddedRect)
Renders scene into a transparent-filled QImage bounded by kMaxImageDimension.
constexpr int SceneNotAvailable
No active circuit scene to operate on.
constexpr int MethodNotFound
The requested method does not exist or is unavailable.
constexpr int OperationFailed
Generic Qt API / handler operation failure (catch-all for tryCommand).
constexpr int InternalError
Internal JSON-RPC error (last-resort).
constexpr int FileError
File save/load/path error.
constexpr int ValidationError
Semantic validation failure (e.g. port index out of range, enum value not allowed).
constexpr int InvalidParams
Invalid method parameters (missing required, wrong type, etc.).