aboutsummaryrefslogtreecommitdiffstats
path: root/gui
diff options
context:
space:
mode:
Diffstat (limited to 'gui')
-rw-r--r--gui/designwidget.cc30
-rw-r--r--gui/designwidget.h6
-rw-r--r--gui/treemodel.cc189
-rw-r--r--gui/treemodel.h114
4 files changed, 144 insertions, 195 deletions
diff --git a/gui/designwidget.cc b/gui/designwidget.cc
index 249df423..ad1362c8 100644
--- a/gui/designwidget.cc
+++ b/gui/designwidget.cc
@@ -51,10 +51,11 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel
propertyEditor->treeWidget()->setContextMenuPolicy(Qt::CustomContextMenu);
propertyEditor->treeWidget()->setSelectionMode(QAbstractItemView::ExtendedSelection);
- QLineEdit *lineEdit = new QLineEdit();
- lineEdit->setClearButtonEnabled(true);
- lineEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition);
- lineEdit->setPlaceholderText("Search...");
+ searchEdit = new QLineEdit();
+ searchEdit->setClearButtonEnabled(true);
+ searchEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition);
+ searchEdit->setPlaceholderText("Search...");
+ connect(searchEdit, SIGNAL(returnPressed()), this, SLOT(onSearchInserted()));
actionFirst = new QAction("", this);
actionFirst->setIcon(QIcon(":/icons/resources/resultset_first.png"));
@@ -123,7 +124,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel
topWidget->setLayout(vbox1);
vbox1->setSpacing(5);
vbox1->setContentsMargins(0, 0, 0, 0);
- vbox1->addWidget(lineEdit);
+ vbox1->addWidget(searchEdit);
vbox1->addWidget(treeView);
QWidget *toolbarWidget = new QWidget();
@@ -214,7 +215,7 @@ void DesignWidget::newContext(Context *ctx)
highlightSelected.clear();
this->ctx = ctx;
- treeModel->loadData(ctx);
+ treeModel->loadContext(ctx);
updateTree();
}
@@ -234,7 +235,7 @@ void DesignWidget::updateTree()
}
}
- treeModel->updateData(ctx);
+ treeModel->updateCellsNets(ctx);
}
QtProperty *DesignWidget::addTopLevelProperty(const QString &id)
{
@@ -714,4 +715,19 @@ void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column)
}
void DesignWidget::onDoubleClicked(const QModelIndex &index) { Q_EMIT zoomSelected(); }
+
+void DesignWidget::onSearchInserted()
+{
+ if (currentSearch == searchEdit->text()) {
+ currentIndex++;
+ if (currentIndex >= currentSearchIndexes.size())
+ currentIndex = 0;
+ } else {
+ currentSearch = searchEdit->text();
+ currentSearchIndexes = treeModel->search(searchEdit->text());
+ currentIndex = 0;
+ }
+ if (currentSearchIndexes.size() > 0 && currentIndex < currentSearchIndexes.size())
+ selectionModel->setCurrentIndex(currentSearchIndexes.at(currentIndex), QItemSelectionModel::ClearAndSelect);
+}
NEXTPNR_NAMESPACE_END
diff --git a/gui/designwidget.h b/gui/designwidget.h
index b229a8a8..d6af83a0 100644
--- a/gui/designwidget.h
+++ b/gui/designwidget.h
@@ -64,6 +64,7 @@ class DesignWidget : public QWidget
void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void onItemDoubleClicked(QTreeWidgetItem *item, int column);
void onDoubleClicked(const QModelIndex &index);
+ void onSearchInserted();
public Q_SLOTS:
void newContext(Context *ctx);
void updateTree();
@@ -77,6 +78,7 @@ class DesignWidget : public QWidget
QTreeView *treeView;
QItemSelectionModel *selectionModel;
ContextTreeModel *treeModel;
+ QLineEdit *searchEdit;
QtVariantPropertyManager *variantManager;
QtVariantPropertyManager *readOnlyManager;
QtGroupPropertyManager *groupManager;
@@ -98,6 +100,10 @@ class DesignWidget : public QWidget
QColor highlightColors[8];
QMap<LazyTreeItem *, int> highlightSelected;
+
+ QString currentSearch;
+ QList<QModelIndex> currentSearchIndexes;
+ int currentIndex;
};
NEXTPNR_NAMESPACE_END
diff --git a/gui/treemodel.cc b/gui/treemodel.cc
index 9a501eb9..fd3ae45b 100644
--- a/gui/treemodel.cc
+++ b/gui/treemodel.cc
@@ -18,114 +18,48 @@
*/
#include "treemodel.h"
+#include "log.h"
NEXTPNR_NAMESPACE_BEGIN
-ContextTreeItem::ContextTreeItem() { parentNode = nullptr; }
-
-ContextTreeItem::ContextTreeItem(QString name)
- : parentNode(nullptr), itemId(IdString()), itemType(ElementType::NONE), itemName(name)
-{
-}
-
-ContextTreeItem::ContextTreeItem(IdString id, ElementType type, QString name)
- : parentNode(nullptr), itemId(id), itemType(type), itemName(name)
-{
-}
-
-ContextTreeItem::~ContextTreeItem()
-{
- if (parentNode)
- parentNode->children.removeOne(this);
- qDeleteAll(children);
-}
-
-//void ContextTreeItem::addChild(ContextTreeItem *item)
-//{
-// item->parentNode = this;
-// children.append(item);
-//}
-
-void ContextTreeItem::sort()
-{
- for (auto item : children)
- if (item->count()>1) item->sort();
- qSort(children.begin(), children.end(), [&](const ContextTreeItem *a, const ContextTreeItem *b){
- QString name_a = a->name();
- QString name_b = b->name();
- // Try to extract a common prefix from both strings.
- QString common;
- for (int i = 0; i < std::min(name_a.size(), name_b.size()); i++) {
- const QChar c_a = name_a[i];
- const QChar c_b = name_b[i];
- if (c_a == c_b) {
- common.push_back(c_a);
- } else {
- break;
- }
- }
- // No common part? lexical sort.
- if (common.size() == 0) {
- return a->name() < b->name();
- }
-
- // Get the non-common parts.
- name_a.remove(0, common.size());
- name_b.remove(0, common.size());
- // And see if they're strings.
- bool ok = true;
- int num_a = name_a.toInt(&ok);
- if (!ok) {
- return a->name() < b->name();
- }
- int num_b = name_b.toInt(&ok);
- if (!ok) {
- return a->name() < b->name();
- }
- return num_a < num_b;
- });
-}
-
ContextTreeModel::ContextTreeModel(QObject *parent) :
QAbstractItemModel(parent),
root_(new StaticTreeItem("Elements", nullptr)) {}
ContextTreeModel::~ContextTreeModel() {}
-void ContextTreeModel::loadData(Context *ctx)
+void ContextTreeModel::loadContext(Context *ctx)
{
if (!ctx)
return;
beginResetModel();
+ // Currently we lack an API to get a proper hierarchy of bels/pip/wires
+ // cross-arch. So we only do this for ICE40 by querying the ChipDB
+ // directly.
+ // TODO(q3k): once AnyId and the tree API land in Arch, move this over.
+#ifdef ARCH_ICE40
{
- printf("generating bel map...\n");
std::map<std::pair<int, int>, std::vector<BelId>> belMap;
for (auto bel : ctx->getBels()) {
auto loc = ctx->getBelLocation(bel);
belMap[std::pair<int, int>(loc.x, loc.y)].push_back(bel);
}
- printf("generating bel static tree...\n");
auto belGetter = [](Context *ctx, BelId id) { return ctx->getBelName(id); };
bel_root_ = std::unique_ptr<BelXYRoot>(new BelXYRoot(ctx, "Bels", root_.get(), belMap, belGetter));
- printf("generating wire map...\n");
std::map<std::pair<int, int>, std::vector<WireId>> wireMap;
- //TODO(q3k): change this once we have an API to get wire categories/locations/labels
for (int i = 0; i < ctx->chip_info->num_wires; i++) {
const auto wire = &ctx->chip_info->wire_data[i];
WireId wireid;
wireid.index = i;
wireMap[std::pair<int, int>(wire->x, wire->y)].push_back(wireid);
}
- printf("generating wire static tree...\n");
auto wireGetter = [](Context *ctx, WireId id) { return ctx->getWireName(id); };
wire_root_ = std::unique_ptr<WireXYRoot>(new WireXYRoot(ctx, "Wires", root_.get(), wireMap, wireGetter));
- printf("generating pip map...\n");
std::map<std::pair<int, int>, std::vector<PipId>> pipMap;
- //TODO(q3k): change this once we have an API to get wire categories/locations/labels
for (int i = 0; i < ctx->chip_info->num_pips; i++) {
const auto pip = &ctx->chip_info->pip_data[i];
PipId pipid;
@@ -136,80 +70,34 @@ void ContextTreeModel::loadData(Context *ctx)
auto pipGetter = [](Context *ctx, PipId id) { return ctx->getPipName(id); };
pip_root_ = std::unique_ptr<PipXYRoot>(new PipXYRoot(ctx, "Pips", root_.get(), pipMap, pipGetter));
}
+#endif
- //nets_root = new ContextTreeItem("Nets");
- //root->addChild(nets_root);
-
- //cells_root = new ContextTreeItem("Cells");
- //root->addChild(cells_root);
+ cell_root_ = std::unique_ptr<IdStringList>(new IdStringList(QString("Cells"), root_.get()));
+ net_root_ = std::unique_ptr<IdStringList>(new IdStringList(QString("Nets"), root_.get()));
endResetModel();
+
+ updateCellsNets(ctx);
}
-void ContextTreeModel::updateData(Context *ctx)
+void ContextTreeModel::updateCellsNets(Context *ctx)
{
if (!ctx)
return;
beginResetModel();
- //QModelIndex nets_index = indexFromNode(nets_root);
- // Remove nets not existing any more
- //QMap<QString, ContextTreeItem *>::iterator i = nameToItem[3].begin();
- //while (i != nameToItem[3].end()) {
- // QMap<QString, ContextTreeItem *>::iterator prev = i;
- // ++i;
- // if (ctx->nets.find(ctx->id(prev.key().toStdString())) == ctx->nets.end()) {
- // //int pos = prev.value()->parent()->indexOf(prev.value());
- // //beginRemoveRows(nets_index, pos, pos);
- // delete prev.value();
- // nameToItem[3].erase(prev);
- // //endRemoveRows();
- // }
- //}
- //// Add nets to tree
- //for (auto &item : ctx->nets) {
- // auto id = item.first;
- // QString name = QString(id.c_str(ctx));
- // if (!nameToItem[3].contains(name)) {
- // //beginInsertRows(nets_index, nets_root->count() + 1, nets_root->count() + 1);
- // ContextTreeItem *newItem = new ContextTreeItem(id, ElementType::NET, name);
- // nets_root->addChild(newItem);
- // nameToItem[3].insert(name, newItem);
- // //endInsertRows();
- // }
- //}
-
- //nets_root->sort();
-
- //QModelIndex cell_index = indexFromNode(cells_root);
- // Remove cells not existing any more
- //i = nameToItem[4].begin();
- //while (i != nameToItem[4].end()) {
- // QMap<QString, ContextTreeItem *>::iterator prev = i;
- // ++i;
- // if (ctx->cells.find(ctx->id(prev.key().toStdString())) == ctx->cells.end()) {
- // //int pos = prev.value()->parent()->indexOf(prev.value());
- // //beginRemoveRows(cell_index, pos, pos);
- // delete prev.value();
- // nameToItem[4].erase(prev);
- // //endRemoveRows();
- // }
- //}
- //// Add cells to tree
- //for (auto &item : ctx->cells) {
- // auto id = item.first;
- // QString name = QString(id.c_str(ctx));
- // if (!nameToItem[4].contains(name)) {
- // //beginInsertRows(cell_index, cells_root->count() + 1, cells_root->count() + 1);
- // ContextTreeItem *newItem = new ContextTreeItem(id, ElementType::CELL, name);
- // cells_root->addChild(newItem);
- // nameToItem[4].insert(name, newItem);
- // //endInsertRows();
- // }
- //}
+ std::vector<IdString> cells;
+ for (auto &pair : ctx->cells) {
+ cells.push_back(pair.first);
+ }
+ cell_root_->updateElements(ctx, cells);
- //cells_root->sort();
+ std::vector<IdString> nets;
+ for (auto &pair : ctx->nets) {
+ nets.push_back(pair.first);
+ }
+ net_root_->updateElements(ctx, nets);
endResetModel();
}
@@ -277,22 +165,6 @@ static int getElementIndex(ElementType type)
return -1;
}
-//ContextTreeItem *ContextTreeModel::nodeForIdType(const ElementType type, const QString name) const
-//{
-// int index = getElementIndex(type);
-// if (type != ElementType::NONE && nameToItem[index].contains(name))
-// return nameToItem[index].value(name);
-// return nullptr;
-//}
-
-//QModelIndex ContextTreeModel::indexFromNode(ContextTreeItem *node)
-//{
-// ContextTreeItem *parent = node->parent();
-// if (parent == root)
-// return QModelIndex();
-// return createIndex(parent->indexOf(node), 0, node);
-//}
-
Qt::ItemFlags ContextTreeModel::flags(const QModelIndex &index) const
{
LazyTreeItem *node = nodeFromIndex(index);
@@ -310,4 +182,19 @@ bool ContextTreeModel::canFetchMore(const QModelIndex &parent) const
return nodeFromIndex(parent)->canFetchMore();
}
+QList<QModelIndex> ContextTreeModel::search(QString text)
+{
+ QList<QModelIndex> list;
+ //for (int i = 0; i < 6; i++) {
+ // for (auto key : nameToItem[i].keys()) {
+ // if (key.contains(text, Qt::CaseInsensitive)) {
+ // list.append(indexFromNode(nameToItem[i].value(key)));
+ // if (list.count() > 500)
+ // break; // limit to 500 results
+ // }
+ // }
+ //}
+ return list;
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/gui/treemodel.h b/gui/treemodel.h
index 7de54db4..f193468a 100644
--- a/gui/treemodel.h
+++ b/gui/treemodel.h
@@ -22,6 +22,7 @@
#include <QAbstractItemModel>
#include "nextpnr.h"
+#include "log.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -36,31 +37,6 @@ enum class ElementType
GROUP
};
-class ContextTreeItem
-{
- public:
- ContextTreeItem();
- ContextTreeItem(QString name);
- ContextTreeItem(IdString id, ElementType type, QString name);
- ~ContextTreeItem();
-
- void addChild(ContextTreeItem *item);
- int indexOf(ContextTreeItem *n) const { return children.indexOf(n); }
- ContextTreeItem *at(int idx) const { return children.at(idx); }
- int count() const { return children.count(); }
- ContextTreeItem *parent() const { return parentNode; }
- IdString id() const { return itemId; }
- ElementType type() const { return itemType; }
- QString name() const { return itemName; }
- void sort();
- private:
- ContextTreeItem *parentNode;
- QList<ContextTreeItem *> children;
- IdString itemId;
- ElementType itemType;
- QString itemName;
-};
-
class LazyTreeItem
{
protected:
@@ -207,6 +183,74 @@ class ElementList : public LazyTreeItem
}
};
+class IdStringList : public StaticTreeItem
+{
+ private:
+ std::unordered_map<IdString, std::unique_ptr<StaticTreeItem>> managed_;
+ public:
+ using StaticTreeItem::StaticTreeItem;
+
+ void updateElements(Context *ctx, std::vector<IdString> elements)
+ {
+ // for any elements that are not yet in managed_, created them.
+ std::unordered_set<IdString> element_set;
+ for (auto elem : elements) {
+ element_set.insert(elem);
+ auto existing = managed_.find(elem);
+ if (existing == managed_.end()) {
+ auto item = new StaticTreeItem(elem.c_str(ctx), this);
+ managed_.emplace(elem, std::unique_ptr<StaticTreeItem>(item));
+ }
+ }
+
+ children_.clear();
+ // for any elements that are in managed_ but not in new, delete them.
+ for (auto &pair : managed_) {
+ if (element_set.count(pair.first) != 0) {
+ children_.push_back(pair.second.get());
+ continue;
+ }
+ managed_.erase(pair.first);
+ }
+
+ // sort new children
+ qSort(children_.begin(), children_.end(), [&](const LazyTreeItem *a, const LazyTreeItem *b){
+ QString name_a = a->name();
+ QString name_b = b->name();
+ // Try to extract a common prefix from both strings.
+ QString common;
+ for (int i = 0; i < std::min(name_a.size(), name_b.size()); i++) {
+ const QChar c_a = name_a[i];
+ const QChar c_b = name_b[i];
+ if (c_a == c_b) {
+ common.push_back(c_a);
+ } else {
+ break;
+ }
+ }
+ // No common part? lexical sort.
+ if (common.size() == 0) {
+ return a->name() < b->name();
+ }
+
+ // Get the non-common parts.
+ name_a.remove(0, common.size());
+ name_b.remove(0, common.size());
+ // And see if they're strings.
+ bool ok = true;
+ int num_a = name_a.toInt(&ok);
+ if (!ok) {
+ return a->name() < b->name();
+ }
+ int num_b = name_b.toInt(&ok);
+ if (!ok) {
+ return a->name() < b->name();
+ }
+ return num_a < num_b;
+ });
+ }
+};
+
template <typename ElementT>
class ElementXYRoot : public StaticTreeItem
{
@@ -217,7 +261,7 @@ class ElementXYRoot : public StaticTreeItem
private:
Context *ctx_;
- std::vector<std::unique_ptr<LazyTreeItem>> bels_;
+ std::vector<std::unique_ptr<LazyTreeItem>> managed_;
ElementMap map_;
ElementGetter getter_;
@@ -241,11 +285,11 @@ class ElementXYRoot : public StaticTreeItem
// create X item for tree
auto item = new StaticTreeItem(QString("X%1").arg(i), this);
- bels_.push_back(std::move(std::unique_ptr<LazyTreeItem>(item)));
+ managed_.push_back(std::move(std::unique_ptr<LazyTreeItem>(item)));
for (auto j : y_present) {
auto item2 = new ElementList<ElementT>(ctx_, QString("Y%1").arg(j), item, &map_, i, j, getter_);
item2->fetchMore(1);
- bels_.push_back(std::move(std::unique_ptr<LazyTreeItem>(item2)));
+ managed_.push_back(std::move(std::unique_ptr<LazyTreeItem>(item2)));
}
}
}
@@ -261,11 +305,10 @@ class ContextTreeModel : public QAbstractItemModel
ContextTreeModel(QObject *parent = nullptr);
~ContextTreeModel();
- void loadData(Context *ctx);
- void updateData(Context *ctx);
+ void loadContext(Context *ctx);
+ void updateCellsNets(Context *ctx);
LazyTreeItem *nodeFromIndex(const QModelIndex &idx) const;
- //QModelIndex indexFromNode(ContextTreeItem *node);
- //ContextTreeItem *nodeForIdType(const ElementType type, const QString name) const;
+ QList<QModelIndex> search(QString text);
// Override QAbstractItemModel methods
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
@@ -283,11 +326,8 @@ class ContextTreeModel : public QAbstractItemModel
std::unique_ptr<BelXYRoot> bel_root_;
std::unique_ptr<WireXYRoot> wire_root_;
std::unique_ptr<PipXYRoot> pip_root_;
- //std::unique_ptr<ElementXYRoot> wires_root_;
- //std::unique_ptr<ElementXYRoot> pips_root_;
- //QMap<QString, ContextTreeItem *> nameToItem[6];
- //ContextTreeItem *nets_root;
- //ContextTreeItem *cells_root;
+ std::unique_ptr<IdStringList> cell_root_;
+ std::unique_ptr<IdStringList> net_root_;
};
NEXTPNR_NAMESPACE_END