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); // direction currently not used
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  }
579  recursionLevelMenu(preSucMenu->addMenu("Highlight predecessors …"), false, &GraphGraphicsView::handleHighlightPredecessor, true);
580  recursionLevelMenu(preSucMenu->addMenu("Highlight predecessors by distance …"), false, &GraphGraphicsView::handlePredecessorDistance);
581  if (isGate)
582  {
583  action = preSucMenu->addAction("Highlight path to predecessor gate …");
584  action->setData(PredecessorGate);
585  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleQueryShortestPathGate);
586  }
587  }
588 
589  action = context_menu.addAction("Remove selected items from view");
591 
593  {
594  action = context_menu.addAction("Cancel pick-item mode");
595  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleCancelPickMode);
596  }
597 
598  if(isModule)
599  ModuleContextMenu::addModuleSubmenu(&context_menu, mItem->id());
600  else if(isGate)
601  ModuleContextMenu::addGateSubmenu(&context_menu, mItem->id());
602  else if(isNet)
603  ModuleContextMenu::addNetSubmenu(&context_menu, mItem->id());
604 
605  // Appended to single selected item menu
606  if(isGate || isModule)
607  {
608  action = context_menu.addAction(" Fold parent module");
609  QObject::connect(action, &QAction::triggered, this, &GraphGraphicsView::handleFoldParentSingle);
610  }
611  if(isModule)
612  {
613  action = context_menu.addAction(" Unfold module");
614  QObject::connect(action, &QAction::triggered, this, &GraphGraphicsView::handleUnfoldSingleAction);
615  }
616 
618  {
620 
621  // Appended to multiple selected items menu
622  action = context_menu.addAction(" Fold all parent modules");
623  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleFoldParentAll);
624  action = context_menu.addAction(" Isolate all in new view");
625  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleIsolationViewAction);
626  action = context_menu.addAction(" Unfold all selected modules");
627  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleUnfoldAllAction);
628 
629  action = context_menu.addAction(" Add comment");
630  QVariant data;
631  data.setValue(Node(mItem->id(), isGate ? Node::NodeType::Gate : Node::NodeType::Module));
632  action->setData(data);
633  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleAddCommentAction);
634  }
635  }
636  else
637  {
638  context_menu.addAction("This view:")->setEnabled(false);
639 
640  action = context_menu.addAction(" Add module to view");
641  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleAddModuleToView);
642 
643  int selectable_modules_count = 0;
644  QSet<u32> not_selectable_modules = getNotSelectableModules();
645 
646  for (Module* m : gNetlist->get_modules())
647  if (!not_selectable_modules.contains(m->get_id()))
648  selectable_modules_count++;
649 
650  if (selectable_modules_count == 0)
651  action->setDisabled(true);
652 
653  action = context_menu.addAction(" Add gate to view");
654  connect(action, &QAction::triggered, this, &GraphGraphicsView::handleAddGateToView);
655  if (getSelectableGates().empty())
656  action->setDisabled(true);
657  }
658 
659  // if (!item || isNet)
660  // {
661  // QAction* antialiasing_action = context_menu.addAction("Antialiasing");
662  // QAction* cosmetic_action = context_menu.addAction("Cosmetic Nets");
663  // QMenu* grid_menu = context_menu.addMenu("Grid");
664  // QMenu* type_menu = grid_menu->addMenu("Type");
665  // QMenu* cluster_menu = grid_menu->addMenu("Clustering");
666  // QAction* lines_action = type_menu->addAction("Lines");
667  // QAction* dots_action = type_menu->addAction("Dots");
668  // QAction* none_action = type_menu->addAction("None");
669  // connect(action, &QAction::triggered, this, SLOT);
670  // }
671 
676  context_menu.exec(mapToGlobal(pos));
677  update();
678  }
679 
680  void GraphGraphicsView::handlePluginContextContributionTriggered()
681  {
682  QAction* act = static_cast<QAction*>(sender());
683  Q_ASSERT(act);
684  ContextMenuContribution* cmc = static_cast<ContextMenuContribution*>(act->data().value<void*>());
685  Q_ASSERT(cmc);
686  Q_ASSERT(cmc->mContributer);
687  cmc->mContributer->execute_function(cmc->mTagname,gNetlist,
691  if (gPythonContext->pythonThread())
692  gPythonContext->pythonThread()->unlock();
693  }
694 
695  void GraphGraphicsView::updateMatrix(const int delta)
696  {
697  qreal scale = qPow(2.0, delta / 100.0);
698 
699  QMatrix matrix;
701  setMatrix(matrix);
702  }
703 
704  void GraphGraphicsView::toggleAntialiasing()
705  {
707  }
708 
709  bool GraphGraphicsView::itemDraggable(GraphicsItem* item)
710  {
711  ItemType type = item->itemType();
712  return type == ItemType::Gate || type == ItemType::Module;
713  }
714 
715  void GraphGraphicsView::gentleZoom(const qreal factor)
716  {
717  scale(factor, factor);
718  centerOn(mTargetScenePos);
719  QPointF delta_viewport_pos = mTargetViewportPos - QPointF(viewport()->width() / 2.0, viewport()->height() / 2.0);
720  QPointF viewport_center = mapFromScene(mTargetScenePos) - delta_viewport_pos;
721  centerOn(mapToScene(viewport_center.toPoint()));
722  }
723 
724  void GraphGraphicsView::viewportCenterZoom(const qreal factor)
725  {
726  QPointF target_pos = mapToScene(viewport()->rect().center());
727  scale(factor, factor);
728  centerOn(target_pos.toPoint());
729  }
730 
731  void GraphGraphicsView::handleCancelPickMode()
732  {
733  gContentManager->getGraphTabWidget()->emitTerminatePicker();
734  }
735 
736  namespace ShortestPath
737  {
738  const Net* net(const Gate* g0, const Gate* g1)
739  {
740  for (const Net* n0 : g0->get_fan_out_nets())
741  for (const Net* n1 : g1->get_fan_in_nets())
742  if (n0 == n1)
743  return n0;
744  return nullptr;
745  }
746 
747  const Module* module(const Gate* g, const NodeBoxes& boxes)
748  {
749  const Module* parent = g->get_module();
750  while (parent)
751  {
752  Node nd(parent->get_id(),Node::Module);
753  if (boxes.boxForNode(nd)) return parent;
754  parent = parent->get_parent_module();
755  }
756  return nullptr;
757  }
758 
759  }
760 
761 
762  void GraphGraphicsView::handleAddModuleToView()
763  {
764  GraphContext* context = mGraphWidget->getContext();
765 
766 // QSet<u32> not_selectable_modules;
767 // QSet<u32> modules_in_context = context->modules();
768 // QSet<u32> gates_in_context = context->gates();
769 
770 // for (Module* module : gNetlist->get_modules())
771 // {
772 // bool module_in_context = false;
773 // for (Module* submodule: module->get_submodules(nullptr, true))
774 // {
775 // if (modules_in_context.contains(submodule->get_id()))
776 // {
777 // module_in_context = true;
778 // break;
779 // }
780 // }
781 // for (Gate* subgate : module->get_gates(nullptr, true))
782 // {
783 // if (gates_in_context.contains(subgate->get_id()))
784 // {
785 // module_in_context = true;
786 // break;
787 // }
788 // }
789 // if (module_in_context)
790 // {
791 // not_selectable_modules.insert(module->get_id());
792 // }
793 // }
794 
795 // not_selectable_modules += modules_in_context;
796 
797 // QSet<u32> direct_par_modules;
798 // for (u32 id : modules_in_context)
799 // {
800 // Module* cur_module = gNetlist->get_module_by_id(id);
801 // for (Module* module : cur_module->get_submodules(nullptr, true))
802 // {
803 // not_selectable_modules.insert(module->get_id());
804 // }
805 
806 // if (!cur_module->is_top_module())
807 // {
808 // direct_par_modules.insert(cur_module->get_parent_module()->get_id());
809 // }
810 // }
811 
812 // if (!gates_in_context.empty())
813 // {
814 // for (u32 id : gates_in_context)
815 // {
816 // direct_par_modules.insert(gNetlist->get_gate_by_id(id)->get_module()->get_id());
817 // }
818 // }
819 
820 // for (u32 id : direct_par_modules)
821 // {
822 // not_selectable_modules.insert(id);
823 
824 // Module* tmp_module = gNetlist->get_module_by_id(id);
825 // while (!tmp_module->is_top_module())
826 // {
827 // Module* par_module = tmp_module->get_parent_module();
828 // tmp_module = par_module;
829 // not_selectable_modules.insert(par_module->get_id());
830 // }
831 // }
832 
833  ModuleDialog module_dialog(getNotSelectableModules(),"Add module to view", true, nullptr, this);
834  if (module_dialog.exec() == QDialog::Accepted)
835  {
836  QSet<u32> module_to_add;
837  module_to_add.insert(module_dialog.selectedId());
838  ActionAddItemsToObject* act = new ActionAddItemsToObject(module_to_add, {});
839  act->setObject(UserActionObject(context->id(), UserActionObjectType::ContextView));
840  act->exec();
841  }
842  }
843 
844 
845  QSet<u32> GraphGraphicsView::getNotSelectableModules()
846  {
847  GraphContext* context = mGraphWidget->getContext();
848 
849  QSet<u32> not_selectable_modules;
850  QSet<u32> modules_in_context = context->modules();
851  QSet<u32> gates_in_context = context->gates();
852 
853  for (Module* module : gNetlist->get_modules())
854  {
855  bool module_in_context = false;
856  for (Module* submodule: module->get_submodules(nullptr, true))
857  {
858  if (modules_in_context.contains(submodule->get_id()))
859  {
860  module_in_context = true;
861  break;
862  }
863  }
864  for (Gate* subgate : module->get_gates(nullptr, true))
865  {
866  if (gates_in_context.contains(subgate->get_id()))
867  {
868  module_in_context = true;
869  break;
870  }
871  }
872  if (module_in_context)
873  {
874  not_selectable_modules.insert(module->get_id());
875  }
876  }
877 
878  not_selectable_modules += modules_in_context;
879 
880  QSet<u32> direct_par_modules;
881  for (u32 id : modules_in_context)
882  {
883  Module* cur_module = gNetlist->get_module_by_id(id);
884  for (Module* module : cur_module->get_submodules(nullptr, true))
885  {
886  not_selectable_modules.insert(module->get_id());
887  }
888 
889  if (!cur_module->is_top_module())
890  {
891  direct_par_modules.insert(cur_module->get_parent_module()->get_id());
892  }
893  }
894 
895  if (!gates_in_context.empty())
896  {
897  for (u32 id : gates_in_context)
898  {
899  direct_par_modules.insert(gNetlist->get_gate_by_id(id)->get_module()->get_id());
900  }
901  }
902 
903  for (u32 id : direct_par_modules)
904  {
905  not_selectable_modules.insert(id);
906 
907  Module* tmp_module = gNetlist->get_module_by_id(id);
908  while (!tmp_module->is_top_module())
909  {
910  Module* par_module = tmp_module->get_parent_module();
911  tmp_module = par_module;
912  not_selectable_modules.insert(par_module->get_id());
913  }
914  }
915 
916  return not_selectable_modules;
917  }
918 
919  QSet<u32> GraphGraphicsView::getSelectableGates()
920  {
921  GraphContext* context = mGraphWidget->getContext();
922 
923  QSet<u32> not_selectable_gates = context->gates();
924  QSet<u32> modules_in_context = context->modules();
925 
926  for (u32 module_id : modules_in_context)
927  {
928  for (Gate* gate : gNetlist->get_module_by_id(module_id)->get_gates(nullptr, true))
929  {
930  not_selectable_gates.insert(gate->get_id());
931  }
932  }
933 
934  QSet<u32> selectable_gates;
935  for (Gate* gate : gNetlist->get_gates())
936  {
937  if (!not_selectable_gates.contains(gate->get_id()))
938  {
939  selectable_gates.insert(gate->get_id());
940  }
941  }
942 
943  return selectable_gates;
944  }
945 
946  void GraphGraphicsView::handleAddGateToView()
947  {
948  QSet<u32> selectable_gates = getSelectableGates();
949 
950  GraphContext* context = mGraphWidget->getContext();
951 
952  GateDialog gate_dialog(selectable_gates, "Add gate to view", nullptr, this);
953  if (gate_dialog.exec() == QDialog::Accepted)
954  {
955  QSet<u32> gate_to_add;
956  gate_to_add.insert(gate_dialog.selectedId());
957  ActionAddItemsToObject* act = new ActionAddItemsToObject({}, gate_to_add);
958  act->setObject(UserActionObject(context->id(), UserActionObjectType::ContextView));
959  act->exec();
960  }
961  }
962 
963 
964  void GraphGraphicsView::handleAddSuccessorToView()
965  {
966  QAction* send = static_cast<QAction*>(sender());
967  Q_ASSERT(send);
968  int level = send->data().toInt();
969  addSuccessorToView(level, true);
970  }
971 
972  void GraphGraphicsView::handleAddPredecessorToView()
973  {
974  QAction* send = static_cast<QAction*>(sender());
975  Q_ASSERT(send);
976  int level = send->data().toInt();
977  addSuccessorToView(level, false);
978  }
979 
980  void GraphGraphicsView::handleAddCommonSuccessorToView()
981  {
982  QAction* send = static_cast<QAction*>(sender());
983  Q_ASSERT(send);
984  int level = send->data().toInt();
985  addCommonSuccessorToView(level, true);
986  }
987 
988  void GraphGraphicsView::handleAddCommonPredecessorToView()
989  {
990  QAction* send = static_cast<QAction*>(sender());
991  Q_ASSERT(send);
992  int level = send->data().toInt();
993  addCommonSuccessorToView(level, false);
994  }
995 
996  void GraphGraphicsView::addSuccessorToView(int maxLevel, bool succ)
997  {
998 
999  QSet<u32> gatsNew;
1000  QSet<const Gate*> gatsHandled;
1001 
1002  QList<const Gate*> startList;
1003  Node startNode;
1004 
1005  switch (mItem->itemType())
1006  {
1007  case ItemType::Gate:
1008  startNode = Node(mItem->id(),Node::Gate);
1009  startList.append(gNetlist->get_gate_by_id(mItem->id()));
1010  break;
1011  case ItemType::Module:
1012  startNode = Node(mItem->id(),Node::Module);
1013  for (const Gate* g : gNetlist->get_module_by_id(mItem->id())->get_gates(nullptr,true))
1014  startList.append(g);
1015  break;
1016  default:
1017  return;
1018  }
1019 
1020  Q_ASSERT(startList.size());
1021 
1022  for (const Gate* g : startList)
1023  gatsHandled.insert(g);
1024 
1025  const NodeBoxes& boxes = mGraphWidget->getContext()->getLayouter()->boxes();
1026  const NodeBox* box = boxes.boxForNode(startNode);
1027  Q_ASSERT(box);
1028  int xOrigin = box->x();
1029  int yOrigin = box->y();
1030  int xDir = succ ? 1 : -1;
1031 
1032  PlacementHint plc(PlacementHint::Standard);
1033 
1034  for (int loop = 0; !maxLevel || loop<maxLevel; loop++)
1035  {
1036  int y = 0;
1037  QList<const Gate*> foundList;
1038 
1039  for (const Gate* gOrigin : startList)
1040  {
1041  for (const Gate* g : netlist_utils::get_next_gates(gOrigin, succ, 1))
1042  {
1043  if (gatsHandled.contains(g)) continue;
1044  gatsHandled.insert(g);
1045  if (boxes.boxForGate(g)) continue; // by in view
1046  foundList.append(g);
1047  }
1048  }
1049 
1050  if (foundList.isEmpty()) break;
1051  for (const Gate* g: foundList)
1052  {
1053  gatsNew.insert(g->get_id());
1054  QPoint point(xOrigin + (loop+1) * xDir, yOrigin + y);
1055  y = y > 0 ? -y : -y+1;
1056  Node nd(g->get_id(),Node::Gate);
1057  if (!boxes.boxForPoint(point)) // not occupied yet
1058  {
1059  if (plc.mode() == PlacementHint::Standard)
1060  plc = PlacementHint(PlacementHint::GridPosition);
1061  plc.addGridPosition(nd,point);
1062  }
1063  }
1064  startList = foundList;
1065  }
1066 
1067  ActionAddItemsToObject* act = new ActionAddItemsToObject({}, gatsNew);
1068  act->setObject(UserActionObject(mGraphWidget->getContext()->id(),UserActionObjectType::ContextView));
1069  act->setPlacementHint(plc);
1070  act->exec();
1071  }
1072 
1073 
1074  void GraphGraphicsView::addCommonSuccessorToView(int maxLevel, bool succ)
1075  {
1076  CommonSuccessorPredecessor csp(gSelectionRelay->selectedGatesList(),succ,maxLevel);
1077  const NodeBoxes& boxes = mGraphWidget->getContext()->getLayouter()->boxes();
1078 
1079  QSet<u32> gatsNew;
1080  for (const Gate* g : csp.result())
1081  {
1082  if (boxes.boxForGate(g)) continue;
1083  gatsNew.insert(g->get_id());
1084  }
1085  ActionAddItemsToObject* act = new ActionAddItemsToObject({}, gatsNew);
1086  act->setObject(UserActionObject(mGraphWidget->getContext()->id(),UserActionObjectType::ContextView));
1087  act->exec();
1088  }
1089 
1090  void GraphGraphicsView::handleHighlightSuccessor()
1091  {
1092  QAction* send = static_cast<QAction*>(sender());
1093  Q_ASSERT(send);
1094  int level = send->data().toInt();
1096  }
1097 
1098  void GraphGraphicsView::handleHighlightPredecessor()
1099  {
1100  QAction* send = static_cast<QAction*>(sender());
1101  Q_ASSERT(send);
1102  int level = send->data().toInt();
1104  }
1105 
1106  void GraphGraphicsView::handleSuccessorDistance()
1107  {
1108  QAction* send = static_cast<QAction*>(sender());
1109  Q_ASSERT(send);
1110  int level = send->data().toInt();
1112  }
1113 
1114  void GraphGraphicsView::handlePredecessorDistance()
1115  {
1116  QAction* send = static_cast<QAction*>(sender());
1117  Q_ASSERT(send);
1118  int level = send->data().toInt();
1120  }
1121 
1122  void GraphGraphicsView::handleShortestModulePathToView()
1123  {
1124 
1125  }
1126 
1127  void GraphGraphicsView::handleShortestPathToView()
1128  {
1129  QAction* send = static_cast<QAction*>(sender());
1130  Q_ASSERT(send);
1131 
1132  bool succ = true;
1133  std::vector<Gate*> spath;
1134  Gate* startGate = gNetlist->get_gate_by_id(mItem->id());
1135  Q_ASSERT(startGate);
1136 
1137  if (send->data().toInt() == SuccessorModule)
1138  {
1139  QSet<u32> excludeModules;
1140  const Module* parMod = startGate->get_module();
1141  while (parMod)
1142  {
1143  excludeModules.insert(parMod->get_id());
1144  parMod = parMod->get_parent_module();
1145  }
1146 
1147  ModuleDialog md(excludeModules, "Shortest path to module", true, nullptr, this);
1148 
1149  if (md.exec() != QDialog::Accepted) return;
1150 
1151  Module* endModule = gNetlist->get_module_by_id(md.selectedId());
1152  Q_ASSERT(endModule);
1153 
1154  spath = netlist_utils::get_shortest_path(startGate,endModule);
1155  }
1156  else
1157  {
1158  succ = (send->data().toInt() == SuccessorGate);
1159 
1160  QSet<u32> selectableGates;
1161 
1162  for (Gate* g : netlist_utils::get_next_gates(startGate,succ))
1163  {
1164  selectableGates.insert(g->get_id());
1165  }
1166 
1167 // GraphGraphicsViewNeighborSelector* ggvns = new GraphGraphicsViewNeighborSelector(mItem->id(), succ, this);
1168  GateDialog gd(selectableGates, QString("Shortest path %1 gate").arg(succ?"to":"from"), nullptr, this);
1169 
1170  if (gd.exec() != QDialog::Accepted) return;
1171 
1172  Gate* endGate = gNetlist->get_gate_by_id(gd.selectedId());
1173  Q_ASSERT(endGate);
1174 
1175  if (succ)
1176  spath = netlist_utils::get_shortest_path(startGate,endGate);
1177  else
1178  {
1179  spath = netlist_utils::get_shortest_path(endGate,startGate);
1180  std::reverse(spath.begin(), spath.end());
1181  }
1182  }
1183  if (spath.empty()) return;
1184  auto it = spath.begin() + 1;
1185  const NodeBoxes& boxes = mGraphWidget->getContext()->getLayouter()->boxes();
1186  const NodeBox* lastBox = boxes.boxForGate(startGate);
1187  Q_ASSERT(lastBox);
1188  QPoint point(lastBox->x(),lastBox->y());
1189  QPoint deltaX(succ ? 1 : -1, 0);
1190  PlacementHint plc(PlacementHint::Standard);
1191 
1192  QSet<u32> gats;
1193 
1194  while (it != spath.end())
1195  {
1196  point += deltaX;
1197  Gate* g = *(it++);
1198  if (boxes.boxForGate(g)) continue; // already in view
1199  gats.insert(g->get_id());
1200  Node nd(g->get_id(),Node::Gate);
1201  if (!boxes.boxForPoint(point)) // not occupied yet
1202  {
1203  if (plc.mode() == PlacementHint::Standard)
1204  plc = PlacementHint(PlacementHint::GridPosition);
1205  plc.addGridPosition(nd,point);
1206  }
1207  startGate = g;
1208  }
1209 
1210  ActionAddItemsToObject* act = new ActionAddItemsToObject({},gats);
1211  act->setObject(UserActionObject(mGraphWidget->getContext()->id(),UserActionObjectType::ContextView));
1212  act->setPlacementHint(plc);
1213  act->exec();
1214  }
1215 
1216  void GraphGraphicsView::handleQueryShortestPathModule()
1217  {
1218  QAction* send = static_cast<QAction*>(sender());
1219  Q_ASSERT(send);
1220 
1221  QSet<u32> excludeModules;
1222  Gate* g = gNetlist->get_gate_by_id(mItem->id());
1223  Q_ASSERT(g);
1224  Module* par = g->get_module();
1225  while(par)
1226  {
1227  excludeModules.insert(par->get_id());
1228  par = par->get_parent_module();
1229  }
1230  ModuleDialog md(excludeModules, "Shortest path to module", true, nullptr, this);
1231 
1232  if (md.exec() != QDialog::Accepted) return;
1233 
1234  handleShortestPath(mItem->id(),Node(md.selectedId(),Node::Module));
1235  }
1236 
1237  void GraphGraphicsView::handleQueryShortestPathGate()
1238  {
1239  QAction* send = static_cast<QAction*>(sender());
1240  Q_ASSERT(send);
1241  bool succ = send->data().toInt() == SuccessorGate;
1242 
1243  QSet<u32> selectableGates;
1244  for (Gate* g : netlist_utils::get_next_gates(gNetlist->get_gate_by_id(mItem->id()),succ))
1245  selectableGates.insert(g->get_id());
1246 
1247  GraphGraphicsViewNeighborSelector* ggvns = new GraphGraphicsViewNeighborSelector(mItem->id(), succ, this);
1248  GateDialog gd(selectableGates,QString("Shortest path %1 gate").arg(succ?"to":"from"),ggvns,this);
1249 
1250  if (gd.exec() != QDialog::Accepted) return;
1251 
1252  u32 targetId = gd.selectedId();
1253  if (!targetId) return;
1254 
1255  if (succ)
1256  handleShortestPath(mItem->id(),Node(targetId,Node::Gate));
1257  else
1258  handleShortestPath(targetId,Node(mItem->id(),Node::Gate));
1259  }
1260 
1262  {
1263  std::vector<Gate*> spath;
1264 
1265  Gate* g0 = gNetlist->get_gate_by_id(idFrom);
1266  Q_ASSERT(g0);
1267  Q_ASSERT(!nodeTo.isNull());
1268 
1269  QString target;
1270 
1271  if(nodeTo.isGate())
1272  {
1273  Gate* g1 = gNetlist->get_gate_by_id(nodeTo.id());
1274  Q_ASSERT(g1);
1275  spath = netlist_utils::get_shortest_path(g0,g1);
1276  target = QString("gate '%1'[%2]").arg(QString::fromStdString(g1->get_name()), g1->get_id());
1277  }
1278  else
1279  {
1280  Module* m = gNetlist->get_module_by_id(nodeTo.id());
1281  Q_ASSERT(m);
1282  spath = netlist_utils::get_shortest_path(g0,m);
1283  target = QString("module '%1'[%2]").arg(QString::fromStdString(m->get_name()), m->get_id());
1284  }
1285 
1286 
1287  QSet<u32> mods;
1288  QSet<u32> gats;
1289  QSet<u32> nets;
1290 
1291  Gate* previousGate = nullptr;
1292  for (Gate* g : spath)
1293  {
1294  const Module* pm = ShortestPath::module(g,mGraphWidget->getContext()->getLayouter()->boxes());
1295  if (pm) mods.insert(pm->get_id());
1296  gats.insert(g->get_id());
1297  if (previousGate)
1298  {
1299  const Net* n = ShortestPath::net(previousGate,g);
1300  if (n) nets.insert(n->get_id());
1301  }
1302  previousGate = g;
1303  }
1304 
1306  act->setUseCreatedObject();
1308  QString("Path from '%1'[%2] to %3")
1309  .arg(QString::fromStdString(g0->get_name())).arg(g0->get_id())
1310  .arg(target)));
1311  act->addAction(new ActionAddItemsToObject(mods,gats,nets));
1312  act->addAction(new ActionSetSelectionFocus());
1313  act->exec();
1314  }
1315 
1316  void GraphGraphicsView::handleSelectOutputs()
1317  {
1318  auto context = mGraphWidget->getContext();
1319  QAction* sender_action = dynamic_cast<QAction*>(sender());
1320  if (sender_action)
1321  {
1322  QSet<u32> gates;
1323  for (auto sel_id : gSelectionRelay->selectedGatesList())
1324  {
1325  auto gate = gNetlist->get_gate_by_id(sel_id);
1326  for (auto net : gate->get_fan_out_nets())
1327  {
1328  for (const auto& suc : net->get_destinations())
1329  {
1330  bool found = false;
1331  for (const auto& id : context->modules())
1332  {
1333  auto m = gNetlist->get_module_by_id(id);
1334  if (m->contains_gate(suc->get_gate(), true))
1335  {
1336  found = true;
1337  break;
1338  }
1339  }
1340  if (!found)
1341  {
1342  gates.insert(suc->get_gate()->get_id());
1343  }
1344  }
1345  }
1346  }
1347  for (auto sel_id : gSelectionRelay->selectedModulesList())
1348  {
1349  auto module = gNetlist->get_module_by_id(sel_id);
1350  for (auto net : module->get_output_nets())
1351  {
1352  for (const auto& suc : net->get_destinations())
1353  {
1354  bool found = false;
1355  for (const auto& id : context->modules())
1356  {
1357  auto m = gNetlist->get_module_by_id(id);
1358  if (m->contains_gate(suc->get_gate(), true))
1359  {
1360  found = true;
1361  break;
1362  }
1363  }
1364  if (!found)
1365  {
1366  gates.insert(suc->get_gate()->get_id());
1367  }
1368  }
1369  }
1370  }
1371 
1372  gates = context->getLayouter()->boxes().filterNotInView(gates);
1373  ActionAddItemsToObject* act = new ActionAddItemsToObject({},gates);
1374  act->setObject(UserActionObject(context->id(),UserActionObjectType::ContextView));
1376  {
1377  Node origin = (gSelectionRelay->numberSelectedModules()==1)
1380  act->setPlacementHint(PlacementHint(PlacementHint::PreferRight,origin));
1381  }
1382  act->exec();
1383  }
1384  }
1385  void GraphGraphicsView::handleSelectInputs()
1386  {
1387  auto context = mGraphWidget->getContext();
1388  QAction* sender_action = dynamic_cast<QAction*>(sender());
1389  if (sender_action)
1390  {
1391  QSet<u32> gates;
1392  for (auto sel_id : gSelectionRelay->selectedGatesList())
1393  {
1394  auto gate = gNetlist->get_gate_by_id(sel_id);
1395  for (auto net : gate->get_fan_in_nets())
1396  {
1397  if (!net->get_sources().empty() && net->get_sources().at(0)->get_gate() != nullptr)
1398  {
1399  bool found = false;
1400  for (const auto& id : context->modules())
1401  {
1402  auto m = gNetlist->get_module_by_id(id);
1403  if (m->contains_gate(net->get_sources().at(0)->get_gate(), true))
1404  {
1405  found = true;
1406  break;
1407  }
1408  }
1409  if (!found)
1410  {
1411  gates.insert(net->get_sources().at(0)->get_gate()->get_id());
1412  }
1413  }
1414  }
1415  }
1416  for (auto sel_id : gSelectionRelay->selectedModulesList())
1417  {
1418  auto module = gNetlist->get_module_by_id(sel_id);
1419  for (auto net : module->get_input_nets())
1420  {
1421  if (!net->get_sources().empty() && net->get_sources().at(0)->get_gate() != nullptr)
1422  {
1423  bool found = false;
1424  for (const auto& id : context->modules())
1425  {
1426  auto m = gNetlist->get_module_by_id(id);
1427  if (m->contains_gate(net->get_sources().at(0)->get_gate(), true))
1428  {
1429  found = true;
1430  break;
1431  }
1432  }
1433  if (!found)
1434  {
1435  gates.insert(net->get_sources().at(0)->get_gate()->get_id());
1436  }
1437  }
1438  }
1439  }
1440 
1441  gates = context->getLayouter()->boxes().filterNotInView(gates);
1442  ActionAddItemsToObject* act = new ActionAddItemsToObject({},gates);
1443  act->setObject(UserActionObject(context->id(),UserActionObjectType::ContextView));
1445  {
1446  Node origin = (gSelectionRelay->numberSelectedModules()==1)
1449  act->setPlacementHint(PlacementHint(PlacementHint::PreferLeft,origin));
1450  }
1451  act->exec();
1452  }
1453  }
1454 
1455  void GraphGraphicsView::selectedNodeToItem()
1456  {
1457  if (gSelectionRelay->numberSelectedItems() != 1) return;
1458  NodeBox* box = nullptr;
1460  {
1461  u32 gatId = gSelectionRelay->selectedGatesList().at(0);
1462  box = mGraphWidget->getContext()->getLayouter()->boxes().boxForNode(Node(gatId,Node::Gate));
1463  }
1464  else if (gSelectionRelay->numberSelectedModules() == 1)
1465  {
1466  u32 modId = gSelectionRelay->selectedModulesList().at(0);
1467  box = mGraphWidget->getContext()->getLayouter()->boxes().boxForNode(Node(modId,Node::Module));
1468  }
1469  if (!box) return;
1470  mItem = box->item();
1471  }
1472 
1474  {
1475  selectedNodeToItem();
1476  if (!mItem) return;
1477  handleFoldParentSingle();
1478  }
1479 
1481  {
1482  selectedNodeToItem();
1483  if (!mItem || mItem->itemType() != ItemType::Module) return;
1484  handleUnfoldSingleAction();
1485  }
1486 
1487  void GraphGraphicsView::handleFoldParentSingle()
1488  {
1489  const Module* parentModule = nullptr;
1490  Node childNode;
1491  u32 id = mItem->id();
1492  GraphContext* context = mGraphWidget->getContext();
1493  switch (mItem->itemType())
1494  {
1495  case ItemType::Module:
1496  parentModule = gNetlist->get_module_by_id(id)->get_parent_module();
1497  childNode = Node(id, Node::Module);
1498  break;
1499  case ItemType::Gate:
1500  parentModule = gNetlist->get_gate_by_id(id)->get_module();
1501  childNode = Node(id, Node::Gate);
1502  break;
1503  default:
1504  return;
1505  }
1506 
1507  if (!parentModule || childNode.type()==Node::None) return;
1508  NodeBox* box = context->getLayouter()->boxes().boxForNode(childNode);
1509  if (!box) return;
1510 
1511  PlacementHint plc(PlacementHint::GridPosition);
1512  plc.addGridPosition(Node(parentModule->get_id(),Node::Module),box->gridPosition());
1513  ActionFoldModule* act = new ActionFoldModule(parentModule->get_id());
1514  act->setContextId(context->id());
1515  act->setPlacementHint(plc);
1516  act->exec();
1517  }
1518 
1519  void GraphGraphicsView::handleUnfoldSingleAction()
1520  {
1521  GraphContext* context = mGraphWidget->getContext();
1522  Module* m = gNetlist->get_module_by_id(mItem->id());
1523  if (m->get_gates().empty() && m->get_submodules().empty())
1524  {
1525  QMessageBox msg;
1526  msg.setText("This module is empty.\nYou can't unfold it.");
1527  msg.setWindowTitle("Error");
1528  msg.exec();
1529  return;
1530  // We would otherwise unfold the empty module into nothing, so the user
1531  // would have nowhere to click to get their module back
1532  }
1533  ActionUnfoldModule* act = new ActionUnfoldModule(mItem->id());
1534  act->setContextId(context->id());
1535  act->exec();
1536  }
1537 
1538  void GraphGraphicsView::handleFoldParentAll()
1539  {
1540  GraphContext* context = mGraphWidget->getContext();
1541 
1542  QSet<const Module*> modSet;
1543 
1544  for (Node& nd : gSelectionRelay->selectedNodesList())
1545  {
1546  if (!context->getLayouter()->boxes().boxForNode(nd)) continue; // not in view
1547 
1548  switch (nd.type())
1549  {
1550  case Node::Gate:
1551  modSet.insert(gNetlist->get_gate_by_id(nd.id())->get_module());
1552  break;
1553  case Node::Module:
1554  modSet.insert(gNetlist->get_module_by_id(nd.id())->get_parent_module());
1555  default:
1556  continue;
1557  }
1558  }
1559 
1561  for (const Module* m : modSet)
1562  if (m) modDepth.insertMulti(m->get_submodule_depth(),m);
1563 
1564  QMapIterator<int,const Module*> it(modDepth);
1565  it.toBack();
1566  while (it.hasPrevious())
1567  {
1568  it.previous();
1569  const Module* m = it.value();
1570  ActionFoldModule* act = new ActionFoldModule(m->get_id());
1571  act->setContextId(context->id());
1572  act->exec();
1573  }
1574  }
1575 
1576  void GraphGraphicsView::handleUnfoldAllAction()
1577  {
1578  auto context = mGraphWidget->getContext();
1579 
1580  context->beginChange();
1581  UserActionCompound* act = new UserActionCompound;
1583  {
1584  ActionUnfoldModule* ufo = new ActionUnfoldModule(id);
1585  ufo->setContextId(context->id());
1586  act->addAction(ufo);
1587  }
1588  act->exec();
1589  context->endChange();
1590  }
1591 
1592 #ifdef GUI_DEBUG_GRID
1593  void GraphGraphicsView::debugShowLayouterGridpos(const QPoint& mouse_pos)
1594  {
1595  auto context = mGraphWidget->getContext();
1596  if (!context)
1597  return;
1598 
1599  const GraphLayouter* layouter = context->getLayouter();
1600  if (!(layouter->done()))
1601  return;
1602 
1603  QPointF scene_mouse_pos = mapToScene(mouse_pos);
1604  QPoint layouter_pos = closestLayouterPos(scene_mouse_pos).first;
1605  m_debug_gridpos = layouter_pos;
1606  }
1607 #endif
1608 
1609  QPair<QPoint,QPointF> GraphGraphicsView::closestLayouterPos(const QPointF& scene_pos) const
1610  {
1611  auto context = mGraphWidget->getContext();
1612  assert(context);
1613 
1614  const GraphLayouter* layouter = context->getLayouter();
1615  assert(layouter->done()); // ensure grid stable
1616 
1617  int default_width = layouter->defaultGridWidth();
1618  int default_height = layouter->defaultGridHeight();
1619  int min_x = layouter->minXIndex();
1620  int min_y = layouter->minYIndex();
1621  QVector<qreal> x_vals = layouter->xValues();
1622  QVector<qreal> y_vals = layouter->yValues();
1623  LayouterPoint x_point = closestLayouterPoint(scene_pos.x(), default_width, min_x, x_vals);
1624  LayouterPoint y_point = closestLayouterPoint(scene_pos.y(), default_height, min_y, y_vals);
1625  return qMakePair(QPoint(x_point.mIndex, y_point.mIndex), QPointF(x_point.mPos, y_point.mPos));
1626  }
1627 
1628  GraphGraphicsView::LayouterPoint GraphGraphicsView::closestLayouterPoint(qreal scene_pos, int default_spacing, int min_index, QVector<qreal> sections) const
1629  {
1630  int index = min_index;
1631  qreal pos = 0;
1632  if (sections.first() > scene_pos)
1633  {
1634  int distance = sections.first() - scene_pos;
1635  int nSections = distance / default_spacing; // this rounds down
1636  index -= (nSections + 1);
1637  pos = sections.first() + index * default_spacing;
1638  }
1639  else if (sections.last() <= scene_pos)
1640  {
1641  int distance = scene_pos - sections.last();
1642  int nSections = distance / default_spacing; // this rounds down
1643  index += (sections.size() + nSections -1);
1644  pos = sections.last() + nSections * default_spacing;
1645  }
1646  else
1647  {
1648  // search for first value in sections larger than or equal to scene_pos
1649  auto it = sections.constBegin();
1650  auto jt = it+1;
1651  while (jt != sections.constEnd())
1652  {
1653  if (scene_pos < *jt) break; // found value in inteval [it..[jt
1654  ++it;
1655  ++jt;
1656  ++index;
1657  }
1658  pos = *it;
1659  }
1660  return LayouterPoint{index, pos};
1661  }
1662 
1663 
1665  {
1666  return mGridType;
1667  }
1668 
1670  {
1671  mGridType = gridType;
1672  }
1673 
1675  {
1676  return mDragModifier;
1677  }
1678 
1680  {
1681  mDragModifier = dragModifier;
1682  }
1683 
1685  {
1686  return mPanModifier;
1687  }
1688 
1690  {
1691  mPanModifier = panModifier;
1692  }
1693 
1695  {
1696  if (!gats.empty())
1697  {
1698  u32 pickedGate = *gats.constBegin();
1699  GraphGraphicsView* ggv = dynamic_cast<GraphGraphicsView*>(parent());
1700  if (ggv)
1701  {
1702  if (mPickSuccessor)
1703  ggv->handleShortestPath(mOrigin,Node(pickedGate,Node::Gate));
1704  else
1705  ggv->handleShortestPath(pickedGate,Node(mOrigin,Node::Gate));
1706  }
1707  }
1708  this->deleteLater();
1709  }
1710 } // 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 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 handleShortestPath(u32 idFrom, Node nodeTo)
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_shortest_path(Gate *start_gate, Module *end_module)
std::vector< Gate * > get_next_gates(const Gate *gate, bool get_successors, int depth, const std::function< bool(const Gate *)> &filter)
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()