Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr into q3k/lock-2-electric-boogaloo

This commit is contained in:
Serge Bazanski 2018-07-15 21:57:42 +01:00
commit f3c6c76fff
16 changed files with 810 additions and 313 deletions

View File

@ -74,6 +74,7 @@ public:
QtProperty *indexToProperty(const QModelIndex &index) const;
QTreeWidgetItem *indexToItem(const QModelIndex &index) const;
QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const;
QtBrowserItem *itemToBrowserItem(QTreeWidgetItem *item) const { return m_itemToIndex.value(item); };
bool lastColumn(int column) const;
void disableItem(QTreeWidgetItem *item) const;
void enableItem(QTreeWidgetItem *item) const;
@ -1068,6 +1069,16 @@ void QtTreePropertyBrowser::editItem(QtBrowserItem *item)
d_ptr->editItem(item);
}
QTreeWidget *QtTreePropertyBrowser::treeWidget() const
{
return d_ptr->treeWidget();
}
QtBrowserItem *QtTreePropertyBrowser::itemToBrowserItem(QTreeWidgetItem *item)
{
return d_ptr->itemToBrowserItem(item);
}
#if QT_VERSION >= 0x040400
QT_END_NAMESPACE
#endif

View File

@ -47,6 +47,7 @@
QT_BEGIN_NAMESPACE
#endif
class QTreeWidget;
class QTreeWidgetItem;
class QtTreePropertyBrowserPrivate;
@ -107,6 +108,9 @@ public:
void editItem(QtBrowserItem *item);
//ADDED:miodrag
QTreeWidget *treeWidget() const;
QtBrowserItem *itemToBrowserItem(QTreeWidgetItem *item);
Q_SIGNALS:
void collapsed(QtBrowserItem *item);

View File

@ -9,5 +9,6 @@
<file>resources/resultset_previous.png</file>
<file>resources/resultset_next.png</file>
<file>resources/resultset_last.png</file>
<file>resources/splash.png</file>
</qresource>
</RCC>

View File

@ -18,6 +18,7 @@
*/
#include <QAction>
#include <QCoreApplication>
#include <QFileDialog>
#include <QGridLayout>
#include <QIcon>
@ -61,15 +62,10 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
setCentralWidget(centralWidget);
DesignWidget *designview = new DesignWidget();
designview = new DesignWidget();
designview->setMinimumWidth(300);
splitter_h->addWidget(designview);
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)));
tabWidget = new QTabWidget();
console = new PythonTab();
@ -81,38 +77,64 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
centralTabWidget->addTab(fpgaView, "Graphics");
connect(this, SIGNAL(contextChanged(Context *)), fpgaView, SLOT(newContext(Context *)));
connect(designview, SIGNAL(selected(std::vector<DecalXY>)), fpgaView, SLOT(onSelectedArchItem(std::vector<DecalXY>)));
connect(designview, SIGNAL(selected(std::vector<DecalXY>)), fpgaView,
SLOT(onSelectedArchItem(std::vector<DecalXY>)));
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);
displaySplash();
}
BaseMainWindow::~BaseMainWindow() {}
void BaseMainWindow::displaySplash()
{
splash = new QSplashScreen();
splash->setPixmap(QPixmap(":/icons/resources/splash.png"));
splash->show();
connect(designview, SIGNAL(finishContextLoad()), splash, SLOT(close()));
connect(designview, SIGNAL(contextLoadStatus(std::string)), this, SLOT(displaySplashMessage(std::string)));
QCoreApplication::instance()->processEvents();
}
void BaseMainWindow::displaySplashMessage(std::string msg)
{
splash->showMessage(msg.c_str(), Qt::AlignCenter | Qt::AlignBottom, Qt::white);
QCoreApplication::instance()->processEvents();
}
void BaseMainWindow::writeInfo(std::string text) { console->info(text); }
void BaseMainWindow::createMenusAndBars()
{
actionNew = new QAction("New", this);
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()));
actionOpen = new QAction("Open", this);
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()));
QAction *actionSave = new QAction("Save", this);
QAction *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()));
QAction *actionExit = new QAction("Exit", this);
QAction *actionExit = new QAction("Exit", this);
actionExit->setIcon(QIcon(":/icons/resources/exit.png"));
actionExit->setShortcuts(QKeySequence::Quit);
actionExit->setStatusTip("Exit the application");

View File

@ -26,6 +26,7 @@
#include <QMenu>
#include <QMenuBar>
#include <QProgressBar>
#include <QSplashScreen>
#include <QStatusBar>
#include <QTabWidget>
#include <QToolBar>
@ -36,6 +37,7 @@ Q_DECLARE_METATYPE(NEXTPNR_NAMESPACE_PREFIX DecalXY)
NEXTPNR_NAMESPACE_BEGIN
class PythonTab;
class DesignWidget;
class BaseMainWindow : public QMainWindow
{
@ -48,9 +50,11 @@ class BaseMainWindow : public QMainWindow
protected:
void createMenusAndBars();
void displaySplash();
protected Q_SLOTS:
void writeInfo(std::string text);
void displaySplashMessage(std::string msg);
virtual void new_proj() = 0;
virtual void open_proj() = 0;
@ -72,6 +76,8 @@ class BaseMainWindow : public QMainWindow
QAction *actionNew;
QAction *actionOpen;
QProgressBar *progressBar;
QSplashScreen *splash;
DesignWidget *designview;
};
NEXTPNR_NAMESPACE_END

View File

@ -29,16 +29,6 @@
NEXTPNR_NAMESPACE_BEGIN
enum class ElementType
{
NONE,
BEL,
WIRE,
PIP,
NET,
CELL
};
class ElementTreeItem : public QTreeWidgetItem
{
public:
@ -87,29 +77,53 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net
propertyEditor = new QtTreePropertyBrowser(this);
propertyEditor->setFactoryForManager(variantManager, variantFactory);
propertyEditor->setPropertiesWithoutValueMarked(true);
propertyEditor->show();
propertyEditor->treeWidget()->setContextMenuPolicy(Qt::CustomContextMenu);
QLineEdit *lineEdit = new QLineEdit();
lineEdit->setClearButtonEnabled(true);
lineEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition);
lineEdit->setPlaceholderText("Search...");
actionFirst = new QAction("", this);
actionFirst = new QAction("", this);
actionFirst->setIcon(QIcon(":/icons/resources/resultset_first.png"));
actionFirst->setEnabled(false);
connect(actionFirst, &QAction::triggered, this, [this] {
history_ignore = true;
history_index = 0;
treeWidget->setCurrentItem(history.at(history_index));
updateButtons();
});
actionPrev = new QAction("", this);
actionPrev = new QAction("", this);
actionPrev->setIcon(QIcon(":/icons/resources/resultset_previous.png"));
actionPrev->setEnabled(false);
connect(actionPrev, &QAction::triggered, this, [this] {
history_ignore = true;
history_index--;
treeWidget->setCurrentItem(history.at(history_index));
updateButtons();
});
actionNext = new QAction("", this);
actionNext = new QAction("", this);
actionNext->setIcon(QIcon(":/icons/resources/resultset_next.png"));
actionNext->setEnabled(false);
connect(actionNext, &QAction::triggered, this, [this] {
history_ignore = true;
history_index++;
treeWidget->setCurrentItem(history.at(history_index));
updateButtons();
});
actionLast = new QAction("", this);
actionLast = new QAction("", this);
actionLast->setIcon(QIcon(":/icons/resources/resultset_last.png"));
actionLast->setEnabled(false);
connect(actionLast, &QAction::triggered, this, [this] {
history_ignore = true;
history_index = int(history.size() - 1);
treeWidget->setCurrentItem(history.at(history_index));
updateButtons();
});
QToolBar *toolbar = new QToolBar();
toolbar->addAction(actionFirst);
@ -153,16 +167,61 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net
setLayout(mainLayout);
// Connection
connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenu);
connect(propertyEditor->treeWidget(), &QTreeWidget::customContextMenuRequested, this,
&DesignWidget::prepareMenuProperty);
connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked);
connect(treeWidget, SIGNAL(itemSelectionChanged()), SLOT(onItemSelectionChanged()));
connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenuTree);
history_index = -1;
history_ignore = false;
highlightColors[0] = QColor("#6495ed");
highlightColors[1] = QColor("#7fffd4");
highlightColors[2] = QColor("#98fb98");
highlightColors[3] = QColor("#ffd700");
highlightColors[4] = QColor("#cd5c5c");
highlightColors[5] = QColor("#fa8072");
highlightColors[6] = QColor("#ff69b4");
highlightColors[7] = QColor("#da70d6");
}
DesignWidget::~DesignWidget() {}
void DesignWidget::updateButtons()
{
int count = int(history.size());
actionFirst->setEnabled(history_index > 0);
actionPrev->setEnabled(history_index > 0);
actionNext->setEnabled(history_index < (count - 1));
actionLast->setEnabled(history_index < (count - 1));
}
void DesignWidget::addToHistory(QTreeWidgetItem *item)
{
if (!history_ignore) {
int count = int(history.size());
for (int i = count - 1; i > history_index; i--)
history.pop_back();
history.push_back(item);
history_index++;
}
history_ignore = false;
updateButtons();
}
void DesignWidget::newContext(Context *ctx)
{
treeWidget->clear();
history_ignore = false;
history_index = -1;
history.clear();
updateButtons();
for (int i = 0; i < 6; i++)
nameToItem[i].clear();
this->ctx = ctx;
// Add bels to tree
@ -171,6 +230,7 @@ void DesignWidget::newContext(Context *ctx)
bel_root->setText(0, "Bels");
treeWidget->insertTopLevelItem(0, bel_root);
if (ctx) {
Q_EMIT contextLoadStatus("Configuring bels...");
for (auto bel : ctx->getBels()) {
auto id = ctx->getBelName(bel);
QStringList items = QString(id.c_str(ctx)).split("/");
@ -182,7 +242,7 @@ void DesignWidget::newContext(Context *ctx)
name += items.at(i);
if (!bel_items.contains(name)) {
if (i == items.size() - 1)
bel_items.insert(name, new IdStringTreeItem(id, ElementType::BEL, items.at(i), parent));
nameToItem[0].insert(name, new IdStringTreeItem(id, ElementType::BEL, items.at(i), parent));
else
bel_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent));
}
@ -193,6 +253,9 @@ void DesignWidget::newContext(Context *ctx)
for (auto bel : bel_items.toStdMap()) {
bel_root->addChild(bel.second);
}
for (auto bel : nameToItem[0].toStdMap()) {
bel_root->addChild(bel.second);
}
// Add wires to tree
QTreeWidgetItem *wire_root = new QTreeWidgetItem(treeWidget);
@ -200,6 +263,7 @@ void DesignWidget::newContext(Context *ctx)
wire_root->setText(0, "Wires");
treeWidget->insertTopLevelItem(0, wire_root);
if (ctx) {
Q_EMIT contextLoadStatus("Configuring wires...");
for (auto wire : ctx->getWires()) {
auto id = ctx->getWireName(wire);
QStringList items = QString(id.c_str(ctx)).split("/");
@ -211,7 +275,7 @@ void DesignWidget::newContext(Context *ctx)
name += items.at(i);
if (!wire_items.contains(name)) {
if (i == items.size() - 1)
wire_items.insert(name, new IdStringTreeItem(id, ElementType::WIRE, items.at(i), parent));
nameToItem[1].insert(name, new IdStringTreeItem(id, ElementType::WIRE, items.at(i), parent));
else
wire_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent));
}
@ -222,13 +286,16 @@ void DesignWidget::newContext(Context *ctx)
for (auto wire : wire_items.toStdMap()) {
wire_root->addChild(wire.second);
}
for (auto wire : nameToItem[1].toStdMap()) {
wire_root->addChild(wire.second);
}
// Add pips to tree
QTreeWidgetItem *pip_root = new QTreeWidgetItem(treeWidget);
QMap<QString, QTreeWidgetItem *> pip_items;
pip_root->setText(0, "Pips");
treeWidget->insertTopLevelItem(0, pip_root);
if (ctx) {
Q_EMIT contextLoadStatus("Configuring pips...");
for (auto pip : ctx->getPips()) {
auto id = ctx->getPipName(pip);
QStringList items = QString(id.c_str(ctx)).split("/");
@ -240,7 +307,7 @@ void DesignWidget::newContext(Context *ctx)
name += items.at(i);
if (!pip_items.contains(name)) {
if (i == items.size() - 1)
pip_items.insert(name, new IdStringTreeItem(id, ElementType::PIP, items.at(i), parent));
nameToItem[2].insert(name, new IdStringTreeItem(id, ElementType::PIP, items.at(i), parent));
else
pip_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent));
}
@ -251,6 +318,9 @@ void DesignWidget::newContext(Context *ctx)
for (auto pip : pip_items.toStdMap()) {
pip_root->addChild(pip.second);
}
for (auto pip : nameToItem[2].toStdMap()) {
pip_root->addChild(pip.second);
}
// Add nets to tree
nets_root = new QTreeWidgetItem(treeWidget);
@ -261,6 +331,8 @@ void DesignWidget::newContext(Context *ctx)
cells_root = new QTreeWidgetItem(treeWidget);
cells_root->setText(0, "Cells");
treeWidget->insertTopLevelItem(0, cells_root);
Q_EMIT finishContextLoad();
}
void DesignWidget::updateTree()
@ -268,45 +340,48 @@ void DesignWidget::updateTree()
clearProperties();
delete nets_root;
delete cells_root;
nameToItem[3].clear();
nameToItem[4].clear();
// Add nets to tree
nets_root = new QTreeWidgetItem(treeWidget);
QMap<QString, QTreeWidgetItem *> nets_items;
nets_root->setText(0, "Nets");
treeWidget->insertTopLevelItem(0, nets_root);
if (ctx) {
for (auto &item : ctx->nets) {
auto id = item.first;
QString name = QString(id.c_str(ctx));
nets_items.insert(name, new IdStringTreeItem(id, ElementType::NET, name, nullptr));
IdStringTreeItem *newItem = new IdStringTreeItem(id, ElementType::NET, name, nullptr);
nameToItem[3].insert(name, newItem);
}
}
for (auto item : nets_items.toStdMap()) {
for (auto item : nameToItem[3].toStdMap()) {
nets_root->addChild(item.second);
}
// Add cells to tree
cells_root = new QTreeWidgetItem(treeWidget);
QMap<QString, QTreeWidgetItem *> cells_items;
cells_root->setText(0, "Cells");
treeWidget->insertTopLevelItem(0, cells_root);
if (ctx) {
for (auto &item : ctx->cells) {
auto id = item.first;
QString name = QString(id.c_str(ctx));
cells_items.insert(name, new IdStringTreeItem(id, ElementType::CELL, name, nullptr));
IdStringTreeItem *newItem = new IdStringTreeItem(id, ElementType::CELL, name, nullptr);
nameToItem[4].insert(name, newItem);
}
}
for (auto item : cells_items.toStdMap()) {
for (auto item : nameToItem[4].toStdMap()) {
cells_root->addChild(item.second);
}
}
void DesignWidget::addProperty(QtProperty *property, const QString &id)
QtProperty *DesignWidget::addTopLevelProperty(const QString &id)
{
propertyToId[property] = id;
idToProperty[id] = property;
propertyEditor->addProperty(property);
QtProperty *topItem = groupManager->addProperty(id);
propertyToId[topItem] = id;
idToProperty[id] = topItem;
propertyEditor->addProperty(topItem);
return topItem;
}
void DesignWidget::clearProperties()
@ -320,10 +395,73 @@ void DesignWidget::clearProperties()
idToProperty.clear();
}
QString DesignWidget::getElementTypeName(ElementType type)
{
if (type == ElementType::NONE)
return "";
if (type == ElementType::BEL)
return "BEL";
if (type == ElementType::WIRE)
return "WIRE";
if (type == ElementType::PIP)
return "PIP";
if (type == ElementType::NET)
return "NET";
if (type == ElementType::CELL)
return "CELL";
return "";
}
int DesignWidget::getElementIndex(ElementType type)
{
if (type == ElementType::BEL)
return 0;
if (type == ElementType::WIRE)
return 1;
if (type == ElementType::PIP)
return 2;
if (type == ElementType::NET)
return 3;
if (type == ElementType::CELL)
return 4;
return -1;
}
ElementType DesignWidget::getElementTypeByName(QString type)
{
if (type == "BEL")
return ElementType::BEL;
if (type == "WIRE")
return ElementType::WIRE;
if (type == "PIP")
return ElementType::PIP;
if (type == "NET")
return ElementType::NET;
if (type == "CELL")
return ElementType::CELL;
return ElementType::NONE;
}
void DesignWidget::addProperty(QtProperty *topItem, int propertyType, const QString &name, QVariant value,
const ElementType &type)
{
QtVariantProperty *item = readOnlyManager->addProperty(propertyType, name);
item->setValue(value);
item->setPropertyId(getElementTypeName(type));
topItem->addSubProperty(item);
}
QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name)
{
QtProperty *item = groupManager->addProperty(name);
topItem->addSubProperty(item);
return item;
}
void DesignWidget::onItemSelectionChanged()
{
if (treeWidget->selectedItems().size()== 0) return;
if (treeWidget->selectedItems().size() == 0)
return;
QTreeWidgetItem *clickItem = treeWidget->selectedItems().at(0);
if (!clickItem->parent())
@ -336,36 +474,24 @@ void DesignWidget::onItemSelectionChanged()
std::vector<DecalXY> decals;
addToHistory(clickItem);
clearProperties();
if (type == ElementType::BEL) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
BelId bel = ctx->getBelByName(c);
decals.push_back(ctx->getBelDecal(bel));
decals.push_back(ctx->getBelDecal(bel));
Q_EMIT selected(decals);
QtProperty *topItem = groupManager->addProperty("Bel");
addProperty(topItem, "Bel");
QtProperty *topItem = addTopLevelProperty("Bel");
QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
nameItem->setValue(c.c_str(ctx));
topItem->addSubProperty(nameItem);
QtVariantProperty *typeItem = readOnlyManager->addProperty(QVariant::String, "Type");
typeItem->setValue(ctx->belTypeToId(ctx->getBelType(bel)).c_str(ctx));
topItem->addSubProperty(typeItem);
QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available");
availItem->setValue(ctx->checkBelAvail(bel));
topItem->addSubProperty(availItem);
QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Cell");
cellItem->setValue(ctx->getBoundBelCell(bel).c_str(ctx));
topItem->addSubProperty(cellItem);
QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Cell");
conflictItem->setValue(ctx->getConflictingBelCell(bel).c_str(ctx));
topItem->addSubProperty(conflictItem);
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
addProperty(topItem, QVariant::String, "Type", ctx->belTypeToId(ctx->getBelType(bel)).c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkBelAvail(bel));
addProperty(topItem, QVariant::String, "Bound Cell", ctx->getBoundBelCell(bel).c_str(ctx), ElementType::CELL);
addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->getConflictingBelCell(bel).c_str(ctx),
ElementType::CELL);
} else if (type == ElementType::WIRE) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
@ -374,76 +500,56 @@ void DesignWidget::onItemSelectionChanged()
decals.push_back(ctx->getWireDecal(wire));
Q_EMIT selected(decals);
QtProperty *topItem = groupManager->addProperty("Wire");
addProperty(topItem, "Wire");
QtProperty *topItem = addTopLevelProperty("Wire");
QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
nameItem->setValue(c.c_str(ctx));
topItem->addSubProperty(nameItem);
QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available");
availItem->setValue(ctx->checkWireAvail(wire));
topItem->addSubProperty(availItem);
QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net");
cellItem->setValue(ctx->getBoundWireNet(wire).c_str(ctx));
topItem->addSubProperty(cellItem);
QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net");
conflictItem->setValue(ctx->getConflictingWireNet(wire).c_str(ctx));
topItem->addSubProperty(conflictItem);
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire));
addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundWireNet(wire).c_str(ctx), ElementType::NET);
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingWireNet(wire).c_str(ctx),
ElementType::NET);
QtProperty *belpinItem = addSubGroup(topItem, "BelPin Uphill");
BelPin uphill = ctx->getBelPinUphill(wire);
QtProperty *belpinItem = groupManager->addProperty("BelPin Uphill");
topItem->addSubProperty(belpinItem);
QtVariantProperty *belUphillItem = readOnlyManager->addProperty(QVariant::String, "Bel");
if (uphill.bel != BelId())
belUphillItem->setValue(ctx->getBelName(uphill.bel).c_str(ctx));
addProperty(belpinItem, QVariant::String, "Bel", ctx->getBelName(uphill.bel).c_str(ctx), ElementType::BEL);
else
belUphillItem->setValue("");
belpinItem->addSubProperty(belUphillItem);
addProperty(belpinItem, QVariant::String, "Bel", "", ElementType::BEL);
QtVariantProperty *portUphillItem = readOnlyManager->addProperty(QVariant::String, "PortPin");
portUphillItem->setValue(ctx->portPinToId(uphill.pin).c_str(ctx));
belpinItem->addSubProperty(portUphillItem);
addProperty(belpinItem, QVariant::String, "PortPin", ctx->portPinToId(uphill.pin).c_str(ctx), ElementType::BEL);
QtProperty *downhillItem = groupManager->addProperty("BelPins Downhill");
topItem->addSubProperty(downhillItem);
QtProperty *downhillItem = addSubGroup(topItem, "BelPin Downhill");
for (const auto &item : ctx->getBelPinsDownhill(wire)) {
QString belname = "";
if (item.bel != BelId())
belname = ctx->getBelName(item.bel).c_str(ctx);
QString pinname = ctx->portPinToId(item.pin).c_str(ctx);
QtProperty *dhItem = groupManager->addProperty(belname + "-" + pinname);
downhillItem->addSubProperty(dhItem);
QtVariantProperty *belItem = readOnlyManager->addProperty(QVariant::String, "Bel");
belItem->setValue(belname);
dhItem->addSubProperty(belItem);
QtVariantProperty *portItem = readOnlyManager->addProperty(QVariant::String, "PortPin");
portItem->setValue(pinname);
dhItem->addSubProperty(portItem);
QtProperty *dhItem = addSubGroup(downhillItem, belname + "-" + pinname);
addProperty(dhItem, QVariant::String, "Bel", belname, ElementType::BEL);
addProperty(dhItem, QVariant::String, "PortPin", pinname);
}
/*
QtProperty *pipsDownItem = groupManager->addProperty("Pips Downhill");
topItem->addSubProperty(pipsDownItem);
int counter = 0;
QtProperty *pipsDownItem = addSubGroup(downhillItem, "Pips Downhill");
for (const auto &item : ctx->getPipsDownhill(wire)) {
QtVariantProperty *pipItem = readOnlyManager->addProperty(QVariant::String, "");
pipItem->setValue(ctx->getPipName(item).c_str(ctx));
pipsDownItem->addSubProperty(pipItem);
addProperty(pipsDownItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP);
counter++;
if (counter == 50) {
addProperty(pipsDownItem, QVariant::String, "Warning", "Too many items...", ElementType::NONE);
break;
}
}
QtProperty *pipsUpItem = groupManager->addProperty("Pips Uphill");
topItem->addSubProperty(pipsUpItem);
counter = 0;
QtProperty *pipsUpItem = addSubGroup(downhillItem, "Pips Uphill");
for (const auto &item : ctx->getPipsUphill(wire)) {
QtVariantProperty *pipItem = readOnlyManager->addProperty(QVariant::String, "");
pipItem->setValue(ctx->getPipName(item).c_str(ctx));
pipsUpItem->addSubProperty(pipItem);
addProperty(pipsUpItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP);
counter++;
if (counter == 50) {
addProperty(pipsUpItem, QVariant::String, "Warning", "Too many items...", ElementType::NONE);
break;
}
}
*/
} else if (type == ElementType::PIP) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
PipId pip = ctx->getPipByName(c);
@ -451,199 +557,108 @@ void DesignWidget::onItemSelectionChanged()
decals.push_back(ctx->getPipDecal(pip));
Q_EMIT selected(decals);
QtProperty *topItem = groupManager->addProperty("Pip");
addProperty(topItem, "Pip");
QtProperty *topItem = addTopLevelProperty("Pip");
QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
nameItem->setValue(c.c_str(ctx));
topItem->addSubProperty(nameItem);
QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available");
availItem->setValue(ctx->checkPipAvail(pip));
topItem->addSubProperty(availItem);
QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net");
cellItem->setValue(ctx->getBoundPipNet(pip).c_str(ctx));
topItem->addSubProperty(cellItem);
QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net");
conflictItem->setValue(ctx->getConflictingPipNet(pip).c_str(ctx));
topItem->addSubProperty(conflictItem);
QtVariantProperty *srcWireItem = readOnlyManager->addProperty(QVariant::String, "Src Wire");
srcWireItem->setValue(ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx));
topItem->addSubProperty(srcWireItem);
QtVariantProperty *destWireItem = readOnlyManager->addProperty(QVariant::String, "Dest Wire");
destWireItem->setValue(ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx));
topItem->addSubProperty(destWireItem);
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip));
addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundPipNet(pip).c_str(ctx), ElementType::NET);
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingPipNet(pip).c_str(ctx),
ElementType::NET);
addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),
ElementType::WIRE);
addProperty(topItem, QVariant::String, "Dest Wire", ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx),
ElementType::WIRE);
DelayInfo delay = ctx->getPipDelay(pip);
QtProperty *delayItem = groupManager->addProperty("Delay");
topItem->addSubProperty(delayItem);
QtVariantProperty *raiseDelayItem = readOnlyManager->addProperty(QVariant::Double, "Raise");
raiseDelayItem->setValue(delay.raiseDelay());
delayItem->addSubProperty(raiseDelayItem);
QtVariantProperty *fallDelayItem = readOnlyManager->addProperty(QVariant::Double, "Fall");
fallDelayItem->setValue(delay.fallDelay());
delayItem->addSubProperty(fallDelayItem);
QtVariantProperty *avgDelayItem = readOnlyManager->addProperty(QVariant::Double, "Average");
avgDelayItem->setValue(delay.avgDelay());
delayItem->addSubProperty(avgDelayItem);
QtProperty *delayItem = addSubGroup(topItem, "Delay");
addProperty(delayItem, QVariant::Double, "Raise", delay.raiseDelay());
addProperty(delayItem, QVariant::Double, "Fall", delay.fallDelay());
addProperty(delayItem, QVariant::Double, "Average", delay.avgDelay());
} else if (type == ElementType::NET) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
NetInfo *net = ctx->nets.at(c).get();
QtProperty *topItem = groupManager->addProperty("Net");
addProperty(topItem, "Net");
QtProperty *topItem = addTopLevelProperty("Net");
QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
nameItem->setValue(net->name.c_str(ctx));
topItem->addSubProperty(nameItem);
addProperty(topItem, QVariant::String, "Name", net->name.c_str(ctx));
QtProperty *driverItem = groupManager->addProperty("Driver");
topItem->addSubProperty(driverItem);
QtVariantProperty *portItem = readOnlyManager->addProperty(QVariant::String, "Port");
portItem->setValue(net->driver.port.c_str(ctx));
driverItem->addSubProperty(portItem);
QtVariantProperty *budgetItem = readOnlyManager->addProperty(QVariant::Double, "Budget");
budgetItem->setValue(net->driver.budget);
driverItem->addSubProperty(budgetItem);
QtVariantProperty *cellNameItem = readOnlyManager->addProperty(QVariant::String, "Cell");
QtProperty *driverItem = addSubGroup(topItem, "Driver");
addProperty(driverItem, QVariant::String, "Port", net->driver.port.c_str(ctx));
addProperty(driverItem, QVariant::Double, "Budget", net->driver.budget);
if (net->driver.cell)
cellNameItem->setValue(net->driver.cell->name.c_str(ctx));
addProperty(driverItem, QVariant::String, "Cell", net->driver.cell->name.c_str(ctx), ElementType::CELL);
else
cellNameItem->setValue("");
driverItem->addSubProperty(cellNameItem);
addProperty(driverItem, QVariant::String, "Cell", "", ElementType::CELL);
QtProperty *usersItem = groupManager->addProperty("Users");
topItem->addSubProperty(usersItem);
QtProperty *usersItem = addSubGroup(topItem, "Users");
for (auto &item : net->users) {
QtProperty *portItem = groupManager->addProperty(item.port.c_str(ctx));
usersItem->addSubProperty(portItem);
QtProperty *portItem = addSubGroup(usersItem, item.port.c_str(ctx));
QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Port");
nameItem->setValue(item.port.c_str(ctx));
portItem->addSubProperty(nameItem);
QtVariantProperty *budgetItem = readOnlyManager->addProperty(QVariant::Double, "Budget");
budgetItem->setValue(item.budget);
portItem->addSubProperty(budgetItem);
QtVariantProperty *userItem = readOnlyManager->addProperty(QVariant::String, "Cell");
addProperty(portItem, QVariant::String, "Port", item.port.c_str(ctx));
addProperty(portItem, QVariant::Double, "Budget", item.budget);
if (item.cell)
userItem->setValue(item.cell->name.c_str(ctx));
addProperty(portItem, QVariant::String, "Cell", item.cell->name.c_str(ctx), ElementType::CELL);
else
userItem->setValue("");
portItem->addSubProperty(userItem);
addProperty(portItem, QVariant::String, "Cell", "", ElementType::CELL);
}
QtProperty *attrsItem = groupManager->addProperty("Attributes");
topItem->addSubProperty(attrsItem);
QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
for (auto &item : net->attrs) {
QtVariantProperty *attrItem = readOnlyManager->addProperty(QVariant::String, item.first.c_str(ctx));
attrItem->setValue(item.second.c_str());
attrsItem->addSubProperty(attrItem);
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
}
QtProperty *wiresItem = groupManager->addProperty("Wires");
topItem->addSubProperty(wiresItem);
QtProperty *wiresItem = addSubGroup(topItem, "Wires");
for (auto &item : net->wires) {
auto name = ctx->getWireName(item.first).c_str(ctx);
QtProperty *wireItem = groupManager->addProperty(name);
QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name");
nameItem->setValue(name);
wireItem->addSubProperty(nameItem);
QtVariantProperty *pipItem = readOnlyManager->addProperty(QVariant::String, "Pip");
QtProperty *wireItem = addSubGroup(wiresItem, name);
addProperty(wireItem, QVariant::String, "Name", name);
if (item.second.pip != PipId())
pipItem->setValue(ctx->getPipName(item.second.pip).c_str(ctx));
addProperty(wireItem, QVariant::String, "Pip", ctx->getPipName(item.second.pip).c_str(ctx),
ElementType::PIP);
else
pipItem->setValue("");
wireItem->addSubProperty(pipItem);
addProperty(wireItem, QVariant::String, "Pip", "", ElementType::PIP);
QtVariantProperty *strengthItem = readOnlyManager->addProperty(QVariant::Int, "Strength");
strengthItem->setValue((int)item.second.strength);
wireItem->addSubProperty(strengthItem);
wiresItem->addSubProperty(wireItem);
addProperty(wireItem, QVariant::Int, "Strength", (int)item.second.strength);
}
} else if (type == ElementType::CELL) {
IdString c = static_cast<IdStringTreeItem *>(clickItem)->getData();
CellInfo *cell = ctx->cells.at(c).get();
QtProperty *topItem = groupManager->addProperty("Cell");
addProperty(topItem, "Cell");
QtProperty *topItem = addTopLevelProperty("Cell");
QtVariantProperty *cellNameItem = readOnlyManager->addProperty(QVariant::String, "Name");
cellNameItem->setValue(cell->name.c_str(ctx));
topItem->addSubProperty(cellNameItem);
QtVariantProperty *cellTypeItem = readOnlyManager->addProperty(QVariant::String, "Type");
cellTypeItem->setValue(cell->type.c_str(ctx));
topItem->addSubProperty(cellTypeItem);
QtVariantProperty *cellBelItem = readOnlyManager->addProperty(QVariant::String, "Bel");
addProperty(topItem, QVariant::String, "Name", cell->name.c_str(ctx));
addProperty(topItem, QVariant::String, "Type", cell->type.c_str(ctx));
if (cell->bel != BelId())
cellBelItem->setValue(ctx->getBelName(cell->bel).c_str(ctx));
addProperty(topItem, QVariant::String, "Bel", ctx->getBelName(cell->bel).c_str(ctx), ElementType::BEL);
else
cellBelItem->setValue("");
topItem->addSubProperty(cellBelItem);
addProperty(topItem, QVariant::String, "Bel", "", ElementType::BEL);
addProperty(topItem, QVariant::Int, "Bel strength", int(cell->belStrength));
QtVariantProperty *cellBelStrItem = readOnlyManager->addProperty(QVariant::Int, "Bel strength");
cellBelStrItem->setValue(int(cell->belStrength));
topItem->addSubProperty(cellBelStrItem);
QtProperty *cellPortsItem = groupManager->addProperty("Ports");
topItem->addSubProperty(cellPortsItem);
QtProperty *cellPortsItem = addSubGroup(topItem, "Ports");
for (auto &item : cell->ports) {
PortInfo p = item.second;
QtProperty *portInfoItem = groupManager->addProperty(p.name.c_str(ctx));
QtVariantProperty *portInfoNameItem = readOnlyManager->addProperty(QVariant::String, "Name");
portInfoNameItem->setValue(p.name.c_str(ctx));
portInfoItem->addSubProperty(portInfoNameItem);
QtVariantProperty *portInfoTypeItem = readOnlyManager->addProperty(QVariant::Int, "Type");
portInfoTypeItem->setValue(int(p.type));
portInfoItem->addSubProperty(portInfoTypeItem);
QtVariantProperty *portInfoNetItem = readOnlyManager->addProperty(QVariant::String, "Net");
QtProperty *portInfoItem = addSubGroup(cellPortsItem, p.name.c_str(ctx));
addProperty(portInfoItem, QVariant::String, "Name", p.name.c_str(ctx));
addProperty(portInfoItem, QVariant::Int, "Type", int(p.type));
if (p.net)
portInfoNetItem->setValue(p.net->name.c_str(ctx));
addProperty(portInfoItem, QVariant::String, "Net", p.net->name.c_str(ctx), ElementType::NET);
else
portInfoNetItem->setValue("");
portInfoItem->addSubProperty(portInfoNetItem);
cellPortsItem->addSubProperty(portInfoItem);
addProperty(portInfoItem, QVariant::String, "Net", "", ElementType::NET);
}
QtProperty *cellAttrItem = groupManager->addProperty("Attributes");
topItem->addSubProperty(cellAttrItem);
QtProperty *cellAttrItem = addSubGroup(topItem, "Attributes");
for (auto &item : cell->attrs) {
QtVariantProperty *attrItem = readOnlyManager->addProperty(QVariant::String, item.first.c_str(ctx));
attrItem->setValue(item.second.c_str());
cellAttrItem->addSubProperty(attrItem);
addProperty(cellAttrItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
}
QtProperty *cellParamsItem = groupManager->addProperty("Parameters");
topItem->addSubProperty(cellParamsItem);
QtProperty *cellParamsItem = addSubGroup(topItem, "Parameters");
for (auto &item : cell->params) {
QtVariantProperty *paramItem = readOnlyManager->addProperty(QVariant::String, item.first.c_str(ctx));
paramItem->setValue(item.second.c_str());
cellParamsItem->addSubProperty(paramItem);
addProperty(cellParamsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
}
QtProperty *cellPinsItem = groupManager->addProperty("Pins");
@ -652,38 +667,159 @@ void DesignWidget::onItemSelectionChanged()
std::string cell_port = item.first.c_str(ctx);
std::string bel_pin = item.second.c_str(ctx);
QtProperty *pinGroupItem = groupManager->addProperty((cell_port + " -> " + bel_pin).c_str());
QtProperty *pinGroupItem = addSubGroup(cellPortsItem, (cell_port + " -> " + bel_pin).c_str());
QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Cell");
cellItem->setValue(cell_port.c_str());
pinGroupItem->addSubProperty(cellItem);
QtVariantProperty *belItem = readOnlyManager->addProperty(QVariant::String, "Bel");
belItem->setValue(bel_pin.c_str());
pinGroupItem->addSubProperty(belItem);
cellPinsItem->addSubProperty(pinGroupItem);
addProperty(pinGroupItem, QVariant::String, "Cell", cell_port.c_str(), ElementType::CELL);
addProperty(pinGroupItem, QVariant::String, "Bel", bel_pin.c_str(), ElementType::BEL);
}
}
}
void DesignWidget::prepareMenu(const QPoint &pos)
std::vector<DecalXY> DesignWidget::getDecals(ElementType type, IdString value)
{
std::vector<DecalXY> decals;
switch (type) {
case ElementType::BEL: {
BelId bel = ctx->getBelByName(value);
if (bel != BelId()) {
decals.push_back(ctx->getBelDecal(bel));
}
} break;
case ElementType::WIRE: {
WireId wire = ctx->getWireByName(value);
if (wire != WireId()) {
decals.push_back(ctx->getWireDecal(wire));
Q_EMIT selected(decals);
}
} break;
case ElementType::PIP: {
PipId pip = ctx->getPipByName(value);
if (pip != PipId()) {
decals.push_back(ctx->getPipDecal(pip));
Q_EMIT selected(decals);
}
} break;
case ElementType::NET: {
} break;
case ElementType::CELL: {
} break;
default:
break;
}
return decals;
}
void DesignWidget::updateHighlightGroup(QTreeWidgetItem *item, int group)
{
if (highlightSelected.contains(item)) {
if (highlightSelected[item] == group) {
highlightSelected.remove(item);
} else
highlightSelected[item] = group;
} else
highlightSelected.insert(item, group);
std::vector<DecalXY> decals;
for (auto it : highlightSelected.toStdMap()) {
if (it.second == group) {
ElementType type = static_cast<ElementTreeItem *>(it.first)->getType();
IdString value = static_cast<IdStringTreeItem *>(it.first)->getData();
std::vector<DecalXY> d = getDecals(type, value);
std::move(d.begin(), d.end(), std::back_inserter(decals));
}
}
Q_EMIT highlight(decals, group);
}
void DesignWidget::prepareMenuProperty(const QPoint &pos)
{
QTreeWidget *tree = propertyEditor->treeWidget();
itemContextMenu = tree->itemAt(pos);
if (itemContextMenu->parent() == nullptr)
return;
QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu);
if (!browserItem)
return;
QtProperty *selectedProperty = browserItem->property();
ElementType type = getElementTypeByName(selectedProperty->propertyId());
if (type == ElementType::NONE)
return;
IdString value = ctx->id(selectedProperty->valueText().toStdString());
QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx));
QMenu menu(this);
QAction *selectAction = new QAction("&Select", this);
connect(selectAction, &QAction::triggered, this, [this, type, value] { Q_EMIT selected(getDecals(type, value)); });
menu.addAction(selectAction);
QMenu *subMenu = menu.addMenu("Highlight");
QActionGroup *group = new QActionGroup(this);
group->setExclusive(true);
for (int i = 0; i < 8; i++) {
QPixmap pixmap(32, 32);
pixmap.fill(QColor(highlightColors[i]));
QAction *action = new QAction(QIcon(pixmap), ("Group " + std::to_string(i)).c_str(), this);
action->setCheckable(true);
subMenu->addAction(action);
group->addAction(action);
if (highlightSelected.contains(item) && highlightSelected[item] == i)
action->setChecked(true);
connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); });
}
menu.exec(tree->mapToGlobal(pos));
}
void DesignWidget::prepareMenuTree(const QPoint &pos)
{
QTreeWidget *tree = treeWidget;
itemContextMenu = tree->itemAt(pos);
QAction *selectAction = new QAction("&Select", this);
selectAction->setStatusTip("Select item on view");
ElementType type = static_cast<ElementTreeItem *>(itemContextMenu)->getType();
IdString value = static_cast<IdStringTreeItem *>(itemContextMenu)->getData();
connect(selectAction, SIGNAL(triggered()), this, SLOT(selectObject()));
if (type == ElementType::NONE)
return;
QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx));
QMenu menu(this);
menu.addAction(selectAction);
QMenu *subMenu = menu.addMenu("Highlight");
QActionGroup *group = new QActionGroup(this);
group->setExclusive(true);
for (int i = 0; i < 8; i++) {
QPixmap pixmap(32, 32);
pixmap.fill(QColor(highlightColors[i]));
QAction *action = new QAction(QIcon(pixmap), ("Group " + std::to_string(i)).c_str(), this);
action->setCheckable(true);
subMenu->addAction(action);
group->addAction(action);
if (highlightSelected.contains(item) && highlightSelected[item] == i)
action->setChecked(true);
connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); });
}
menu.exec(tree->mapToGlobal(pos));
}
void DesignWidget::selectObject() { Q_EMIT info("selected " + itemContextMenu->text(0).toStdString() + "\n"); }
void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column)
{
QtProperty *selectedProperty = propertyEditor->itemToBrowserItem(item)->property();
ElementType type = getElementTypeByName(selectedProperty->propertyId());
QString value = selectedProperty->valueText();
int index = getElementIndex(type);
switch (type) {
case ElementType::NONE:
return;
default: {
if (nameToItem[index].contains(value))
treeWidget->setCurrentItem(nameToItem[index].value(value));
} break;
}
}
NEXTPNR_NAMESPACE_END

View File

@ -21,6 +21,7 @@
#define DESIGNWIDGET_H
#include <QTreeWidget>
#include <QVariant>
#include "nextpnr.h"
#include "qtgroupboxpropertybrowser.h"
#include "qtpropertymanager.h"
@ -29,6 +30,16 @@
NEXTPNR_NAMESPACE_BEGIN
enum class ElementType
{
NONE,
BEL,
WIRE,
PIP,
NET,
CELL
};
class DesignWidget : public QWidget
{
Q_OBJECT
@ -38,17 +49,30 @@ class DesignWidget : public QWidget
~DesignWidget();
private:
void addProperty(QtProperty *property, const QString &id);
void clearProperties();
QtProperty *addTopLevelProperty(const QString &id);
QtProperty *addSubGroup(QtProperty *topItem, const QString &name);
void addProperty(QtProperty *topItem, int propertyType, const QString &name, QVariant value,
const ElementType &type = ElementType::NONE);
QString getElementTypeName(ElementType type);
ElementType getElementTypeByName(QString type);
int getElementIndex(ElementType type);
void updateButtons();
void addToHistory(QTreeWidgetItem *item);
std::vector<DecalXY> getDecals(ElementType type, IdString value);
void updateHighlightGroup(QTreeWidgetItem *item, int group);
Q_SIGNALS:
void info(std::string text);
void selected(std::vector<DecalXY> decal);
void highlight(std::vector<DecalXY> decal, int group);
void finishContextLoad();
void contextLoadStatus(std::string text);
private Q_SLOTS:
void prepareMenu(const QPoint &pos);
void prepareMenuProperty(const QPoint &pos);
void prepareMenuTree(const QPoint &pos);
void onItemSelectionChanged();
void selectObject();
void onItemDoubleClicked(QTreeWidgetItem *item, int column);
public Q_SLOTS:
void newContext(Context *ctx);
void updateTree();
@ -67,6 +91,12 @@ class DesignWidget : public QWidget
QMap<QtProperty *, QString> propertyToId;
QMap<QString, QtProperty *> idToProperty;
QMap<QString, QTreeWidgetItem *> nameToItem[6];
std::vector<QTreeWidgetItem *> history;
int history_index;
bool history_ignore;
QTreeWidgetItem *nets_root;
QTreeWidgetItem *cells_root;
@ -74,6 +104,9 @@ class DesignWidget : public QWidget
QAction *actionPrev;
QAction *actionNext;
QAction *actionLast;
QColor highlightColors[8];
QMap<QTreeWidgetItem *, int> highlightSelected;
};
NEXTPNR_NAMESPACE_END

View File

@ -240,7 +240,8 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, float thi
vao_.release();
}
FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged(false)
FPGAViewWidget::FPGAViewWidget(QWidget *parent)
: QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged_(false)
{
backgroundColor_ = QColor("#000000");
gridColor_ = QColor("#333");
@ -250,6 +251,16 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineSha
gActiveColor_ = QColor("#f0f0f0");
gSelectedColor_ = QColor("#ff6600");
frameColor_ = QColor("#0066ba");
highlightColors[0] = QColor("#6495ed");
highlightColors[1] = QColor("#7fffd4");
highlightColors[2] = QColor("#98fb98");
highlightColors[3] = QColor("#ffd700");
highlightColors[4] = QColor("#cd5c5c");
highlightColors[5] = QColor("#fa8072");
highlightColors[6] = QColor("#ff69b4");
highlightColors[7] = QColor("#da70d6");
for (int i = 0; i < 8; i++)
highlightItemsChanged_[i] = false;
auto fmt = format();
fmt.setMajorVersion(3);
@ -272,6 +283,7 @@ FPGAViewWidget::~FPGAViewWidget() {}
void FPGAViewWidget::newContext(Context *ctx)
{
ctx_ = ctx;
selectedItems_.clear();
update();
}
@ -411,27 +423,44 @@ void FPGAViewWidget::paintGL()
drawDecal(shaders, ctx_->getGroupDecal(group));
}
if (selectedItemsChanged)
{
selectedItemsChanged = false;
if (selectedItemsChanged_) {
selectedItemsChanged_ = false;
selectedShader_.clear();
for (auto decal : selectedItems_) {
drawDecal(selectedShader_, decal);
}
}
for (int i = 0; i < 8; i++) {
if (highlightItemsChanged_[i]) {
highlightItemsChanged_[i] = false;
highlightShader_[i].clear();
for (auto decal : highlightItems_[i]) {
drawDecal(highlightShader_[i], decal);
}
}
}
}
lineShader_.draw(shaders[0], gFrameColor_, thick11Px, matrix);
lineShader_.draw(shaders[1], gHiddenColor_, thick11Px, matrix);
lineShader_.draw(shaders[2], gInactiveColor_, thick11Px, matrix);
lineShader_.draw(shaders[3], gActiveColor_, thick11Px, matrix);
for (int i = 0; i < 8; i++)
lineShader_.draw(highlightShader_[i], highlightColors[i], thick11Px, matrix);
lineShader_.draw(selectedShader_, gSelectedColor_, thick11Px, matrix);
}
void FPGAViewWidget::onSelectedArchItem(std::vector<DecalXY> decals)
{
selectedItems_ = decals;
selectedItemsChanged = true;
selectedItemsChanged_ = true;
update();
}
void FPGAViewWidget::onHighlightGroupChanged(std::vector<DecalXY> decals, int group)
{
highlightItems_[group] = decals;
highlightItemsChanged_[group] = true;
update();
}

View File

@ -245,6 +245,8 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
public Q_SLOTS:
void newContext(Context *ctx);
void onSelectedArchItem(std::vector<DecalXY> decals);
void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
private:
QPoint lastPos_;
LineShader lineShader_;
@ -272,7 +274,12 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
LineShaderData selectedShader_;
std::vector<DecalXY> selectedItems_;
bool selectedItemsChanged;
bool selectedItemsChanged_;
LineShaderData highlightShader_[8];
std::vector<DecalXY> highlightItems_[8];
bool highlightItemsChanged_[8];
QColor highlightColors[8];
};
NEXTPNR_NAMESPACE_END

View File

@ -71,43 +71,43 @@ void MainWindow::createMenu()
QMenu *menu_Design = new QMenu("&Design", menuBar);
menuBar->addAction(menu_Design->menuAction());
actionLoadJSON = new QAction("Open JSON", this);
actionLoadJSON = new QAction("Open JSON", this);
actionLoadJSON->setIcon(QIcon(":/icons/resources/open_json.png"));
actionLoadJSON->setStatusTip("Open an existing JSON file");
actionLoadJSON->setEnabled(true);
connect(actionLoadJSON, SIGNAL(triggered()), this, SLOT(open_json()));
actionLoadPCF = new QAction("Open PCF", this);
actionLoadPCF = 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 = 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 = 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 = 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 = new QAction("Route", this);
actionRoute->setIcon(QIcon(":/icons/resources/route.png"));
actionRoute->setStatusTip("Route current design");
actionRoute->setEnabled(false);
connect(actionRoute, SIGNAL(triggered()), task, SIGNAL(route()));
actionSaveAsc = new QAction("Save ASC", this);
actionSaveAsc = new QAction("Save ASC", this);
actionSaveAsc->setIcon(QIcon(":/icons/resources/save_asc.png"));
actionSaveAsc->setStatusTip("Save ASC file");
actionSaveAsc->setEnabled(false);
@ -132,19 +132,19 @@ void MainWindow::createMenu()
menu_Design->addAction(actionRoute);
menu_Design->addAction(actionSaveAsc);
actionPlay = new QAction("Play", this);
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 = 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 = new QAction("Stop", this);
actionStop->setIcon(QIcon(":/icons/resources/control_stop.png"));
actionStop->setStatusTip("Stop running task");
actionStop->setEnabled(false);
@ -226,6 +226,7 @@ void MainWindow::new_proj()
ctx = std::unique_ptr<Context>(new Context(chipArgs));
actionLoadJSON->setEnabled(true);
Q_EMIT displaySplash();
Q_EMIT contextChanged(ctx.get());
}
}

BIN
gui/resources/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -334,6 +334,7 @@ IdString Arch::getPipName(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
#if 1
int x = chip_info->pip_data[pip.index].x;
int y = chip_info->pip_data[pip.index].y;
@ -344,6 +345,9 @@ IdString Arch::getPipName(PipId pip) const
std::replace(dst_name.begin(), dst_name.end(), '/', '.');
return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name);
#else
return id(chip_info->pip_data[pip.index].name.get());
#endif
}
// -----------------------------------------------------------------------
@ -480,9 +484,9 @@ DecalXY Arch::getWireDecal(WireId wire) const
DecalXY Arch::getPipDecal(PipId pip) const
{
DecalXY decalxy;
decalxy.decal.type = DecalId::TYPE_PIP;
decalxy.decal.index = pip.index;
decalxy.decal.active = pip_to_net.at(pip.index) != IdString();
// decalxy.decal.type = DecalId::TYPE_PIP;
// decalxy.decal.index = pip.index;
// decalxy.decal.active = pip_to_net.at(pip.index) != IdString();
return decalxy;
};
@ -512,11 +516,8 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
}
if (decal.type == DecalId::TYPE_WIRE) {
WireId wire;
wire.index = decal.index;
int n = chip_info->wire_data[wire.index].num_segments;
const WireSegmentPOD *p = chip_info->wire_data[wire.index].segments.get();
int n = chip_info->wire_data[decal.index].num_segments;
const WireSegmentPOD *p = chip_info->wire_data[decal.index].segments.get();
GraphicElement::style_t style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE;
@ -524,6 +525,12 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style);
}
if (decal.type == DecalId::TYPE_PIP) {
const PipInfoPOD &p = chip_info->pip_data[decal.index];
GraphicElement::style_t style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_HIDDEN;
gfxTilePip(ret, p.x, p.y, GfxTileWireId(p.src_seg), GfxTileWireId(p.dst_seg), style);
}
if (decal.type == DecalId::TYPE_BEL) {
BelId bel;
bel.index = decal.index;

View File

@ -63,9 +63,11 @@ NPNR_PACKED_STRUCT(struct BelPortPOD {
});
NPNR_PACKED_STRUCT(struct PipInfoPOD {
// RelPtr<char> name;
int32_t src, dst;
int32_t delay;
int8_t x, y;
int16_t src_seg, dst_seg;
int16_t switch_mask;
int32_t switch_index;
});

View File

@ -390,9 +390,9 @@ with open(args.filename, "r") as f:
wire_xy[mode[1]] = list()
wire_xy[mode[1]].append((int(line[0]), int(line[1])))
if mode[1] not in wire_segments:
wire_segments[mode[1]] = set()
wire_segments[mode[1]] = dict()
if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids:
wire_segments[mode[1]].add((wname[0], wname[1], gfx_wire_ids["TILE_WIRE_" + wname[2].upper().replace("/", "_")]))
wire_segments[mode[1]][(wname[0], wname[1])] = wname[2]
continue
if mode[0] in ("buffer", "routing"):
@ -1077,6 +1077,7 @@ for wire, info in enumerate(wireinfo):
bba.r("wire_segments_%d" % wire, "segments")
else:
bba.u32(0, "segments")
bba.u8(info["x"], "x")
bba.u8(info["y"], "y")
bba.u8(wiretypes[wire_type(info["name"])], "type")
@ -1085,18 +1086,35 @@ for wire, info in enumerate(wireinfo):
for wire in range(num_wires):
if len(wire_segments[wire]):
bba.l("wire_segments_%d" % wire, "WireSegmentPOD")
for seg in sorted(wire_segments[wire]):
bba.u8(seg[0], "x")
bba.u8(seg[1], "y")
bba.u16(seg[2], "index")
for xy, seg in sorted(wire_segments[wire].items()):
bba.u8(xy[0], "x")
bba.u8(xy[1], "y")
bba.u16(gfx_wire_ids["TILE_WIRE_" + seg.upper().replace("/", "_")], "index")
bba.l("pip_data_%s" % dev_name, "PipInfoPOD")
for info in pipinfo:
src_seg = -1
src_segname = wire_names_r[info["src"]]
if (info["x"], info["y"]) in wire_segments[info["src"]]:
src_segname = wire_segments[info["src"]][(info["x"], info["y"])]
src_seg = gfx_wire_ids["TILE_WIRE_" + src_segname.upper().replace("/", "_")]
src_segname = src_segname.replace("/", ".")
dst_seg = -1
dst_segname = wire_names_r[info["dst"]]
if (info["x"], info["y"]) in wire_segments[info["dst"]]:
dst_segname = wire_segments[info["dst"]][(info["x"], info["y"])]
dst_seg = gfx_wire_ids["TILE_WIRE_" + dst_segname.upper().replace("/", "_")]
dst_segname = dst_segname.replace("/", ".")
# bba.s("X%d/Y%d/%s->%s" % (info["x"], info["y"], src_segname, dst_segname), "name")
bba.u32(info["src"], "src")
bba.u32(info["dst"], "dst")
bba.u32(info["delay"], "delay")
bba.u8(info["x"], "x")
bba.u8(info["y"], "y")
bba.u16(src_seg, "src_seg")
bba.u16(dst_seg, "dst_seg")
bba.u16(info["switch_mask"], "switch_mask")
bba.u32(info["switch_index"], "switch_index")

View File

@ -485,4 +485,223 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
}
}
static bool getWireXY_main(GfxTileWireId id, float &x, float &y)
{
// Horizontal Span-4 Wires
if (id >= TILE_WIRE_SP4_H_L_36 && id <= TILE_WIRE_SP4_H_L_47) {
int idx = (id - TILE_WIRE_SP4_H_L_36) + 48;
x = main_swbox_x1 + 0.0025 * (idx + 35);
y = main_swbox_y2;
return true;
}
if (id >= TILE_WIRE_SP4_H_R_0 && id <= TILE_WIRE_SP4_H_R_47) {
int idx = id - TILE_WIRE_SP4_H_R_0;
x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35);
y = main_swbox_y2;
return true;
}
// Vertical Span-4 Wires
if (id >= TILE_WIRE_SP4_V_T_36 && id <= TILE_WIRE_SP4_V_T_47) {
int idx = (id - TILE_WIRE_SP4_V_T_36) + 48;
y = 1.0 - (0.03 + 0.0025 * (270 - idx));
x = main_swbox_x1;
return true;
}
if (id >= TILE_WIRE_SP4_V_B_0 && id <= TILE_WIRE_SP4_V_B_47) {
int idx = id - TILE_WIRE_SP4_V_B_0;
y = 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1)));
x = main_swbox_x1;
return true;
}
// Horizontal Span-12 Wires
if (id >= TILE_WIRE_SP12_H_L_22 && id <= TILE_WIRE_SP12_H_L_23) {
int idx = (id - TILE_WIRE_SP12_H_L_22) + 24;
x = main_swbox_x1 + 0.0025 * (idx + 5);
y = main_swbox_y2;
return true;
}
if (id >= TILE_WIRE_SP12_H_R_0 && id <= TILE_WIRE_SP12_H_R_23) {
int idx = id - TILE_WIRE_SP12_H_R_0;
x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5);
y = main_swbox_y2;
return true;
}
// Vertical Right Span-4
if (id >= TILE_WIRE_SP4_R_V_B_0 && id <= TILE_WIRE_SP4_R_V_B_47) {
int idx = id - TILE_WIRE_SP4_R_V_B_0;
y = 1.0 - (0.03 + 0.0025 * (145 - (idx ^ 1)));
x = main_swbox_x2;
return true;
}
// Vertical Span-12 Wires
if (id >= TILE_WIRE_SP12_V_T_22 && id <= TILE_WIRE_SP12_V_T_23) {
int idx = (id - TILE_WIRE_SP12_V_T_22) + 24;
y = 1.0 - (0.03 + 0.0025 * (300 - idx));
x = main_swbox_x1;
return true;
}
if (id >= TILE_WIRE_SP12_V_B_0 && id <= TILE_WIRE_SP12_V_B_23) {
int idx = id - TILE_WIRE_SP12_V_B_0;
y = 1.0 - (0.03 + 0.0025 * (300 - (idx ^ 1)));
x = main_swbox_x1;
return true;
}
// Global2Local
if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) {
int idx = id - TILE_WIRE_GLB2LOCAL_0;
x = main_swbox_x1 + 0.005 * (idx + 5);
y = main_swbox_y1;
return true;
}
// GlobalNets
if (id >= TILE_WIRE_GLB_NETWK_0 && id <= TILE_WIRE_GLB_NETWK_7) {
int idx = id - TILE_WIRE_GLB_NETWK_0;
x = main_swbox_x1;
y = main_swbox_y1 + 0.005 * (13 - idx);
return true;
}
// Neighbours
if (id >= TILE_WIRE_NEIGH_OP_BNL_0 && id <= TILE_WIRE_NEIGH_OP_TOP_7) {
int idx = id - TILE_WIRE_NEIGH_OP_BNL_0;
y = main_swbox_y2 - (0.0025 * (idx + 10) + 0.01 * (idx / 8));
x = main_swbox_x1;
return true;
}
// Local Tracks
if (id >= TILE_WIRE_LOCAL_G0_0 && id <= TILE_WIRE_LOCAL_G3_7) {
int idx = id - TILE_WIRE_LOCAL_G0_0;
float yoff = (local_swbox_y1 + local_swbox_y2) / 2 - 0.005 * 16 - 0.075;
x = main_swbox_x2;
y = yoff + 0.005 * idx + 0.05 * (idx / 8);
return true;
}
// LC Outputs
if (id >= TILE_WIRE_LUTFF_0_OUT && id <= TILE_WIRE_LUTFF_7_OUT) {
int idx = id - TILE_WIRE_LUTFF_0_OUT;
y = 1.0 - (0.03 + 0.0025 * (152 + idx));
x = main_swbox_x2;
return true;
}
// LC Control
if (id >= TILE_WIRE_LUTFF_GLOBAL_CEN && id <= TILE_WIRE_LUTFF_GLOBAL_S_R) {
int idx = id - TILE_WIRE_LUTFF_GLOBAL_CEN;
x = main_swbox_x2 - 0.005 * (idx + 5);
y = main_swbox_y1;
return true;
}
return false;
}
static bool getWireXY_local(GfxTileWireId id, float &x, float &y)
{
if (id >= TILE_WIRE_LOCAL_G0_0 && id <= TILE_WIRE_LOCAL_G3_7) {
int idx = id - TILE_WIRE_LOCAL_G0_0;
float yoff = (local_swbox_y1 + local_swbox_y2) / 2 - 0.005 * 16 - 0.075;
x = local_swbox_x1;
y = yoff + 0.005 * idx + 0.05 * (idx / 8);
return true;
}
if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_7_IN_3) {
int idx = id - TILE_WIRE_LUTFF_0_IN_0;
int z = idx / 4;
int input = idx % 4;
x = local_swbox_x2;
y = (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch;
return true;
}
return false;
}
void pipGfx(std::vector<GraphicElement> &g, int x, int y,
float x1, float y1, float x2, float y2,
float swx1, float swy1, float swx2, float swy2,
GraphicElement::style_t style)
{
float tx = 0.5 * (x1 + x2);
float ty = 0.5 * (y1 + y2);
GraphicElement el;
el.type = GraphicElement::G_LINE;
el.style = style;
if (fabsf(x1 - swx1) < 0.001 && fabsf(x2 - swx1) < 0.001) {
tx = x1 + 0.25 * fabsf(y1 - y2);
goto edge_pip;
}
if (fabsf(x1 - swx2) < 0.001 && fabsf(x2 - swx2) < 0.001) {
tx = x1 - 0.25 * fabsf(y1 - y2);
goto edge_pip;
}
if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) {
ty = y1 + 0.25 * fabsf(x1 - x2);
goto edge_pip;
}
if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) {
ty = y1 + 0.25 * fabsf(x1 - x2);
goto edge_pip;
}
el.x1 = x + x1;
el.y1 = y + y1;
el.x2 = x + x2;
el.y2 = y + y2;
g.push_back(el);
return;
edge_pip:
el.x1 = x + x1;
el.y1 = y + y1;
el.x2 = x + tx;
el.y2 = y + ty;
g.push_back(el);
el.x1 = x + tx;
el.y1 = y + ty;
el.x2 = x + x2;
el.y2 = y + y2;
g.push_back(el);
}
void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, GraphicElement::style_t style)
{
float x1, y1, x2, y2;
if (getWireXY_main(src, x1, y1) && getWireXY_main(dst, x2, y2))
pipGfx(g, x, y, x1, y1, x2, y2, main_swbox_x1, main_swbox_y1, main_swbox_x2, main_swbox_y2, style);
if (getWireXY_local(src, x1, y1) && getWireXY_local(dst, x2, y2))
pipGfx(g, x, y, x1, y1, x2, y2, local_swbox_x1, local_swbox_y1, local_swbox_x2, local_swbox_y2, style);
}
NEXTPNR_NAMESPACE_END

View File

@ -468,6 +468,7 @@ enum GfxTileWireId
};
void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style);
void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, GraphicElement::style_t style);
NEXTPNR_NAMESPACE_END