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