Split design widget on side

This commit is contained in:
Miodrag Milanovic 2018-06-14 20:03:59 +02:00
parent 4a734d6cc7
commit 1336eb0630
6 changed files with 289 additions and 258 deletions

233
gui/designwidget.cc Normal file
View File

@ -0,0 +1,233 @@
#include "designwidget.h"
#include <QAction>
#include <QGridLayout>
#include <QMenu>
#include <QSplitter>
#include <QTreeWidgetItem>
#include "fpgaviewwidget.h"
#include "pybindings.h"
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;
};
DesignWidget::DesignWidget(Design *_design, QWidget *parent)
: QWidget(parent), design(_design)
{
treeWidget = new QTreeWidget();
// Add tree view
treeWidget->setColumnCount(1);
treeWidget->setHeaderLabel(QString("Items"));
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
// Add bels to tree
QTreeWidgetItem *bel_root = new QTreeWidgetItem(treeWidget);
bel_root->setText(0, QString("Bels"));
treeWidget->insertTopLevelItem(0, bel_root);
QList<QTreeWidgetItem *> 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(treeWidget);
QList<QTreeWidgetItem *> wire_items;
wire_root->setText(0, QString("Wires"));
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(treeWidget);
QList<QTreeWidgetItem *> pip_items;
pip_root->setText(0, QString("Pips"));
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();
QSplitter *splitter = new QSplitter(Qt::Vertical);
splitter->addWidget(treeWidget);
splitter->addWidget(propertyEditor);
QGridLayout *mainLayout = new QGridLayout();
mainLayout->addWidget(splitter);
setLayout(mainLayout);
// Connection
connect(treeWidget, &QTreeWidget::customContextMenuRequested, this,
&DesignWidget::prepareMenu);
connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)),
SLOT(onItemClicked(QTreeWidgetItem *, int)));
}
DesignWidget::~DesignWidget()
{
delete variantManager;
delete variantFactory;
delete propertyEditor;
}
void DesignWidget::addProperty(QtVariantProperty *property, const QString &id)
{
propertyToId[property] = id;
idToProperty[id] = property;
QtBrowserItem *item = propertyEditor->addProperty(property);
}
void DesignWidget::clearProperties()
{
QMap<QtProperty *, QString>::ConstIterator itProp =
propertyToId.constBegin();
while (itProp != propertyToId.constEnd()) {
delete itProp.key();
itProp++;
}
propertyToId.clear();
idToProperty.clear();
}
void DesignWidget::onItemClicked(QTreeWidgetItem *item, int pos)
{
if (!item->parent())
return;
clearProperties();
ElementType type = static_cast<ElementTreeItem *>(item)->getType();
if (type == ElementType::BEL) {
IdString c = static_cast<BelTreeItem *>(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<WireTreeItem *>(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<PipTreeItem *>(item)->getData();
QtVariantProperty *topItem =
variantManager->addProperty(QVariant::String, QString("Name"));
topItem->setValue(QString(c.c_str()));
addProperty(topItem, QString("Name"));
}
}
void DesignWidget::prepareMenu(const QPoint &pos)
{
QTreeWidget *tree = 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 DesignWidget::selectObject()
{
// info->info("selected " + itemContextMenu->text(0).toStdString() + "\n");
}

45
gui/designwidget.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef DESIGNWIDGET_H
#define DESIGNWIDGET_H
#include <QTreeWidget>
#include "nextpnr.h"
#include "qtpropertymanager.h"
#include "qttreepropertybrowser.h"
#include "qtvariantproperty.h"
// FIXME
USING_NEXTPNR_NAMESPACE
class DesignWidget : public QWidget
{
Q_OBJECT
public:
explicit DesignWidget(Design *design, QWidget *parent = 0);
~DesignWidget();
Design *getDesign() { return design; }
private:
void addProperty(QtVariantProperty *property, const QString &id);
void clearProperties();
private Q_SLOTS:
void prepareMenu(const QPoint &pos);
void selectObject();
void onItemClicked(QTreeWidgetItem *item, int);
private:
Design *design;
QTreeWidget *treeWidget;
QtVariantPropertyManager *variantManager;
QtVariantEditorFactory *variantFactory;
QtTreePropertyBrowser *propertyEditor;
QTreeWidgetItem *itemContextMenu;
QMap<QtProperty *, QString> propertyToId;
QMap<QString, QtVariantProperty *> idToProperty;
};
#endif // DESIGNWIDGET_H

View File

@ -11,12 +11,14 @@ qt5_generate_moc(gui/mainwindow.h ${CMAKE_CURRENT_BINARY_DIR}/generated/moc_main
qt5_generate_moc(gui/fpgaviewwidget.h ${CMAKE_CURRENT_BINARY_DIR}/generated/moc_fpgaviewwidget.cc)
qt5_generate_moc(gui/pythontab.h ${CMAKE_CURRENT_BINARY_DIR}/generated/moc_pythontab.cc)
qt5_generate_moc(gui/infotab.h ${CMAKE_CURRENT_BINARY_DIR}/generated/moc_infotab.cc)
qt5_generate_moc(gui/designwidget.h ${CMAKE_CURRENT_BINARY_DIR}/generated/moc_designwidget.cc)
set(GENERATED_MOC_FILES
${CMAKE_CURRENT_BINARY_DIR}/generated/moc_mainwindow.cc
${CMAKE_CURRENT_BINARY_DIR}/generated/moc_fpgaviewwidget.cc
${CMAKE_CURRENT_BINARY_DIR}/generated/moc_pythontab.cc
${CMAKE_CURRENT_BINARY_DIR}/generated/moc_infotab.cc
${CMAKE_CURRENT_BINARY_DIR}/generated/moc_designwidget.cc
)
set(UI_SOURCES
@ -25,7 +27,7 @@ set(UI_SOURCES
qt5_wrap_ui_custom(GENERATED_UI_HEADERS ${UI_SOURCES})
qt5_add_resources_custom(GUI_RESOURCE_FILES gui/nextpnr.qrc)
set(GUI_SOURCE_FILES gui/mainwindow.cc gui/fpgaviewwidget.cc gui/pythontab.cc gui/infotab.cc gui/emb.cc ${GENERATED_MOC_FILES} ${GENERATED_UI_HEADERS} ${GUI_RESOURCE_FILES})
set(GUI_SOURCE_FILES gui/mainwindow.cc gui/fpgaviewwidget.cc gui/pythontab.cc gui/infotab.cc gui/designwidget.cc gui/emb.cc ${GENERATED_MOC_FILES} ${GENERATED_UI_HEADERS} ${GUI_RESOURCE_FILES})
set(GUI_LIBRARY_FILES Qt5::Widgets Qt5::OpenGL ${OPENGL_LIBRARIES} QtPropertyBrowser)

View File

@ -1,84 +1,9 @@
#include "mainwindow.h"
#include <functional>
#include <iostream>
#include <string>
#include "emb.h"
#include "pybindings.h"
#include "designwidget.h"
#include "fpgaviewwidget.h"
#include "pythontab.h"
#include "ui_mainwindow.h"
#include <QDate>
#include <QLocale>
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)
{
@ -86,61 +11,11 @@ MainWindow::MainWindow(Design *_design, QWidget *parent)
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);
ui->splitter->addWidget(new FPGAViewWidget());
// Add bels to tree
QTreeWidgetItem *bel_root = new QTreeWidgetItem(ui->treeWidget);
bel_root->setText(0, QString("Bels"));
ui->treeWidget->insertTopLevelItem(0, bel_root);
QList<QTreeWidgetItem *> 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<QTreeWidgetItem *> 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<QTreeWidgetItem *> 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)));
ui->splitter_2->addWidget(new DesignWidget(design));
ui->splitter_2->setMinimumWidth(300);
ui->splitter_2->setMaximumWidth(300);
tabWidget = new QTabWidget();
tabWidget->addTab(new PythonTab(), "Python");
@ -149,85 +24,4 @@ MainWindow::MainWindow(Design *_design, QWidget *parent)
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::clearProperties()
{
QMap<QtProperty *, QString>::ConstIterator itProp =
propertyToId.constBegin();
while (itProp != propertyToId.constEnd()) {
delete itProp.key();
itProp++;
}
propertyToId.clear();
idToProperty.clear();
}
void MainWindow::onItemClicked(QTreeWidgetItem *item, int pos)
{
if (!item->parent())
return;
clearProperties();
ElementType type = static_cast<ElementTreeItem *>(item)->getType();
if (type == ElementType::BEL) {
IdString c = static_cast<BelTreeItem *>(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<WireTreeItem *>(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<PipTreeItem *>(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");
}
MainWindow::~MainWindow() { delete ui; }

View File

@ -1,16 +1,10 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "emb.h"
#include "infotab.h"
#include "nextpnr.h"
#include "pythontab.h"
#include "qtpropertymanager.h"
#include "qttreepropertybrowser.h"
#include "qtvariantproperty.h"
#include <QMainWindow>
#include <QPlainTextEdit>
#include <QTabWidget>
// FIXME
@ -29,25 +23,10 @@ class MainWindow : public QMainWindow
~MainWindow();
Design *getDesign() { return design; }
private:
void addProperty(QtVariantProperty *property, const QString &id);
void clearProperties();
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;

View File

@ -24,26 +24,11 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="FPGAViewWidget" name="openGLWidget" native="true"/>
</widget>
<widget class="QSplitter" name="splitter_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTreeWidget" name="treeWidget">
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
</widget>
</widget>
</widget>
</item>
@ -144,13 +129,6 @@
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>FPGAViewWidget</class>
<extends>QWidget</extends>
<header>fpgaviewwidget.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="nextpnr.qrc"/>
</resources>