HAL
gate_pin_tree.cpp
Go to the documentation of this file.
3 //#include "gui/gui_globals.h"
5 #include <QHeaderView>
6 #include <QClipboard>
7 #include <QApplication>
8 #include <QMenu>
11 #include <QMouseEvent>
12 
13 namespace hal
14 {
15 
16  GatePinTree::GatePinTree(QWidget *parent) : QTreeView(parent), mPinModel(new GatePinsTreeModel(this)),
17  mGateID(-1), mClearSelection(false)
18  {
24  setModel(mPinModel);
25 
26  mNavigationTable = new GraphNavigationWidget(true);
27  mNavigationTable->setWindowFlags(Qt::CustomizeWindowHint);
28  mNavigationTable->hide();
29 
30  //connections
32  connect(mNavigationTable, &GraphNavigationWidget::closeRequested, this, &GatePinTree::handleNavigationCloseRequested);
33  connect(mNavigationTable, &GraphNavigationWidget::navigationRequested, this, &GatePinTree::handleNavigationJumpRequested);
34 
35  }
36 
38  {
39  Gate* g = gNetlist->get_gate_by_id(gateID);
40  if(!g) return;
41 
42  mPinModel->setGate(g);
43  mGateID = gateID;
44 
45  Q_EMIT updateText(QString("Pins (%1)").arg(mPinModel->getNumberOfDisplayedPins()));
46  }
47 
49  {
50  if(!g) return;
51 
52  mPinModel->setGate(g);
53  mGateID = g->get_id();
54 
55  Q_EMIT updateText(QString("Pins (%1)").arg(mPinModel->getNumberOfDisplayedPins()));
56  }
57 
59  {
60  mGateID = -1;
61  mPinModel->clear();
62  }
63 
65  {
67 
68  QModelIndex idx = indexAt(event->pos());
69  if(!idx.isValid())
70  return;
71 
72  GatePinsTreeItem* clickedItem = dynamic_cast<GatePinsTreeItem*>(mPinModel->getItemFromIndex(idx));
73  if(!clickedItem || clickedItem->type() != GatePinsTreeItem::Pin)
74  return;
75 
76  auto netId = clickedItem->netIds().front();
77  auto clickedNet = gNetlist->get_net_by_id(netId);
78  if(clickedNet)
79  {
81  if(direction == "output" && !clickedNet->is_global_output_net())
82  {
83  mClearSelection = true;
84  addSourceOurDestinationToSelection(netId, false);
85  }else if (direction == "input" && !clickedNet->is_global_input_net())
86  {
87  mClearSelection = true;
88  addSourceOurDestinationToSelection(netId, true);
89  }
90  }
91  }
92 
94  {
95  QModelIndex idx = indexAt(pos);
96  if(!idx.isValid())
97  return;
98 
99  GatePinsTreeItem* clickedItem = dynamic_cast<GatePinsTreeItem*>(mPinModel->getItemFromIndex(idx));
100  QMenu menu;
101  bool isMiscSectionSet = false;//so that the misc-section is not set multiple times
102 
103  //PLAINTEXT: NAME, DIRECTION, TYPE
104  menu.addAction("Name to clipboard",
105  [clickedItem](){
107  });
108 
109  menu.addAction("Direction to clipboard",
110  [clickedItem](){
112  });
113 
114  menu.addAction("Type to clipboard",
115  [clickedItem](){
117  });
118 
119  //Check if jump to source or destination is possible
120  if(clickedItem->type() == GatePinsTreeItem::Pin && clickedItem->netIds().size()==1)
121  {
122  auto netId = clickedItem->netIds().front();
123  auto clickedNet = gNetlist->get_net_by_id(netId);
124  if(clickedNet)
125  {
126 // //check if input or output pin (use enums, todo: save PinDirection in items as additional data(?))
127 // auto direction = clickedItem->getData(GatePinsTreeModel::sDirectionColumn).toString();
128 // if(direction == "output" && !clickedNet->is_global_output_net())
129 // {
130 // menu.addSection("Misc");
131 // isMiscSectionSet = true;
132 // menu.addAction("Overwrite selection with destination gate", [this, netId](){
133 // mClearSelection = true;
134 // addSourceOurDestinationToSelection(netId, false);
135 // });
136 // menu.addAction("Add destination gate to selection", [this, netId](){
137 // mClearSelection = false;
138 // addSourceOurDestinationToSelection(netId, false);
139 // });
140 // }
141 // else if (direction == "input" && !clickedNet->is_global_input_net())
142 // {
143 // menu.addSection("Misc");
144 // isMiscSectionSet = true;
145 // menu.addAction("Overwrite selection with source gate", [this, netId](){
146 // mClearSelection = true;
147 // addSourceOurDestinationToSelection(netId, true);
148 // });
149 // menu.addAction("Add source gate to selection", [this, netId](){
150 // mClearSelection = false;
151 // addSourceOurDestinationToSelection(netId, true);
152 // });
153 // }
154  }
155  }
156 
157  //Add nets to selection if possible
158  QList<u32> netIds;
159  if(clickedItem->type() == GatePinsTreeItem::Pin)
160  {
161  netIds = clickedItem->netIds();
162  if (mGateID > 0 && (clickedItem->direction() == PinDirection::input || clickedItem->direction() == PinDirection::output))
163  menu.addAction("Set focus to pin", [this, clickedItem]() {
164  const Gate* g = gNetlist->get_gate_by_id(this->mGateID);
165  auto pins = clickedItem->direction() == PinDirection::input
166  ? g->get_type()->get_input_pins() : g->get_type()->get_output_pins();
169  int cnt = 0;
170  for (auto pin: pins)
171  {
172  if (clickedItem->pinName() == pin->get_name())
173  break;
174  ++cnt;
175  }
176  gSelectionRelay->setFocus(SelectionRelay::ItemType::Gate, this->mGateID, sfoc, cnt);
178  });
179 
180  }
181  else
182  {
183  for(auto childItem : clickedItem->getChildren())
184  {
185  GatePinsTreeItem* pti = dynamic_cast<GatePinsTreeItem*>(childItem);
186  if (pti)
187  netIds.append(pti->netIds());
188  }
189  }
190  if(netIds.size() != 0)
191  {
192  QString desc = (netIds.size() == 1) ? "Set net as current selection" : "Set net(s) as current selection";
193  QString desc2 = (netIds.size() == 1) ? "Add net to current selection" : "Add net(s) to current selection";
194  if(!isMiscSectionSet)
195  {
196  menu.addSection("Misc");
197  isMiscSectionSet = true;
198  }
199  menu.addAction(desc, [this, netIds](){
201  for(const int id : netIds)
202  gSelectionRelay->addNet(id);
204  });
205  menu.addAction(desc2,
206  [this, netIds](){
207  for(const int id : netIds)
208  gSelectionRelay->addNet(id);
210  });
211  }
212 
213  menu.addSection("Python");
214 
215  if(clickedItem->type() == GatePinsTreeItem::Pin)
216  buildPythonMenuForPin(menu, clickedItem);
217  else
218  buildPythonMenuForPinGroup(menu, clickedItem);
219 
220  menu.move(mapToGlobal(pos));
221  menu.exec();
222 
223  }
224 
225  void GatePinTree::buildPythonMenuForPin(QMenu &menu, GatePinsTreeItem *clickedPinItem)
226  {
227  // 1.) NET-OBJECT
228  QList<u32> netIdsOfItem = clickedPinItem->netIds();
229  QString pythonCommandNetIds, pythonCommandName;
230 
231  if(netIdsOfItem.size() == 1)
232  {
233  pythonCommandNetIds = PyCodeProvider::pyCodeNet(netIdsOfItem.at(0));
234  pythonCommandName = PyCodeProvider::pyCodeNetName(netIdsOfItem.at(0));
235  }
236  else if(netIdsOfItem.size() == 2)
237  {
238  pythonCommandNetIds = "netInput = " + PyCodeProvider::pyCodeNet(netIdsOfItem.at(0)) + "\nnetOutput = " + PyCodeProvider::pyCodeNet(netIdsOfItem.at(1));
239  pythonCommandName = "netInputName = " + PyCodeProvider::pyCodeNetName(netIdsOfItem.at(0)) + "\nnetOutputName = " + PyCodeProvider::pyCodeNetName(netIdsOfItem.at(1));
240  }
241 
242  menu.addAction(QIcon(":/icons/python"), "Extract net(s) as python code",
243  [pythonCommandNetIds]()
244  {
245  QApplication::clipboard()->setText(pythonCommandNetIds);
246  });
247 
248  // 2.) DIRECTION
250  menu.addAction(QIcon(":/icons/python"), "Extract pin direction as python code",
251  [pythonCommandDirection]()
252  {
253  QApplication::clipboard()->setText(pythonCommandDirection);
254  });
255 
256 
257  // 3.) type
259  menu.addAction(QIcon(":/icons/python"), "Extract pin type as python code",
260  [pythonCommandType]()
261  {
262  QApplication::clipboard()->setText(pythonCommandType);
263  });
264 
265  }
266 
267  void GatePinTree::buildPythonMenuForPinGroup(QMenu &menu, GatePinsTreeItem *clickedPinIGrouptem)
268  {
269  // 1. PYTHON LIST OF PIN GROUPS
270  QString pythonList = "[";
271  for(auto childPin : clickedPinIGrouptem->getChildren())
272  pythonList += "\"" + childPin->getData(GatePinsTreeModel::sNameColumn).toString() + "\", ";
273  pythonList = pythonList.left(pythonList.size()-2);
274  pythonList += "]";
275 
276  menu.addAction(QIcon(":/icons/python"), "Extract pingroup as python list",
277  [pythonList]()
278  {
279  QApplication::clipboard()->setText(pythonList);
280  });
281 
282  //2. DIRECTION and TYPE(determined by the pin(s) within the group)
283  BaseTreeItem* firstPinItemOfGroup = clickedPinIGrouptem->getChild(0);
284  if(firstPinItemOfGroup)
285  {
286  QString pythonCommandGroupDirection = PyCodeProvider::pyCodeGateTypePinDirection(mPinModel->getCurrentGateID(),
287  firstPinItemOfGroup->getData(GatePinsTreeModel::sNameColumn).toString());
288  menu.addAction(QIcon(":/icons/python"), "Extract direction of pingroup as python code",
289  [pythonCommandGroupDirection]()
290  {
291  QApplication::clipboard()->setText(pythonCommandGroupDirection);
292  });
293 
294  QString pythonCommandGroupType = PyCodeProvider::pyCodeGateTypePinType(mPinModel->getCurrentGateID(),
295  firstPinItemOfGroup->getData(GatePinsTreeModel::sNameColumn).toString());
296  menu.addAction(QIcon(":/icons/python"), "Extract type of pingroup as python code",
297  [pythonCommandGroupType]()
298  {
299  QApplication::clipboard()->setText(pythonCommandGroupType);
300  });
301  }
302  }
303 
304  void GatePinTree::addSourceOurDestinationToSelection(int netId, bool isInputPin)
305  {
306  auto net = gNetlist->get_net_by_id(netId);
307  if(!net) return;
308 
309  auto sourcesOrDesti = isInputPin ? net->get_sources() : net->get_destinations();
310  if(sourcesOrDesti.empty() || net->is_global_input_net() || net->is_global_output_net())
311  {
312  return; //for now, maybe simply add/oberwrite net (check global mClearSelection)?
313  }
314  else if (sourcesOrDesti.size() == 1)
315  {
316  if(mClearSelection)
318  auto ep = *sourcesOrDesti.begin();
319  gSelectionRelay->addGate(ep->get_gate()->get_id());
320  auto pins = isInputPin ? ep->get_gate()->get_type()->get_output_pins() : ep->get_gate()->get_type()->get_input_pins();
321  auto index = std::distance(pins.begin(), std::find(pins.begin(), pins.end(), ep->get_pin()));
324  }
325  else
326  {
327  mNavigationTable->setup(Node(), net, isInputPin ? SelectionRelay::Subfocus::Left : SelectionRelay::Subfocus::Right);
328  if(mNavigationTable->isEmpty())
329  mNavigationTable->closeRequest();
330  else
331  {
332  mNavigationTable->move(QCursor::pos());
333  mNavigationTable->show();
334  mNavigationTable->setFocus();
335  }
336 
337  }
338  }
339 
340  void GatePinTree::handleNavigationCloseRequested()
341  {
342  mNavigationTable->hide();
343  }
344 
345  void GatePinTree::handleNavigationJumpRequested(const Node &origin, const u32 via_net, const QSet<u32> &to_gates, const QSet<u32> &to_modules)
346  {
347  Q_UNUSED(origin)
348  Q_UNUSED(to_modules)
349 
350  mNavigationTable->hide();
351 
352  auto n = gNetlist->get_net_by_id(via_net);
353  if(!n || to_gates.isEmpty())
354  return;
355  for(u32 id : to_gates)
356  if(!gNetlist->get_gate_by_id(id))
357  return;
358 
359  if(mClearSelection)
361  for(u32 id : to_gates)
363 
364  if(to_gates.size()==1)
365  {
366  auto g = gNetlist->get_gate_by_id(*to_gates.begin());
367  u32 index = 0;
368  bool isNavDirLeft = mNavigationTable->direction() == SelectionRelay::Subfocus::Left;
369  auto pins = isNavDirLeft ? g->get_type()->get_output_pins() : g->get_type()->get_input_pins();
370  for(auto pin : pins)
371  {
372  if(isNavDirLeft ? g->get_fan_out_net(pin) == n : g->get_fan_in_net(pin) == n)
373  {
375  break;
376  }
377  index++;
378  }
379  }
381  }
382 
383 }
virtual QList< BaseTreeItem * > getChildren() const
BaseTreeItem * getItemFromIndex(QModelIndex index) const
Definition: gate.h:58
virtual void mouseDoubleClickEvent(QMouseEvent *event) override
void updateText(const QString &newHeadline)
void handleContextMenuRequested(const QPoint &pos)
void setGate(u32 gateID)
GatePinTree(QWidget *parent=nullptr)
std::string pinName() const
QVariant getData(int column) const override
PinDirection direction() const
QList< u32 > netIds() const
A model to display the pins of a gate.
static const int sDirectionColumn
SelectionRelay::Subfocus direction() const
void navigationRequested(const Node &origin, const u32 via_net, const QSet< u32 > &to_gates, const QSet< u32 > &to_modules)
void setup(SelectionRelay::Subfocus direction)
Gate * get_gate_by_id(const u32 gate_id) const
Definition: netlist.cpp:193
Net * get_net_by_id(u32 net_id) const
Definition: netlist.cpp:353
static QString pyCodeGateTypePinDirection(u32 gateId, QString pin)
static QString pyCodeGateTypePinType(u32 gateId, QString pin)
static QString pyCodeNet(u32 netId)
static QString pyCodeNetName(u32 netId)
void setFocus(ItemType ftype, u32 fid, Subfocus sfoc=Subfocus::None, u32 sfinx=0)
void relaySelectionChanged(void *sender)
SelectionRelay * gSelectionRelay
Definition: plugin_gui.cpp:83
Netlist * gNetlist
Definition: plugin_gui.cpp:80
n
Definition: test.py:6
quint32 u32
std::vector< PinInformation > pins
Net * net
PinDirection direction
virtual bool event(QEvent *event) override
void setSelectionMode(QAbstractItemView::SelectionMode mode)
void setText(const QString &text, QClipboard::Mode mode)
QPoint pos()
QClipboard * clipboard()
void setStretchLastSection(bool stretch)
void append(const T &value)
const T & at(int i) const const
T & front()
int size() const const
QAction * addAction(const QString &text)
QAction * addSection(const QString &text)
QAction * exec()
bool isValid() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool isEmpty() const const
QString left(int n) const const
int size() const const
CustomContextMenu
CustomizeWindowHint
QHeaderView * header() const const
virtual QModelIndex indexAt(const QPoint &point) const const override
virtual void mouseDoubleClickEvent(QMouseEvent *event) override
virtual void setModel(QAbstractItemModel *model) override
QString toString() const const
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
void customContextMenuRequested(const QPoint &pos)
void setFocusPolicy(Qt::FocusPolicy policy)
void hide()
QPoint mapToGlobal(const QPoint &pos) const const
void move(int x, int y)
void setFocus()
void show()
void setSizePolicy(QSizePolicy)
void setWindowFlags(Qt::WindowFlags type)