Merge pull request #20 from YosysHQ/gui4all

Refactor GUI
This commit is contained in:
Miodrag Milanović 2018-08-03 03:31:37 -07:00 committed by GitHub
commit 751a5457dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 402 additions and 446 deletions

View File

@ -454,6 +454,7 @@ struct Arch : BaseCtx
bel_to_cell[bel] = cell;
cells[cell]->bel = bel;
cells[cell]->belStrength = strength;
refreshUiBel(bel);
}
void unbindBel(BelId bel)
@ -463,6 +464,7 @@ struct Arch : BaseCtx
cells[bel_to_cell[bel]]->bel = BelId();
cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE;
bel_to_cell[bel] = IdString();
refreshUiBel(bel);
}
Loc getBelLocation(BelId bel) const

View File

@ -14,5 +14,13 @@
<file>resources/zoom_out.png</file>
<file>resources/shape_handles.png</file>
<file>resources/shape_square.png</file>
<file>resources/control_play.png</file>
<file>resources/control_pause.png</file>
<file>resources/control_stop.png</file>
<file>resources/pack.png</file>
<file>resources/place.png</file>
<file>resources/route.png</file>
<file>resources/time_add.png</file>
<file>resources/open_json.png</file>
</qresource>
</RCC>

View File

@ -23,9 +23,12 @@
#include <QFileDialog>
#include <QGridLayout>
#include <QIcon>
#include <QInputDialog>
#include <QSplitter>
#include <fstream>
#include "designwidget.h"
#include "fpgaviewwidget.h"
#include "jsonparse.h"
#include "log.h"
#include "mainwindow.h"
#include "pythontab.h"
@ -35,7 +38,7 @@ 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,10 +49,10 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
setObjectName("BaseMainWindow");
resize(1024, 768);
createMenusAndBars();
task = new TaskManager();
// Create and deploy widgets on main screen
QWidget *centralWidget = new QWidget(this);
QGridLayout *gridLayout = new QGridLayout(centralWidget);
gridLayout->setSpacing(6);
gridLayout->setContentsMargins(11, 11, 11, 11);
@ -70,38 +73,54 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
console = new PythonTab();
tabWidget->addTab(console, "Console");
connect(this, SIGNAL(contextChanged(Context *)), console, SLOT(newContext(Context *)));
centralTabWidget = new QTabWidget();
centralTabWidget->setTabsClosable(true);
connect(centralTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
fpgaView = new FPGAViewWidget();
centralTabWidget->addTab(fpgaView, "Device");
centralTabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, 0);
centralTabWidget->tabBar()->setTabButton(0, QTabBar::LeftSide, 0);
connect(this, SIGNAL(contextChanged(Context *)), fpgaView, SLOT(newContext(Context *)));
connect(designview, SIGNAL(selected(std::vector<DecalXY>, bool)), fpgaView,
SLOT(onSelectedArchItem(std::vector<DecalXY>, bool)));
connect(fpgaView, SIGNAL(clickedBel(BelId, bool)), designview, SLOT(onClickedBel(BelId, bool)));
connect(fpgaView, SIGNAL(clickedWire(WireId, bool)), designview, SLOT(onClickedWire(WireId, bool)));
connect(fpgaView, SIGNAL(clickedPip(PipId, bool)), designview, SLOT(onClickedPip(PipId, bool)));
connect(designview, SIGNAL(zoomSelected()), fpgaView, SLOT(zoomSelected()));
connect(designview, SIGNAL(highlight(std::vector<DecalXY>, int)), fpgaView,
SLOT(onHighlightGroupChanged(std::vector<DecalXY>, int)));
connect(this, SIGNAL(contextChanged(Context *)), designview, SLOT(newContext(Context *)));
connect(this, SIGNAL(updateTreeView()), designview, SLOT(updateTree()));
connect(designview, SIGNAL(info(std::string)), this, SLOT(writeInfo(std::string)));
splitter_v->addWidget(centralTabWidget);
splitter_v->addWidget(tabWidget);
// Connect Worker
connect(task, &TaskManager::log, this, &BaseMainWindow::writeInfo);
connect(task, &TaskManager::pack_finished, this, &BaseMainWindow::pack_finished);
connect(task, &TaskManager::budget_finish, this, &BaseMainWindow::budget_finish);
connect(task, &TaskManager::place_finished, this, &BaseMainWindow::place_finished);
connect(task, &TaskManager::route_finished, this, &BaseMainWindow::route_finished);
connect(task, &TaskManager::taskCanceled, this, &BaseMainWindow::taskCanceled);
connect(task, &TaskManager::taskStarted, this, &BaseMainWindow::taskStarted);
connect(task, &TaskManager::taskPaused, this, &BaseMainWindow::taskPaused);
// Events for context change
connect(this, &BaseMainWindow::contextChanged, task, &TaskManager::contextChanged);
connect(this, &BaseMainWindow::contextChanged, console, &PythonTab::newContext);
connect(this, &BaseMainWindow::contextChanged, fpgaView, &FPGAViewWidget::newContext);
connect(this, &BaseMainWindow::contextChanged, designview, &DesignWidget::newContext);
// Catch close tab events
connect(centralTabWidget, &QTabWidget::tabCloseRequested, this, &BaseMainWindow::closeTab);
// Propagate events from design view to device view
connect(designview, &DesignWidget::selected, fpgaView, &FPGAViewWidget::onSelectedArchItem);
connect(designview, &DesignWidget::zoomSelected, fpgaView, &FPGAViewWidget::zoomSelected);
connect(designview, &DesignWidget::highlight, fpgaView, &FPGAViewWidget::onHighlightGroupChanged);
// Click event on device view
connect(fpgaView, &FPGAViewWidget::clickedBel, designview, &DesignWidget::onClickedBel);
connect(fpgaView, &FPGAViewWidget::clickedWire, designview, &DesignWidget::onClickedWire);
connect(fpgaView, &FPGAViewWidget::clickedPip, designview, &DesignWidget::onClickedPip);
// Update tree event
connect(this, &BaseMainWindow::updateTreeView, designview, &DesignWidget::updateTree);
createMenusAndBars();
}
BaseMainWindow::~BaseMainWindow() {}
BaseMainWindow::~BaseMainWindow() { delete task; }
void BaseMainWindow::closeTab(int index) { delete centralTabWidget->widget(index); }
@ -109,44 +128,162 @@ void BaseMainWindow::writeInfo(std::string text) { console->info(text); }
void BaseMainWindow::createMenusAndBars()
{
// File menu / project toolbar actions
actionNew = new QAction("New", this);
actionNew->setIcon(QIcon(":/icons/resources/new.png"));
actionNew->setShortcuts(QKeySequence::New);
actionNew->setStatusTip("New project file");
connect(actionNew, SIGNAL(triggered()), this, SLOT(new_proj()));
connect(actionNew, &QAction::triggered, this, &BaseMainWindow::new_proj);
actionOpen = new QAction("Open", this);
actionOpen->setIcon(QIcon(":/icons/resources/open.png"));
actionOpen->setShortcuts(QKeySequence::Open);
actionOpen->setStatusTip("Open an existing project file");
connect(actionOpen, SIGNAL(triggered()), this, SLOT(open_proj()));
connect(actionOpen, &QAction::triggered, this, &BaseMainWindow::open_proj);
actionSave = new QAction("Save", this);
actionSave->setIcon(QIcon(":/icons/resources/save.png"));
actionSave->setShortcuts(QKeySequence::Save);
actionSave->setStatusTip("Save existing project to disk");
actionSave->setEnabled(false);
connect(actionSave, SIGNAL(triggered()), this, SLOT(save_proj()));
connect(actionSave, &QAction::triggered, this, &BaseMainWindow::save_proj);
QAction *actionExit = new QAction("Exit", this);
actionExit->setIcon(QIcon(":/icons/resources/exit.png"));
actionExit->setShortcuts(QKeySequence::Quit);
actionExit->setStatusTip("Exit the application");
connect(actionExit, SIGNAL(triggered()), this, SLOT(close()));
connect(actionExit, &QAction::triggered, this, &BaseMainWindow::close);
// Help menu actions
QAction *actionAbout = new QAction("About", this);
// Design menu options
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);
actionPack = new QAction("Pack", this);
actionPack->setIcon(QIcon(":/icons/resources/pack.png"));
actionPack->setStatusTip("Pack current design");
actionPack->setEnabled(false);
connect(actionPack, &QAction::triggered, task, &TaskManager::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, &QAction::triggered, this, &BaseMainWindow::budget);
actionPlace = new QAction("Place", this);
actionPlace->setIcon(QIcon(":/icons/resources/place.png"));
actionPlace->setStatusTip("Place current design");
actionPlace->setEnabled(false);
connect(actionPlace, &QAction::triggered, this, &BaseMainWindow::place);
actionRoute = new QAction("Route", this);
actionRoute->setIcon(QIcon(":/icons/resources/route.png"));
actionRoute->setStatusTip("Route current design");
actionRoute->setEnabled(false);
connect(actionRoute, &QAction::triggered, task, &TaskManager::route);
// Worker control toolbar actions
actionPlay = new QAction("Play", this);
actionPlay->setIcon(QIcon(":/icons/resources/control_play.png"));
actionPlay->setStatusTip("Continue running task");
actionPlay->setEnabled(false);
connect(actionPlay, &QAction::triggered, task, &TaskManager::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, &QAction::triggered, task, &TaskManager::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, &QAction::triggered, task, &TaskManager::terminate_thread);
// Device view control toolbar actions
QAction *actionZoomIn = new QAction("Zoom In", this);
actionZoomIn->setIcon(QIcon(":/icons/resources/zoom_in.png"));
connect(actionZoomIn, &QAction::triggered, fpgaView, &FPGAViewWidget::zoomIn);
QAction *actionZoomOut = new QAction("Zoom Out", this);
actionZoomOut->setIcon(QIcon(":/icons/resources/zoom_out.png"));
connect(actionZoomOut, &QAction::triggered, fpgaView, &FPGAViewWidget::zoomOut);
QAction *actionZoomSelected = new QAction("Zoom Selected", this);
actionZoomSelected->setIcon(QIcon(":/icons/resources/shape_handles.png"));
connect(actionZoomSelected, &QAction::triggered, fpgaView, &FPGAViewWidget::zoomSelected);
QAction *actionZoomOutbound = new QAction("Zoom Outbound", this);
actionZoomOutbound->setIcon(QIcon(":/icons/resources/shape_square.png"));
connect(actionZoomOutbound, &QAction::triggered, fpgaView, &FPGAViewWidget::zoomOutbound);
// Add main menu
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());
setMenuBar(menuBar);
QMenu *menuFile = new QMenu("&File", menuBar);
QMenu *menuHelp = new QMenu("&Help", menuBar);
menuDesign = new QMenu("&Design", menuBar);
menuBar->addAction(menuFile->menuAction());
menuBar->addAction(menuDesign->menuAction());
menuBar->addAction(menuHelp->menuAction());
mainToolBar = new QToolBar();
addToolBar(Qt::TopToolBarArea, mainToolBar);
// Add File menu actions
menuFile->addAction(actionNew);
menuFile->addAction(actionOpen);
menuFile->addAction(actionSave);
menuFile->addSeparator();
menuFile->addAction(actionExit);
// Add Design menu actions
menuDesign->addAction(actionLoadJSON);
menuDesign->addAction(actionPack);
menuDesign->addAction(actionAssignBudget);
menuDesign->addAction(actionPlace);
menuDesign->addAction(actionRoute);
// Add Help menu actions
menuHelp->addAction(actionAbout);
// Project toolbar
QToolBar *projectToolBar = new QToolBar("Project");
addToolBar(Qt::TopToolBarArea, projectToolBar);
projectToolBar->addAction(actionNew);
projectToolBar->addAction(actionOpen);
projectToolBar->addAction(actionSave);
// Main action bar
mainActionBar = new QToolBar("Main");
addToolBar(Qt::TopToolBarArea, mainActionBar);
mainActionBar->addAction(actionLoadJSON);
mainActionBar->addAction(actionPack);
mainActionBar->addAction(actionAssignBudget);
mainActionBar->addAction(actionPlace);
mainActionBar->addAction(actionRoute);
// Add worker control toolbar
QToolBar *workerControlToolBar = new QToolBar("Worker");
addToolBar(Qt::TopToolBarArea, workerControlToolBar);
workerControlToolBar->addAction(actionPlay);
workerControlToolBar->addAction(actionPause);
workerControlToolBar->addAction(actionStop);
// Add device view control toolbar
QToolBar *deviceViewToolBar = new QToolBar("Device");
addToolBar(Qt::TopToolBarArea, deviceViewToolBar);
deviceViewToolBar->addAction(actionZoomIn);
deviceViewToolBar->addAction(actionZoomOut);
deviceViewToolBar->addAction(actionZoomSelected);
deviceViewToolBar->addAction(actionZoomOutbound);
// Add status bar with progress bar
statusBar = new QStatusBar();
progressBar = new QProgressBar(statusBar);
progressBar->setAlignment(Qt::AlignRight);
@ -155,43 +292,137 @@ void BaseMainWindow::createMenusAndBars()
progressBar->setValue(0);
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);
mainToolBar->addAction(actionNew);
mainToolBar->addAction(actionOpen);
mainToolBar->addAction(actionSave);
}
void BaseMainWindow::createGraphicsBar()
void BaseMainWindow::load_json(std::string filename)
{
QAction *actionZoomIn = new QAction("Zoom In", this);
actionZoomIn->setIcon(QIcon(":/icons/resources/zoom_in.png"));
connect(actionZoomIn, SIGNAL(triggered()), fpgaView, SLOT(zoomIn()));
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");
}
}
QAction *actionZoomOut = new QAction("Zoom Out", this);
actionZoomOut->setIcon(QIcon(":/icons/resources/zoom_out.png"));
connect(actionZoomOut, SIGNAL(triggered()), fpgaView, SLOT(zoomOut()));
void BaseMainWindow::open_json()
{
QString fileName = QFileDialog::getOpenFileName(this, QString("Open JSON"), QString(), QString("*.json"));
if (!fileName.isEmpty()) {
load_json(fileName.toStdString());
}
}
QAction *actionZoomSelected = new QAction("Zoom Selected", this);
actionZoomSelected->setIcon(QIcon(":/icons/resources/shape_handles.png"));
connect(actionZoomSelected, SIGNAL(triggered()), fpgaView, SLOT(zoomSelected()));
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");
}
}
QAction *actionZoomOutbound = new QAction("Zoom Outbound", this);
actionZoomOutbound->setIcon(QIcon(":/icons/resources/shape_square.png"));
connect(actionZoomOutbound, SIGNAL(triggered()), fpgaView, SLOT(zoomOutbound()));
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");
}
}
graphicsToolBar = new QToolBar();
addToolBar(Qt::TopToolBarArea, graphicsToolBar);
graphicsToolBar->addAction(actionZoomIn);
graphicsToolBar->addAction(actionZoomOut);
graphicsToolBar->addAction(actionZoomSelected);
graphicsToolBar->addAction(actionZoomOutbound);
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,17 @@ 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,26 +69,56 @@ 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:
// state variables
std::unique_ptr<Context> ctx;
TaskManager *task;
bool timing_driven;
std::string currentJson;
// main widgets
QTabWidget *tabWidget;
QTabWidget *centralTabWidget;
PythonTab *console;
DesignWidget *designview;
FPGAViewWidget *fpgaView;
// Menus, bars and actions
QMenuBar *menuBar;
QToolBar *mainToolBar;
QToolBar *graphicsToolBar;
QMenu *menuDesign;
QStatusBar *statusBar;
QToolBar *mainActionBar;
QProgressBar *progressBar;
QAction *actionNew;
QAction *actionOpen;
QAction *actionSave;
QProgressBar *progressBar;
DesignWidget *designview;
FPGAViewWidget *fpgaView;
QAction *actionLoadJSON;
QAction *actionPack;
QAction *actionAssignBudget;
QAction *actionPlace;
QAction *actionRoute;
QAction *actionPlay;
QAction *actionPause;
QAction *actionStop;
};
NEXTPNR_NAMESPACE_END

View File

@ -55,7 +55,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel
searchEdit->setClearButtonEnabled(true);
searchEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition);
searchEdit->setPlaceholderText("Search...");
connect(searchEdit, SIGNAL(returnPressed()), this, SLOT(onSearchInserted()));
connect(searchEdit, &QLineEdit::returnPressed, this, &DesignWidget::onSearchInserted);
actionFirst = new QAction("", this);
actionFirst->setIcon(QIcon(":/icons/resources/resultset_first.png"));
@ -162,8 +162,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel
connect(treeView, &QTreeView::customContextMenuRequested, this, &DesignWidget::prepareMenuTree);
connect(treeView, &QTreeView::doubleClicked, this, &DesignWidget::onDoubleClicked);
selectionModel = treeView->selectionModel();
connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &)));
connect(selectionModel, &QItemSelectionModel::selectionChanged, this, &DesignWidget::onSelectionChanged);
history_index = -1;
history_ignore = false;
@ -317,7 +316,7 @@ QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name)
void DesignWidget::onClickedBel(BelId bel, bool keep)
{
boost::optional<TreeModel::Item*> item;
boost::optional<TreeModel::Item *> item;
{
std::lock_guard<std::mutex> lock_ui(ctx->ui_mutex);
std::lock_guard<std::mutex> lock(ctx->mutex);
@ -334,7 +333,7 @@ void DesignWidget::onClickedBel(BelId bel, bool keep)
void DesignWidget::onClickedWire(WireId wire, bool keep)
{
boost::optional<TreeModel::Item*> item;
boost::optional<TreeModel::Item *> item;
{
std::lock_guard<std::mutex> lock_ui(ctx->ui_mutex);
std::lock_guard<std::mutex> lock(ctx->mutex);
@ -351,7 +350,7 @@ void DesignWidget::onClickedWire(WireId wire, bool keep)
void DesignWidget::onClickedPip(PipId pip, bool keep)
{
boost::optional<TreeModel::Item*> item;
boost::optional<TreeModel::Item *> item;
{
std::lock_guard<std::mutex> lock_ui(ctx->ui_mutex);
std::lock_guard<std::mutex> lock(ctx->mutex);

View File

@ -53,7 +53,6 @@ class DesignWidget : public QWidget
std::vector<DecalXY> getDecals(ElementType type, IdString value);
void updateHighlightGroup(QList<TreeModel::Item *> item, int group);
Q_SIGNALS:
void info(std::string text);
void selected(std::vector<DecalXY> decal, bool keep);
void highlight(std::vector<DecalXY> decal, int group);
void zoomSelected();

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,130 +37,45 @@ 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(loadfile_finished(bool)), this, SLOT(loadfile_finished(bool)));
connect(task, SIGNAL(loadpcf_finished(bool)), this, SLOT(loadpcf_finished(bool)));
connect(task, SIGNAL(saveasc_finished(bool)), this, SLOT(saveasc_finished(bool)));
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 *)));
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
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()));
// Add arch specific actions
actionLoadPCF = new QAction("Open PCF", this);
actionLoadPCF->setIcon(QIcon(":/icons/resources/open_pcf.png"));
actionLoadPCF->setStatusTip("Open PCF file");
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()));
connect(actionLoadPCF, &QAction::triggered, this, &MainWindow::open_pcf);
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()));
connect(actionSaveAsc, &QAction::triggered, this, &MainWindow::save_asc);
QToolBar *taskFPGABar = new QToolBar();
addToolBar(Qt::TopToolBarArea, taskFPGABar);
// Add actions in menus
mainActionBar->addSeparator();
mainActionBar->addAction(actionLoadPCF);
mainActionBar->addAction(actionSaveAsc);
taskFPGABar->addAction(actionLoadJSON);
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);
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();
menuDesign->addSeparator();
menuDesign->addAction(actionLoadPCF);
menuDesign->addAction(actionSaveAsc);
}
#if defined(_MSC_VER)
@ -238,19 +153,18 @@ void MainWindow::new_proj()
}
}
void MainWindow::load_json(std::string filename, std::string pcf)
{
disableActions();
currentJson = filename;
currentPCF = pcf;
Q_EMIT task->loadfile(filename);
}
void MainWindow::load_pcf(std::string filename)
{
disableActions();
currentPCF = filename;
Q_EMIT task->loadpcf(filename);
std::ifstream f(filename);
if (apply_pcf(ctx.get(), f)) {
log("Loading PCF successful.\n");
actionPack->setEnabled(true);
} else {
actionLoadPCF->setEnabled(true);
log("Loading PCF failed.\n");
}
}
void MainWindow::newContext(Context *ctx)
@ -331,20 +245,14 @@ void MainWindow::open_proj()
}
log_info("Loading json: %s...\n", json.c_str());
load_json(json, pcf);
load_json(json);
if (!pcf.empty())
load_pcf(json);
} catch (log_execution_error_exception) {
}
}
}
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"));
@ -389,149 +297,19 @@ void MainWindow::save_asc()
if (!fileName.isEmpty()) {
std::string fn = fileName.toStdString();
disableActions();
Q_EMIT task->saveasc(fn);
}
}
void MainWindow::disableActions()
{
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::loadfile_finished(bool status)
{
disableActions();
if (status) {
log("Loading design successful.\n");
actionLoadPCF->setEnabled(true);
actionPack->setEnabled(true);
if (!currentPCF.empty())
load_pcf(currentPCF);
Q_EMIT updateTreeView();
} else {
log("Loading design failed.\n");
currentPCF = "";
}
}
void MainWindow::loadpcf_finished(bool status)
{
disableActions();
if (status) {
log("Loading PCF successful.\n");
actionPack->setEnabled(true);
} else {
log("Loading PCF failed.\n");
}
}
void MainWindow::saveasc_finished(bool status)
{
disableActions();
if (status) {
std::ofstream f(fn);
write_asc(ctx.get(), f);
log("Saving ASC successful.\n");
} else {
log("Saving ASC failed.\n");
}
}
void MainWindow::pack_finished(bool status)
void MainWindow::onDisableActions()
{
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(false);
actionSaveAsc->setEnabled(false);
}
void MainWindow::budget_finish(bool status)
{
disableActions();
if (status) {
log("Assigning timing budget successful.\n");
actionPlace->setEnabled(true);
} else {
log("Assigning timing budget failed.\n");
}
}
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); }
void MainWindow::onJsonLoaded() { actionLoadPCF->setEnabled(true); }
void MainWindow::onRouteFinished() { actionSaveAsc->setEnabled(true); }
NEXTPNR_NAMESPACE_END

View File

@ -21,7 +21,6 @@
#define MAINWINDOW_H
#include "../basewindow.h"
#include "worker.h"
NEXTPNR_NAMESPACE_BEGIN
@ -35,53 +34,30 @@ class MainWindow : public BaseMainWindow
public:
void createMenu();
void load_json(std::string filename, std::string pcf);
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 loadfile_finished(bool status);
void loadpcf_finished(bool status);
void saveasc_finished(bool status);
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;
};

View File

@ -1,14 +1,6 @@
<RCC>
<qresource prefix="/icons">
<file>resources/control_play.png</file>
<file>resources/control_pause.png</file>
<file>resources/control_stop.png</file>
<file>resources/pack.png</file>
<file>resources/place.png</file>
<file>resources/route.png</file>
<file>resources/time_add.png</file>
<file>resources/open_pcf.png</file>
<file>resources/save_asc.png</file>
<file>resources/open_json.png</file>
</qresource>
</RCC>

View File

@ -32,13 +32,13 @@ LineEditor::LineEditor(ParseHelper *helper, QWidget *parent) : QLineEdit(parent)
setContextMenuPolicy(Qt::CustomContextMenu);
QAction *clearAction = new QAction("Clear &history", this);
clearAction->setStatusTip("Clears line edit history");
connect(clearAction, SIGNAL(triggered()), this, SLOT(clearHistory()));
connect(clearAction, &QAction::triggered, this, &LineEditor::clearHistory);
contextMenu = createStandardContextMenu();
contextMenu->addSeparator();
contextMenu->addAction(clearAction);
connect(this, SIGNAL(returnPressed()), SLOT(textInserted()));
connect(this, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint)));
connect(this, &LineEditor::returnPressed, this, &LineEditor::textInserted);
connect(this, &LineEditor::customContextMenuRequested, this, &LineEditor::showContextMenu);
}
void LineEditor::keyPressEvent(QKeyEvent *ev)

View File

@ -42,18 +42,18 @@ PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false)
console->setContextMenuPolicy(Qt::CustomContextMenu);
QAction *clearAction = new QAction("Clear &buffer", this);
clearAction->setStatusTip("Clears display buffer");
connect(clearAction, SIGNAL(triggered()), this, SLOT(clearBuffer()));
connect(clearAction, &QAction::triggered, this, &PythonTab::clearBuffer);
contextMenu = console->createStandardContextMenu();
contextMenu->addSeparator();
contextMenu->addAction(clearAction);
connect(console, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint)));
connect(console, &PythonConsole::customContextMenuRequested, this, &PythonTab::showContextMenu);
lineEdit = new LineEditor(&parseHelper);
lineEdit->setMinimumHeight(30);
lineEdit->setMaximumHeight(30);
lineEdit->setFont(f);
lineEdit->setPlaceholderText(PythonTab::PROMPT);
connect(lineEdit, SIGNAL(textLineInserted(QString)), this, SLOT(editLineReturnPressed(QString)));
connect(lineEdit, &LineEditor::textLineInserted, this, &PythonTab::editLineReturnPressed);
QGridLayout *mainLayout = new QGridLayout();
mainLayout->addWidget(console, 0, 0);

View File

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 721 B

View File

Before

Width:  |  Height:  |  Size: 717 B

After

Width:  |  Height:  |  Size: 717 B

View File

Before

Width:  |  Height:  |  Size: 695 B

After

Width:  |  Height:  |  Size: 695 B

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 853 B

After

Width:  |  Height:  |  Size: 853 B

View File

Before

Width:  |  Height:  |  Size: 825 B

After

Width:  |  Height:  |  Size: 825 B

View File

Before

Width:  |  Height:  |  Size: 683 B

After

Width:  |  Height:  |  Size: 683 B

View File

Before

Width:  |  Height:  |  Size: 827 B

After

Width:  |  Height:  |  Size: 827 B

View File

@ -19,11 +19,8 @@
#include "worker.h"
#include <fstream>
#include "bitstream.h"
#include "design_utils.h"
#include "jsonparse.h"
#include "log.h"
#include "pcf.h"
#include "timing.h"
NEXTPNR_NAMESPACE_BEGIN
@ -55,43 +52,6 @@ Worker::Worker(TaskManager *parent) : ctx(nullptr)
void Worker::newContext(Context *ctx_) { ctx = ctx_; }
void Worker::loadfile(const std::string &filename)
{
Q_EMIT taskStarted();
std::string fn = filename;
std::ifstream f(fn);
try {
Q_EMIT loadfile_finished(parse_json_file(f, fn, ctx));
} catch (WorkerInterruptionRequested) {
Q_EMIT taskCanceled();
}
}
void Worker::loadpcf(const std::string &filename)
{
Q_EMIT taskStarted();
std::string fn = filename;
std::ifstream f(fn);
try {
Q_EMIT loadpcf_finished(apply_pcf(ctx, f));
} catch (WorkerInterruptionRequested) {
Q_EMIT taskCanceled();
}
}
void Worker::saveasc(const std::string &filename)
{
Q_EMIT taskStarted();
std::string fn = filename;
std::ofstream f(fn);
try {
write_asc(ctx, f);
Q_EMIT saveasc_finished(true);
} catch (WorkerInterruptionRequested) {
Q_EMIT taskCanceled();
}
}
void Worker::pack()
{
Q_EMIT taskStarted();
@ -144,9 +104,6 @@ TaskManager::TaskManager() : toTerminate(false), toPause(false)
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &TaskManager::loadfile, worker, &Worker::loadfile);
connect(this, &TaskManager::loadpcf, worker, &Worker::loadpcf);
connect(this, &TaskManager::saveasc, worker, &Worker::saveasc);
connect(this, &TaskManager::pack, worker, &Worker::pack);
connect(this, &TaskManager::budget, worker, &Worker::budget);
connect(this, &TaskManager::place, worker, &Worker::place);
@ -155,9 +112,6 @@ TaskManager::TaskManager() : toTerminate(false), toPause(false)
connect(this, &TaskManager::contextChanged, worker, &Worker::newContext);
connect(worker, &Worker::log, this, &TaskManager::info);
connect(worker, &Worker::loadfile_finished, this, &TaskManager::loadfile_finished);
connect(worker, &Worker::loadpcf_finished, this, &TaskManager::loadpcf_finished);
connect(worker, &Worker::saveasc_finished, this, &TaskManager::saveasc_finished);
connect(worker, &Worker::pack_finished, this, &TaskManager::pack_finished);
connect(worker, &Worker::budget_finish, this, &TaskManager::budget_finish);
connect(worker, &Worker::place_finished, this, &TaskManager::place_finished);

View File

@ -35,18 +35,12 @@ class Worker : public QObject
explicit Worker(TaskManager *parent);
public Q_SLOTS:
void newContext(Context *);
void loadfile(const std::string &);
void loadpcf(const std::string &);
void saveasc(const std::string &);
void pack();
void budget(double freq);
void place(bool timing_driven);
void route();
Q_SIGNALS:
void log(const std::string &text);
void loadfile_finished(bool status);
void loadpcf_finished(bool status);
void saveasc_finished(bool status);
void pack_finished(bool status);
void budget_finish(bool status);
void place_finished(bool status);
@ -78,9 +72,6 @@ class TaskManager : public QObject
Q_SIGNALS:
void contextChanged(Context *ctx);
void terminate();
void loadfile(const std::string &);
void loadpcf(const std::string &);
void saveasc(const std::string &);
void pack();
void budget(double freq);
void place(bool timing_driven);
@ -88,9 +79,6 @@ class TaskManager : public QObject
// redirected signals
void log(const std::string &text);
void loadfile_finished(bool status);
void loadpcf_finished(bool status);
void saveasc_finished(bool status);
void pack_finished(bool status);
void budget_finish(bool status);
void place_finished(bool status);

View File

@ -406,9 +406,11 @@ int main(int argc, char *argv[])
if (vm.count("json")) {
std::string filename = vm["json"].as<std::string>();
std::string pcf = "";
if (vm.count("pcf"))
w.load_json(filename);
if (vm.count("pcf")) {
pcf = vm["pcf"].as<std::string>();
w.load_json(filename, pcf);
w.load_pcf(pcf);
}
}
w.show();