diff --git a/include/hal_core/netlist/netlist_utils.h b/include/hal_core/netlist/netlist_utils.h index ad7e24aa539e..49fd74dc1025 100644 --- a/include/hal_core/netlist/netlist_utils.h +++ b/include/hal_core/netlist/netlist_utils.h @@ -337,7 +337,6 @@ namespace hal const std::function& filter = nullptr); /** - * \deprecated * Find the shortest path (i.e., theresult set with the lowest number of gates) that connects the start gate with the end gate. * The gate where the search started from will be the first in the result vector, the end gate will be the last. * If there is no such path an empty vector is returned. If there is more than one path with the same length only the first one is returned. @@ -347,7 +346,18 @@ namespace hal * @param[in] search_both_directions - True to additionally check whether a shorter path from end to start exists, false otherwise. * @return A vector of gates that connect the start with end gate (possibly in reverse order). */ - [[deprecated("Will be removed in a future version, use NetlistTraversalDecorator::get_shortest_path instead.")]] CORE_API std::vector - get_shortest_path(Gate* start_gate, Gate* end_gate, bool search_both_directions = false); + CORE_API std::vector get_shortest_path(Gate* start_gate, Gate* end_gate, bool search_both_directions = false); + + /** + * Find the shortest path (i.e., theresult set with the lowest number of gates) that connects the start gate with any gate from the given module. + * The gate where the search started from will be the first in the result vector, the end gate will be the last. + * If there is no such path an empty vector is returned. If there is more than one path with the same length only the first one is returned. + * + * @param[in] start_gate - The gate to start from. + * @param[in] end_gate - The gate to connect to. + * @param[in] search_both_directions - True to additionally check whether a shorter path from end to start exists, false otherwise. + * @return A vector of gates that connect the start with end gate (possibly in reverse order). + */ + CORE_API std::vector get_shortest_path(Gate* start_gate, Module* end_module); } // namespace netlist_utils -} // namespace hal \ No newline at end of file +} // namespace hal diff --git a/plugins/gui/include/gui/graph_widget/contexts/graph_context.h b/plugins/gui/include/gui/graph_widget/contexts/graph_context.h index 5af6e8fb1cdb..0b3436e3e598 100644 --- a/plugins/gui/include/gui/graph_widget/contexts/graph_context.h +++ b/plugins/gui/include/gui/graph_widget/contexts/graph_context.h @@ -126,6 +126,9 @@ namespace hal */ bool isModuleUnfolded(const u32 moduleId) const; + + void refreshModule(const u32 moduleId); + /** * Unfold a specific module. The specified module is removed from the context and replaced by its Gate%s and * submodules. @@ -322,9 +325,10 @@ namespace hal } /** - * Move node to antother grid location - */ - void moveNodeAction(const QPoint& from, const QPoint& to); + * Update placement of nodes already existing in view + * @param plc - the placement hash (Node -> QPoint) + */ + void updatePlacement(const GridPlacement& plc); /** * Returns whether the scene is in an updating process (i.e. layouter process) or not. diff --git a/plugins/gui/include/gui/graph_widget/graph_context_manager.h b/plugins/gui/include/gui/graph_widget/graph_context_manager.h index 6dcc1f6dcb1e..3a7e903e5fd4 100644 --- a/plugins/gui/include/gui/graph_widget/graph_context_manager.h +++ b/plugins/gui/include/gui/graph_widget/graph_context_manager.h @@ -417,6 +417,8 @@ namespace hal static SettingsItemCheckbox* sSettingNetGroupingToPins; static SettingsItemCheckbox* sSettingPanOnMiddleButton; + + static SettingsItemCheckbox* sSettingLayoutOnEveryChange; Q_SIGNALS: /** * Q_SIGNAL that notifies about the creation of a new context by the context manager. diff --git a/plugins/gui/include/gui/graph_widget/graph_graphics_view.h b/plugins/gui/include/gui/graph_widget/graph_graphics_view.h index dee61ade1cb0..0f8f88d36a65 100644 --- a/plugins/gui/include/gui/graph_widget/graph_graphics_view.h +++ b/plugins/gui/include/gui/graph_widget/graph_graphics_view.h @@ -122,12 +122,12 @@ namespace hal public Q_SLOTS: /** - * highlight shortest path between two gates by putting the items on path into a new group + * highlight shortest path between source gate and target node by putting the items on path into a new group * * @param idFrom - id of gate where path starts * @param idTo - id of gate where path ends */ - void handleShortestPath(u32 idFrom, u32 idTo); + void handleShortestPath(u32 idFrom, Node nodeTo); /** * remove selected nodes from view @@ -146,7 +146,9 @@ namespace hal void handleUnfoldAllAction(); void handleShortestPathToView(); - void handleQueryShortestPath(); + void handleShortestModulePathToView(); + void handleQueryShortestPathGate(); + void handleQueryShortestPathModule(); void handleSelectOutputs(); void handleSelectInputs(); @@ -182,6 +184,8 @@ namespace hal void resizeEvent(QResizeEvent* event) override; private: + + enum SearchAction {PredecessorGate, SuccessorGate, SuccessorModule}; void mousePressEventNotItemDrag(QMouseEvent* event); void showContextMenu(const QPoint& pos); diff --git a/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h b/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h index a4f5c22395ad..3d702a8d8db5 100644 --- a/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h +++ b/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h @@ -35,7 +35,6 @@ namespace hal { * @brief A standard net that has parts of a separated net. * * The GraphicsNet that can be used to display nets in the scene. - * Currently only used in GraphLayouter::alternateLayout(). */ class StandardArrowNet : public StandardGraphicsNet { diff --git a/plugins/gui/include/gui/graph_widget/items/nodes/gates/standard_graphics_gate.h b/plugins/gui/include/gui/graph_widget/items/nodes/gates/standard_graphics_gate.h index 97e1fe2bdc85..3adc272d78fb 100644 --- a/plugins/gui/include/gui/graph_widget/items/nodes/gates/standard_graphics_gate.h +++ b/plugins/gui/include/gui/graph_widget/items/nodes/gates/standard_graphics_gate.h @@ -116,10 +116,8 @@ namespace hal static QPen sPen; - static QFont sTextFont[2]; static QFont sPinFont; - static qreal sTextFontHeight[2]; static qreal sColorBarHeight; @@ -144,8 +142,6 @@ namespace hal void format(const bool& adjust_size_to_grid); - QPointF mTextPosition[2]; - QVector mInputPinTextWidth; QVector mOutputPinTextWidth; static const int sIconPadding; @@ -155,7 +151,5 @@ namespace hal static const QPixmap& iconPixmap(); static QColor legibleColor(const QColor& bgColor); - public: - static QColor sTextColor; }; } diff --git a/plugins/gui/include/gui/graph_widget/items/nodes/graphics_node.h b/plugins/gui/include/gui/graph_widget/items/nodes/graphics_node.h index 4cf871fdddc6..64ebacd807a8 100644 --- a/plugins/gui/include/gui/graph_widget/items/nodes/graphics_node.h +++ b/plugins/gui/include/gui/graph_widget/items/nodes/graphics_node.h @@ -28,6 +28,7 @@ #include "gui/graph_widget/items/graphics_item.h" #include +#include namespace hal { @@ -63,9 +64,8 @@ namespace hal * * @param type - The type of the GraphicsItem (i.e. module, gate or net) * @param id - The id of the underlying object (e.g. the module id if ItemType::Module) - * @param name - The name of the node */ - GraphicsNode(const ItemType type, const u32 id, const QString& name); + GraphicsNode(const ItemType type, const u32 id); /** * Get the bounding rectangle of the GrahpicsNode that represent its size. Therefore the returned rectangle is @@ -200,16 +200,48 @@ namespace hal */ void set_name(const QString& name); + /** + * Loads the cosmetic setting that will be applied to all GraphicsModules. + */ + static void loadSettings(); + + /** + * Pen color for text lines + */ + static QColor sTextColor; + + // qreal xOffset() const; // qreal yOffset() const; protected: + /** + * The text font for node name and type. Consider to change it to non-static in case derived class wants to overwrite + */ + static QFont sTextFont[3]; + + /** + * Height of selected font + */ + static qreal sTextFontHeight[3]; + + /** * The text in the center of the GraphicsNode. Each index stores one line of text. Therefore there is a maximum * of 3 lines in total. */ QString mNodeText[3]; + /** + * Text position in box. + */ + QPointF mTextPosition[3]; + + /** + * Maximum text width, used to determine box width + */ + qreal mMaxTextWidth; + /** * The width of the GraphicsNode */ @@ -233,5 +265,15 @@ namespace hal * netId=0 implies that no net is connected to the output pin at pinIdx. */ QMultiHash mOutputByNet; + + /** + * Set text lines, on init adjust width, else truncate lines + */ + void setNodeText(const QString* lines, bool init); + + /** + * Init text position after box width has been calculated + */ + void initTextPosition(qreal y0, qreal spacing); }; } diff --git a/plugins/gui/include/gui/graph_widget/items/nodes/modules/graphics_module.h b/plugins/gui/include/gui/graph_widget/items/nodes/modules/graphics_module.h index 91131b9aa954..c8ca67a0547a 100644 --- a/plugins/gui/include/gui/graph_widget/items/nodes/modules/graphics_module.h +++ b/plugins/gui/include/gui/graph_widget/items/nodes/modules/graphics_module.h @@ -51,6 +51,13 @@ namespace hal */ explicit GraphicsModule(Module* m); + /** + * Set the text label for module box. + * + * @param m - The underlying module of this GraphicsModule + */ + void setModuleLabel(const Module* m, bool init=false); + protected: /** * Represents one pin (both input or output) of a module. It stores the pin type name and the id of the net diff --git a/plugins/gui/include/gui/graph_widget/items/nodes/modules/standard_graphics_module.h b/plugins/gui/include/gui/graph_widget/items/nodes/modules/standard_graphics_module.h index f765d9794b73..d8c004eb2d7e 100644 --- a/plugins/gui/include/gui/graph_widget/items/nodes/modules/standard_graphics_module.h +++ b/plugins/gui/include/gui/graph_widget/items/nodes/modules/standard_graphics_module.h @@ -117,11 +117,8 @@ namespace hal static QPen sPen; - static QFont sTextFont[3]; static QFont sPinFont; - static qreal sTextFontHeight[3]; - static qreal sColorBarHeight; static qreal sPinInnerHorizontalSpacing; @@ -142,15 +139,11 @@ namespace hal void format(const bool& adjust_size_to_grid); - QPointF mTextPosition[3]; - QVector mOutputPinPositions; static const int sIconPadding; static const QSize sIconSize; static QPixmap* sIconInstance; static const QPixmap& iconPixmap(); - public: - static QColor sTextColor; }; } // namespace hal diff --git a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h index 6fd0498649b0..de4b07c78ff3 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h +++ b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h @@ -260,7 +260,6 @@ namespace hal * Does the actual layout process. */ void layout(); - void alternateLayout(); /** * Gets the GraphicsScene the layouter works on. @@ -285,6 +284,8 @@ namespace hal void dumpNodePositions(const QPoint& search) const; + void updatePlacement(const GridPlacement& plc); + void setNodePosition(const Node& n, const QPoint& p); void swapNodePositions(const Node& n1, const Node& n2); void removeNodeFromMaps(const Node& n); diff --git a/plugins/gui/include/gui/gui_def.h b/plugins/gui/include/gui/gui_def.h index 9091c6e5bda2..286586db74c6 100644 --- a/plugins/gui/include/gui/gui_def.h +++ b/plugins/gui/include/gui/gui_def.h @@ -144,7 +144,13 @@ namespace hal GridPlacement(const QHash& data) : QHash(data) {;} void setGatePosition(u32 gateId, std::pairp, bool swap = false) { - QPoint pos = QPoint(gatePosition(gateId)->first, gatePosition(gateId)->second); //position of current gate to move + std::pair* posPtr = gatePosition(gateId); + if (!posPtr) + { + log_warning("gui", "Gate id {} cannot be moved, not found in current placement", gateId); + return; + } + QPoint pos = QPoint(posPtr->first, posPtr->second); //position of current gate to move hal::Node nd = key(QPoint(p.first, p.second)); //find the node in the destination if(!nd.isNull() && !swap) //if the destination placement is not available @@ -159,8 +165,15 @@ namespace hal else operator[](hal::Node(gateId,hal::Node::Gate)) = QPoint(p.first,p.second); } + void setModulePosition(u32 moduleId, std::pairp, bool swap = false){ - QPoint pos = QPoint(modulePosition(moduleId)->first, modulePosition(moduleId)->second); + std::pair* posPtr = modulePosition(moduleId); + if (!posPtr) + { + log_warning("gui", "Module id {} cannot be moved, not found in current placement", moduleId); + return; + } + QPoint pos = QPoint(posPtr->first, posPtr->second); //position of current module to move hal::Node nd = key(QPoint(p.first, p.second)); if(!nd.isNull() && !swap) @@ -174,11 +187,13 @@ namespace hal } else operator[](hal::Node(moduleId,hal::Node::Module)) = QPoint(p.first,p.second);}; + std::pair* gatePosition(u32 gateId) const { auto it = constFind(hal::Node(gateId,hal::Node::Gate)); return (it == constEnd() ? nullptr : new std::pair(it->x(),it->y())); } + std::pair* modulePosition(u32 moduleId) const { auto it = constFind(hal::Node(moduleId,hal::Node::Module)); diff --git a/plugins/gui/include/gui/module_model/module_model.h b/plugins/gui/include/gui/module_model/module_model.h index 74dde2fb73da..f5d7966902c6 100644 --- a/plugins/gui/include/gui/module_model/module_model.h +++ b/plugins/gui/include/gui/module_model/module_model.h @@ -252,12 +252,19 @@ namespace hal void updateModuleParent(const Module* module); /** - * Updates the ModuleItems for the specified module. The specified module MUST be contained in the item model. + * Updates the ModuleItems name for the specified module. The specified module MUST be contained in the item model. * * @param id - The id of the module to update */ void updateModuleName(const u32 id); + /** + * Updates the ModuleItems type for the specified module. The specified module MUST be contained in the item model. + * + * @param id - The id of the module to update + */ + void updateModuleType(const u32 id); + /** * Updates the ModuleItems for the specified gate. The specified gate MUST be contained in the item model. * @@ -284,6 +291,8 @@ namespace hal private Q_SLOTS: void handleModuleNameChanged(Module* mod); + void handleModuleTypeChanged(Module* mod); + void handleModuleRemoved(Module* mod); void handleModuleCreated(Module* mod); diff --git a/plugins/gui/src/graph_widget/contexts/graph_context.cpp b/plugins/gui/src/graph_widget/contexts/graph_context.cpp index 552e72c86643..7366fcc21f27 100644 --- a/plugins/gui/src/graph_widget/contexts/graph_context.cpp +++ b/plugins/gui/src/graph_widget/contexts/graph_context.cpp @@ -7,6 +7,7 @@ #include "gui/graph_widget/layout_locker.h" #include "gui/graph_widget/graphics_scene.h" #include "gui/graph_widget/graph_widget.h" +#include "gui/graph_widget/items/nodes/modules/standard_graphics_module.h" #include "gui/context_manager_widget/context_manager_widget.h" #include "gui/gui_globals.h" #include "gui/gui_def.h" @@ -481,6 +482,18 @@ namespace hal update(); } + void GraphContext::refreshModule(const u32 moduleId) + { + NodeBox* box = getLayouter()->boxes().boxForNode(Node(moduleId,Node::Module)); + if (!box) return; + Module* m = gNetlist->get_module_by_id(moduleId); + if (!m) return; + GraphicsModule* gm = dynamic_cast(box->item()); + if (!gm) return; + gm->setModuleLabel(m); + gm->update(); + } + Node GraphContext::nodeForGate(const u32 id) const { if (mGates.contains(id)) @@ -520,12 +533,9 @@ namespace hal if (mParentWidget) mParentWidget->storeViewport(); } - void GraphContext::moveNodeAction(const QPoint& from, const QPoint& to) + void GraphContext::updatePlacement(const GridPlacement& plc) { - const QMap nodeMap = mLayouter->positionToNodeMap(); - auto it = nodeMap.find(from); - if (it==nodeMap.constEnd()) return; - mLayouter->setNodePosition(it.value(),to); + mLayouter->updatePlacement(plc); scheduleSceneUpdate(); } diff --git a/plugins/gui/src/graph_widget/graph_context_manager.cpp b/plugins/gui/src/graph_widget/graph_context_manager.cpp index d5d9eb79b895..449a81ec299b 100644 --- a/plugins/gui/src/graph_widget/graph_context_manager.cpp +++ b/plugins/gui/src/graph_widget/graph_context_manager.cpp @@ -42,6 +42,13 @@ namespace hal "If enabled middle mouse button will pan the graphics.\n" "If disabled middle mouse button can be used for rubber band selection."); + SettingsItemCheckbox* GraphContextManager::sSettingLayoutOnEveryChange = new SettingsItemCheckbox("Invoke Layout on Every Change", + "graph_view/layout_on_chage", + false, + "Graph View", + "If enabled every change will invoke layout() routine,\n" + "which will not happen upon rename and recolor otherwise."); + GraphContextManager::GraphContextManager() : mMaxContextId(0) { @@ -341,14 +348,20 @@ namespace hal { for (GraphContext* context : mContextTreeModel->list()) if (context->modules().contains(m->get_id())) - context->scheduleSceneUpdate(); + if (sSettingLayoutOnEveryChange->value().toBool()) + context->scheduleSceneUpdate(); + else + context->refreshModule(m->get_id()); } void GraphContextManager::handleModuleTypeChanged(Module* m) const { for (GraphContext* context : mContextTreeModel->list()) if (context->modules().contains(m->get_id())) - context->scheduleSceneUpdate(); + if (sSettingLayoutOnEveryChange->value().toBool()) + context->scheduleSceneUpdate(); + else + context->refreshModule(m->get_id()); } void GraphContextManager::handleModuleColorChanged(Module* m) const @@ -360,7 +373,13 @@ namespace hal for (GraphContext* context : mContextTreeModel->list()) if (context->modules().contains(m->get_id()) // contains module || context->gates().intersects(gateIDs)) // contains gate from module - context->scheduleSceneUpdate(); + if (sSettingLayoutOnEveryChange->value().toBool()) + context->scheduleSceneUpdate(); + else + { + context->handleLayouterFinished(); + context->refreshModule(m->get_id()); + } // a context can contain a gate from a module if it is showing the module // or if it's showing a parent and the module is unfolded } diff --git a/plugins/gui/src/graph_widget/graph_graphics_view.cpp b/plugins/gui/src/graph_widget/graph_graphics_view.cpp index b9fe180dc205..fb962b04b198 100644 --- a/plugins/gui/src/graph_widget/graph_graphics_view.cpp +++ b/plugins/gui/src/graph_widget/graph_graphics_view.cpp @@ -547,17 +547,23 @@ namespace hal recursionLevelMenu(preSucMenu->addMenu("Add common successors to view …"),true, &GraphGraphicsView::handleAddCommonSuccessorToView); if (isGate) { - action = preSucMenu->addAction("Add path to successor to view …"); - action->setData(true); + action = preSucMenu->addAction("Add path to successor gate to view …"); + action->setData(SuccessorGate); + connect(action, &QAction::triggered, this, &GraphGraphicsView::handleShortestPathToView); + action = preSucMenu->addAction("Add path to successor module to view …"); + action->setData(SuccessorModule); connect(action, &QAction::triggered, this, &GraphGraphicsView::handleShortestPathToView); } recursionLevelMenu(preSucMenu->addMenu("Highlight successors …"), true, &GraphGraphicsView::handleHighlightSuccessor, true); recursionLevelMenu(preSucMenu->addMenu("Highlight successors by distance …"), true, &GraphGraphicsView::handleSuccessorDistance); if (isGate) { - action = preSucMenu->addAction("Highlight path to successor …"); - action->setData(true); - connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPath); + action = preSucMenu->addAction("Highlight path to successor gate …"); + action->setData(SuccessorGate); + connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPathGate); + action = preSucMenu->addAction("Highlight path to successor module …"); + action->setData(SuccessorModule); // direction currently not used + connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPathModule); } preSucMenu->addSeparator(); @@ -566,17 +572,17 @@ namespace hal recursionLevelMenu(preSucMenu->addMenu("Add common predecessors to view …"),false, &GraphGraphicsView::handleAddCommonPredecessorToView); if (isGate) { - action = preSucMenu->addAction("Add path to predecessor to view …"); - action->setData(false); + action = preSucMenu->addAction("Add path to predecessor gate to view …"); + action->setData(PredecessorGate); connect(action, &QAction::triggered, this, &GraphGraphicsView::handleShortestPathToView); } recursionLevelMenu(preSucMenu->addMenu("Highlight predecessors …"), false, &GraphGraphicsView::handleHighlightPredecessor, true); recursionLevelMenu(preSucMenu->addMenu("Highlight predecessors by distance …"), false, &GraphGraphicsView::handlePredecessorDistance); if (isGate) { - action = preSucMenu->addAction("Highlight path to predecessor …"); - action->setData(false); - connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPath); + action = preSucMenu->addAction("Highlight path to predecessor gate …"); + action->setData(PredecessorGate); + connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPathGate); } } @@ -1113,41 +1119,71 @@ namespace hal gContentManager->getGroupingManagerWidget()->newGroupingByDistance(level,false,mItem); } + void GraphGraphicsView::handleShortestModulePathToView() + { + + } + void GraphGraphicsView::handleShortestPathToView() { QAction* send = static_cast(sender()); Q_ASSERT(send); - bool succ = send->data().toBool(); - QSet selectableGates; - Gate* gOrigin = gNetlist->get_gate_by_id(mItem->id()); - Q_ASSERT(gOrigin); + bool succ = true; + std::vector spath; + Gate* startGate = gNetlist->get_gate_by_id(mItem->id()); + Q_ASSERT(startGate); - for (Gate* g : netlist_utils::get_next_gates(gOrigin,succ)) + if (send->data().toInt() == SuccessorModule) { - selectableGates.insert(g->get_id()); - } + QSet excludeModules; + const Module* parMod = startGate->get_module(); + while (parMod) + { + excludeModules.insert(parMod->get_id()); + parMod = parMod->get_parent_module(); + } -// GraphGraphicsViewNeighborSelector* ggvns = new GraphGraphicsViewNeighborSelector(mItem->id(), succ, this); - GateDialog gd(selectableGates, QString("Shortest path %1 gate").arg(succ?"to":"from"), nullptr, this); + ModuleDialog md(excludeModules, "Shortest path to module", true, nullptr, this); - if (gd.exec() != QDialog::Accepted) return; + if (md.exec() != QDialog::Accepted) return; - Gate* gTarget = gNetlist->get_gate_by_id(gd.selectedId()); - Q_ASSERT(gTarget); + Module* endModule = gNetlist->get_module_by_id(md.selectedId()); + Q_ASSERT(endModule); - std::vector spath; - if (succ) - spath = netlist_utils::get_shortest_path(gOrigin,gTarget); + spath = netlist_utils::get_shortest_path(startGate,endModule); + } else { - spath = netlist_utils::get_shortest_path(gTarget,gOrigin); - std::reverse(spath.begin(), spath.end()); + succ = (send->data().toInt() == SuccessorGate); + + QSet selectableGates; + + for (Gate* g : netlist_utils::get_next_gates(startGate,succ)) + { + selectableGates.insert(g->get_id()); + } + +// GraphGraphicsViewNeighborSelector* ggvns = new GraphGraphicsViewNeighborSelector(mItem->id(), succ, this); + GateDialog gd(selectableGates, QString("Shortest path %1 gate").arg(succ?"to":"from"), nullptr, this); + + if (gd.exec() != QDialog::Accepted) return; + + Gate* endGate = gNetlist->get_gate_by_id(gd.selectedId()); + Q_ASSERT(endGate); + + if (succ) + spath = netlist_utils::get_shortest_path(startGate,endGate); + else + { + spath = netlist_utils::get_shortest_path(endGate,startGate); + std::reverse(spath.begin(), spath.end()); + } } if (spath.empty()) return; auto it = spath.begin() + 1; const NodeBoxes& boxes = mGraphWidget->getContext()->getLayouter()->boxes(); - const NodeBox* lastBox = boxes.boxForGate(gOrigin); + const NodeBox* lastBox = boxes.boxForGate(startGate); Q_ASSERT(lastBox); QPoint point(lastBox->x(),lastBox->y()); QPoint deltaX(succ ? 1 : -1, 0); @@ -1168,7 +1204,7 @@ namespace hal plc = PlacementHint(PlacementHint::GridPosition); plc.addGridPosition(nd,point); } - gOrigin = g; + startGate = g; } ActionAddItemsToObject* act = new ActionAddItemsToObject({},gats); @@ -1177,11 +1213,32 @@ namespace hal act->exec(); } - void GraphGraphicsView::handleQueryShortestPath() + void GraphGraphicsView::handleQueryShortestPathModule() + { + QAction* send = static_cast(sender()); + Q_ASSERT(send); + + QSet excludeModules; + Gate* g = gNetlist->get_gate_by_id(mItem->id()); + Q_ASSERT(g); + Module* par = g->get_module(); + while(par) + { + excludeModules.insert(par->get_id()); + par = par->get_parent_module(); + } + ModuleDialog md(excludeModules, "Shortest path to module", true, nullptr, this); + + if (md.exec() != QDialog::Accepted) return; + + handleShortestPath(mItem->id(),Node(md.selectedId(),Node::Module)); + } + + void GraphGraphicsView::handleQueryShortestPathGate() { QAction* send = static_cast(sender()); Q_ASSERT(send); - bool succ = send->data().toBool(); + bool succ = send->data().toInt() == SuccessorGate; QSet selectableGates; for (Gate* g : netlist_utils::get_next_gates(gNetlist->get_gate_by_id(mItem->id()),succ)) @@ -1196,18 +1253,36 @@ namespace hal if (!targetId) return; if (succ) - handleShortestPath(mItem->id(),targetId); + handleShortestPath(mItem->id(),Node(targetId,Node::Gate)); else - handleShortestPath(targetId,mItem->id()); + handleShortestPath(targetId,Node(mItem->id(),Node::Gate)); } - void GraphGraphicsView::handleShortestPath(u32 idFrom, u32 idTo) + void GraphGraphicsView::handleShortestPath(u32 idFrom, Node nodeTo) { + std::vector spath; + Gate* g0 = gNetlist->get_gate_by_id(idFrom); Q_ASSERT(g0); - Gate* g1 = gNetlist->get_gate_by_id(idTo); - Q_ASSERT(g1); - std::vector spath = netlist_utils::get_shortest_path(g0,g1); + Q_ASSERT(!nodeTo.isNull()); + + QString target; + + if(nodeTo.isGate()) + { + Gate* g1 = gNetlist->get_gate_by_id(nodeTo.id()); + Q_ASSERT(g1); + spath = netlist_utils::get_shortest_path(g0,g1); + target = QString("gate '%1'[%2]").arg(QString::fromStdString(g1->get_name()), g1->get_id()); + } + else + { + Module* m = gNetlist->get_module_by_id(nodeTo.id()); + Q_ASSERT(m); + spath = netlist_utils::get_shortest_path(g0,m); + target = QString("module '%1'[%2]").arg(QString::fromStdString(m->get_name()), m->get_id()); + } + QSet mods; QSet gats; @@ -1230,9 +1305,9 @@ namespace hal UserActionCompound* act = new UserActionCompound; act->setUseCreatedObject(); act->addAction(new ActionCreateObject(UserActionObjectType::Grouping, - QString("Path from %1[%2] to %3[%4]") + QString("Path from '%1'[%2] to %3") .arg(QString::fromStdString(g0->get_name())).arg(g0->get_id()) - .arg(QString::fromStdString(g1->get_name())).arg(g1->get_id()))); + .arg(target))); act->addAction(new ActionAddItemsToObject(mods,gats,nets)); act->addAction(new ActionSetSelectionFocus()); act->exec(); @@ -1625,9 +1700,9 @@ namespace hal if (ggv) { if (mPickSuccessor) - ggv->handleShortestPath(mOrigin,pickedGate); + ggv->handleShortestPath(mOrigin,Node(pickedGate,Node::Gate)); else - ggv->handleShortestPath(pickedGate,mOrigin); + ggv->handleShortestPath(pickedGate,Node(mOrigin,Node::Gate)); } } this->deleteLater(); diff --git a/plugins/gui/src/graph_widget/graphics_qss_adapter.cpp b/plugins/gui/src/graph_widget/graphics_qss_adapter.cpp index 03aca43cbba7..258bb59f939b 100644 --- a/plugins/gui/src/graph_widget/graphics_qss_adapter.cpp +++ b/plugins/gui/src/graph_widget/graphics_qss_adapter.cpp @@ -40,8 +40,7 @@ namespace hal s->polish(this); ModuleShader::debugSetNetColor(mNetBaseColor); - StandardGraphicsGate::sTextColor = mNodeTextColor; - StandardGraphicsModule::sTextColor = mNodeTextColor; + GraphicsNode::sTextColor = mNodeTextColor; } void GraphicsQssAdapter::setGridAlpha(int alpha) diff --git a/plugins/gui/src/graph_widget/items/nodes/gates/graphics_gate.cpp b/plugins/gui/src/graph_widget/items/nodes/gates/graphics_gate.cpp index edb666d0a139..d950d5ed2fc0 100644 --- a/plugins/gui/src/graph_widget/items/nodes/gates/graphics_gate.cpp +++ b/plugins/gui/src/graph_widget/items/nodes/gates/graphics_gate.cpp @@ -5,8 +5,10 @@ namespace hal { - GraphicsGate::GraphicsGate(Gate* g) : GraphicsNode(ItemType::Gate, g->get_id(), QString::fromStdString(g->get_name())), mGate(g), mType(QString::fromStdString(g->get_type()->get_name())) + GraphicsGate::GraphicsGate(Gate* g) : GraphicsNode(ItemType::Gate, g->get_id()), mGate(g), mType(QString::fromStdString(g->get_type()->get_name())) { + QString textLines[3]; + textLines[0] = QString::fromStdString(g->get_name()); const GateType* gt = g->get_type(); for (const GatePin* input_pin : gt->get_input_pins()) { @@ -36,6 +38,7 @@ namespace hal mOutputPins.append(QString::fromStdString(output_pin->get_name())); } - mNodeText[1] = QString::fromStdString(gt->get_name()); + textLines[1] = QString::fromStdString(gt->get_name()); + setNodeText(textLines,true); } } // namespace hal diff --git a/plugins/gui/src/graph_widget/items/nodes/gates/standard_graphics_gate.cpp b/plugins/gui/src/graph_widget/items/nodes/gates/standard_graphics_gate.cpp index 9924f0240fd0..24dbfdf2f58b 100644 --- a/plugins/gui/src/graph_widget/items/nodes/gates/standard_graphics_gate.cpp +++ b/plugins/gui/src/graph_widget/items/nodes/gates/standard_graphics_gate.cpp @@ -11,8 +11,6 @@ #include "gui/graph_widget/graph_context_manager.h" #include "gui/gui_globals.h" -#include -#include #include #include #include @@ -25,13 +23,8 @@ qreal StandardGraphicsGate::sAlpha; QPen StandardGraphicsGate::sPen; -QColor StandardGraphicsGate::sTextColor; - -QFont StandardGraphicsGate::sTextFont[2]; QFont StandardGraphicsGate::sPinFont; -qreal StandardGraphicsGate::sTextFontHeight[2]; - qreal StandardGraphicsGate::sColorBarHeight = 30; qreal StandardGraphicsGate::sPinInnerHorizontalSpacing = 12; @@ -76,13 +69,6 @@ void StandardGraphicsGate::loadSettings() QFont font = QFont("Iosevka"); font.setPixelSize(graph_widget_constants::sFontSize); - for (int iline=0; iline<2; iline++) - { - sTextFont[iline] = font; - QFontMetricsF fmf(font); - sTextFontHeight[iline] = fmf.height(); - } - sPinFont = font; QFontMetricsF pin_fm(sPinFont); sPinFontHeight = pin_fm.height(); @@ -310,13 +296,6 @@ QPointF StandardGraphicsGate::endpointPositionByIndex(int index, bool isInput) c void StandardGraphicsGate::format(const bool& adjust_size_to_grid) { - qreal textWidth[2]; - for (int iline=0; iline<2; iline++) - { - QFontMetricsF fmf(sTextFont[iline]); - textWidth[iline] = fmf.width(mNodeText[iline]); - } - QFontMetricsF pin_fm(sPinFont); qreal max_pin_width = 0; @@ -351,15 +330,13 @@ void StandardGraphicsGate::format(const bool& adjust_size_to_grid) qreal max_pin_height = std::max(total_input_pin_height, total_output_pin_height); qreal min_body_height = sInnerNameTypeSpacing + 2 * sOuterNameTypeSpacing; - qreal maxTextWidth = 0; for (int iline=0; iline<2; iline++) { min_body_height += sTextFontHeight[iline]; - if (maxTextWidth < textWidth[iline]) maxTextWidth = textWidth[iline]; } - mWidth = max_pin_width * 2 + sPinInnerHorizontalSpacing * 2 + sPinOuterHorizontalSpacing * 2 + maxTextWidth; + mWidth = max_pin_width * 2 + sPinInnerHorizontalSpacing * 2 + sPinOuterHorizontalSpacing * 2 + mMaxTextWidth; mHeight = std::max(max_pin_height, min_body_height) + sColorBarHeight; if (adjust_size_to_grid) @@ -377,12 +354,10 @@ void StandardGraphicsGate::format(const bool& adjust_size_to_grid) mHeight = (quotient + 1) * graph_widget_constants::sGridSize; } - mTextPosition[0].setX(mWidth / 2 - textWidth[0] / 2); - mTextPosition[0].setY(std::max(mHeight / 2 - sTextFontHeight[0] / 2 - sInnerNameTypeSpacing / 2, - sColorBarHeight + sOuterNameTypeSpacing + sTextFontHeight[0])); - - mTextPosition[1].setX(mWidth / 2 - textWidth[1] / 2); - mTextPosition[1].setY(mTextPosition[0].y() + sTextFontHeight[1] + sInnerNameTypeSpacing / 2); + // reproduce formatting, sTextFontHeight[0] will be added befor placing line + qreal y0 = std::max(mHeight / 2 - sTextFontHeight[0] * 3 / 2 - sInnerNameTypeSpacing / 2, + sColorBarHeight + sOuterNameTypeSpacing); + initTextPosition(y0, sInnerNameTypeSpacing); qreal y = sColorBarHeight + sPinUpperVerticalSpacing + sPinFontAscent + sBaseline; diff --git a/plugins/gui/src/graph_widget/items/nodes/graphics_node.cpp b/plugins/gui/src/graph_widget/items/nodes/graphics_node.cpp index 557bfc6329f3..7022b1728b6d 100644 --- a/plugins/gui/src/graph_widget/items/nodes/graphics_node.cpp +++ b/plugins/gui/src/graph_widget/items/nodes/graphics_node.cpp @@ -3,18 +3,81 @@ #include "gui/graph_widget/graph_widget_constants.h" #include +#include namespace hal { - GraphicsNode::GraphicsNode(const ItemType type, const u32 id, const QString& name) - : GraphicsItem(type, id) + QColor GraphicsNode::sTextColor; + QFont GraphicsNode::sTextFont[3]; + qreal GraphicsNode::sTextFontHeight[3] = {0, 0, 0}; + + + GraphicsNode::GraphicsNode(const ItemType type, const u32 id) + : GraphicsItem(type, id), mMaxTextWidth(0) { - mNodeText[0] = name; setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); + //setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsGeometryChanges | ItemIsFocusable); //setAcceptHoverEvents(true); } + void GraphicsNode::loadSettings() + { + QFont font = QFont("Iosevka"); + font.setPixelSize(graph_widget_constants::sFontSize); + + for (int iline=0; iline<3; iline++) + { + sTextFont[iline] = font; + QFontMetricsF fmf(font); + sTextFontHeight[iline] = fmf.height(); + } + } + + void GraphicsNode::setNodeText(const QString* lines, bool init) + { + for (int iline=0; iline<3; iline++) + { + if (lines[iline].isEmpty()) continue; + QFontMetricsF fmf(sTextFont[iline]); + mNodeText[iline] = lines[iline]; + qreal textWidth = fmf.width(mNodeText[iline]); + if (init) + { + if (textWidth > mMaxTextWidth) + mMaxTextWidth = textWidth; + } + else + { + if (textWidth > mMaxTextWidth) + { + QString shorter = mNodeText[iline]; + while (!mNodeText[iline].isEmpty() && textWidth > mMaxTextWidth) + { + shorter.chop(1); + textWidth = fmf.width(shorter + "…"); + } + mNodeText[iline] = shorter + "…"; + } + mTextPosition[iline].setX(mWidth / 2 - textWidth / 2); + } + } + } + + void GraphicsNode::initTextPosition(qreal y0, qreal spacing) + { + for (int iline=0; iline<3; iline++) + { + QFontMetricsF fmf(sTextFont[iline]); + qreal textWidth = fmf.width(mNodeText[iline]); + y0 += sTextFontHeight[iline]; + mTextPosition[iline].setX(mWidth / 2 - textWidth / 2); + mTextPosition[iline].setY(y0); + y0 += spacing; + } + } + + QRectF GraphicsNode::boundingRect() const { return QRectF(0, 0, mWidth, mHeight); diff --git a/plugins/gui/src/graph_widget/items/nodes/modules/graphics_module.cpp b/plugins/gui/src/graph_widget/items/nodes/modules/graphics_module.cpp index 47c79292a604..743714d9776a 100644 --- a/plugins/gui/src/graph_widget/items/nodes/modules/graphics_module.cpp +++ b/plugins/gui/src/graph_widget/items/nodes/modules/graphics_module.cpp @@ -7,10 +7,9 @@ namespace hal { - GraphicsModule::GraphicsModule(Module* m) : GraphicsNode(ItemType::Module, m->get_id(), QString::fromStdString(m->get_name())) + GraphicsModule::GraphicsModule(Module* m) : GraphicsNode(ItemType::Module, m->get_id()) { - mNodeText[1] = QString::fromStdString(m->get_type()); - mNodeText[mNodeText[1].isEmpty() ? 1 : 2] = "Module"; + setModuleLabel(m, true); for (hal::ModulePin* pin : m->get_pins()) { @@ -38,4 +37,13 @@ namespace hal } } } + + void GraphicsModule::setModuleLabel(const Module* m, bool init) + { + QString textLines[3]; + textLines[0] = QString::fromStdString(m->get_name()); + textLines[1] = QString::fromStdString(m->get_type()); + textLines[textLines[1].isEmpty() ? 1 : 2] = "Module"; + setNodeText(textLines,init); + } } // namespace hal diff --git a/plugins/gui/src/graph_widget/items/nodes/modules/standard_graphics_module.cpp b/plugins/gui/src/graph_widget/items/nodes/modules/standard_graphics_module.cpp index 3afc267a53bc..cd5291bb6b10 100644 --- a/plugins/gui/src/graph_widget/items/nodes/modules/standard_graphics_module.cpp +++ b/plugins/gui/src/graph_widget/items/nodes/modules/standard_graphics_module.cpp @@ -6,8 +6,6 @@ #include "gui/gui_utils/graphics.h" #include "hal_core/netlist/gate.h" -#include -#include #include #include #include @@ -22,13 +20,8 @@ namespace hal QPen StandardGraphicsModule::sPen; - QColor StandardGraphicsModule::sTextColor; - - QFont StandardGraphicsModule::sTextFont[3]; QFont StandardGraphicsModule::sPinFont; - qreal StandardGraphicsModule::sTextFontHeight[3] = {0, 0, 0}; - qreal StandardGraphicsModule::sColorBarHeight = 30; qreal StandardGraphicsModule::sPinInnerHorizontalSpacing = 12; @@ -68,13 +61,6 @@ namespace hal QFont font = QFont("Iosevka"); font.setPixelSize(graph_widget_constants::sFontSize); - for (int iline = 0; iline < 3; iline++) - { - sTextFont[iline] = font; - QFontMetricsF fmf(font); - sTextFontHeight[iline] = fmf.height(); - } - sPinFont = font; QFontMetricsF pin_fm(sPinFont); @@ -243,13 +229,6 @@ namespace hal void StandardGraphicsModule::format(const bool& adjust_size_to_grid) { - qreal textWidth[3] = {0, 0, 0}; - for (int iline = 0; iline < 3; iline++) - { - QFontMetricsF fmf(sTextFont[iline]); - textWidth[iline] = fmf.width(mNodeText[iline]); - } - QFontMetricsF pin_fm(sPinFont); qreal max_pin_width = 0; @@ -280,16 +259,12 @@ namespace hal qreal max_pin_height = std::max(total_input_pin_height, total_output_pin_height); qreal min_body_height = sInnerNameTypeSpacing + 2 * sOuterNameTypeSpacing; - qreal maxTextWidth = 0; for (int iline = 0; iline < 3; iline++) { - if (iline != 2 || !mNodeText[iline].isEmpty()) - min_body_height += sTextFontHeight[iline]; - if (maxTextWidth < textWidth[iline]) - maxTextWidth = textWidth[iline]; + min_body_height += sTextFontHeight[iline]; } - mWidth = max_pin_width * 2 + sPinInnerHorizontalSpacing * 2 + sPinOuterHorizontalSpacing * 2 + maxTextWidth; + mWidth = max_pin_width * 2 + sPinInnerHorizontalSpacing * 2 + sPinOuterHorizontalSpacing * 2 + mMaxTextWidth; mHeight = std::max(max_pin_height, min_body_height) + sColorBarHeight; if (adjust_size_to_grid) @@ -309,13 +284,7 @@ namespace hal qreal ytext = std::max(mHeight / 2 - sTextFontHeight[0] * 3 / 2 - sInnerNameTypeSpacing / 2, sColorBarHeight + sOuterNameTypeSpacing); - for (int iline = 0; iline < 3; iline++) - { - ytext += sTextFontHeight[iline]; - mTextPosition[iline].setX(mWidth / 2 - textWidth[iline] / 2); - mTextPosition[iline].setY(ytext); - ytext += sInnerNameTypeSpacing / 2; - } + initTextPosition(ytext, sInnerNameTypeSpacing); qreal y = sColorBarHeight + sPinUpperVerticalSpacing + sPinFontAscent + sBaseline; diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 9a465eaaae1a..bd2ea7fd0103 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -107,6 +107,29 @@ namespace hal return mPositionToNodeMap; } + void GraphLayouter::updatePlacement(const GridPlacement& plc) + { + // Keep track which positions are occupied by new nodes, possible values: + // -1 : position no longer occupied + // 1 : position which was not occupied before now occupied + // 0 : old position taken by new node + QHash positionOccupied; + + for (auto it = plc.constBegin(); it != plc.constEnd(); ++it) + { + auto jt = mNodeToPositionMap.find(it.key()); + if (jt == mNodeToPositionMap.end()) continue; + --positionOccupied[jt.value()]; // old value from mNodePositionMap + ++positionOccupied[it.value()]; // new value from plc + jt.value() = it.value(); + mPositionToNodeMap[it.value()] = it.key(); + } + + for (auto rpit = positionOccupied.begin(); rpit != positionOccupied.end(); ++rpit) + if (rpit.value() < 0) + mPositionToNodeMap.remove(rpit.key()); + } + void GraphLayouter::setNodePosition(const Node& n, const QPoint& p) { if (mNodeToPositionMap.contains(n)) diff --git a/plugins/gui/src/module_model/module_model.cpp b/plugins/gui/src/module_model/module_model.cpp index e4fb97e0d222..3eb26fd427c9 100644 --- a/plugins/gui/src/module_model/module_model.cpp +++ b/plugins/gui/src/module_model/module_model.cpp @@ -17,6 +17,7 @@ namespace hal setHeaderLabels(QStringList() << "Name" << "ID" << "Type"); connect(gNetlistRelay, &NetlistRelay::moduleCreated, this, &ModuleModel::handleModuleCreated); connect(gNetlistRelay, &NetlistRelay::moduleNameChanged, this, &ModuleModel::handleModuleNameChanged); + connect(gNetlistRelay, &NetlistRelay::moduleTypeChanged, this, &ModuleModel::handleModuleTypeChanged); connect(gNetlistRelay, &NetlistRelay::moduleParentChanged, this, &ModuleModel::handleModuleParentChanged); connect(gNetlistRelay, &NetlistRelay::moduleSubmoduleAdded, this, &ModuleModel::handleModuleSubmoduleAdded); connect(gNetlistRelay, &NetlistRelay::moduleSubmoduleRemoved, this, &ModuleModel::handleModuleSubmoduleRemoved); @@ -369,6 +370,11 @@ namespace hal updateModuleName(mod->get_id()); } + void ModuleModel::handleModuleTypeChanged(Module* mod) + { + updateModuleType(mod->get_id()); + } + void ModuleModel::handleModuleRemoved(Module* mod) { removeModule(mod->get_id()); @@ -786,7 +792,23 @@ namespace hal ModuleItem* item = it.value(); Q_ASSERT(item); - item->setName(QString::fromStdString(gNetlist->get_module_by_id(id)->get_name())); // REMOVE & ADD AGAIN + item->setName(QString::fromStdString(gNetlist->get_module_by_id(id)->get_name())); + + QModelIndex index = getIndexFromItem(item); + Q_EMIT dataChanged(index, index); + } + } + + void ModuleModel::updateModuleType(u32 id) + { + Q_ASSERT(gNetlist->get_module_by_id(id)); + + for (auto it = mModuleMap.lowerBound(id); it != mModuleMap.upperBound(id); ++it) + { + ModuleItem* item = it.value(); + Q_ASSERT(item); + + item->setModuleType(QString::fromStdString(gNetlist->get_module_by_id(id)->get_type())); QModelIndex index = getIndexFromItem(item); Q_EMIT dataChanged(index, index); diff --git a/plugins/gui/src/style/style.cpp b/plugins/gui/src/style/style.cpp index cdb20462cbfa..f5b84375eab3 100644 --- a/plugins/gui/src/style/style.cpp +++ b/plugins/gui/src/style/style.cpp @@ -28,6 +28,7 @@ namespace hal void debugUpdate() { GraphicsItem::loadSettings(); + GraphicsNode::loadSettings(); StandardGraphicsModule::loadSettings(); StandardGraphicsGate::loadSettings(); GraphicsNet::loadSettings(); diff --git a/plugins/gui/src/user_action/action_move_node.cpp b/plugins/gui/src/user_action/action_move_node.cpp index 17c8810b13d6..6f8cc2033052 100644 --- a/plugins/gui/src/user_action/action_move_node.cpp +++ b/plugins/gui/src/user_action/action_move_node.cpp @@ -160,18 +160,7 @@ namespace hal } LayoutLocker llock; - ctx->clear(); - - QSet modIds; - QSet gateIds; - - for (Node node : mGridPlacement.keys()) - { - if(node.isModule()) modIds.insert(node.id()); - else gateIds.insert(node.id()); - } - - ctx->add(modIds, gateIds, PlacementHint(mGridPlacement)); + ctx->updatePlacement(mGridPlacement); ctx->scheduleSceneUpdate(); return UserAction::exec(); diff --git a/src/netlist/netlist_utils.cpp b/src/netlist/netlist_utils.cpp index 556d7d012d83..aba279b4ef53 100644 --- a/src/netlist/netlist_utils.cpp +++ b/src/netlist/netlist_utils.cpp @@ -19,10 +19,26 @@ namespace hal { namespace { - std::vector get_shortest_path_internal(Gate* start_gate, Gate* end_gate) + + std::vector get_shortest_path_internal(Gate* start_gate, const std::unordered_set& end_gates) { - if (start_gate == end_gate) + if (end_gates.empty()) + return std::vector(); + + Gate* end_gate_single = *(end_gates.begin()); + + auto heurekaSingle = [end_gate_single] (Gate* test_gate) { return test_gate==end_gate_single; } ; + + auto heurekaMultiple = [end_gates] (Gate* test_gate) { return end_gates.find(test_gate) != end_gates.end(); } ; + + auto heureka = [heurekaSingle, heurekaMultiple, end_gates] (Gate* test_gate) { + if (end_gates.size() > 1) + return heurekaMultiple(test_gate); + return heurekaSingle(test_gate);} ; + + if (heureka(start_gate)) return std::vector(); + std::vector v0; v0.push_back(start_gate); std::unordered_map originMap; @@ -37,11 +53,11 @@ namespace hal continue; // already routed to v1.push_back(g1); originMap[g1] = g0; - if (g1 == end_gate) + if (heureka(g1)) { // heureka! std::vector retval; - Gate* g = end_gate; + Gate* g = g1; while (g != start_gate) { retval.insert(retval.begin(), g); @@ -268,12 +284,26 @@ namespace hal return retval; } + std::vector get_shortest_path(Gate* start_gate, Module* end_module) + { + std::unordered_set end_gates; + for (Gate* g : end_module->get_gates(nullptr, true)) + { + end_gates.insert(g); + } + return get_shortest_path_internal(start_gate, end_gates); + } + std::vector get_shortest_path(Gate* start_gate, Gate* end_gate, bool search_both_directions) { - std::vector path_forward = get_shortest_path_internal(start_gate, end_gate); + std::unordered_set end_gates_forward; + end_gates_forward.insert(end_gate); + std::vector path_forward = get_shortest_path_internal(start_gate, end_gates_forward); if (!search_both_directions) return path_forward; - std::vector path_reverse = get_shortest_path_internal(end_gate, start_gate); + std::unordered_set start_gates_reverse; + start_gates_reverse.insert(start_gate); + std::vector path_reverse = get_shortest_path_internal(end_gate, start_gates_reverse); return (path_reverse.size() < path_forward.size()) ? path_reverse : path_forward; } diff --git a/src/python_bindings/bindings/netlist_utils.cpp b/src/python_bindings/bindings/netlist_utils.cpp index 21a0a5d1bcc8..34ea97b51ca9 100644 --- a/src/python_bindings/bindings/netlist_utils.cpp +++ b/src/python_bindings/bindings/netlist_utils.cpp @@ -391,14 +391,25 @@ namespace hal :rtype: list[hal_py.Gate] )"); - py_netlist_utils.def("get_shortest_path", &netlist_utils::get_shortest_path, py::arg("start_gate"), py::arg("end_gate"), py::arg("search_both_directions") = false, R"( + py_netlist_utils.def("get_shortest_path", py::overload_cast(&netlist_utils::get_shortest_path), py::arg("start_gate"), py::arg("end_gate"), py::arg("search_both_directions") = false, R"( Find the shortest path (i.e., theresult set with the lowest number of gates) that connects the start gate with the end gate. The gate where the search started from will be the first in the result vector, the end gate will be the last. If there is no such path an empty vector is returned. If there is more than one path with the same length only the first one is returned. - :param dict[hal_py.GateType,list[hal_py.GatePin]] input_pins: The input pins (of every gate type of the sequence) through which the gates must be connected. - :param dict[hal_py.GateType,list[hal_py.GatePin]] output_pins: The output pins (of every gate type of the sequence) through which the gates must be connected. - :param lambda filter: An optional filter function to be evaluated on each gate. + :param hal_py.Gate start_gate: The start gate for the path (might be the end if searching both directions) + :param hal_py.Gate end_gate: The end gate for the path (might be the start if searching both directions) + :bool search_both_directions: If true checking start <-> end, which ever direction is shorter + :returns: A list of gates that form a chain on success, an empty list on error. + :rtype: list[hal_py.Gate] + )"); + + py_netlist_utils.def("get_shortest_path", py::overload_cast(&netlist_utils::get_shortest_path), py::arg("start_gate"), py::arg("end_module"), R"( + Find the shortest path (i.e., theresult set with the lowest number of gates) that connects the start gate with any gate for the given module. + The gate where the search started from will be the first in the result vector, the end gate will be the last. + If there is no such path an empty vector is returned. If there is more than one path with the same length only the first one is returned. + + :param hal_py.Gate start_gate: The start gate for the path + :param hal_py.Module end_module: The module which contains the end gate for the path :returns: A list of gates that form a chain on success, an empty list on error. :rtype: list[hal_py.Gate] )");