HAL
graph_graphics_view.cpp
Go to the documentation of this file.
2 
23 #include "gui/gui_globals.h"
24 #include "gui/gui_utils/netlist.h"
42 #include "hal_core/netlist/gate.h"
45 #include "hal_core/netlist/net.h"
47 #include "hal_core/utilities/log.h"
50 
51 #include <QAction>
52 #include <QApplication>
53 #include <QColorDialog>
54 #include <QDrag>
55 #include <QInputDialog>
56 #include <QLabel>
57 #include <QLineEdit>
58 #include <QList>
59 #include <QMenu>
60 #include <QMessageBox>
61 #include <QMimeData>
62 #include <QScrollBar>
63 #include <QStyleOptionGraphicsItem>
64 #include <QWheelEvent>
65 #include <QWidgetAction>
66 #include <QDebug>
67 #include <algorithm>
68 #include <qmath.h>
69 
70 
71 namespace hal
72 {
73  const QString GraphGraphicsView::sAssignToGrouping("Assign to grouping ");
74 
76  : QGraphicsView(parent), mGraphWidget(parent),
77  mMinimapEnabled(false), mGridEnabled(true), mGridClustersEnabled(true),
78  mGridType(GraphicsScene::GridType::Dots),
79  mDragController(new DragController(mGraphWidget,this)),
80  mDragModifier(Qt::KeyboardModifier::AltModifier),
81  mPanModifier(Qt::KeyboardModifier::ShiftModifier),
82  mZoomModifier(Qt::NoModifier),
83  mZoomFactorBase(1.0015)
84  {
85  connect(gSelectionRelay, &SelectionRelay::subfocusChanged, this, &GraphGraphicsView::conditionalUpdate);
86  connect(this, &GraphGraphicsView::customContextMenuRequested, this, &GraphGraphicsView::showContextMenu);
87 
91 
92  setAcceptDrops(true);
93  setMouseTracking(true);
94  }
95 
96  void GraphGraphicsView::conditionalUpdate()
97  {
98  if (QStyleOptionGraphicsItem::levelOfDetailFromTransform(transform()) >= graph_widget_constants::sGateMinLod)
99  update();
100  }
101 
103  {
105  if (!ctx) return;
110 
111  // delete context/view if nothing left to show
112  QSet<u32> remainingMods = ctx->modules() - gSelectionRelay->selectedModules();
113  QSet<u32> remainingGats = ctx->gates() - gSelectionRelay->selectedGates();
114  if (remainingMods.isEmpty() && remainingGats.isEmpty())
115  {
116  UserActionCompound* compound = new UserActionCompound;
117  compound->setUseCreatedObject();
118  act->setObjectLock(true);
119  compound->addAction(act);
120  compound->addAction(new ActionDeleteObject);
121  compound->exec();
122  }
123  else
124  act->exec();
125  }
126 
127  void GraphGraphicsView::handleIsolationViewAction()
128  {
129  auto selected_modules = gSelectionRelay->selectedModules();
130  auto selected_gates = gSelectionRelay->selectedGates();
131 
132  // When there is only one module selected, check if there is a context connected to that module
133  // If yes, select the context
134  // If no, create a new context and connect the module to the context
135  if (selected_modules.size() == 1 && selected_gates.empty())
136  {
137  u32 module_id = *selected_modules.begin();
138  auto module_context = gGraphContextManager->getContextByExclusiveModuleId(module_id);
139  if (module_context)
140  {
143  }
144  else
145  {
146  UserActionCompound* act = new UserActionCompound;
147  act->setUseCreatedObject();
148  QString name = QString::fromStdString(gNetlist->get_module_by_id(module_id)->get_name()) + " (ID: " + QString::number(module_id) + ")";
149  act->addAction(new ActionCreateObject(UserActionObjectType::ContextView, name));
150  act->addAction(new ActionAddItemsToObject(selected_modules, selected_gates));
151  act->exec();
152  GraphContext* context = gGraphContextManager->getContextById(act->object().id());
153  context->setDirty(false);
154  context->setExclusiveModuleId(module_id);
155  }
156  return;
157  }
158 
159  QString name = gGraphContextManager->nextViewName("Isolated View");
160  UserActionCompound* act = new UserActionCompound;
161  act->setUseCreatedObject();
162  act->addAction(new ActionCreateObject(UserActionObjectType::ContextView, name));
163  act->addAction(new ActionAddItemsToObject(selected_modules, selected_gates));
164  act->exec();
165  GraphContext* context = gGraphContextManager->getContextById(act->object().id());
166  context->setDirty(false);
167  }
168 
169  void GraphGraphicsView::adjustMinScale()
170  {
171  if (!scene())
172  return;
173  mMinScale = std::min(viewport()->width() / scene()->width(), viewport()->height() / scene()->height());
174  }
175 
176  void GraphGraphicsView::handleAddCommentAction()
177  {
178  auto action = dynamic_cast<QAction*>(sender());
179  if(!action) return;
180 
181  auto node = action->data().value<Node>();
182  CommentDialog commentDialog("New Comment");
183  if(commentDialog.exec() == QDialog::Accepted)
184  gCommentManager->addComment(new CommentEntry(node, commentDialog.getText(), commentDialog.getHeader()));
185  commentDialog.close();
186  }
187 
189  {
191 
192  // USE CONSISTENT METHOD NAMES
194  GraphicsScene::setGridEnabled(mGridEnabled);
195  GraphicsScene::setGridClustersEnabled(mGridClustersEnabled);
196  GraphicsScene::setGridType(mGridType);
197 
200 
205 
207  }
208 
210  {
211  if (event->button() != Qt::LeftButton)
212  return;
213 
214  QGraphicsItem* item = itemAt(event->pos());
215  if (!item) return;
216 
217  CommentSpeechBubble* csb = dynamic_cast<CommentSpeechBubble*>(item);
218  if (csb)
219  {
220  csb->mouseDoubleClickEvent(nullptr);
221  return;
222  }
223 
224  GraphicsItem* git = dynamic_cast<GraphicsItem*>(itemAt(event->pos()));
225 
226  if (!git || git->itemType() != ItemType::Module)
227  return;
228 
229  Q_EMIT moduleDoubleClicked(git->id());
230  }
231 
233  {
234  Q_UNUSED(rect)
235 
236 #ifdef GUI_DEBUG_GRID
237  if(mGraphWidget->getContext()->scene()->debugGridEnabled())
238  debugDrawLayouterGridpos(painter);
239 #endif
240 
241  if (!mMinimapEnabled)
242  return;
243 
244  QRectF map(viewport()->width() - 210, viewport()->height() - 130, 200, 120);
245  painter->resetTransform();
246  painter->fillRect(map, QColor(0, 0, 0, 170));
247  }
248 
249 #ifdef GUI_DEBUG_GRID
250  void GraphGraphicsView::debugDrawLayouterGridpos(QPainter* painter)
251  {
252  painter->resetTransform();
253  painter->setPen(QPen(Qt::magenta));
254  QString pos_str = QString("(%1, %2)").arg(m_debug_gridpos.x()).arg(m_debug_gridpos.y());
255  painter->drawText(QPoint(25, 25), pos_str);
256  }
257 #endif
258 
260  {
261  // it the clicked item is a speechbubble, simply return so that it does
262  // not change / clear the current selection, double-click however works fine
263  if(dynamic_cast<CommentSpeechBubble*>(itemAt(event->pos())))
264  return;
265 
266  if ((event->modifiers() == mPanModifier && event->button() == Qt::LeftButton) ||
268  {
269  mMovePosition = event->pos();
270  }
271  else if (event->button() == Qt::LeftButton)
272  {
273  GraphicsNode* item = dynamic_cast<GraphicsNode*>(itemAt(event->pos()));
274  if (item && itemDraggable(item))
275  {
276  mDragController->set(item, event->pos());
277  }
278  else
279  {
280  mDragController->clear();
281  }
282 
283  // we still need the normal mouse logic for single clicks
284  mousePressEventNotItemDrag(event);
285  }
286  else
287  mousePressEventNotItemDrag(event);
288  }
289 
290  void GraphGraphicsView::mousePressEventNotItemDrag(QMouseEvent *event)
291  {
293  GraphicsScene* sc = dynamic_cast<GraphicsScene*>(scene());
294  if (sc) sc->setMousePressed(true);
295  }
296 
297 
299  {
300  GraphicsScene* sc = dynamic_cast<GraphicsScene*>(scene());
301  if (sc) sc->setMousePressed(false);
303  }
304 
306  {
307  if (!scene())
308  return;
309 
310  QPointF delta = mTargetViewportPos - event->pos();
311 
312  if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5)
313  {
314  mTargetViewportPos = event->pos();
315  mTargetScenePos = mapToScene(event->pos());
316  }
317 
318  if ((event->buttons().testFlag(Qt::LeftButton) && event->modifiers() == mPanModifier) ||
320  {
322  QScrollBar* vBar = verticalScrollBar();
323  QPoint delta_move = event->pos() - mMovePosition;
324  mMovePosition = event->pos();
325  hBar->setValue(hBar->value() + (isRightToLeft() ? delta_move.x() : -delta_move.x()));
326  vBar->setValue(vBar->value() - delta_move.y());
327  }
328  else if (event->buttons().testFlag(Qt::LeftButton))
329  {
330  if (mDragController->hasDragged(event->pos()))
331  {
332  QDrag* drag = new QDrag(this);
333  QMimeData* mimeData = new QMimeData;
334 
335  // TODO set MIME type and icon
336  mimeData->setText("dragTest");
337  drag->setMimeData(mimeData);
338  // drag->setPixmap(iconPixmap);
339 
340  // enable DragMoveEvents until mouse released
341  drag->exec(Qt::MoveAction);
342  }
343  }
344 #ifdef GUI_DEBUG_GRID
345  debugShowLayouterGridpos(event->pos());
346 #endif
347 
349  }
350 
352  {
353  if (event->source() == this && event->proposedAction() == Qt::MoveAction)
354  {
355  mDragController->enterDrag(event->keyboardModifiers() == mDragModifier);
356  event->acceptProposedAction();
357  }
358  else
359  {
360  //causes a bug where dockbar-buttons just disappear instead of snapping back when dragged into the view
361 // QGraphicsView::dragEnterEvent(event);
362  }
363  }
364 
366  {
367  Q_UNUSED(event)
368  mDragController->clear();
369  }
370 
371  void GraphGraphicsView::dragPan(float dpx, float dpy)
372  {
373  if (dpx != 0)
374  {
376  int hValue = hBar->value() + 10*dpx;
377  if (hValue < hBar->minimum()) hBar->setMinimum(hValue);
378  if (hValue > hBar->maximum()) hBar->setMaximum(hValue);
379  hBar->setValue(hValue);
380  }
381  if (dpy != 0)
382  {
383  QScrollBar* vBar = verticalScrollBar();
384  int vValue = vBar->value() + 10*dpy;
385  if (vValue < vBar->minimum()) vBar->setMinimum(vValue);
386  if (vValue > vBar->maximum()) vBar->setMaximum(vValue);
387  vBar->setValue(vValue);
388  }
389  }
390 
392  {
393  if (event->source() == this && event->proposedAction() == Qt::MoveAction)
394  {
395  QPair<QPoint,QPointF> snap = closestLayouterPos(mapToScene(event->pos()));
396 
397  mDragController->move(event->pos(),event->keyboardModifiers() == mDragModifier,snap.first);
398 
399  QPoint p = event->pos() - viewport()->geometry().topLeft();
400  float rx = 100. * p.x() / viewport()->geometry().width();
401  float ry = 100. * p.y() / viewport()->geometry().height();
402 // qDebug() << "move it" << event->pos() << viewport()->geometry() << rx << ry;
403  float dpx = 0;
404  float dpy = 0;
405  if (rx < 10) dpx = -10+rx;
406  if (rx > 90) dpx = rx-90;
407  if (ry < 10) dpy = -10+ry;
408  if (ry > 90) dpy = ry-90;
409  if (dpx !=0 || dpy != 0)
410  dragPan(dpx, dpy);
411  }
412  }
413 
415  {
416  if (event->source() == this && event->proposedAction() == Qt::MoveAction)
417  {
418  event->acceptProposedAction();
419  if (mDragController->isDropAllowed())
420  {
421  GridPlacement* plc = mDragController->finalGridPlacement();
422  GraphContext* context = mGraphWidget->getContext();
423  GraphLayouter* layouter = context->getLayouter();
424  assert(layouter->done()); // ensure grid stable
425  ActionMoveNode* act = new ActionMoveNode(context->id(),plc);
426  if (act->exec())
427  context->setDirty(true);
428  delete plc;
429  }
430  }
431  else
432  {
434  }
435  mDragController->clear();
436  }
437 
439  {
440  if (QApplication::keyboardModifiers() == mZoomModifier)
441  {
442  if (event->orientation() == Qt::Vertical)
443  {
444  qreal angle = event->angleDelta().y();
445  qreal factor = qPow(mZoomFactorBase, angle);
446  gentleZoom(factor);
447  }
448  }
449  }
450 
452  {
453  switch (event->key())
454  {
455  case Qt::Key_Space: {
456  //qDebug() << "Space pressed";
457  }
458  break;
459  }
460 
461  event->ignore();
462  }
463 
465  {
466  switch (event->key())
467  {
468  case Qt::Key_Space: {
469  //qDebug() << "Space released";
470  }
471  break;
472  }
473 
474  event->ignore();
475  }
476 
478  {
480  adjustMinScale();
481  }
482 
483  void GraphGraphicsView::showContextMenu(const QPoint& pos)
484  {
485  GraphicsScene* s = static_cast<GraphicsScene*>(scene());
486 
487  if (!s)
488  return;
489 
490  QMenu context_menu(this);
491  QAction* action;
492 
493  QGraphicsItem* item = itemAt(pos);
494  bool isGate = false;
495  bool isModule = false;
496  bool isNet = false;
497 
498  // otherwise crashes, speechbubbles do not need a context menu (for now)
499  // add ItemType::SpeechBubble so that it can be handled better?
500  if(dynamic_cast<CommentSpeechBubble*>(item)) return;
501 
502  bool isMultiGates = gSelectionRelay->selectedGates().size() > 1 &&
504  if (item)
505  {
506  mItem = static_cast<GraphicsItem*>(item);
507  isGate = mItem->itemType() == ItemType::Gate;
508  isModule = mItem->itemType() == ItemType::Module;
509  isNet = mItem->itemType() == ItemType::Net;
510 
511  if (isGate)
512  {
513  if (!gSelectionRelay->containsGate(mItem->id()))
514  {
516  gSelectionRelay->addGate(mItem->id());
519  }
520  }
521  else if (isModule)
522  {
523  if (!gSelectionRelay->containsModule(mItem->id()))
524  {
526  gSelectionRelay->addModule(mItem->id());
529  }
530  }
531  else if (isNet)
532  {
533  if (!gSelectionRelay->containsNet((mItem->id())))
534  {
536  gSelectionRelay->addNet(mItem->id());
539  }
540  }
541 
542  if (isGate || isModule)
543  {
544  QMenu* preSucMenu = context_menu.addMenu("Successor/Predecessor …");
545  recursionLevelMenu(preSucMenu->addMenu("Add successors to view …"), true, &GraphGraphicsView::handleAddSuccessorToView);
546  if (isMultiGates)
547  recursionLevelMenu(preSucMenu->addMenu("Add common successors to view …"),true, &GraphGraphicsView::handleAddCommonSuccessorToView);
548  if (isGate)
549  {
550  action = preSucMenu->addAction("Add path to successor gate to view …");
551  action->setData(SuccessorGate);
552  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleShortestPathToView);
553  action = preSucMenu->addAction("Add path to successor module to view …");
554  action->setData(SuccessorModule);
555  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleShortestPathToView);
556  }
557  recursionLevelMenu(preSucMenu->addMenu("Highlight successors …"), true, &GraphGraphicsView::handleHighlightSuccessor, true);
558  recursionLevelMenu(preSucMenu->addMenu("Highlight successors by distance …"), true, &GraphGraphicsView::handleSuccessorDistance);
559  if (isGate)
560  {
561  action = preSucMenu->addAction("Highlight path to successor gate …");
562  action->setData(SuccessorGate);
563  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPathGate);
564  action = preSucMenu->addAction("Highlight path to successor module …");
565  action->setData(SuccessorModule);
566  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPathModule);
567  }
568 
569  preSucMenu->addSeparator();
570  recursionLevelMenu(preSucMenu->addMenu("Add predecessors to view …"), false, &GraphGraphicsView::handleAddPredecessorToView);
571  if (isMultiGates)
572  recursionLevelMenu(preSucMenu->addMenu("Add common predecessors to view …"),false, &GraphGraphicsView::handleAddCommonPredecessorToView);
573  if (isGate)
574  {
575  action = preSucMenu->addAction("Add path to predecessor gate to view …");
576  action->setData(PredecessorGate);
577  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleShortestPathToView);
578  action = preSucMenu->addAction("Add path to predecessor module to view …");
579  action->setData(PredecessorModule);
580  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleShortestPathToView);
581  }
582  recursionLevelMenu(preSucMenu->addMenu("Highlight predecessors …"), false, &GraphGraphicsView::handleHighlightPredecessor, true);
583  recursionLevelMenu(preSucMenu->addMenu("Highlight predecessors by distance …"), false, &GraphGraphicsView::handlePredecessorDistance);
584  if (isGate)
585  {
586  action = preSucMenu->addAction("Highlight path to predecessor gate …");
587  action->setData(PredecessorGate);
588  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPathGate);
589  action = preSucMenu->addAction("Highlight path to predecessor module …");
590  action->setData(PredecessorModule);
591  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPathModule);
592  }
593  }
594 
595  action = context_menu.addAction("Remove selected items from view");
597 
599  {
600  action = context_menu.addAction("Cancel pick-item mode");
601  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleCancelPickMode);
602  }
603 
604  if(isModule)
605  ModuleContextMenu::addModuleSubmenu(&context_menu, mItem->id());
606  else if(isGate)
607  ModuleContextMenu::addGateSubmenu(&context_menu, mItem->id());
608  else if(isNet)
609  ModuleContextMenu::addNetSubmenu(&context_menu, mItem->id());
610 
611  // Appended to single selected item menu
612  if(isGate || isModule)
613  {
614  action = context_menu.addAction(" Fold parent module");
615  QObject::connect(action, &QAction::triggered, this, &GraphGraphicsView::handleFoldParentSingle);
616  }
617  if(isModule)
618  {
619  action = context_menu.addAction(" Unfold module");
620  QObject::connect(action, &QAction::triggered, this, &GraphGraphicsView::handleUnfoldSingleAction);
621  }
622 
624  {
626 
627  // Appended to multiple selected items menu
628  action = context_menu.addAction(" Fold all parent modules");
629  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleFoldParentAll);
630  action = context_menu.addAction(" Isolate all in new view");
631  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleIsolationViewAction);
632  action = context_menu.addAction(" Unfold all selected modules");
633  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleUnfoldAllAction);
634 
635  action = context_menu.addAction(" Add comment");
636  QVariant data;
637  data.setValue(Node(mItem->id(), isGate ? Node::NodeType::Gate : Node::NodeType::Module));
638  action->setData(data);
639  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleAddCommentAction);
640  }
641  }
642  else
643  {
644  context_menu.addAction("This view:")->setEnabled(false);
645 
646  action = context_menu.addAction(" Add module to view");
647  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleAddModuleToView);
648 
649  int selectable_modules_count = 0;
650  QSet<u32> not_selectable_modules = getNotSelectableModules();
651 
652  for (Module* m : gNetlist->get_modules())
653  if (!not_selectable_modules.contains(m->get_id()))
654  selectable_modules_count++;
655 
656  if (selectable_modules_count == 0)
657  action->setDisabled(true);
658 
659  action = context_menu.addAction(" Add gate to view");
660  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleAddGateToView);
661  if (getSelectableGates().empty())
662  action->setDisabled(true);
663  }
664 
665  // if (!item || isNet)
666  // {
667  // QAction* antialiasing_action = context_menu.addAction("Antialiasing");
668  // QAction* cosmetic_action = context_menu.addAction("Cosmetic Nets");
669  // QMenu* grid_menu = context_menu.addMenu("Grid");
670  // QMenu* type_menu = grid_menu->addMenu("Type");
671  // QMenu* cluster_menu = grid_menu->addMenu("Clustering");
672  // QAction* lines_action = type_menu->addAction("Lines");
673  // QAction* dots_action = type_menu->addAction("Dots");
674  // QAction* none_action = type_menu->addAction("None");
675  // connect(action, &QAction::triggered, this, SLOT);
676  // }
677 
682  context_menu.exec(mapToGlobal(pos));
683  update();
684  }
685 
686  void GraphGraphicsView::handlePluginContextContributionTriggered()
687  {
688  QAction* act = static_cast<QAction*>(sender());
689  Q_ASSERT(act);
690  ContextMenuContribution* cmc = static_cast<ContextMenuContribution*>(act->data().value<void*>());
691  Q_ASSERT(cmc);
692  Q_ASSERT(cmc->mContributer);
693  cmc->mContributer->execute_function(cmc->mTagname,gNetlist,
697  if (gPythonContext->pythonThread())
698  gPythonContext->pythonThread()->unlock();
699  }
700 
701  void GraphGraphicsView::updateMatrix(const int delta)
702  {
703  qreal scale = qPow(2.0, delta / 100.0);
704 
705  QMatrix matrix;
707  setMatrix(matrix);
708  }
709 
710  void GraphGraphicsView::toggleAntialiasing()
711  {
713  }
714 
715  bool GraphGraphicsView::itemDraggable(GraphicsItem* item)
716  {
717  ItemType type = item->itemType();
718  return type == ItemType::Gate || type == ItemType::Module;
719  }
720 
721  void GraphGraphicsView::gentleZoom(const qreal factor)
722  {
723  scale(factor, factor);
724  centerOn(mTargetScenePos);
725  QPointF delta_viewport_pos = mTargetViewportPos - QPointF(viewport()->width() / 2.0, viewport()->height() / 2.0);
726  QPointF viewport_center = mapFromScene(mTargetScenePos) - delta_viewport_pos;
727  centerOn(mapToScene(viewport_center.toPoint()));
728  }
729 
730  void GraphGraphicsView::viewportCenterZoom(const qreal factor)
731  {
732  QPointF target_pos = mapToScene(viewport()->rect().center());
733  scale(factor, factor);
734  centerOn(target_pos.toPoint());
735  }
736 
737  void GraphGraphicsView::handleCancelPickMode()
738  {
739  gContentManager->getGraphTabWidget()->emitTerminatePicker();
740  }
741 
742  namespace ShortestPath
743  {
744  const Net* net(const Gate* g0, const Gate* g1)
745  {
746  for (const Net* n0 : g0->get_fan_out_nets())
747  for (const Net* n1 : g1->get_fan_in_nets())
748  if (n0 == n1)
749  return n0;
750  return nullptr;
751  }
752 
753  const Module* module(const Gate* g, const NodeBoxes& boxes)
754  {
755  const Module* parent = g->get_module();
756  while (parent)
757  {
758  Node nd(parent->get_id(),Node::Module);
759  if (boxes.boxForNode(nd)) return parent;
760  parent = parent->get_parent_module();
761  }
762  return nullptr;
763  }
764 
765  }
766 
767 
768  void GraphGraphicsView::handleAddModuleToView()
769  {
770  GraphContext* context = mGraphWidget->getContext();
771 
772 // QSet<u32> not_selectable_modules;
773 // QSet<u32> modules_in_context = context->modules();
774 // QSet<u32> gates_in_context = context->gates();
775 
776 // for (Module* module : gNetlist->get_modules())
777 // {
778 // bool module_in_context = false;
779 // for (Module* submodule: module->get_submodules(nullptr, true))
780 // {
781 // if (modules_in_context.contains(submodule->get_id()))
782 // {
783 // module_in_context = true;
784 // break;
785 // }
786 // }
787 // for (Gate* subgate : module->get_gates(nullptr, true))
788 // {
789 // if (gates_in_context.contains(subgate->get_id()))
790 // {
791 // module_in_context = true;
792 // break;
793 // }
794 // }
795 // if (module_in_context)
796 // {
797 // not_selectable_modules.insert(module->get_id());
798 // }
799 // }
800 
801 // not_selectable_modules += modules_in_context;
802 
803 // QSet<u32> direct_par_modules;
804 // for (u32 id : modules_in_context)
805 // {
806 // Module* cur_module = gNetlist->get_module_by_id(id);
807 // for (Module* module : cur_module->get_submodules(nullptr, true))
808 // {
809 // not_selectable_modules.insert(module->get_id());
810 // }
811 
812 // if (!cur_module->is_top_module())
813 // {
814 // direct_par_modules.insert(cur_module->get_parent_module()->get_id());
815 // }
816 // }
817 
818 // if (!gates_in_context.empty())
819 // {
820 // for (u32 id : gates_in_context)
821 // {
822 // direct_par_modules.insert(gNetlist->get_gate_by_id(id)->get_module()->get_id());
823 // }
824 // }
825 
826 // for (u32 id : direct_par_modules)
827 // {
828 // not_selectable_modules.insert(id);
829 
830 // Module* tmp_module = gNetlist->get_module_by_id(id);
831 // while (!tmp_module->is_top_module())
832 // {
833 // Module* par_module = tmp_module->get_parent_module();
834 // tmp_module = par_module;
835 // not_selectable_modules.insert(par_module->get_id());
836 // }
837 // }
838 
839  ModuleDialog module_dialog(getNotSelectableModules(),"Add module to view", true, nullptr, this);
840  if (module_dialog.exec() == QDialog::Accepted)
841  {
842  QSet<u32> module_to_add;
843  module_to_add.insert(module_dialog.selectedId());
844  ActionAddItemsToObject* act = new ActionAddItemsToObject(module_to_add, {});
845  act->setObject(UserActionObject(context->id(), UserActionObjectType::ContextView));
846  act->exec();
847  }
848  }
849 
850 
851  QSet<u32> GraphGraphicsView::getNotSelectableModules()
852  {
853  GraphContext* context = mGraphWidget->getContext();
854 
855  QSet<u32> not_selectable_modules;
856  QSet<u32> modules_in_context = context->modules();
857  QSet<u32> gates_in_context = context->gates();
858 
859  for (Module* module : gNetlist->get_modules())
860  {
861  bool module_in_context = false;
862  for (Module* submodule: module->get_submodules(nullptr, true))
863  {
864  if (modules_in_context.contains(submodule->get_id()))
865  {
866  module_in_context = true;
867  break;
868  }
869  }
870  for (Gate* subgate : module->get_gates(nullptr, true))
871  {
872  if (gates_in_context.contains(subgate->get_id()))
873  {
874  module_in_context = true;
875  break;
876  }
877  }
878  if (module_in_context)
879  {
880  not_selectable_modules.insert(module->get_id());
881  }
882  }
883 
884  not_selectable_modules += modules_in_context;
885 
886  QSet<u32> direct_par_modules;
887  for (u32 id : modules_in_context)
888  {
889  Module* cur_module = gNetlist->get_module_by_id(id);
890  for (Module* module : cur_module->get_submodules(nullptr, true))
891  {
892  not_selectable_modules.insert(module->get_id());
893  }
894 
895  if (!cur_module->is_top_module())
896  {
897  direct_par_modules.insert(cur_module->get_parent_module()->get_id());
898  }
899  }
900 
901  if (!gates_in_context.empty())
902  {
903  for (u32 id : gates_in_context)
904  {
905  direct_par_modules.insert(gNetlist->get_gate_by_id(id)->get_module()->get_id());
906  }
907  }
908 
909  for (u32 id : direct_par_modules)
910  {
911  not_selectable_modules.insert(id);
912 
913  Module* tmp_module = gNetlist->get_module_by_id(id);
914  while (!tmp_module->is_top_module())
915  {
916  Module* par_module = tmp_module->get_parent_module();
917  tmp_module = par_module;
918  not_selectable_modules.insert(par_module->get_id());
919  }
920  }
921 
922  return not_selectable_modules;
923  }
924 
925  QSet<u32> GraphGraphicsView::getSelectableGates()
926  {
927  GraphContext* context = mGraphWidget->getContext();
928 
929  QSet<u32> not_selectable_gates = context->gates();
930  QSet<u32> modules_in_context = context->modules();
931 
932  for (u32 module_id : modules_in_context)
933  {
934  for (Gate* gate : gNetlist->get_module_by_id(module_id)->get_gates(nullptr, true))
935  {
936  not_selectable_gates.insert(gate->get_id());
937  }
938  }
939 
940  QSet<u32> selectable_gates;
941  for (Gate* gate : gNetlist->get_gates())
942  {
943  if (!not_selectable_gates.contains(gate->get_id()))
944  {
945  selectable_gates.insert(gate->get_id());
946  }
947  }
948 
949  return selectable_gates;
950  }
951 
952  void GraphGraphicsView::handleAddGateToView()
953  {
954  QSet<u32> selectable_gates = getSelectableGates();
955 
956  GraphContext* context = mGraphWidget->getContext();
957 
958  GateDialog gate_dialog(selectable_gates, "Add gate to view", nullptr, this);
959  if (gate_dialog.exec() == QDialog::Accepted)
960  {
961  QSet<u32> gate_to_add;
962  gate_to_add.insert(gate_dialog.selectedId());
963  ActionAddItemsToObject* act = new ActionAddItemsToObject({}, gate_to_add);
964  act->setObject(UserActionObject(context->id(), UserActionObjectType::ContextView));
965  act->exec();
966  }
967  }
968 
969 
970  void GraphGraphicsView::handleAddSuccessorToView()
971  {
972  QAction* send = static_cast<QAction*>(sender());
973  Q_ASSERT(send);
974  int level = send->data().toInt();
975  addSuccessorToView(level, true);
976  }
977 
978  void GraphGraphicsView::handleAddPredecessorToView()
979  {
980  QAction* send = static_cast<QAction*>(sender());
981  Q_ASSERT(send);
982  int level = send->data().toInt();
983  addSuccessorToView(level, false);
984  }
985 
986  void GraphGraphicsView::handleAddCommonSuccessorToView()
987  {
988  QAction* send = static_cast<QAction*>(sender());
989  Q_ASSERT(send);
990  int level = send->data().toInt();
991  addCommonSuccessorToView(level, true);
992  }
993 
994  void GraphGraphicsView::handleAddCommonPredecessorToView()
995  {
996  QAction* send = static_cast<QAction*>(sender());
997  Q_ASSERT(send);
998  int level = send->data().toInt();
999  addCommonSuccessorToView(level, false);
1000  }
1001 
1002  void GraphGraphicsView::addSuccessorToView(int maxLevel, bool succ)
1003  {
1004 
1005  QSet<u32> gatsNew;
1006  QSet<const Gate*> gatsHandled;
1007 
1008  QList<const Gate*> startList;
1009  Node startNode;
1010 
1011  switch (mItem->itemType())
1012  {
1013  case ItemType::Gate:
1014  startNode = Node(mItem->id(),Node::Gate);
1015  startList.append(gNetlist->get_gate_by_id(mItem->id()));
1016  break;
1017  case ItemType::Module:
1018  startNode = Node(mItem->id(),Node::Module);
1019  for (const Gate* g : gNetlist->get_module_by_id(mItem->id())->get_gates(nullptr,true))
1020  startList.append(g);
1021  break;
1022  default:
1023  return;
1024  }
1025 
1026  Q_ASSERT(startList.size());
1027 
1028  for (const Gate* g : startList)
1029  gatsHandled.insert(g);
1030 
1031  const NodeBoxes& boxes = mGraphWidget->getContext()->getLayouter()->boxes();
1032  const NodeBox* box = boxes.boxForNode(startNode);
1033  Q_ASSERT(box);
1034  int xOrigin = box->x();
1035  int yOrigin = box->y();
1036  int xDir = succ ? 1 : -1;
1037 
1038  PlacementHint plc(PlacementHint::Standard);
1039 
1040  for (int loop = 0; !maxLevel || loop<maxLevel; loop++)
1041  {
1042  int y = 0;
1043  QList<const Gate*> foundList;
1044 
1045  for (const Gate* gOrigin : startList)
1046  {
1047  for (const Gate* g : netlist_utils::get_next_gates(gOrigin, succ, 1))
1048  {
1049  if (gatsHandled.contains(g)) continue;
1050  gatsHandled.insert(g);
1051  if (boxes.boxForGate(g)) continue; // by in view
1052  foundList.append(g);
1053  }
1054  }
1055 
1056  if (foundList.isEmpty()) break;
1057  for (const Gate* g: foundList)
1058  {
1059  gatsNew.insert(g->get_id());
1060  QPoint point(xOrigin + (loop+1) * xDir, yOrigin + y);
1061  y = y > 0 ? -y : -y+1;
1062  Node nd(g->get_id(),Node::Gate);
1063  if (!boxes.boxForPoint(point)) // not occupied yet
1064  {
1065  if (plc.mode() == PlacementHint::Standard)
1066  plc = PlacementHint(PlacementHint::GridPosition);
1067  plc.addGridPosition(nd,point);
1068  }
1069  }
1070  startList = foundList;
1071  }
1072 
1073  ActionAddItemsToObject* act = new ActionAddItemsToObject({}, gatsNew);
1074  act->setObject(UserActionObject(mGraphWidget->getContext()->id(),UserActionObjectType::ContextView));
1075  act->setPlacementHint(plc);
1076  act->exec();
1077  }
1078 
1079 
1080  void GraphGraphicsView::addCommonSuccessorToView(int maxLevel, bool succ)
1081  {
1082  CommonSuccessorPredecessor csp(gSelectionRelay->selectedGatesList(),succ,maxLevel);
1083  const NodeBoxes& boxes = mGraphWidget->getContext()->getLayouter()->boxes();
1084 
1085  QSet<u32> gatsNew;
1086  for (const Gate* g : csp.result())
1087  {
1088  if (boxes.boxForGate(g)) continue;
1089  gatsNew.insert(g->get_id());
1090  }
1091  ActionAddItemsToObject* act = new ActionAddItemsToObject({}, gatsNew);
1092  act->setObject(UserActionObject(mGraphWidget->getContext()->id(),UserActionObjectType::ContextView));
1093  act->exec();
1094  }
1095 
1096  void GraphGraphicsView::handleHighlightSuccessor()
1097  {
1098  QAction* send = static_cast<QAction*>(sender());
1099  Q_ASSERT(send);
1100  int level = send->data().toInt();
1102  }
1103 
1104  void GraphGraphicsView::handleHighlightPredecessor()
1105  {
1106  QAction* send = static_cast<QAction*>(sender());
1107  Q_ASSERT(send);
1108  int level = send->data().toInt();
1110  }
1111 
1112  void GraphGraphicsView::handleSuccessorDistance()
1113  {
1114  QAction* send = static_cast<QAction*>(sender());
1115  Q_ASSERT(send);
1116  int level = send->data().toInt();
1118  }
1119 
1120  void GraphGraphicsView::handlePredecessorDistance()
1121  {
1122  QAction* send = static_cast<QAction*>(sender());
1123  Q_ASSERT(send);
1124  int level = send->data().toInt();
1126  }
1127 
1128  void GraphGraphicsView::handleShortestPathToView()
1129  {
1130  QAction* send = static_cast<QAction*>(sender());
1131  Q_ASSERT(send);
1132 
1133  int param = send->data().toInt();
1134  bool succ = (param == SuccessorModule || param == SuccessorGate);
1135  bool isMod = (param == SuccessorModule || param == PredecessorModule);
1136  std::vector<Gate*> spath;
1137  Gate* startGate = gNetlist->get_gate_by_id(mItem->id());
1138  Q_ASSERT(startGate);
1139 
1140  if (isMod)
1141  {
1142  QSet<u32> excludeModules;
1143  const Module* parMod = startGate->get_module();
1144  while (parMod)
1145  {
1146  excludeModules.insert(parMod->get_id());
1147  parMod = parMod->get_parent_module();
1148  }
1149 
1150  ModuleDialog md(excludeModules, "Shortest path to module", true, nullptr, this);
1151 
1152  if (md.exec() != QDialog::Accepted) return;
1153 
1154  Module* endModule = gNetlist->get_module_by_id(md.selectedId());
1155  Q_ASSERT(endModule);
1156 
1157  spath = netlist_utils::get_shortest_path(startGate,endModule,succ);
1158  }
1159  else
1160  {
1161  QSet<u32> selectableGates;
1162 
1163  for (Gate* g : netlist_utils::get_next_gates(startGate,succ))
1164  {
1165  selectableGates.insert(g->get_id());
1166  }
1167 
1168 // GraphGraphicsViewNeighborSelector* ggvns = new GraphGraphicsViewNeighborSelector(mItem->id(), succ, this);
1169  GateDialog gd(selectableGates, QString("Shortest path %1 gate").arg(succ?"to":"from"), nullptr, this);
1170 
1171  if (gd.exec() != QDialog::Accepted) return;
1172 
1173  Gate* endGate = gNetlist->get_gate_by_id(gd.selectedId());
1174  Q_ASSERT(endGate);
1175 
1176  if (succ)
1177  spath = netlist_utils::get_shortest_path(startGate,endGate);
1178  else
1179  {
1180  spath = netlist_utils::get_shortest_path(endGate,startGate);
1181  }
1182  }
1183  if (spath.empty()) return;
1184  if (!succ) std::reverse(spath.begin(), spath.end());
1185 
1186  const NodeBoxes& boxes = mGraphWidget->getContext()->getLayouter()->boxes();
1187  const NodeBox* originBox = boxes.boxForGate(startGate);
1188  Q_ASSERT(originBox);
1189  QPoint point(originBox->x(),originBox->y());
1190  QPoint deltaX(succ ? 1 : -1, 0);
1191  PlacementHint plc(PlacementHint::Standard);
1192 
1193  QSet<u32> gats;
1194 
1195  for (Gate* g : spath)
1196  {
1197  if (boxes.boxForGate(g)) continue; // already in view
1198  do {
1199  point += deltaX;
1200  } while (boxes.boxForPoint(point)); // find grid point not occupied
1201  gats.insert(g->get_id());
1202  Node nd(g->get_id(),Node::Gate);
1203  if (plc.mode() == PlacementHint::Standard)
1204  plc = PlacementHint(PlacementHint::GridPosition);
1205  plc.addGridPosition(nd,point);
1206  }
1207 
1208  ActionAddItemsToObject* act = new ActionAddItemsToObject({},gats);
1209  act->setObject(UserActionObject(mGraphWidget->getContext()->id(),UserActionObjectType::ContextView));
1210  act->setPlacementHint(plc);
1211  act->exec();
1212  }
1213 
1214  void GraphGraphicsView::handleQueryShortestPathModule()
1215  {
1216  QAction* send = static_cast<QAction*>(sender());
1217  Q_ASSERT(send);
1218  bool succ = send->data().toInt() == SuccessorGate;
1219 
1220  QSet<u32> excludeModules;
1221  Gate* g = gNetlist->get_gate_by_id(mItem->id());
1222  Q_ASSERT(g);
1223  Module* par = g->get_module();
1224  while(par)
1225  {
1226  excludeModules.insert(par->get_id());
1227  par = par->get_parent_module();
1228  }
1229  ModuleDialog md(excludeModules, "Shortest path to module", true, nullptr, this);
1230 
1231  if (md.exec() != QDialog::Accepted) return;
1232 
1233  handleShortestPathToGrouping(mItem->id(),Node(md.selectedId(),Node::Module),succ);
1234  }
1235 
1236  void GraphGraphicsView::handleQueryShortestPathGate()
1237  {
1238  QAction* send = static_cast<QAction*>(sender());
1239  Q_ASSERT(send);
1240  bool succ = send->data().toInt() == SuccessorGate;
1241 
1242  QSet<u32> selectableGates;
1243  for (Gate* g : netlist_utils::get_next_gates(gNetlist->get_gate_by_id(mItem->id()),succ))
1244  selectableGates.insert(g->get_id());
1245 
1246  GraphGraphicsViewNeighborSelector* ggvns = new GraphGraphicsViewNeighborSelector(mItem->id(), succ, this);
1247  GateDialog gd(selectableGates,QString("Shortest path %1 gate").arg(succ?"to":"from"),ggvns,this);
1248 
1249  if (gd.exec() != QDialog::Accepted) return;
1250 
1251  u32 targetId = gd.selectedId();
1252  if (!targetId) return;
1253 
1254  if (succ)
1255  handleShortestPathToGrouping(mItem->id(),Node(targetId,Node::Gate),true);
1256  else
1257  handleShortestPathToGrouping(targetId,Node(mItem->id(),Node::Gate),true);
1258  }
1259 
1260  void GraphGraphicsView::handleShortestPathToGrouping(u32 idFrom, Node nodeTo, bool forwardDirection)
1261  {
1262  std::vector<Gate*> spath;
1263 
1264  Gate* g0 = gNetlist->get_gate_by_id(idFrom);
1265  Q_ASSERT(g0);
1266  Q_ASSERT(!nodeTo.isNull());
1267 
1268  QString target;
1269 
1270  if(nodeTo.isGate())
1271  {
1272  Gate* g1 = gNetlist->get_gate_by_id(nodeTo.id());
1273  Q_ASSERT(g1);
1274  spath = forwardDirection ?
1277  target = QString("gate '%1'[%2]").arg(QString::fromStdString(g1->get_name()), g1->get_id());
1278  }
1279  else
1280  {
1281  Module* m = gNetlist->get_module_by_id(nodeTo.id());
1282  Q_ASSERT(m);
1283  spath = netlist_utils::get_shortest_path(g0,m,forwardDirection);
1284  target = QString("module '%1'[%2]").arg(QString::fromStdString(m->get_name()), m->get_id());
1285  }
1286 
1287 
1288  QSet<u32> mods;
1289  QSet<u32> gats;
1290  QSet<u32> nets;
1291 
1292  Gate* previousGate = nullptr;
1293  for (Gate* g : spath)
1294  {
1295  const Module* pm = ShortestPath::module(g,mGraphWidget->getContext()->getLayouter()->boxes());
1296  if (pm) mods.insert(pm->get_id());
1297  gats.insert(g->get_id());
1298  if (previousGate)
1299  {
1300  const Net* n = ShortestPath::net(previousGate,g);
1301  if (n) nets.insert(n->get_id());
1302  }
1303  previousGate = g;
1304  }
1305 
1307  act->setUseCreatedObject();
1309  QString("Path from '%1'[%2] to %3")
1310  .arg(QString::fromStdString(g0->get_name())).arg(g0->get_id())
1311  .arg(target)));
1312  act->addAction(new ActionAddItemsToObject(mods,gats,nets));
1313  act->addAction(new ActionSetSelectionFocus());
1314  act->exec();
1315  }
1316 
1317  void GraphGraphicsView::handleSelectOutputs()
1318  {
1319  auto context = mGraphWidget->getContext();
1320  QAction* sender_action = dynamic_cast<QAction*>(sender());
1321  if (sender_action)
1322  {
1323  QSet<u32> gates;
1324  for (auto sel_id : gSelectionRelay->selectedGatesList())
1325  {
1326  auto gate = gNetlist->get_gate_by_id(sel_id);
1327  for (auto net : gate->get_fan_out_nets())
1328  {
1329  for (const auto& suc : net->get_destinations())
1330  {
1331  bool found = false;
1332  for (const auto& id : context->modules())
1333  {
1334  auto m = gNetlist->get_module_by_id(id);
1335  if (m->contains_gate(suc->get_gate(), true))
1336  {
1337  found = true;
1338  break;
1339  }
1340  }
1341  if (!found)
1342  {
1343  gates.insert(suc->get_gate()->get_id());
1344  }
1345  }
1346  }
1347  }
1348  for (auto sel_id : gSelectionRelay->selectedModulesList())
1349  {
1350  auto module = gNetlist->get_module_by_id(sel_id);
1351  for (auto net : module->get_output_nets())
1352  {
1353  for (const auto& suc : net->get_destinations())
1354  {
1355  bool found = false;
1356  for (const auto& id : context->modules())
1357  {
1358  auto m = gNetlist->get_module_by_id(id);
1359  if (m->contains_gate(suc->get_gate(), true))
1360  {
1361  found = true;
1362  break;
1363  }
1364  }
1365  if (!found)
1366  {
1367  gates.insert(suc->get_gate()->get_id());
1368  }
1369  }
1370  }
1371  }
1372 
1373  gates = context->getLayouter()->boxes().filterNotInView(gates);
1374  ActionAddItemsToObject* act = new ActionAddItemsToObject({},gates);
1375  act->setObject(UserActionObject(context->id(),UserActionObjectType::ContextView));
1377  {
1378  Node origin = (gSelectionRelay->numberSelectedModules()==1)
1381  act->setPlacementHint(PlacementHint(PlacementHint::PreferRight,origin));
1382  }
1383  act->exec();
1384  }
1385  }
1386  void GraphGraphicsView::handleSelectInputs()
1387  {
1388  auto context = mGraphWidget->getContext();
1389  QAction* sender_action = dynamic_cast<QAction*>(sender());
1390  if (sender_action)
1391  {
1392  QSet<u32> gates;
1393  for (auto sel_id : gSelectionRelay->selectedGatesList())
1394  {
1395  auto gate = gNetlist->get_gate_by_id(sel_id);
1396  for (auto net : gate->get_fan_in_nets())
1397  {
1398  if (!net->get_sources().empty() && net->get_sources().at(0)->get_gate() != nullptr)
1399  {
1400  bool found = false;
1401  for (const auto& id : context->modules())
1402  {
1403  auto m = gNetlist->get_module_by_id(id);
1404  if (m->contains_gate(net->get_sources().at(0)->get_gate(), true))
1405  {
1406  found = true;
1407  break;
1408  }
1409  }
1410  if (!found)
1411  {
1412  gates.insert(net->get_sources().at(0)->get_gate()->get_id());
1413  }
1414  }
1415  }
1416  }
1417  for (auto sel_id : gSelectionRelay->selectedModulesList())
1418  {
1419  auto module = gNetlist->get_module_by_id(sel_id);
1420  for (auto net : module->get_input_nets())
1421  {
1422  if (!net->get_sources().empty() && net->get_sources().at(0)->get_gate() != nullptr)
1423  {
1424  bool found = false;
1425  for (const auto& id : context->modules())
1426  {
1427  auto m = gNetlist->get_module_by_id(id);
1428  if (m->contains_gate(net->get_sources().at(0)->get_gate(), true))
1429  {
1430  found = true;
1431  break;
1432  }
1433  }
1434  if (!found)
1435  {
1436  gates.insert(net->get_sources().at(0)->get_gate()->get_id());
1437  }
1438  }
1439  }
1440  }
1441 
1442  gates = context->getLayouter()->boxes().filterNotInView(gates);
1443  ActionAddItemsToObject* act = new ActionAddItemsToObject({},gates);
1444  act->setObject(UserActionObject(context->id(),UserActionObjectType::ContextView));
1446  {
1447  Node origin = (gSelectionRelay->numberSelectedModules()==1)
1450  act->setPlacementHint(PlacementHint(PlacementHint::PreferLeft,origin));
1451  }
1452  act->exec();
1453  }
1454  }
1455 
1456  void GraphGraphicsView::selectedNodeToItem()
1457  {
1458  if (gSelectionRelay->numberSelectedItems() != 1) return;
1459  NodeBox* box = nullptr;
1461  {
1462  u32 gatId = gSelectionRelay->selectedGatesList().at(0);
1463  box = mGraphWidget->getContext()->getLayouter()->boxes().boxForNode(Node(gatId,Node::Gate));
1464  }
1465  else if (gSelectionRelay->numberSelectedModules() == 1)
1466  {
1467  u32 modId = gSelectionRelay->selectedModulesList().at(0);
1468  box = mGraphWidget->getContext()->getLayouter()->boxes().boxForNode(Node(modId,Node::Module));
1469  }
1470  if (!box) return;
1471  mItem = box->item();
1472  }
1473 
1475  {
1476  selectedNodeToItem();
1477  if (!mItem) return;
1478  handleFoldParentSingle();
1479  }
1480 
1482  {
1483  selectedNodeToItem();
1484  if (!mItem || mItem->itemType() != ItemType::Module) return;
1485  handleUnfoldSingleAction();
1486  }
1487 
1488  void GraphGraphicsView::handleFoldParentSingle()
1489  {
1490  const Module* parentModule = nullptr;
1491  Node childNode;
1492  u32 id = mItem->id();
1493  GraphContext* context = mGraphWidget->getContext();
1494  switch (mItem->itemType())
1495  {
1496  case ItemType::Module:
1497  parentModule = gNetlist->get_module_by_id(id)->get_parent_module();
1498  childNode = Node(id, Node::Module);
1499  break;
1500  case ItemType::Gate:
1501  parentModule = gNetlist->get_gate_by_id(id)->get_module();
1502  childNode = Node(id, Node::Gate);
1503  break;
1504  default:
1505  return;
1506  }
1507 
1508  if (!parentModule || childNode.type()==Node::None) return;
1509  NodeBox* box = context->getLayouter()->boxes().boxForNode(childNode);
1510  if (!box) return;
1511 
1512  PlacementHint plc(PlacementHint::GridPosition);
1513  plc.addGridPosition(Node(parentModule->get_id(),Node::Module),box->gridPosition());
1514  ActionFoldModule* act = new ActionFoldModule(parentModule->get_id());
1515  act->setContextId(context->id());
1516  act->setPlacementHint(plc);
1517  act->exec();
1518  }
1519 
1520  void GraphGraphicsView::handleUnfoldSingleAction()
1521  {
1522  GraphContext* context = mGraphWidget->getContext();
1523  Module* m = gNetlist->get_module_by_id(mItem->id());
1524  if (m->get_gates().empty() && m->get_submodules().empty())
1525  {
1526  QMessageBox msg;
1527  msg.setText("This module is empty.\nYou can't unfold it.");
1528  msg.setWindowTitle("Error");
1529  msg.exec();
1530  return;
1531  // We would otherwise unfold the empty module into nothing, so the user
1532  // would have nowhere to click to get their module back
1533  }
1534  ActionUnfoldModule* act = new ActionUnfoldModule(mItem->id());
1535  act->setContextId(context->id());
1536  act->exec();
1537  }
1538 
1539  void GraphGraphicsView::handleFoldParentAll()
1540  {
1541  GraphContext* context = mGraphWidget->getContext();
1542 
1543  QSet<const Module*> modSet;
1544 
1545  for (Node& nd : gSelectionRelay->selectedNodesList())
1546  {
1547  if (!context->getLayouter()->boxes().boxForNode(nd)) continue; // not in view
1548 
1549  switch (nd.type())
1550  {
1551  case Node::Gate:
1552  modSet.insert(gNetlist->get_gate_by_id(nd.id())->get_module());
1553  break;
1554  case Node::Module:
1555  modSet.insert(gNetlist->get_module_by_id(nd.id())->get_parent_module());
1556  default:
1557  continue;
1558  }
1559  }
1560 
1562  for (const Module* m : modSet)
1563  if (m) modDepth.insertMulti(m->get_submodule_depth(),m);
1564 
1565  QMapIterator<int,const Module*> it(modDepth);
1566  it.toBack();
1567  while (it.hasPrevious())
1568  {
1569  it.previous();
1570  const Module* m = it.value();
1571  ActionFoldModule* act = new ActionFoldModule(m->get_id());
1572  act->setContextId(context->id());
1573  act->exec();
1574  }
1575  }
1576 
1577  void GraphGraphicsView::handleUnfoldAllAction()
1578  {
1579  auto context = mGraphWidget->getContext();
1580 
1581  context->beginChange();
1582  UserActionCompound* act = new UserActionCompound;
1584  {
1585  ActionUnfoldModule* ufo = new ActionUnfoldModule(id);
1586  ufo->setContextId(context->id());
1587  act->addAction(ufo);
1588  }
1589  act->exec();
1590  context->endChange();
1591  }
1592 
1593 #ifdef GUI_DEBUG_GRID
1594  void GraphGraphicsView::debugShowLayouterGridpos(const QPoint& mouse_pos)
1595  {
1596  auto context = mGraphWidget->getContext();
1597  if (!context)
1598  return;
1599 
1600  const GraphLayouter* layouter = context->getLayouter();
1601  if (!(layouter->done()))
1602  return;
1603 
1604  QPointF scene_mouse_pos = mapToScene(mouse_pos);
1605  QPoint layouter_pos = closestLayouterPos(scene_mouse_pos).first;
1606  m_debug_gridpos = layouter_pos;
1607  }
1608 #endif
1609 
1610  QPair<QPoint,QPointF> GraphGraphicsView::closestLayouterPos(const QPointF& scene_pos) const
1611  {
1612  auto context = mGraphWidget->getContext();
1613  assert(context);
1614 
1615  const GraphLayouter* layouter = context->getLayouter();
1616  assert(layouter->done()); // ensure grid stable
1617 
1618  int default_width = layouter->defaultGridWidth();
1619  int default_height = layouter->defaultGridHeight();
1620  int min_x = layouter->minXIndex();
1621  int min_y = layouter->minYIndex();
1622  QVector<qreal> x_vals = layouter->xValues();
1623  QVector<qreal> y_vals = layouter->yValues();
1624  LayouterPoint x_point = closestLayouterPoint(scene_pos.x(), default_width, min_x, x_vals);
1625  LayouterPoint y_point = closestLayouterPoint(scene_pos.y(), default_height, min_y, y_vals);
1626  return qMakePair(QPoint(x_point.mIndex, y_point.mIndex), QPointF(x_point.mPos, y_point.mPos));
1627  }
1628 
1629  GraphGraphicsView::LayouterPoint GraphGraphicsView::closestLayouterPoint(qreal scene_pos, int default_spacing, int min_index, QVector<qreal> sections) const
1630  {
1631  int index = min_index;
1632  qreal pos = 0;
1633  if (sections.first() > scene_pos)
1634  {
1635  int distance = sections.first() - scene_pos;
1636  int nSections = distance / default_spacing; // this rounds down
1637  index -= (nSections + 1);
1638  pos = sections.first() + index * default_spacing;
1639  }
1640  else if (sections.last() <= scene_pos)
1641  {
1642  int distance = scene_pos - sections.last();
1643  int nSections = distance / default_spacing; // this rounds down
1644  index += (sections.size() + nSections -1);
1645  pos = sections.last() + nSections * default_spacing;
1646  }
1647  else
1648  {
1649  // search for first value in sections larger than or equal to scene_pos
1650  auto it = sections.constBegin();
1651  auto jt = it+1;
1652  while (jt != sections.constEnd())
1653  {
1654  if (scene_pos < *jt) break; // found value in inteval [it..[jt
1655  ++it;
1656  ++jt;
1657  ++index;
1658  }
1659  pos = *it;
1660  }
1661  return LayouterPoint{index, pos};
1662  }
1663 
1664 
1666  {
1667  return mGridType;
1668  }
1669 
1671  {
1672  mGridType = gridType;
1673  }
1674 
1676  {
1677  return mDragModifier;
1678  }
1679 
1681  {
1682  mDragModifier = dragModifier;
1683  }
1684 
1686  {
1687  return mPanModifier;
1688  }
1689 
1691  {
1692  mPanModifier = panModifier;
1693  }
1694 
1696  {
1697  if (!gats.empty())
1698  {
1699  u32 pickedGate = *gats.constBegin();
1700  GraphGraphicsView* ggv = dynamic_cast<GraphGraphicsView*>(parent());
1701  if (ggv)
1702  {
1703  if (mPickSuccessor)
1704  ggv->handleShortestPathToGrouping(mOrigin,Node(pickedGate,Node::Gate),true);
1705  else
1706  ggv->handleShortestPathToGrouping(pickedGate,Node(mOrigin,Node::Gate),true);
1707  }
1708  }
1709  this->deleteLater();
1710  }
1711 } // namespace hal
Adds an item to a module or grouping.
Removes an item from a Module or Grouping.
Set the selection and focus.
void addComment(CommentEntry *entry)
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override
GraphTabWidget * getGraphTabWidget()
Get hal's graph tab widget.
GroupingManagerWidget * getGroupingManagerWidget()
ContextManagerWidget * getContextManagerWidget()
void selectViewContext(GraphContext *context)
GridPlacement * finalGridPlacement() const
void move(const QPoint &eventPos, bool wantSwap, const QPoint &gridPos)
bool hasDragged(const QPoint &eventPos)
void set(GraphicsNode *drgItem, const QPoint &eventPos)
bool isDropAllowed() const
void enterDrag(bool wantSwap)
Definition: gate.h:58
const std::vector< Net * > & get_fan_in_nets() const
Definition: gate.cpp:591
const std::string & get_name() const
Definition: gate.cpp:105
Module * get_module() const
Definition: gate.cpp:174
const std::vector< Net * > & get_fan_out_nets() const
Definition: gate.cpp:735
u32 get_id() const
Definition: gate.cpp:95
Logical container for modules, gates, and nets.
Definition: graph_context.h:55
GraphicsScene * scene()
void setDirty(bool dty)
const QSet< u32 > & gates() const
const QSet< u32 > & modules() const
GraphLayouter * getLayouter() const
QString nextViewName(const QString &prefix) const
GraphContext * getContextById(u32 id) const
GraphContext * getContextByExclusiveModuleId(u32 module_id) const
static SettingsItemCheckbox * sSettingPanOnMiddleButton
A view to display the rendered graph (needs a GraphicsScene).
void keyPressEvent(QKeyEvent *event) override
void dragLeaveEvent(QDragLeaveEvent *event) override
void setGridType(GraphicsScene::GridType gridType)
void dropEvent(QDropEvent *event) override
void wheelEvent(QWheelEvent *event) override
void setPanModifier(Qt::KeyboardModifier panModifier)
Qt::KeyboardModifier panModifier()
void keyReleaseEvent(QKeyEvent *event) override
void viewportCenterZoom(const qreal factor)
void handleShortestPathToGrouping(u32 idFrom, Node nodeTo, bool forwardDirection)
void setDragModifier(Qt::KeyboardModifier dragModifier)
GraphGraphicsView(GraphWidget *parent)
void paintEvent(QPaintEvent *event) override
void moduleDoubleClicked(u32 id)
void mouseMoveEvent(QMouseEvent *event) override
Qt::KeyboardModifier dragModifier()
void resizeEvent(QResizeEvent *event) override
GraphicsScene::GridType gridType()
void dragEnterEvent(QDragEnterEvent *event) override
void mouseDoubleClickEvent(QMouseEvent *event) override
void mouseReleaseEvent(QMouseEvent *event) override
void mousePressEvent(QMouseEvent *event) override
void drawForeground(QPainter *painter, const QRectF &rect) override
void gentleZoom(const qreal factor)
void dragMoveEvent(QDragMoveEvent *event) override
void handleGatesPicked(const QSet< u32 > &gats) override
Base class for all specific layouters.
const NodeBoxes & boxes() const
bool isSelectMode() const
Wraps a GraphContext and a GraphGraphicsView.
Definition: graph_widget.h:55
GraphContext * getContext() const
Superclass for all graphic items used ins the GraphicsScene. It contains information about the underl...
Definition: graphics_item.h:44
static void setLod(const qreal lod)
ItemType itemType() const
Abstract base class for nodes (e.g. gates, modules)
Definition: graphics_node.h:42
Container for a GraphGraphicsView containing gates, nets, and modules.
static void setLod(const qreal &lod)
void setMousePressed(bool isPressed)
static void setGridEnabled(const bool &value)
static void setGridType(const GridType &gridType)
static void setGridClustersEnabled(const bool &value)
void newGroupingSuccOrPred(int maxDepth, bool succ, const GraphicsItem *item)
void newGroupingByDistance(int maxDepth, bool succ, const GraphicsItem *item)
static void addPluginSubmenus(QMenu *contextMenu, Netlist *netlist, const std::vector< u32 > &modules, const std::vector< u32 > &gates, const std::vector< u32 > &nets)
static void addModuleSubmenu(QMenu *contextMenu, u32 id)
static void addMultipleElementsSubmenu(QMenu *contextMenu, const QSet< u32 > &modules=QSet< u32 >(), const QSet< u32 > &gates=QSet< u32 >(), const QSet< u32 > &nets=QSet< u32 >())
static void addGateSubmenu(QMenu *contextMenu, u32 id)
static void addNetSubmenu(QMenu *contextMenu, u32 id)
Module * get_parent_module() const
Definition: module.cpp:125
const std::vector< Gate * > & get_gates() const
Definition: module.cpp:391
std::string get_name() const
Definition: module.cpp:87
const std::unordered_set< Net * > & get_input_nets() const
Definition: module.cpp:540
std::vector< Module * > get_submodules(const std::function< bool(Module *)> &filter=nullptr, bool recursive=false) const
Definition: module.cpp:259
const std::unordered_set< Net * > & get_output_nets() const
Definition: module.cpp:545
u32 get_id() const
Definition: module.cpp:82
Definition: net.h:58
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:204
Gate * get_gate_by_id(const u32 gate_id) const
Definition: netlist.cpp:193
const std::vector< Module * > & get_modules() const
Definition: netlist.cpp:624
Module * get_module_by_id(u32 module_id) const
Definition: netlist.cpp:613
The NodeBoxes class owns all NodeBox'es from hal view.
Definition: node_box.h:150
NodeBox * boxForNode(const Node &n) const
boxForNode find NodeBox by node
Definition: node_box.h:200
NodeBox * boxForGate(const Gate *g) const
boxForGate find NodeBox by Gate pointer.
Definition: node_box.h:184
static void setLod(const qreal lod)
The Node class object represents a module or a gate.
Definition: gui_def.h:61
NodeType type() const
type getter for type information
Definition: gui_def.h:71
bool isGate() const
isGate test whether node is a gate
Definition: gui_def.h:89
@ Module
Definition: gui_def.h:63
@ Gate
Definition: gui_def.h:63
@ None
Definition: gui_def.h:63
bool isNull() const
isNull test for null-Node object typically returned from functions
Definition: gui_def.h:83
u32 id() const
id getter for ID information
Definition: gui_def.h:77
int numberSelectedGates() const
int numberSelectedItems() const
bool containsGate(u32 id) const
void setFocus(ItemType ftype, u32 fid, Subfocus sfoc=Subfocus::None, u32 sfinx=0)
const QSet< u32 > & selectedNets() const
void relaySelectionChanged(void *sender)
QList< Node > selectedNodesList() const
QList< u32 > selectedModulesList() const
const QSet< u32 > & selectedGates() const
const QSet< u32 > & selectedModules() const
std::vector< u32 > selectedGatesVector() const
int numberSelectedModules() const
bool containsModule(u32 id) const
std::vector< u32 > selectedNetsVector() const
bool containsNet(u32 id) const
QList< u32 > selectedGatesList() const
std::vector< u32 > selectedModulesVector() const
void subfocusChanged(void *sender)
int numberSelectedNodes() const
virtual QVariant value() const override
void addAction(UserAction *act)
virtual void setObject(const UserActionObject &obj)
Definition: user_action.cpp:32
void setObjectLock(bool lock)
Definition: user_action.h:166
The UserActionObject class represents a single object used in UserAction.
ItemType
The ItemType enum provides the enum type to classify graphic items into Modules, Gates or Nets....
Definition: gui_def.h:45
action
Definition: control.py:16
const Module * module(const Gate *g, const NodeBoxes &boxes)
const Net * net(const Gate *g0, const Gate *g1)
std::vector< Gate * > get_next_gates(const Gate *gate, bool get_successors, int depth, const std::function< bool(const Gate *)> &filter)
std::vector< Gate * > get_shortest_path(Gate *start_gate, Module *end_module, bool forward_direction)
PythonContext * gPythonContext
Definition: plugin_gui.cpp:88
ContentManager * gContentManager
Definition: plugin_gui.cpp:78
GraphContextManager * gGraphContextManager
Definition: plugin_gui.cpp:85
SelectionRelay * gSelectionRelay
Definition: plugin_gui.cpp:83
CommentManager * gCommentManager
Definition: plugin_gui.cpp:87
Netlist * gNetlist
Definition: plugin_gui.cpp:80
n
Definition: test.py:6
quint32 u32
PinType type
Net * net
std::string name
QScrollBar * horizontalScrollBar() const const
QScrollBar * verticalScrollBar() const const
QWidget * viewport() const const
void setMinimum(int)
void setValue(int)
QVariant data() const const
void triggered(bool checked)
Qt::DropAction exec(Qt::DropActions supportedActions)
void setMimeData(QMimeData *data)
QMatrix matrix() const const
void setMatrix(const QMatrix &matrix, bool combine)
void centerOn(const QPointF &pos)
virtual void dropEvent(QDropEvent *event) override
virtual bool event(QEvent *event) override
QGraphicsItem * itemAt(const QPoint &pos) const const
QPoint mapFromScene(const QPointF &point) const const
QPointF mapToScene(const QPoint &point) const const
virtual void mouseMoveEvent(QMouseEvent *event) override
virtual void mousePressEvent(QMouseEvent *event) override
virtual void mouseReleaseEvent(QMouseEvent *event) override
void setOptimizationFlags(QGraphicsView::OptimizationFlags flags)
virtual void paintEvent(QPaintEvent *event) override
virtual void resizeEvent(QResizeEvent *event) override
void scale(qreal sx, qreal sy)
QGraphicsScene * scene() const const
void setRenderHint(QPainter::RenderHint hint, bool enabled)
QTransform transform() const const
void setViewportUpdateMode(QGraphicsView::ViewportUpdateMode mode)
Qt::KeyboardModifiers keyboardModifiers()
void append(const T &value)
const T & at(int i) const const
bool isEmpty() const const
int size() const const
QMap::iterator insertMulti(const Key &key, const T &value)
QMatrix & scale(qreal sx, qreal sy)
QAction * addAction(const QString &text)
QAction * addMenu(QMenu *menu)
QAction * addSeparator()
virtual int exec() override
void setWindowTitle(const QString &title)
void setText(const QString &text)
void setText(const QString &text)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void deleteLater()
QObject * parent() const const
QObject * sender() const const
void drawText(const QPointF &position, const QString &text)
void fillRect(const QRectF &rectangle, const QBrush &brush)
void resetTransform()
void setPen(const QColor &color)
int x() const const
int y() const const
QPoint toPoint() const const
qreal x() const const
qreal y() const const
QSet::iterator begin()
QSet::const_iterator constBegin() const const
bool contains(const T &value) const const
bool empty() const const
QSet::iterator insert(const T &value)
bool isEmpty() const const
int size() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromStdString(const std::string &str)
QString number(int n, int base)
qreal levelOfDetailFromTransform(const QTransform &worldTransform)
CustomContextMenu
MoveAction
Key_Space
KeyboardModifier
LeftButton
Vertical
bool toBool() const const
int toInt(bool *ok) const const
T value() const const
QVector::const_iterator constBegin() const const
QVector::const_iterator constEnd() const const
T & first()
T & last()
int size() const const
void setAcceptDrops(bool on)
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
void customContextMenuRequested(const QPoint &pos)
QPoint mapToGlobal(const QPoint &pos) const const
void setMouseTracking(bool enable)
void update()