From 0d8c80ad5daafc02030385da90c5a57182a5d4e5 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 14 Jun 2019 11:14:18 +0200 Subject: [PATCH] gui for json write and proper statuses --- common/command.cc | 2 +- gui/base.qrc | 1 + gui/basewindow.cc | 71 +++++++++++++++++++++++++++--------- gui/basewindow.h | 13 ++++--- gui/create_img.sh | 5 ++- gui/ecp5/mainwindow.cc | 11 ++++-- gui/ecp5/mainwindow.h | 3 +- gui/ice40/mainwindow.cc | 8 +++- gui/ice40/mainwindow.h | 3 +- gui/resources/save_json.png | Bin 0 -> 1546 bytes json/jsonparse.cc | 3 +- 11 files changed, 84 insertions(+), 36 deletions(-) create mode 100644 gui/resources/save_json.png diff --git a/common/command.cc b/common/command.cc index 209f8cab..7b0b2caa 100644 --- a/common/command.cc +++ b/common/command.cc @@ -255,7 +255,7 @@ int CommandHandler::executeMain(std::unique_ptr ctx) customAfterLoad(w.getContext()); w.notifyChangeContext(); - w.updateLoaded(); + w.updateActions(); } else w.notifyChangeContext(); } catch (log_execution_error_exception) { diff --git a/gui/base.qrc b/gui/base.qrc index 644b16a6..85d1432a 100644 --- a/gui/base.qrc +++ b/gui/base.qrc @@ -22,6 +22,7 @@ resources/route.png resources/time_add.png resources/open_json.png + resources/save_json.png resources/py.png diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 63e30f27..59dd6f7b 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -29,6 +29,7 @@ #include "designwidget.h" #include "fpgaviewwidget.h" #include "jsonparse.h" +#include "jsonwrite.h" #include "log.h" #include "mainwindow.h" #include "pythontab.h" @@ -138,13 +139,26 @@ void BaseMainWindow::createMenusAndBars() // Help menu actions QAction *actionAbout = new QAction("About", this); - // Design menu options + // Gile menu options + actionNew = new QAction("New", this); + actionNew->setIcon(QIcon(":/icons/resources/new.png")); + actionNew->setShortcuts(QKeySequence::New); + actionNew->setStatusTip("New project"); + connect(actionNew, &QAction::triggered, this, &BaseMainWindow::new_proj); + actionLoadJSON = new QAction("Open JSON", this); actionLoadJSON->setIcon(QIcon(":/icons/resources/open_json.png")); actionLoadJSON->setStatusTip("Open an existing JSON file"); actionLoadJSON->setEnabled(true); connect(actionLoadJSON, &QAction::triggered, this, &BaseMainWindow::open_json); + actionSaveJSON = new QAction("Save JSON", this); + actionSaveJSON->setIcon(QIcon(":/icons/resources/save_json.png")); + actionSaveJSON->setStatusTip("Write to JSON file"); + actionSaveJSON->setEnabled(true); + connect(actionSaveJSON, &QAction::triggered, this, &BaseMainWindow::save_json); + + // Design menu options actionPack = new QAction("Pack", this); actionPack->setIcon(QIcon(":/icons/resources/pack.png")); actionPack->setStatusTip("Pack current design"); @@ -223,10 +237,13 @@ void BaseMainWindow::createMenusAndBars() menuBar->addAction(menuHelp->menuAction()); // Add File menu actions + menuFile->addAction(actionNew); + menuFile->addAction(actionLoadJSON); + menuFile->addAction(actionSaveJSON); + menuFile->addSeparator(); menuFile->addAction(actionExit); // Add Design menu actions - menuDesign->addAction(actionLoadJSON); menuDesign->addAction(actionPack); menuDesign->addAction(actionAssignBudget); menuDesign->addAction(actionPlace); @@ -240,7 +257,10 @@ void BaseMainWindow::createMenusAndBars() // Main action bar mainActionBar = new QToolBar("Main"); addToolBar(Qt::TopToolBarArea, mainActionBar); + mainActionBar->addAction(actionNew); mainActionBar->addAction(actionLoadJSON); + mainActionBar->addAction(actionSaveJSON); + mainActionBar->addSeparator(); mainActionBar->addAction(actionPack); mainActionBar->addAction(actionAssignBudget); mainActionBar->addAction(actionPlace); @@ -280,7 +300,7 @@ void BaseMainWindow::load_json(std::string filename) if (parse_json_file(f, filename, ctx.get())) { log("Loading design successful.\n"); Q_EMIT updateTreeView(); - updateLoaded(); + updateActions(); } else { actionLoadJSON->setEnabled(true); log("Loading design failed.\n"); @@ -295,15 +315,26 @@ void BaseMainWindow::open_json() } } +void BaseMainWindow::save_json() +{ + QString fileName = QFileDialog::getSaveFileName(this, QString("Save JSON"), QString(), QString("*.json")); + if (!fileName.isEmpty()) { + std::string fn = fileName.toStdString(); + std::ofstream f(fn); + if (write_json_file(f, fn, ctx.get())) + log("Saving JSON successful.\n"); + else + log("Saving JSON failed.\n"); + } +} + void BaseMainWindow::pack_finished(bool status) { disableActions(); if (status) { log("Packing design successful.\n"); Q_EMIT updateTreeView(); - actionPlace->setEnabled(true); - actionAssignBudget->setEnabled(true); - onPackFinished(); + updateActions(); } else { log("Packing design failed.\n"); } @@ -313,9 +344,8 @@ void BaseMainWindow::budget_finish(bool status) { disableActions(); if (status) { - log("Assigning timing budget successful.\n"); - actionPlace->setEnabled(true); - onBudgetFinished(); + log("Assigning timing budget successful.\n"); + updateActions(); } else { log("Assigning timing budget failed.\n"); } @@ -327,8 +357,7 @@ void BaseMainWindow::place_finished(bool status) if (status) { log("Placing design successful.\n"); Q_EMIT updateTreeView(); - actionRoute->setEnabled(true); - onPlaceFinished(); + updateActions(); } else { log("Placing design failed.\n"); } @@ -339,7 +368,7 @@ void BaseMainWindow::route_finished(bool status) if (status) { log("Routing design successful.\n"); Q_EMIT updateTreeView(); - onRouteFinished(); + updateActions(); } else log("Routing design failed.\n"); } @@ -379,11 +408,12 @@ void BaseMainWindow::place() { Q_EMIT task->place(timing_driven); } void BaseMainWindow::disableActions() { - actionLoadJSON->setEnabled(false); + actionLoadJSON->setEnabled(true); actionPack->setEnabled(false); actionAssignBudget->setEnabled(false); actionPlace->setEnabled(false); actionRoute->setEnabled(false); + actionExecutePy->setEnabled(true); actionPlay->setEnabled(false); @@ -393,11 +423,18 @@ void BaseMainWindow::disableActions() onDisableActions(); } -void BaseMainWindow::updateLoaded() +void BaseMainWindow::updateActions() { - disableActions(); - actionPack->setEnabled(true); - onJsonLoaded(); + if (ctx->settings.find(ctx->id("pack"))==ctx->settings.end()) + actionPack->setEnabled(true); + else if (ctx->settings.find(ctx->id("place"))==ctx->settings.end()) { + actionAssignBudget->setEnabled(true); + actionPlace->setEnabled(true); + } + else if (ctx->settings.find(ctx->id("route"))==ctx->settings.end()) + actionRoute->setEnabled(true); + + onUpdateActions(); } void BaseMainWindow::execute_python() diff --git a/gui/basewindow.h b/gui/basewindow.h index 91389978..d2640813 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -48,7 +48,8 @@ class BaseMainWindow : public QMainWindow explicit BaseMainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent = 0); virtual ~BaseMainWindow(); Context *getContext() { return ctx.get(); } - void updateLoaded(); + void updateActions(); + void notifyChangeContext(); protected: @@ -57,11 +58,7 @@ class BaseMainWindow : public QMainWindow void load_json(std::string filename); virtual void onDisableActions(){}; - virtual void onJsonLoaded(){}; - virtual void onPackFinished(){}; - virtual void onBudgetFinished(){}; - virtual void onPlaceFinished(){}; - virtual void onRouteFinished(){}; + virtual void onUpdateActions(){}; protected Q_SLOTS: void writeInfo(std::string text); @@ -70,6 +67,7 @@ class BaseMainWindow : public QMainWindow virtual void new_proj() = 0; void open_json(); + void save_json(); void budget(); void place(); @@ -110,7 +108,10 @@ class BaseMainWindow : public QMainWindow QToolBar *mainActionBar; QProgressBar *progressBar; + QAction *actionNew; QAction *actionLoadJSON; + QAction *actionSaveJSON; + QAction *actionPack; QAction *actionAssignBudget; QAction *actionPlace; diff --git a/gui/create_img.sh b/gui/create_img.sh index 1508d023..fcce4e88 100755 --- a/gui/create_img.sh +++ b/gui/create_img.sh @@ -2,5 +2,6 @@ convert -font helvetica -fill red -pointsize 8 -gravity center -draw "text 2,8 ' convert -font helvetica -fill red -pointsize 8 -gravity center -draw "text 2,8 'PCF'" resources/open.png ice40/resources/open_pcf.png convert -font helvetica -fill red -pointsize 8 -gravity center -draw "text 2,8 'BASE'" resources/open.png ecp5/resources/open_base.png convert -font helvetica -fill red -pointsize 8 -gravity center -draw "text 2,8 'LPF'" resources/open.png ecp5/resources/open_lpf.png -convert -font helvetica -fill red -pointsize 8 -gravity center -draw "text 2,8 'ASC'" resources/save.png ice40/resources/save_asc.png -convert -font helvetica -fill red -pointsize 7 -gravity center -draw "text 2,8 'CONFIG'" resources/save.png ecp5/resources/save_config.png \ No newline at end of file +convert -font helvetica -fill red -pointsize 8 -gravity center -draw "text 2,8 'ASC'" resources/save.png ice40/resources/save_asc.png +convert -font helvetica -fill red -pointsize 7 -gravity center -draw "text 2,8 'CONFIG'" resources/save.png ecp5/resources/save_config.png +convert -font helvetica -fill red -pointsize 8 -gravity center -draw "text 2,8 'JSON'" resources/save.png resources/save_json.png \ No newline at end of file diff --git a/gui/ecp5/mainwindow.cc b/gui/ecp5/mainwindow.cc index a54ab8b5..43b31f4c 100644 --- a/gui/ecp5/mainwindow.cc +++ b/gui/ecp5/mainwindow.cc @@ -188,8 +188,13 @@ void MainWindow::onDisableActions() actionSaveConfig->setEnabled(false); } -void MainWindow::onJsonLoaded() { actionLoadLPF->setEnabled(true); } - -void MainWindow::onRouteFinished() { actionLoadBase->setEnabled(true); } +void MainWindow::onUpdateActions() { + if (ctx->settings.find(ctx->id("pack"))==ctx->settings.end()) + actionLoadLPF->setEnabled(true); + if (ctx->settings.find(ctx->id("pack"))==ctx->settings.end()) + actionLoadBase->setEnabled(true); + if (ctx->settings.find(ctx->id("route"))!=ctx->settings.end()) + actionSaveConfig->setEnabled(true); +} NEXTPNR_NAMESPACE_END diff --git a/gui/ecp5/mainwindow.h b/gui/ecp5/mainwindow.h index 186a7974..b47e7ec7 100644 --- a/gui/ecp5/mainwindow.h +++ b/gui/ecp5/mainwindow.h @@ -38,8 +38,7 @@ class MainWindow : public BaseMainWindow protected: void onDisableActions() override; - void onJsonLoaded() override; - void onRouteFinished() override; + void onUpdateActions() override; protected Q_SLOTS: void new_proj() override; diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index b766734f..7c8effac 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -186,7 +186,11 @@ void MainWindow::onDisableActions() actionSaveAsc->setEnabled(false); } -void MainWindow::onJsonLoaded() { actionLoadPCF->setEnabled(true); } -void MainWindow::onRouteFinished() { actionSaveAsc->setEnabled(true); } +void MainWindow::onUpdateActions() { + if (ctx->settings.find(ctx->id("pack"))==ctx->settings.end()) + actionLoadPCF->setEnabled(true); + if (ctx->settings.find(ctx->id("route"))!=ctx->settings.end()) + actionSaveAsc->setEnabled(true); +} NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h index de160174..ed1b6aaf 100644 --- a/gui/ice40/mainwindow.h +++ b/gui/ice40/mainwindow.h @@ -39,8 +39,7 @@ class MainWindow : public BaseMainWindow void load_pcf(std::string filename); void onDisableActions() override; - void onJsonLoaded() override; - void onRouteFinished() override; + void onUpdateActions() override; protected Q_SLOTS: void new_proj() override; diff --git a/gui/resources/save_json.png b/gui/resources/save_json.png new file mode 100644 index 0000000000000000000000000000000000000000..cbeb324352b856077ccef123c1877b2a37e6bcdc GIT binary patch literal 1546 zcmV+l2KD)gP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8x00(qQO+^Rd2m%oU0@dbd%K!ic4oO5oR9M5kmThQOWf;eQ z_jAtEhV!Mwp+d~HHc`~vq7+RKuD?ZhOu-_tl5{ob#OfJkRul!yC54eeRe4|N3A5>w1pj7Ne!5 zMHq(B*4CzmT61rAxW2v~$8pGHGPsU|#brDa27c3wjjDirLCom*qb6KqP#x3JQx-Xl+N?{^iP; z^6@|ZE!+E17sG4}-sTHuYB=1^Wy<^Yen z7KoS&iU6@qEJo{s6B5hjtSv!0B?1ie=K(5X0$Re0bqtY)jNd8*QBuH7Z`Z{NB$!*< z3k0;3yvra)P=!6E3VY6+xwx(=L5ojFKs1Q5K~f4B8ImMUojS#xjvx>uO05=)eM}$- zWfKY>SoZoxTNMGFAejuts4K?pX#(L(vC^C-5T!{ZN>y>YNuUY#dNh~tpV&vk_2M*J z3PhC<(Kpf7k@J!>Dyg z0@Lv#@Y)Gu;@kYN*LbA}4EmaWPt!Z#$BSB^q58g9$|(9k6Gs}&gXn$ei6HhzK?2X$ zF;)=)fXmnONKRmX5 z3%U7^!;G0s{IC^1`6%{)7uXoqmqXqc%Y?~N5`n>{XYuc^V#MZ+RJ^~5{G@8Kf1jYQ zaY<-Kp}%e_&Xq1ipm))ernekDYCNEI?1PdDc!9QmD%Y>$#JX0-cXpvO4#EC|T(6x< zZr(HCdCYowDVFVugK;5Lgc?%QPzsT600N)q#DIeG= z2vT1%)2B1L?H$PFxUq9D(wn2EbtAfB6k0+4)zy@*Sk1((o2cIQ7NRoX`&`_ihZ*ho>d=y__Zx%Hw7nRvb7ztl&^+ z#X}NknlXOZL2ox=0$bi|zw6*oD7so;N%*{*data_dict_keys); attrid++) { json_import_top_attrib(ctx, modname, attr_node, &ctx->attrs, attrid); } - + ctx->settings[ctx->id("synth")] = "1"; + JsonNode *ports_parent = nullptr; if (node->data_dict.count("ports") > 0) ports_parent = node->data_dict.at("ports");