diff options
Diffstat (limited to 'gui')
| -rw-r--r-- | gui/designwidget.cc | 138 | ||||
| -rw-r--r-- | gui/designwidget.h | 4 | ||||
| -rw-r--r-- | gui/treemodel.cc | 312 | ||||
| -rw-r--r-- | gui/treemodel.h | 216 | 
4 files changed, 414 insertions, 256 deletions
| diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 5107fbee..249df423 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -222,9 +222,9 @@ void DesignWidget::updateTree()  {
      clearProperties();
 -    QMap<ContextTreeItem *, int>::iterator i = highlightSelected.begin();
 +    QMap<LazyTreeItem *, int>::iterator i = highlightSelected.begin();
      while (i != highlightSelected.end()) {
 -        QMap<ContextTreeItem *, int>::iterator prev = i;
 +        QMap<LazyTreeItem *, int>::iterator prev = i;
          ++i;
          if (prev.key()->type() == ElementType::NET && ctx->nets.find(prev.key()->id()) == ctx->nets.end()) {
              highlightSelected.erase(prev);
 @@ -308,25 +308,25 @@ QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name)  void DesignWidget::onClickedBel(BelId bel, bool keep)
  {
 -    ContextTreeItem *item = treeModel->nodeForIdType(ElementType::BEL, ctx->getBelName(bel).c_str(ctx));
 -    selectionModel->setCurrentIndex(treeModel->indexFromNode(item),
 -                                    keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect);
 +    //LazyTreeItem *item = treeModel->nodeForIdType(ElementType::BEL, ctx->getBelName(bel).c_str(ctx));
 +    //selectionModel->setCurrentIndex(treeModel->indexFromNode(item),
 +    //                                keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect);
      Q_EMIT selected(getDecals(ElementType::BEL, ctx->getBelName(bel)), keep);
  }
  void DesignWidget::onClickedWire(WireId wire, bool keep)
  {
 -    ContextTreeItem *item = treeModel->nodeForIdType(ElementType::WIRE, ctx->getWireName(wire).c_str(ctx));
 -    selectionModel->setCurrentIndex(treeModel->indexFromNode(item),
 -                                    keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect);
 +    //LazyTreeItem *item = treeModel->nodeForIdType(ElementType::WIRE, ctx->getWireName(wire).c_str(ctx));
 +    //selectionModel->setCurrentIndex(treeModel->indexFromNode(item),
 +    //                                keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect);
      Q_EMIT selected(getDecals(ElementType::WIRE, ctx->getWireName(wire)), keep);
  }
  void DesignWidget::onClickedPip(PipId pip, bool keep)
  {
 -    ContextTreeItem *item = treeModel->nodeForIdType(ElementType::PIP, ctx->getPipName(pip).c_str(ctx));
 -    selectionModel->setCurrentIndex(treeModel->indexFromNode(item),
 -                                    keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect);
 +    //LazyTreeItem *item = treeModel->nodeForIdType(ElementType::PIP, ctx->getPipName(pip).c_str(ctx));
 +    //selectionModel->setCurrentIndex(treeModel->indexFromNode(item),
 +    //                                keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect);
      Q_EMIT selected(getDecals(ElementType::PIP, ctx->getPipName(pip)), keep);
  }
 @@ -338,7 +338,7 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti      if (selectionModel->selectedIndexes().size() > 1) {
          std::vector<DecalXY> decals;
          for (auto index : selectionModel->selectedIndexes()) {
 -            ContextTreeItem *item = treeModel->nodeFromIndex(index);
 +            LazyTreeItem *item = treeModel->nodeFromIndex(index);
              std::vector<DecalXY> d = getDecals(item->type(), item->id());
              std::move(d.begin(), d.end(), std::back_inserter(decals));
          }
 @@ -348,7 +348,7 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti      QModelIndex index = selectionModel->selectedIndexes().at(0);
      if (!index.isValid())
          return;
 -    ContextTreeItem *clickItem = treeModel->nodeFromIndex(index);
 +    LazyTreeItem *clickItem = treeModel->nodeFromIndex(index);
      ElementType type = clickItem->type();
      if (type == ElementType::NONE)
 @@ -596,7 +596,7 @@ std::vector<DecalXY> DesignWidget::getDecals(ElementType type, IdString value)      return decals;
  }
 -void DesignWidget::updateHighlightGroup(QList<ContextTreeItem *> items, int group)
 +void DesignWidget::updateHighlightGroup(QList<LazyTreeItem *> items, int group)
  {
      const bool shouldClear = items.size() == 1;
      for (auto item : items) {
 @@ -620,53 +620,53 @@ void DesignWidget::updateHighlightGroup(QList<ContextTreeItem *> items, int grou  void DesignWidget::prepareMenuProperty(const QPoint &pos)
  {
 -    QTreeWidget *tree = propertyEditor->treeWidget();
 -    QList<ContextTreeItem *> items;
 -    for (auto itemContextMenu : tree->selectedItems()) {
 -        QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu);
 -        if (!browserItem)
 -            continue;
 -        QtProperty *selectedProperty = browserItem->property();
 -        ElementType type = getElementTypeByName(selectedProperty->propertyId());
 -        if (type == ElementType::NONE)
 -            continue;
 -        IdString value = ctx->id(selectedProperty->valueText().toStdString());
 -        items.append(treeModel->nodeForIdType(type, value.c_str(ctx)));
 -    }
 -    int selectedIndex = -1;
 -    if (items.size() == 1) {
 -        ContextTreeItem *item = items.at(0);
 -        if (highlightSelected.contains(item))
 -            selectedIndex = highlightSelected[item];
 -    }
 -
 -    QMenu menu(this);
 -    QAction *selectAction = new QAction("&Select", this);
 -    connect(selectAction, &QAction::triggered, this, [this, items] {
 -        std::vector<DecalXY> decals;
 -        for (auto clickItem : items) {
 -            std::vector<DecalXY> d = getDecals(clickItem->type(), clickItem->id());
 -            std::move(d.begin(), d.end(), std::back_inserter(decals));
 -        }
 -        Q_EMIT selected(decals, false);
 -    });
 -    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 (selectedIndex == i)
 -            action->setChecked(true);
 -        connect(action, &QAction::triggered, this, [this, i, items] { updateHighlightGroup(items, i); });
 -    }
 -    menu.exec(tree->mapToGlobal(pos));
 +    //QTreeWidget *tree = propertyEditor->treeWidget();
 +    //QList<LazyTreeItem *> items;
 +    //for (auto itemContextMenu : tree->selectedItems()) {
 +    //    QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu);
 +    //    if (!browserItem)
 +    //        continue;
 +    //    QtProperty *selectedProperty = browserItem->property();
 +    //    ElementType type = getElementTypeByName(selectedProperty->propertyId());
 +    //    if (type == ElementType::NONE)
 +    //        continue;
 +    //    IdString value = ctx->id(selectedProperty->valueText().toStdString());
 +    //    items.append(treeModel->nodeForIdType(type, value.c_str(ctx)));
 +    //}
 +    //int selectedIndex = -1;
 +    //if (items.size() == 1) {
 +    //    LazyTreeItem *item = items.at(0);
 +    //    if (highlightSelected.contains(item))
 +    //        selectedIndex = highlightSelected[item];
 +    //}
 +
 +    //QMenu menu(this);
 +    //QAction *selectAction = new QAction("&Select", this);
 +    //connect(selectAction, &QAction::triggered, this, [this, items] {
 +    //    std::vector<DecalXY> decals;
 +    //    for (auto clickItem : items) {
 +    //        std::vector<DecalXY> d = getDecals(clickItem->type(), clickItem->id());
 +    //        std::move(d.begin(), d.end(), std::back_inserter(decals));
 +    //    }
 +    //    Q_EMIT selected(decals, false);
 +    //});
 +    //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 (selectedIndex == i)
 +    //        action->setChecked(true);
 +    //    connect(action, &QAction::triggered, this, [this, i, items] { updateHighlightGroup(items, i); });
 +    //}
 +    //menu.exec(tree->mapToGlobal(pos));
  }
  void DesignWidget::prepareMenuTree(const QPoint &pos)
 @@ -676,13 +676,13 @@ void DesignWidget::prepareMenuTree(const QPoint &pos)      if (selectionModel->selectedIndexes().size() == 0)
          return;
 -    QList<ContextTreeItem *> items;
 +    QList<LazyTreeItem *> items;
      for (auto index : selectionModel->selectedIndexes()) {
 -        ContextTreeItem *item = treeModel->nodeFromIndex(index);
 +        LazyTreeItem *item = treeModel->nodeFromIndex(index);
          items.append(item);
      }
      if (items.size() == 1) {
 -        ContextTreeItem *item = items.at(0);
 +        LazyTreeItem *item = items.at(0);
          if (highlightSelected.contains(item))
              selectedIndex = highlightSelected[item];
      }
 @@ -706,11 +706,11 @@ void DesignWidget::prepareMenuTree(const QPoint &pos)  void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column)
  {
 -    QtProperty *selectedProperty = propertyEditor->itemToBrowserItem(item)->property();
 -    ElementType type = getElementTypeByName(selectedProperty->propertyId());
 -    ContextTreeItem *it = treeModel->nodeForIdType(type, selectedProperty->valueText());
 -    if (it)
 -        selectionModel->setCurrentIndex(treeModel->indexFromNode(it), QItemSelectionModel::ClearAndSelect);
 +    //QtProperty *selectedProperty = propertyEditor->itemToBrowserItem(item)->property();
 +    //ElementType type = getElementTypeByName(selectedProperty->propertyId());
 +    //LazyTreeItem *it = treeModel->nodeForIdType(type, selectedProperty->valueText());
 +    //if (it)
 +    //    selectionModel->setCurrentIndex(treeModel->indexFromNode(it), QItemSelectionModel::ClearAndSelect);
  }
  void DesignWidget::onDoubleClicked(const QModelIndex &index) { Q_EMIT zoomSelected(); }
 diff --git a/gui/designwidget.h b/gui/designwidget.h index 27ead589..b229a8a8 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -51,7 +51,7 @@ class DesignWidget : public QWidget      void updateButtons();
      void addToHistory(QModelIndex item);
      std::vector<DecalXY> getDecals(ElementType type, IdString value);
 -    void updateHighlightGroup(QList<ContextTreeItem *> item, int group);
 +    void updateHighlightGroup(QList<LazyTreeItem *> item, int group);
    Q_SIGNALS:
      void info(std::string text);
      void selected(std::vector<DecalXY> decal, bool keep);
 @@ -97,7 +97,7 @@ class DesignWidget : public QWidget      QAction *actionClear;
      QColor highlightColors[8];
 -    QMap<ContextTreeItem *, int> highlightSelected;
 +    QMap<LazyTreeItem *, int> highlightSelected;
  };
  NEXTPNR_NAMESPACE_END
 diff --git a/gui/treemodel.cc b/gui/treemodel.cc index 0a503003..9a501eb9 100644 --- a/gui/treemodel.cc +++ b/gui/treemodel.cc @@ -39,11 +39,12 @@ ContextTreeItem::~ContextTreeItem()          parentNode->children.removeOne(this);      qDeleteAll(children);  } -void ContextTreeItem::addChild(ContextTreeItem *item) -{ -    item->parentNode = this; -    children.append(item); -} + +//void ContextTreeItem::addChild(ContextTreeItem *item) +//{ +//    item->parentNode = this; +//    children.append(item); +//}  void ContextTreeItem::sort()  { @@ -85,9 +86,11 @@ void ContextTreeItem::sort()      });  } -ContextTreeModel::ContextTreeModel(QObject *parent) : QAbstractItemModel(parent) { root = new ContextTreeItem(); } +ContextTreeModel::ContextTreeModel(QObject *parent) : +        QAbstractItemModel(parent), +        root_(new StaticTreeItem("Elements", nullptr)) {} -ContextTreeModel::~ContextTreeModel() { delete root; } +ContextTreeModel::~ContextTreeModel() {}  void ContextTreeModel::loadData(Context *ctx)  { @@ -96,109 +99,49 @@ void ContextTreeModel::loadData(Context *ctx)      beginResetModel(); -    delete root; -    root = new ContextTreeItem(); - -    for (int i = 0; i < 6; i++) -        nameToItem[i].clear(); - -    IdString none; - -    ContextTreeItem *bels_root = new ContextTreeItem("Bels"); -    root->addChild(bels_root); -    QMap<QString, ContextTreeItem *> bel_items; - -    // Add bels to tree -    for (auto bel : ctx->getBels()) { -        IdString id = ctx->getBelName(bel); -        QStringList items = QString(id.c_str(ctx)).split("/"); -        QString name; -        ContextTreeItem *parent = bels_root; -        for (int i = 0; i < items.size(); i++) { -            if (!name.isEmpty()) -                name += "/"; -            name += items.at(i); -            if (!bel_items.contains(name)) { -                if (i == items.size() - 1) { -                    ContextTreeItem *item = new ContextTreeItem(id, ElementType::BEL, items.at(i)); -                    parent->addChild(item); -                    nameToItem[0].insert(name, item); -                } else { -                    ContextTreeItem *item = new ContextTreeItem(none, ElementType::NONE, items.at(i)); -                    parent->addChild(item); -                    bel_items.insert(name, item); -                } -            } -            parent = bel_items[name]; +    { +        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);          } -    }     -    bels_root->sort(); -     -    ContextTreeItem *wire_root = new ContextTreeItem("Wires"); -    root->addChild(wire_root); -    QMap<QString, ContextTreeItem *> wire_items; - -    // Add wires to tree -    for (auto wire : ctx->getWires()) { -        auto id = ctx->getWireName(wire); -        QStringList items = QString(id.c_str(ctx)).split("/"); -        QString name; -        ContextTreeItem *parent = wire_root; -        for (int i = 0; i < items.size(); i++) { -            if (!name.isEmpty()) -                name += "/"; -            name += items.at(i); -            if (!wire_items.contains(name)) { -                if (i == items.size() - 1) { -                    ContextTreeItem *item = new ContextTreeItem(id, ElementType::WIRE, items.at(i)); -                    parent->addChild(item); -                    nameToItem[1].insert(name, item); -                } else { -                    ContextTreeItem *item = new ContextTreeItem(none, ElementType::NONE, items.at(i)); -                    parent->addChild(item); -                    wire_items.insert(name, item); -                } -            } -            parent = wire_items[name]; +        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);          } -    } -    wire_root->sort(); - -    ContextTreeItem *pip_root = new ContextTreeItem("Pips"); -    root->addChild(pip_root); -    QMap<QString, ContextTreeItem *> pip_items; - -    // Add pips to tree -    for (auto pip : ctx->getPips()) { -        auto id = ctx->getPipName(pip); -        QStringList items = QString(id.c_str(ctx)).split("/"); -        QString name; -        ContextTreeItem *parent = pip_root; -        for (int i = 0; i < items.size(); i++) { -            if (!name.isEmpty()) -                name += "/"; -            name += items.at(i); -            if (!pip_items.contains(name)) { -                if (i == items.size() - 1) { -                    ContextTreeItem *item = new ContextTreeItem(id, ElementType::PIP, items.at(i)); -                    parent->addChild(item); -                    nameToItem[2].insert(name, item); -                } else { -                    ContextTreeItem *item = new ContextTreeItem(none, ElementType::NONE, items.at(i)); -                    parent->addChild(item); -                    pip_items.insert(name, item); -                } -            } -            parent = pip_items[name]; +        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; +            pipid.index = i; +            pipMap[std::pair<int, int>(pip->x, pip->y)].push_back(pipid);          } +        printf("generating pip static tree...\n"); +        auto pipGetter = [](Context *ctx, PipId id) { return ctx->getPipName(id); }; +        pip_root_ = std::unique_ptr<PipXYRoot>(new PipXYRoot(ctx, "Pips", root_.get(), pipMap, pipGetter));      } -    pip_root->sort(); -    nets_root = new ContextTreeItem("Nets"); -    root->addChild(nets_root); +    //nets_root = new ContextTreeItem("Nets"); +    //root->addChild(nets_root); -    cells_root = new ContextTreeItem("Cells"); -    root->addChild(cells_root); +    //cells_root = new ContextTreeItem("Cells"); +    //root->addChild(cells_root);      endResetModel();  } @@ -212,61 +155,61 @@ void ContextTreeModel::updateData(Context *ctx)      //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(); +    //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(); -        } -    } - -    cells_root->sort(); +    //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(); +    //    } +    //} + +    //cells_root->sort();      endResetModel();  } @@ -277,18 +220,19 @@ int ContextTreeModel::columnCount(const QModelIndex &parent) const { return 1; }  QModelIndex ContextTreeModel::index(int row, int column, const QModelIndex &parent) const  { -    ContextTreeItem *node = nodeFromIndex(parent); +    LazyTreeItem *node = nodeFromIndex(parent);      if (row >= node->count())          return QModelIndex(); -    return createIndex(row, column, node->at(row)); + +    return createIndex(row, column, node->child(row));  }  QModelIndex ContextTreeModel::parent(const QModelIndex &child) const  { -    ContextTreeItem *parent = nodeFromIndex(child)->parent(); -    if (parent == root) +    LazyTreeItem *parent = nodeFromIndex(child)->parent(); +    if (parent == root_.get())          return QModelIndex(); -    ContextTreeItem *node = parent->parent(); +    LazyTreeItem *node = parent->parent();      return createIndex(node->indexOf(parent), 0, parent);  } @@ -298,7 +242,7 @@ QVariant ContextTreeModel::data(const QModelIndex &index, int role) const          return QVariant();      if (role != Qt::DisplayRole)          return QVariant(); -    ContextTreeItem *node = nodeFromIndex(index); +    LazyTreeItem *node = nodeFromIndex(index);      return node->name();  } @@ -311,11 +255,11 @@ QVariant ContextTreeModel::headerData(int section, Qt::Orientation orientation,      return QVariant();  } -ContextTreeItem *ContextTreeModel::nodeFromIndex(const QModelIndex &idx) const +LazyTreeItem *ContextTreeModel::nodeFromIndex(const QModelIndex &idx) const  {      if (idx.isValid()) -        return (ContextTreeItem *)idx.internalPointer(); -    return root; +        return (LazyTreeItem *)idx.internalPointer(); +    return root_.get();  }  static int getElementIndex(ElementType type) @@ -333,25 +277,37 @@ static int getElementIndex(ElementType type)      return -1;  } -ContextTreeItem *ContextTreeModel::nodeForIdType(const ElementType type, const QString name) const +//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  { -    int index = getElementIndex(type); -    if (type != ElementType::NONE && nameToItem[index].contains(name)) -        return nameToItem[index].value(name); -    return nullptr; +    LazyTreeItem *node = nodeFromIndex(index); +    return Qt::ItemIsEnabled | (node->type() != ElementType::NONE ? Qt::ItemIsSelectable : Qt::NoItemFlags);  } -QModelIndex ContextTreeModel::indexFromNode(ContextTreeItem *node) + +void ContextTreeModel::fetchMore(const QModelIndex &parent)  { -    ContextTreeItem *parent = node->parent(); -    if (parent == root) -        return QModelIndex(); -    return createIndex(parent->indexOf(node), 0, node); +    nodeFromIndex(parent)->fetchMore();  } -Qt::ItemFlags ContextTreeModel::flags(const QModelIndex &index) const +bool ContextTreeModel::canFetchMore(const QModelIndex &parent) const  { -    ContextTreeItem *node = nodeFromIndex(index); -    return Qt::ItemIsEnabled | (node->type() != ElementType::NONE ? Qt::ItemIsSelectable : Qt::NoItemFlags); +    return nodeFromIndex(parent)->canFetchMore();  } +  NEXTPNR_NAMESPACE_END diff --git a/gui/treemodel.h b/gui/treemodel.h index a85c290a..7de54db4 100644 --- a/gui/treemodel.h +++ b/gui/treemodel.h @@ -61,17 +61,212 @@ class ContextTreeItem      QString itemName;  }; +class LazyTreeItem +{ +  protected: +    QString name_; +    LazyTreeItem *parent_; +    QList<LazyTreeItem *> children_; + +    void addChild(LazyTreeItem *child) +    { +        children_.append(child); +    } + +  public: +    LazyTreeItem(QString name, LazyTreeItem *parent) : +            name_(name), parent_(parent) +    { +        // Register in parent if exists. +        if (parent_ != nullptr) { +            parent_->addChild(this); +        } +    }; + +    int count() const +    { +        return children_.count(); +    } + +    QString name() const +    { +        return name_; +    } + +    LazyTreeItem *child(int index) +    { +        return children_.at(index); +    } + +    int indexOf(LazyTreeItem *child) const +    {  +        return children_.indexOf(child, 0); +    } + +    LazyTreeItem *parent() +    { +        return parent_; +    } + +    virtual bool canFetchMore() const = 0; +    virtual void fetchMore() = 0; +    virtual ElementType type() const = 0; +    virtual IdString id() const = 0; + +    virtual ~LazyTreeItem() {} +}; + +class StaticTreeItem : public LazyTreeItem +{ +  public: +    using LazyTreeItem::LazyTreeItem; + +    virtual bool canFetchMore() const override +    { +        return false; +    } + +    virtual void fetchMore() override +    { +    } + +    virtual ~StaticTreeItem() {} + +    virtual ElementType type() const override +    { +        return ElementType::NONE; +    } +     +    virtual IdString id() const override +    { +        return IdString(); +    } +}; + +template <typename ElementT> +class ElementList : public LazyTreeItem +{ +  public: +    using ElementMap = std::map<std::pair<int, int>, std::vector<ElementT>>; +    using ElementGetter = std::function<IdString(Context *, ElementT)>; + +  private: +    Context *ctx_; +    const ElementMap *map_; +    int x_, y_; +    ElementGetter getter_; +    std::vector<std::unique_ptr<StaticTreeItem>> managed_; + +    // scope valid until map gets mutated... +    const std::vector<ElementT> *elements() const +    { +        return &map_->at(std::pair<int, int>(x_, y_)); +    } + +  public: +    ElementList(Context *ctx, QString name, LazyTreeItem *parent, ElementMap *map, int x, int y, ElementGetter getter) : +            LazyTreeItem(name, parent), ctx_(ctx), map_(map), x_(x), y_(y), getter_(getter) +    { +    } + +    virtual bool canFetchMore() const override +    { +        return children_.size() < elements()->size(); +    } + +    void fetchMore(int count) +    { +        int start = children_.size(); +        size_t end = std::min(start + count, (int)elements()->size()); +        for (int i = start; i < end; i++) { +            QString name(getter_(ctx_, elements()->at(i)).c_str(ctx_)); + +            // Remove X.../Y.../ prefix +            QString prefix = QString("X%1/Y%2/").arg(x_).arg(y_); +            if (name.startsWith(prefix)) +                name.remove(0, prefix.size()); + +            auto item = new StaticTreeItem(name, this); +            managed_.push_back(std::move(std::unique_ptr<StaticTreeItem>(item))); +        } +    } + +    virtual void fetchMore() override +    { +         fetchMore(100); +    } + +    virtual ElementType type() const override +    { +        return ElementType::NONE; +    } +     +    virtual IdString id() const override +    { +        return IdString(); +    } +}; + +template <typename ElementT> +class ElementXYRoot : public StaticTreeItem +{ +  public: +    using ElementMap = std::map<std::pair<int, int>, std::vector<ElementT>>; +    using ElementGetter = std::function<IdString(Context *, ElementT)>; + + +  private: +    Context *ctx_; +    std::vector<std::unique_ptr<LazyTreeItem>> bels_; +    ElementMap map_; +    ElementGetter getter_; + +  public: +    ElementXYRoot(Context *ctx, QString name, LazyTreeItem *parent, ElementMap map, ElementGetter getter) : +            StaticTreeItem(name, parent), ctx_(ctx), map_(map), getter_(getter) +    { +        std::vector<int> y_present; + +        for (int i = 0; i < ctx->getGridDimX(); i++) { +            y_present.clear(); +            // first find all the elements in all Y coordinates in this X +            for (int j = 0; j < ctx->getGridDimY(); j++) { +                if (map_.count(std::pair<int, int>(i, j)) == 0) +                    continue; +                y_present.push_back(j); +            } +            // no bels in any X coordinate? do not add X tree item. +            if (y_present.size() == 0) +                continue; + +            // 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))); +            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))); +            } +        } +    } +}; +  class ContextTreeModel : public QAbstractItemModel  {    public: +    using BelXYRoot = ElementXYRoot<BelId>; +    using WireXYRoot = ElementXYRoot<WireId>; +    using PipXYRoot = ElementXYRoot<PipId>; +      ContextTreeModel(QObject *parent = nullptr);      ~ContextTreeModel();      void loadData(Context *ctx);      void updateData(Context *ctx); -    ContextTreeItem *nodeFromIndex(const QModelIndex &idx) const; -    QModelIndex indexFromNode(ContextTreeItem *node); -    ContextTreeItem *nodeForIdType(const ElementType type, const QString name) const; +    LazyTreeItem *nodeFromIndex(const QModelIndex &idx) const; +    //QModelIndex indexFromNode(ContextTreeItem *node); +    //ContextTreeItem *nodeForIdType(const ElementType type, const QString name) const; +       // Override QAbstractItemModel methods      int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;      int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; @@ -80,12 +275,19 @@ class ContextTreeModel : public QAbstractItemModel      QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;      QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;      Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; +    void fetchMore(const QModelIndex &parent) Q_DECL_OVERRIDE; +    bool canFetchMore(const QModelIndex &parent) const Q_DECL_OVERRIDE;    private: -    ContextTreeItem *root; -    QMap<QString, ContextTreeItem *> nameToItem[6]; -    ContextTreeItem *nets_root; -    ContextTreeItem *cells_root; +    std::unique_ptr<LazyTreeItem> root_; +    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;  };  NEXTPNR_NAMESPACE_END | 
