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