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