Move common logic to basewindow

This commit is contained in:
Miodrag Milanovic 2018-08-02 18:50:08 +02:00
parent a761b772c8
commit 4fa0c81ed7
6 changed files with 292 additions and 265 deletions

View File

@ -23,19 +23,22 @@
#include <QFileDialog>
#include <QGridLayout>
#include <QIcon>
#include <QInputDialog>
#include <QSplitter>
#include "designwidget.h"
#include "fpgaviewwidget.h"
#include "log.h"
#include "mainwindow.h"
#include "pythontab.h"
#include "jsonparse.h"
#include <fstream>
static void initBasenameResource() { Q_INIT_RESOURCE(base); }
NEXTPNR_NAMESPACE_BEGIN
BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent)
: QMainWindow(parent), ctx(std::move(context))
: QMainWindow(parent), ctx(std::move(context)), timing_driven(false)
{
initBasenameResource();
qRegisterMetaType<std::string>();
@ -46,7 +49,18 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
setObjectName("BaseMainWindow");
resize(1024, 768);
createMenusAndBars();
task = new TaskManager();
connect(task, SIGNAL(log(std::string)), this, SLOT(writeInfo(std::string)));
connect(task, SIGNAL(pack_finished(bool)), this, SLOT(pack_finished(bool)));
connect(task, SIGNAL(budget_finish(bool)), this, SLOT(budget_finish(bool)));
connect(task, SIGNAL(place_finished(bool)), this, SLOT(place_finished(bool)));
connect(task, SIGNAL(route_finished(bool)), this, SLOT(route_finished(bool)));
connect(task, SIGNAL(taskCanceled()), this, SLOT(taskCanceled()));
connect(task, SIGNAL(taskStarted()), this, SLOT(taskStarted()));
connect(task, SIGNAL(taskPaused()), this, SLOT(taskPaused()));
connect(this, SIGNAL(contextChanged(Context *)), task, SIGNAL(contextChanged(Context *)));
QWidget *centralWidget = new QWidget(this);
@ -99,9 +113,11 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
splitter_v->addWidget(centralTabWidget);
splitter_v->addWidget(tabWidget);
createMenusAndBars();
}
BaseMainWindow::~BaseMainWindow() {}
BaseMainWindow::~BaseMainWindow() { delete task; }
void BaseMainWindow::closeTab(int index) { delete centralTabWidget->widget(index); }
@ -138,10 +154,9 @@ void BaseMainWindow::createMenusAndBars()
menuBar = new QMenuBar();
menuBar->setGeometry(QRect(0, 0, 1024, 27));
QMenu *menu_File = new QMenu("&File", menuBar);
QMenu *menu_Help = new QMenu("&Help", menuBar);
menuBar->addAction(menu_File->menuAction());
menuBar->addAction(menu_Help->menuAction());
QMenu *menuFile = new QMenu("&File", menuBar);
QMenu *menuHelp = new QMenu("&Help", menuBar);
menuDesign = new QMenu("&Design", menuBar);
setMenuBar(menuBar);
mainToolBar = new QToolBar();
@ -156,20 +171,92 @@ void BaseMainWindow::createMenusAndBars()
progressBar->setEnabled(false);
setStatusBar(statusBar);
menu_File->addAction(actionNew);
menu_File->addAction(actionOpen);
menu_File->addAction(actionSave);
menu_File->addSeparator();
menu_File->addAction(actionExit);
menu_Help->addAction(actionAbout);
menuFile->addAction(actionNew);
menuFile->addAction(actionOpen);
menuFile->addAction(actionSave);
menuFile->addSeparator();
menuFile->addAction(actionExit);
menuHelp->addAction(actionAbout);
mainToolBar->addAction(actionNew);
mainToolBar->addAction(actionOpen);
mainToolBar->addAction(actionSave);
}
void BaseMainWindow::createGraphicsBar()
{
menuBar->addAction(menuFile->menuAction());
menuBar->addAction(menuDesign->menuAction());
menuBar->addAction(menuHelp->menuAction());
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, SIGNAL(triggered()), this, SLOT(open_json()));
actionPack = new QAction("Pack", this);
actionPack->setIcon(QIcon(":/icons/resources/pack.png"));
actionPack->setStatusTip("Pack current design");
actionPack->setEnabled(false);
connect(actionPack, SIGNAL(triggered()), task, SIGNAL(pack()));
actionAssignBudget = new QAction("Assign Budget", this);
actionAssignBudget->setIcon(QIcon(":/icons/resources/time_add.png"));
actionAssignBudget->setStatusTip("Assign time budget for current design");
actionAssignBudget->setEnabled(false);
connect(actionAssignBudget, SIGNAL(triggered()), this, SLOT(budget()));
actionPlace = new QAction("Place", this);
actionPlace->setIcon(QIcon(":/icons/resources/place.png"));
actionPlace->setStatusTip("Place current design");
actionPlace->setEnabled(false);
connect(actionPlace, SIGNAL(triggered()), this, SLOT(place()));
actionRoute = new QAction("Route", this);
actionRoute->setIcon(QIcon(":/icons/resources/route.png"));
actionRoute->setStatusTip("Route current design");
actionRoute->setEnabled(false);
connect(actionRoute, SIGNAL(triggered()), task, SIGNAL(route()));
taskFPGABar = new QToolBar();
addToolBar(Qt::TopToolBarArea, taskFPGABar);
taskFPGABar->addAction(actionLoadJSON);
taskFPGABar->addAction(actionPack);
taskFPGABar->addAction(actionAssignBudget);
taskFPGABar->addAction(actionPlace);
taskFPGABar->addAction(actionRoute);
menuDesign->addAction(actionLoadJSON);
menuDesign->addAction(actionPack);
menuDesign->addAction(actionAssignBudget);
menuDesign->addAction(actionPlace);
menuDesign->addAction(actionRoute);
actionPlay = new QAction("Play", this);
actionPlay->setIcon(QIcon(":/icons/resources/control_play.png"));
actionPlay->setStatusTip("Continue running task");
actionPlay->setEnabled(false);
connect(actionPlay, SIGNAL(triggered()), task, SLOT(continue_thread()));
actionPause = new QAction("Pause", this);
actionPause->setIcon(QIcon(":/icons/resources/control_pause.png"));
actionPause->setStatusTip("Pause running task");
actionPause->setEnabled(false);
connect(actionPause, SIGNAL(triggered()), task, SLOT(pause_thread()));
actionStop = new QAction("Stop", this);
actionStop->setIcon(QIcon(":/icons/resources/control_stop.png"));
actionStop->setStatusTip("Stop running task");
actionStop->setEnabled(false);
connect(actionStop, SIGNAL(triggered()), task, SLOT(terminate_thread()));
QToolBar *taskToolBar = new QToolBar();
addToolBar(Qt::TopToolBarArea, taskToolBar);
taskToolBar->addAction(actionPlay);
taskToolBar->addAction(actionPause);
taskToolBar->addAction(actionStop);
QAction *actionZoomIn = new QAction("Zoom In", this);
actionZoomIn->setIcon(QIcon(":/icons/resources/zoom_in.png"));
connect(actionZoomIn, SIGNAL(triggered()), fpgaView, SLOT(zoomIn()));
@ -194,4 +281,135 @@ void BaseMainWindow::createGraphicsBar()
graphicsToolBar->addAction(actionZoomOutbound);
}
void BaseMainWindow::load_json(std::string filename)
{
disableActions();
currentJson = filename;
std::ifstream f(filename);
if (parse_json_file(f, filename, ctx.get())) {
log("Loading design successful.\n");
Q_EMIT updateTreeView();
actionPack->setEnabled(true);
onJsonLoaded();
} else {
actionLoadJSON->setEnabled(true);
log("Loading design failed.\n");
}
}
void BaseMainWindow::open_json()
{
QString fileName = QFileDialog::getOpenFileName(this, QString("Open JSON"), QString(), QString("*.json"));
if (!fileName.isEmpty()) {
load_json(fileName.toStdString());
}
}
void BaseMainWindow::pack_finished(bool status)
{
disableActions();
if (status) {
log("Packing design successful.\n");
Q_EMIT updateTreeView();
actionPlace->setEnabled(true);
actionAssignBudget->setEnabled(true);
onPackFinished();
} else {
log("Packing design failed.\n");
}
}
void BaseMainWindow::budget_finish(bool status)
{
disableActions();
if (status) {
log("Assigning timing budget successful.\n");
actionPlace->setEnabled(true);
onBudgetFinished();
} else {
log("Assigning timing budget failed.\n");
}
}
void BaseMainWindow::place_finished(bool status)
{
disableActions();
if (status) {
log("Placing design successful.\n");
Q_EMIT updateTreeView();
actionRoute->setEnabled(true);
onPlaceFinished();
} else {
log("Placing design failed.\n");
}
}
void BaseMainWindow::route_finished(bool status)
{
disableActions();
if (status) {
log("Routing design successful.\n");
Q_EMIT updateTreeView();
onRouteFinished();
} else
log("Routing design failed.\n");
}
void BaseMainWindow::taskCanceled()
{
log("CANCELED\n");
disableActions();
}
void BaseMainWindow::taskStarted()
{
disableActions();
actionPause->setEnabled(true);
actionStop->setEnabled(true);
actionNew->setEnabled(false);
actionOpen->setEnabled(false);
}
void BaseMainWindow::taskPaused()
{
disableActions();
actionPlay->setEnabled(true);
actionStop->setEnabled(true);
actionNew->setEnabled(false);
actionOpen->setEnabled(false);
}
void BaseMainWindow::budget()
{
bool ok;
double freq = QInputDialog::getDouble(this, "Assign timing budget", "Frequency [MHz]:", 50, 0, 250, 2, &ok);
if (ok) {
freq *= 1e6;
timing_driven = true;
Q_EMIT task->budget(freq);
}
}
void BaseMainWindow::place() { Q_EMIT task->place(timing_driven); }
void BaseMainWindow::disableActions()
{
actionLoadJSON->setEnabled(false);
actionPack->setEnabled(false);
actionAssignBudget->setEnabled(false);
actionPlace->setEnabled(false);
actionRoute->setEnabled(false);
actionPlay->setEnabled(false);
actionPause->setEnabled(false);
actionStop->setEnabled(false);
actionNew->setEnabled(true);
actionOpen->setEnabled(true);
actionSave->setEnabled(!currentJson.empty());
onDisableActions();
}
NEXTPNR_NAMESPACE_END

View File

@ -21,6 +21,7 @@
#define BASEMAINWINDOW_H
#include "nextpnr.h"
#include "worker.h"
#include <QMainWindow>
#include <QMenu>
@ -48,9 +49,16 @@ class BaseMainWindow : public QMainWindow
virtual ~BaseMainWindow();
Context *getContext() { return ctx.get(); }
void load_json(std::string filename);
protected:
void createMenusAndBars();
void createGraphicsBar();
void disableActions();
virtual void onDisableActions() {};
virtual void onJsonLoaded() {};
virtual void onPackFinished() {};
virtual void onBudgetFinished() {};
virtual void onPlaceFinished() {};
virtual void onRouteFinished() {};
protected Q_SLOTS:
void writeInfo(std::string text);
@ -60,12 +68,26 @@ class BaseMainWindow : public QMainWindow
virtual void open_proj() = 0;
virtual bool save_proj() = 0;
void open_json();
void budget();
void place();
void pack_finished(bool status);
void budget_finish(bool status);
void place_finished(bool status);
void route_finished(bool status);
void taskCanceled();
void taskStarted();
void taskPaused();
Q_SIGNALS:
void contextChanged(Context *ctx);
void updateTreeView();
protected:
std::unique_ptr<Context> ctx;
TaskManager *task;
QTabWidget *tabWidget;
QTabWidget *centralTabWidget;
PythonTab *console;
@ -77,9 +99,24 @@ class BaseMainWindow : public QMainWindow
QAction *actionNew;
QAction *actionOpen;
QAction *actionSave;
QAction *actionLoadJSON;
QAction *actionPack;
QAction *actionAssignBudget;
QAction *actionPlace;
QAction *actionRoute;
QAction *actionPlay;
QAction *actionPause;
QAction *actionStop;
QMenu *menuDesign;
QToolBar *taskFPGABar;
QProgressBar *progressBar;
DesignWidget *designview;
FPGAViewWidget *fpgaView;
bool timing_driven;
std::string currentJson;
};
NEXTPNR_NAMESPACE_END

View File

@ -36,13 +36,7 @@ MainWindow::MainWindow(std::unique_ptr<Context> context, QWidget *parent) : Base
MainWindow::~MainWindow() {}
void MainWindow::createMenu()
{
QMenu *menu_Custom = new QMenu("&Generic", menuBar);
menuBar->addAction(menu_Custom->menuAction());
createGraphicsBar();
}
void MainWindow::createMenu() {}
void MainWindow::new_proj() {}

View File

@ -36,13 +36,7 @@ MainWindow::MainWindow(std::unique_ptr<Context> context, QWidget *parent) : Base
MainWindow::~MainWindow() {}
void MainWindow::createMenu()
{
QMenu *menu_Custom = new QMenu("&Generic", menuBar);
menuBar->addAction(menu_Custom->menuAction());
createGraphicsBar();
}
void MainWindow::createMenu() {}
void MainWindow::new_proj() {}

View File

@ -37,45 +37,24 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
NEXTPNR_NAMESPACE_BEGIN
MainWindow::MainWindow(std::unique_ptr<Context> context, ArchArgs args, QWidget *parent)
: BaseMainWindow(std::move(context), parent), timing_driven(false), chipArgs(args)
: BaseMainWindow(std::move(context), parent), chipArgs(args)
{
initMainResource();
std::string title = "nextpnr-ice40 - [EMPTY]";
setWindowTitle(title.c_str());
task = new TaskManager();
connect(task, SIGNAL(log(std::string)), this, SLOT(writeInfo(std::string)));
connect(task, SIGNAL(pack_finished(bool)), this, SLOT(pack_finished(bool)));
connect(task, SIGNAL(budget_finish(bool)), this, SLOT(budget_finish(bool)));
connect(task, SIGNAL(place_finished(bool)), this, SLOT(place_finished(bool)));
connect(task, SIGNAL(route_finished(bool)), this, SLOT(route_finished(bool)));
connect(task, SIGNAL(taskCanceled()), this, SLOT(taskCanceled()));
connect(task, SIGNAL(taskStarted()), this, SLOT(taskStarted()));
connect(task, SIGNAL(taskPaused()), this, SLOT(taskPaused()));
connect(this, SIGNAL(contextChanged(Context *)), this, SLOT(newContext(Context *)));
connect(this, SIGNAL(contextChanged(Context *)), task, SIGNAL(contextChanged(Context *)));
createMenu();
Q_EMIT contextChanged(ctx.get());
}
MainWindow::~MainWindow() { delete task; }
MainWindow::~MainWindow() {}
void MainWindow::createMenu()
{
QMenu *menu_Design = new QMenu("&Design", menuBar);
menuBar->addAction(menu_Design->menuAction());
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, SIGNAL(triggered()), this, SLOT(open_json()));
actionLoadPCF = new QAction("Open PCF", this);
actionLoadPCF->setIcon(QIcon(":/icons/resources/open_pcf.png"));
@ -83,81 +62,20 @@ void MainWindow::createMenu()
actionLoadPCF->setEnabled(false);
connect(actionLoadPCF, SIGNAL(triggered()), this, SLOT(open_pcf()));
actionPack = new QAction("Pack", this);
actionPack->setIcon(QIcon(":/icons/resources/pack.png"));
actionPack->setStatusTip("Pack current design");
actionPack->setEnabled(false);
connect(actionPack, SIGNAL(triggered()), task, SIGNAL(pack()));
actionAssignBudget = new QAction("Assign Budget", this);
actionAssignBudget->setIcon(QIcon(":/icons/resources/time_add.png"));
actionAssignBudget->setStatusTip("Assign time budget for current design");
actionAssignBudget->setEnabled(false);
connect(actionAssignBudget, SIGNAL(triggered()), this, SLOT(budget()));
actionPlace = new QAction("Place", this);
actionPlace->setIcon(QIcon(":/icons/resources/place.png"));
actionPlace->setStatusTip("Place current design");
actionPlace->setEnabled(false);
connect(actionPlace, SIGNAL(triggered()), this, SLOT(place()));
actionRoute = new QAction("Route", this);
actionRoute->setIcon(QIcon(":/icons/resources/route.png"));
actionRoute->setStatusTip("Route current design");
actionRoute->setEnabled(false);
connect(actionRoute, SIGNAL(triggered()), task, SIGNAL(route()));
actionSaveAsc = new QAction("Save ASC", this);
actionSaveAsc->setIcon(QIcon(":/icons/resources/save_asc.png"));
actionSaveAsc->setStatusTip("Save ASC file");
actionSaveAsc->setEnabled(false);
connect(actionSaveAsc, SIGNAL(triggered()), this, SLOT(save_asc()));
QToolBar *taskFPGABar = new QToolBar();
addToolBar(Qt::TopToolBarArea, taskFPGABar);
taskFPGABar->addAction(actionLoadJSON);
taskFPGABar->addSeparator();
taskFPGABar->addAction(actionLoadPCF);
taskFPGABar->addAction(actionPack);
taskFPGABar->addAction(actionAssignBudget);
taskFPGABar->addAction(actionPlace);
taskFPGABar->addAction(actionRoute);
taskFPGABar->addAction(actionSaveAsc);
menu_Design->addAction(actionLoadJSON);
menu_Design->addAction(actionLoadPCF);
menu_Design->addAction(actionPack);
menu_Design->addAction(actionAssignBudget);
menu_Design->addAction(actionPlace);
menu_Design->addAction(actionRoute);
menu_Design->addAction(actionSaveAsc);
menuDesign->addSeparator();
menuDesign->addAction(actionLoadPCF);
menuDesign->addAction(actionSaveAsc);
actionPlay = new QAction("Play", this);
actionPlay->setIcon(QIcon(":/icons/resources/control_play.png"));
actionPlay->setStatusTip("Continue running task");
actionPlay->setEnabled(false);
connect(actionPlay, SIGNAL(triggered()), task, SLOT(continue_thread()));
actionPause = new QAction("Pause", this);
actionPause->setIcon(QIcon(":/icons/resources/control_pause.png"));
actionPause->setStatusTip("Pause running task");
actionPause->setEnabled(false);
connect(actionPause, SIGNAL(triggered()), task, SLOT(pause_thread()));
actionStop = new QAction("Stop", this);
actionStop->setIcon(QIcon(":/icons/resources/control_stop.png"));
actionStop->setStatusTip("Stop running task");
actionStop->setEnabled(false);
connect(actionStop, SIGNAL(triggered()), task, SLOT(terminate_thread()));
QToolBar *taskToolBar = new QToolBar();
addToolBar(Qt::TopToolBarArea, taskToolBar);
taskToolBar->addAction(actionPlay);
taskToolBar->addAction(actionPause);
taskToolBar->addAction(actionStop);
createGraphicsBar();
}
#if defined(_MSC_VER)
@ -235,22 +153,6 @@ void MainWindow::new_proj()
}
}
void MainWindow::load_json(std::string filename)
{
disableActions();
currentJson = filename;
std::ifstream f(filename);
if (parse_json_file(f, filename, ctx.get())) {
log("Loading design successful.\n");
actionLoadPCF->setEnabled(true);
actionPack->setEnabled(true);
Q_EMIT updateTreeView();
} else {
actionLoadJSON->setEnabled(true);
log("Loading design failed.\n");
}
}
void MainWindow::load_pcf(std::string filename)
{
disableActions();
@ -351,14 +253,6 @@ void MainWindow::open_proj()
}
}
void MainWindow::open_json()
{
QString fileName = QFileDialog::getOpenFileName(this, QString("Open JSON"), QString(), QString("*.json"));
if (!fileName.isEmpty()) {
load_json(fileName.toStdString());
}
}
void MainWindow::open_pcf()
{
QString fileName = QFileDialog::getOpenFileName(this, QString("Open PCF"), QString(), QString("*.pcf"));
@ -409,108 +303,20 @@ void MainWindow::save_asc()
}
}
void MainWindow::disableActions()
void MainWindow::onDisableActions()
{
actionLoadJSON->setEnabled(false);
actionLoadPCF->setEnabled(false);
actionPack->setEnabled(false);
actionAssignBudget->setEnabled(false);
actionPlace->setEnabled(false);
actionRoute->setEnabled(false);
actionSaveAsc->setEnabled(false);
actionPlay->setEnabled(false);
actionPause->setEnabled(false);
actionStop->setEnabled(false);
actionNew->setEnabled(true);
actionOpen->setEnabled(true);
actionSave->setEnabled(!currentJson.empty());
}
void MainWindow::pack_finished(bool status)
void MainWindow::onJsonLoaded()
{
disableActions();
if (status) {
log("Packing design successful.\n");
Q_EMIT updateTreeView();
actionPlace->setEnabled(true);
actionAssignBudget->setEnabled(true);
} else {
log("Packing design failed.\n");
}
actionLoadPCF->setEnabled(true);
}
void MainWindow::budget_finish(bool status)
void MainWindow::onRouteFinished()
{
disableActions();
if (status) {
log("Assigning timing budget successful.\n");
actionPlace->setEnabled(true);
} else {
log("Assigning timing budget failed.\n");
}
actionSaveAsc->setEnabled(true);
}
void MainWindow::place_finished(bool status)
{
disableActions();
if (status) {
log("Placing design successful.\n");
Q_EMIT updateTreeView();
actionRoute->setEnabled(true);
} else {
log("Placing design failed.\n");
}
}
void MainWindow::route_finished(bool status)
{
disableActions();
if (status) {
log("Routing design successful.\n");
Q_EMIT updateTreeView();
actionSaveAsc->setEnabled(true);
} else
log("Routing design failed.\n");
}
void MainWindow::taskCanceled()
{
log("CANCELED\n");
disableActions();
}
void MainWindow::taskStarted()
{
disableActions();
actionPause->setEnabled(true);
actionStop->setEnabled(true);
actionNew->setEnabled(false);
actionOpen->setEnabled(false);
}
void MainWindow::taskPaused()
{
disableActions();
actionPlay->setEnabled(true);
actionStop->setEnabled(true);
actionNew->setEnabled(false);
actionOpen->setEnabled(false);
}
void MainWindow::budget()
{
bool ok;
double freq = QInputDialog::getDouble(this, "Assign timing budget", "Frequency [MHz]:", 50, 0, 250, 2, &ok);
if (ok) {
freq *= 1e6;
timing_driven = true;
Q_EMIT task->budget(freq);
}
}
void MainWindow::place() { Q_EMIT task->place(timing_driven); }
NEXTPNR_NAMESPACE_END

View File

@ -21,7 +21,6 @@
#define MAINWINDOW_H
#include "../basewindow.h"
#include "worker.h"
NEXTPNR_NAMESPACE_BEGIN
@ -35,50 +34,29 @@ class MainWindow : public BaseMainWindow
public:
void createMenu();
void load_json(std::string filename);
void load_pcf(std::string filename);
protected:
void onDisableActions() override;
void onJsonLoaded() override;
void onRouteFinished() override;
protected Q_SLOTS:
virtual void new_proj();
virtual void open_proj();
virtual bool save_proj();
void open_json();
void open_pcf();
void budget();
void place();
void save_asc();
void pack_finished(bool status);
void budget_finish(bool status);
void place_finished(bool status);
void route_finished(bool status);
void taskCanceled();
void taskStarted();
void taskPaused();
void newContext(Context *ctx);
private:
void disableActions();
TaskManager *task;
QAction *actionLoadJSON;
QAction *actionLoadPCF;
QAction *actionPack;
QAction *actionAssignBudget;
QAction *actionPlace;
QAction *actionRoute;
QAction *actionSaveAsc;
QAction *actionPlay;
QAction *actionPause;
QAction *actionStop;
bool timing_driven;
ArchArgs chipArgs;
std::string currentProj;
std::string currentJson;
std::string currentPCF;
};