Split per widgets

This commit is contained in:
Miodrag Milanovic 2018-06-14 18:37:57 +02:00
parent 8c46cc2fce
commit 9c0640240f
2 changed files with 414 additions and 360 deletions

View File

@ -1,304 +1,330 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include "emb.h" #include "emb.h"
#include "pybindings.h" #include "pybindings.h"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include <QDate> #include <QDate>
#include <QLocale> #include <QLocale>
enum class ElementType enum class ElementType
{ {
BEL, BEL,
WIRE, WIRE,
PIP PIP
}; };
class ElementTreeItem : public QTreeWidgetItem class ElementTreeItem : public QTreeWidgetItem
{ {
public: public:
ElementTreeItem(ElementType t, QString str) ElementTreeItem(ElementType t, QString str)
: QTreeWidgetItem((QTreeWidget *)nullptr, QStringList(str)), type(t) : QTreeWidgetItem((QTreeWidget *)nullptr, QStringList(str)), type(t)
{ {
} }
virtual ~ElementTreeItem(){}; virtual ~ElementTreeItem(){};
ElementType getType() { return type; }; ElementType getType() { return type; };
private: private:
ElementType type; ElementType type;
}; };
class BelTreeItem : public ElementTreeItem class BelTreeItem : public ElementTreeItem
{ {
public: public:
BelTreeItem(IdString d, ElementType type, QString str) BelTreeItem(IdString d, ElementType type, QString str)
: ElementTreeItem(type, str) : ElementTreeItem(type, str)
{ {
this->data = d; this->data = d;
} }
virtual ~BelTreeItem(){}; virtual ~BelTreeItem(){};
IdString getData() { return this->data; }; IdString getData() { return this->data; };
private: private:
IdString data; IdString data;
}; };
class WireTreeItem : public ElementTreeItem class WireTreeItem : public ElementTreeItem
{ {
public: public:
WireTreeItem(IdString d, ElementType type, QString str) WireTreeItem(IdString d, ElementType type, QString str)
: ElementTreeItem(type, str) : ElementTreeItem(type, str)
{ {
this->data = d; this->data = d;
} }
virtual ~WireTreeItem(){}; virtual ~WireTreeItem(){};
IdString getData() { return this->data; }; IdString getData() { return this->data; };
private: private:
IdString data; IdString data;
}; };
class PipTreeItem : public ElementTreeItem class PipTreeItem : public ElementTreeItem
{ {
public: public:
PipTreeItem(IdString d, ElementType type, QString str) PipTreeItem(IdString d, ElementType type, QString str)
: ElementTreeItem(type, str) : ElementTreeItem(type, str)
{ {
this->data = d; this->data = d;
} }
virtual ~PipTreeItem(){}; virtual ~PipTreeItem(){};
IdString getData() { return this->data; }; IdString getData() { return this->data; };
private: private:
IdString data; IdString data;
}; };
MainWindow::MainWindow(Design *_design, QWidget *parent) PythonTab::PythonTab(QWidget *parent) : QWidget(parent)
: QMainWindow(parent), ui(new Ui::MainWindow), design(_design) {
{ PyImport_ImportModule("emb");
ui->setupUi(this);
PyImport_ImportModule("emb"); // Add text area for Python output and input line
plainTextEdit = new QPlainTextEdit();
write = [this](std::string s) { plainTextEdit->setReadOnly(true);
plainTextEdit->moveCursor(QTextCursor::End); plainTextEdit->setMinimumHeight(100);
plainTextEdit->insertPlainText(s.c_str()); lineEdit = new QLineEdit();
plainTextEdit->moveCursor(QTextCursor::End); lineEdit->setMinimumHeight(30);
}; lineEdit->setMaximumHeight(30);
emb::set_stdout(write);
std::string title = "nextpnr-ice40 - " + design->chip.getChipName(); QGridLayout *mainLayout = new QGridLayout();
setWindowTitle(title.c_str()); mainLayout->addWidget(plainTextEdit, 0, 0);
mainLayout->addWidget(lineEdit, 1, 0);
// Add tree view setLayout(mainLayout);
ui->treeWidget->setColumnCount(1);
ui->treeWidget->setHeaderLabel(QString("Items")); connect(lineEdit, SIGNAL(returnPressed()), this,
ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); SLOT(editLineReturnPressed()));
connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this,
&MainWindow::prepareMenu); write = [this](std::string s) {
plainTextEdit->moveCursor(QTextCursor::End);
// Add bels to tree plainTextEdit->insertPlainText(s.c_str());
QTreeWidgetItem *bel_root = new QTreeWidgetItem(ui->treeWidget); plainTextEdit->moveCursor(QTextCursor::End);
bel_root->setText(0, QString("Bels")); };
ui->treeWidget->insertTopLevelItem(0, bel_root); emb::set_stdout(write);
QList<QTreeWidgetItem *> bel_items; }
for (auto bel : design->chip.getBels()) {
auto name = design->chip.getBelName(bel); void handle_system_exit() { exit(-1); }
bel_items.append(
new BelTreeItem(name, ElementType::BEL, QString(name.c_str()))); int PythonTab::executePython(std::string command)
} {
bel_root->addChildren(bel_items); PyObject *m, *d, *v;
m = PyImport_AddModule("__main__");
// Add wires to tree if (m == NULL)
QTreeWidgetItem *wire_root = new QTreeWidgetItem(ui->treeWidget); return -1;
QList<QTreeWidgetItem *> wire_items; d = PyModule_GetDict(m);
wire_root->setText(0, QString("Wires")); v = PyRun_StringFlags(command.c_str(),
ui->treeWidget->insertTopLevelItem(0, wire_root); (command.empty() ? Py_file_input : Py_single_input),
for (auto wire : design->chip.getWires()) { d, d, NULL);
auto name = design->chip.getWireName(wire); if (v == NULL) {
wire_items.append(new WireTreeItem(name, ElementType::WIRE, PyObject *exception, *v, *tb;
QString(name.c_str())));
} if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
wire_root->addChildren(wire_items); handle_system_exit();
}
// Add pips to tree PyErr_Fetch(&exception, &v, &tb);
QTreeWidgetItem *pip_root = new QTreeWidgetItem(ui->treeWidget); if (exception == NULL)
QList<QTreeWidgetItem *> pip_items; return 0;
pip_root->setText(0, QString("Pips")); PyErr_NormalizeException(&exception, &v, &tb);
ui->treeWidget->insertTopLevelItem(0, pip_root); if (tb == NULL) {
for (auto pip : design->chip.getPips()) { tb = Py_None;
auto name = design->chip.getPipName(pip); Py_INCREF(tb);
pip_items.append( }
new PipTreeItem(name, ElementType::PIP, QString(name.c_str()))); PyException_SetTraceback(v, tb);
} if (exception == NULL)
pip_root->addChildren(pip_items); return 0;
PyErr_Clear();
// Add property view
variantManager = new QtVariantPropertyManager(); PyObject *objectsRepresentation = PyObject_Str(v);
variantFactory = new QtVariantEditorFactory(); std::string errorStr =
propertyEditor = new QtTreePropertyBrowser(); PyUnicode_AsUTF8(objectsRepresentation) + std::string("\n");
propertyEditor->setFactoryForManager(variantManager, variantFactory); plainTextEdit->moveCursor(QTextCursor::End);
propertyEditor->setPropertiesWithoutValueMarked(true); plainTextEdit->insertPlainText(errorStr.c_str());
propertyEditor->setRootIsDecorated(false); plainTextEdit->moveCursor(QTextCursor::End);
propertyEditor->show(); Py_DECREF(objectsRepresentation);
ui->splitter_2->addWidget(propertyEditor); Py_XDECREF(exception);
Py_XDECREF(v);
connect(ui->treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), Py_XDECREF(tb);
SLOT(onItemClicked(QTreeWidgetItem *, int))); return -1;
}
// Add text area for Python output and input line Py_DECREF(v);
plainTextEdit = new QPlainTextEdit(); return 0;
plainTextEdit->setReadOnly(true); }
plainTextEdit->setMinimumHeight(50);
plainTextEdit->setMaximumHeight(200); void PythonTab::editLineReturnPressed()
ui->splitter->addWidget(plainTextEdit); {
lineEdit = new QLineEdit(); std::string input = lineEdit->text().toStdString();
lineEdit->setMinimumHeight(30); plainTextEdit->moveCursor(QTextCursor::End);
lineEdit->setMaximumHeight(30); plainTextEdit->insertPlainText(std::string(">>> " + input + "\n").c_str());
ui->splitter->addWidget(lineEdit); plainTextEdit->moveCursor(QTextCursor::End);
connect(lineEdit, SIGNAL(returnPressed()), this, plainTextEdit->update();
SLOT(editLineReturnPressed())); lineEdit->clear();
} int error = executePython(input);
}
MainWindow::~MainWindow()
{ InfoTab::InfoTab(QWidget *parent) : QWidget(parent)
delete variantManager; {
delete variantFactory; // Add text area for Python output and input line
delete propertyEditor; plainTextEdit = new QPlainTextEdit();
delete ui; plainTextEdit->setReadOnly(true);
}
QGridLayout *mainLayout = new QGridLayout();
void MainWindow::addProperty(QtVariantProperty *property, const QString &id) mainLayout->addWidget(plainTextEdit);
{ setLayout(mainLayout);
propertyToId[property] = id; }
idToProperty[id] = property;
QtBrowserItem *item = propertyEditor->addProperty(property); void InfoTab::info(std::string str)
} {
plainTextEdit->moveCursor(QTextCursor::End);
void MainWindow::onItemClicked(QTreeWidgetItem *item, int pos) plainTextEdit->insertPlainText(str.c_str());
{ plainTextEdit->moveCursor(QTextCursor::End);
if (!item->parent()) }
return;
ElementType type = static_cast<ElementTreeItem *>(item)->getType(); MainWindow::MainWindow(Design *_design, QWidget *parent)
QMap<QtProperty *, QString>::ConstIterator itProp = : QMainWindow(parent), ui(new Ui::MainWindow), design(_design)
propertyToId.constBegin(); {
while (itProp != propertyToId.constEnd()) { ui->setupUi(this);
delete itProp.key(); std::string title = "nextpnr-ice40 - " + design->chip.getChipName();
itProp++; setWindowTitle(title.c_str());
}
propertyToId.clear(); // Add tree view
idToProperty.clear(); ui->treeWidget->setColumnCount(1);
ui->treeWidget->setHeaderLabel(QString("Items"));
if (type == ElementType::BEL) { ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
IdString c = static_cast<BelTreeItem *>(item)->getData(); connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this,
&MainWindow::prepareMenu);
QtVariantProperty *topItem =
variantManager->addProperty(QVariant::String, QString("Name")); // Add bels to tree
topItem->setValue(QString(c.c_str())); QTreeWidgetItem *bel_root = new QTreeWidgetItem(ui->treeWidget);
addProperty(topItem, QString("Name")); bel_root->setText(0, QString("Bels"));
} else if (type == ElementType::WIRE) { ui->treeWidget->insertTopLevelItem(0, bel_root);
IdString c = static_cast<WireTreeItem *>(item)->getData(); QList<QTreeWidgetItem *> bel_items;
for (auto bel : design->chip.getBels()) {
QtVariantProperty *topItem = auto name = design->chip.getBelName(bel);
variantManager->addProperty(QVariant::String, QString("Name")); bel_items.append(
topItem->setValue(QString(c.c_str())); new BelTreeItem(name, ElementType::BEL, QString(name.c_str())));
addProperty(topItem, QString("Name")); }
bel_root->addChildren(bel_items);
} else if (type == ElementType::PIP) {
IdString c = static_cast<PipTreeItem *>(item)->getData(); // Add wires to tree
QTreeWidgetItem *wire_root = new QTreeWidgetItem(ui->treeWidget);
QtVariantProperty *topItem = QList<QTreeWidgetItem *> wire_items;
variantManager->addProperty(QVariant::String, QString("Name")); wire_root->setText(0, QString("Wires"));
topItem->setValue(QString(c.c_str())); ui->treeWidget->insertTopLevelItem(0, wire_root);
addProperty(topItem, QString("Name")); for (auto wire : design->chip.getWires()) {
} auto name = design->chip.getWireName(wire);
} wire_items.append(new WireTreeItem(name, ElementType::WIRE,
QString(name.c_str())));
void MainWindow::prepareMenu(const QPoint &pos) }
{ wire_root->addChildren(wire_items);
QTreeWidget *tree = ui->treeWidget;
// Add pips to tree
itemContextMenu = tree->itemAt(pos); QTreeWidgetItem *pip_root = new QTreeWidgetItem(ui->treeWidget);
QList<QTreeWidgetItem *> pip_items;
QAction *selectAction = new QAction("&Select", this); pip_root->setText(0, QString("Pips"));
selectAction->setStatusTip("Select item on view"); ui->treeWidget->insertTopLevelItem(0, pip_root);
connect(selectAction, SIGNAL(triggered()), this, SLOT(selectObject())); for (auto pip : design->chip.getPips()) {
auto name = design->chip.getPipName(pip);
QMenu menu(this); pip_items.append(
menu.addAction(selectAction); new PipTreeItem(name, ElementType::PIP, QString(name.c_str())));
}
QPoint pt(pos); pip_root->addChildren(pip_items);
menu.exec(tree->mapToGlobal(pos));
} // Add property view
variantManager = new QtVariantPropertyManager();
void MainWindow::selectObject() variantFactory = new QtVariantEditorFactory();
{ propertyEditor = new QtTreePropertyBrowser();
plainTextEdit->moveCursor(QTextCursor::End); propertyEditor->setFactoryForManager(variantManager, variantFactory);
plainTextEdit->insertPlainText( propertyEditor->setPropertiesWithoutValueMarked(true);
std::string("selected " + itemContextMenu->text(0).toStdString() + propertyEditor->setRootIsDecorated(false);
"\n") propertyEditor->show();
.c_str()); ui->splitter_2->addWidget(propertyEditor);
plainTextEdit->moveCursor(QTextCursor::End);
} connect(ui->treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)),
SLOT(onItemClicked(QTreeWidgetItem *, int)));
void handle_system_exit() { exit(-1); }
tabWidget = new QTabWidget();
int MainWindow::executePython(std::string command) tabWidget->addTab(new PythonTab(), "Python");
{ info = new InfoTab();
PyObject *m, *d, *v; tabWidget->addTab(info, "Info");
m = PyImport_AddModule("__main__"); ui->splitter->addWidget(tabWidget);
if (m == NULL) }
return -1;
d = PyModule_GetDict(m); MainWindow::~MainWindow()
v = PyRun_StringFlags(command.c_str(), {
(command.empty() ? Py_file_input : Py_single_input), delete variantManager;
d, d, NULL); delete variantFactory;
if (v == NULL) { delete propertyEditor;
PyObject *exception, *v, *tb; delete ui;
}
if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
handle_system_exit(); void MainWindow::addProperty(QtVariantProperty *property, const QString &id)
} {
PyErr_Fetch(&exception, &v, &tb); propertyToId[property] = id;
if (exception == NULL) idToProperty[id] = property;
return 0; QtBrowserItem *item = propertyEditor->addProperty(property);
PyErr_NormalizeException(&exception, &v, &tb); }
if (tb == NULL) {
tb = Py_None; void MainWindow::onItemClicked(QTreeWidgetItem *item, int pos)
Py_INCREF(tb); {
} if (!item->parent())
PyException_SetTraceback(v, tb); return;
if (exception == NULL) ElementType type = static_cast<ElementTreeItem *>(item)->getType();
return 0; QMap<QtProperty *, QString>::ConstIterator itProp =
PyErr_Clear(); propertyToId.constBegin();
while (itProp != propertyToId.constEnd()) {
PyObject *objectsRepresentation = PyObject_Str(v); delete itProp.key();
std::string errorStr = itProp++;
PyUnicode_AsUTF8(objectsRepresentation) + std::string("\n"); }
plainTextEdit->moveCursor(QTextCursor::End); propertyToId.clear();
plainTextEdit->insertPlainText(errorStr.c_str()); idToProperty.clear();
plainTextEdit->moveCursor(QTextCursor::End);
Py_DECREF(objectsRepresentation); if (type == ElementType::BEL) {
Py_XDECREF(exception); IdString c = static_cast<BelTreeItem *>(item)->getData();
Py_XDECREF(v);
Py_XDECREF(tb); QtVariantProperty *topItem =
return -1; variantManager->addProperty(QVariant::String, QString("Name"));
} topItem->setValue(QString(c.c_str()));
Py_DECREF(v); addProperty(topItem, QString("Name"));
return 0; } else if (type == ElementType::WIRE) {
} IdString c = static_cast<WireTreeItem *>(item)->getData();
void MainWindow::editLineReturnPressed() QtVariantProperty *topItem =
{ variantManager->addProperty(QVariant::String, QString("Name"));
std::string input = lineEdit->text().toStdString(); topItem->setValue(QString(c.c_str()));
plainTextEdit->moveCursor(QTextCursor::End); addProperty(topItem, QString("Name"));
plainTextEdit->insertPlainText(std::string(">>> " + input + "\n").c_str());
plainTextEdit->moveCursor(QTextCursor::End); } else if (type == ElementType::PIP) {
plainTextEdit->update(); IdString c = static_cast<PipTreeItem *>(item)->getData();
lineEdit->clear();
int error = executePython(input); QtVariantProperty *topItem =
} variantManager->addProperty(QVariant::String, QString("Name"));
topItem->setValue(QString(c.c_str()));
addProperty(topItem, QString("Name"));
}
}
void MainWindow::prepareMenu(const QPoint &pos)
{
QTreeWidget *tree = ui->treeWidget;
itemContextMenu = tree->itemAt(pos);
QAction *selectAction = new QAction("&Select", this);
selectAction->setStatusTip("Select item on view");
connect(selectAction, SIGNAL(triggered()), this, SLOT(selectObject()));
QMenu menu(this);
menu.addAction(selectAction);
QPoint pt(pos);
menu.exec(tree->mapToGlobal(pos));
}
void MainWindow::selectObject()
{
info->info("selected " + itemContextMenu->text(0).toStdString() + "\n");
}

View File

@ -1,56 +1,84 @@
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
#include "emb.h" #include "emb.h"
#include "nextpnr.h" #include "nextpnr.h"
#include "qtpropertymanager.h" #include "qtpropertymanager.h"
#include "qttreepropertybrowser.h" #include "qttreepropertybrowser.h"
#include "qtvariantproperty.h" #include "qtvariantproperty.h"
#include <QLineEdit> #include <QLineEdit>
#include <QMainWindow> #include <QMainWindow>
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QTabWidget>
// FIXME
USING_NEXTPNR_NAMESPACE // FIXME
USING_NEXTPNR_NAMESPACE
namespace Ui {
class MainWindow; namespace Ui {
} class MainWindow;
}
class MainWindow : public QMainWindow
{ class PythonTab : public QWidget
Q_OBJECT {
Q_OBJECT
public:
explicit MainWindow(Design *design, QWidget *parent = 0); public:
~MainWindow(); explicit PythonTab(QWidget *parent = 0);
Design *getDesign() { return design; }
private:
private: int executePython(std::string command);
int executePython(std::string command); private Q_SLOTS:
void addProperty(QtVariantProperty *property, const QString &id); void editLineReturnPressed();
private Q_SLOTS: private:
void editLineReturnPressed(); QPlainTextEdit *plainTextEdit;
void prepareMenu(const QPoint &pos); QLineEdit *lineEdit;
void selectObject(); emb::stdout_write_type write;
void onItemClicked(QTreeWidgetItem *item, int); };
private: class InfoTab : public QWidget
Ui::MainWindow *ui; {
emb::stdout_write_type write; Q_OBJECT
Design *design;
QtVariantPropertyManager *variantManager; public:
QtVariantEditorFactory *variantFactory; explicit InfoTab(QWidget *parent = 0);
QtTreePropertyBrowser *propertyEditor; void info(std::string str);
QTreeWidgetItem *itemContextMenu;
private:
QMap<QtProperty *, QString> propertyToId; QPlainTextEdit *plainTextEdit;
QMap<QString, QtVariantProperty *> idToProperty; };
QPlainTextEdit *plainTextEdit; class MainWindow : public QMainWindow
QLineEdit *lineEdit; {
}; Q_OBJECT
#endif // MAINWINDOW_H public:
explicit MainWindow(Design *design, QWidget *parent = 0);
~MainWindow();
Design *getDesign() { return design; }
private:
void addProperty(QtVariantProperty *property, const QString &id);
private Q_SLOTS:
void prepareMenu(const QPoint &pos);
void selectObject();
void onItemClicked(QTreeWidgetItem *item, int);
private:
Ui::MainWindow *ui;
Design *design;
QtVariantPropertyManager *variantManager;
QtVariantEditorFactory *variantFactory;
QtTreePropertyBrowser *propertyEditor;
QTreeWidgetItem *itemContextMenu;
QMap<QtProperty *, QString> propertyToId;
QMap<QString, QtVariantProperty *> idToProperty;
QTabWidget *tabWidget;
InfoTab *info;
};
#endif // MAINWINDOW_H