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  PinTreeItem* clickedItem = dynamic_cast<PinTreeItem*>(mPinModel->getItemFromIndex(idx));
73  if(!clickedItem || clickedItem->type() != PinTreeItem::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  PinTreeItem* clickedItem = dynamic_cast<PinTreeItem*>(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() == PinTreeItem::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() == PinTreeItem::Pin)
160  {
161  netIds = clickedItem->netIds();
162  }
163  else
164  {
165  for(auto childItem : clickedItem->getChildren())
166  {
167  PinTreeItem* pti = dynamic_cast<PinTreeItem*>(childItem);
168  if (pti)
169  netIds.append(pti->netIds());
170  }
171  }
172  if(netIds.size() != 0)
173  {
174  QString desc = (netIds.size() == 1) ? "Set net as current selection" : "Set net(s) as current selection";
175  QString desc2 = (netIds.size() == 1) ? "Add net to current selection" : "Add net(s) to current selection";
176  if(!isMiscSectionSet)
177  {
178  menu.addSection("Misc");
179  isMiscSectionSet = true;
180  }
181  menu.addAction(desc, [this, netIds](){
183  for(const int id : netIds)
184  gSelectionRelay->addNet(id);
186  });
187  menu.addAction(desc2,
188  [this, netIds](){
189  for(const int id : netIds)
190  gSelectionRelay->addNet(id);
192  });
193  }
194 
195  menu.addSection("Python");
196 
197  if(clickedItem->type() == PinTreeItem::Pin)
198  buildPythonMenuForPin(menu, clickedItem);
199  else
200  buildPythonMenuForPinGroup(menu, clickedItem);
201 
202  menu.move(mapToGlobal(pos));
203  menu.exec();
204 
205  }
206 
207  void GatePinTree::buildPythonMenuForPin(QMenu &menu, PinTreeItem *clickedPinItem)
208  {
209  // 1.) NET-OBJECT
210  QList<u32> netIdsOfItem = clickedPinItem->netIds();
211  QString pythonCommandNetIds, pythonCommandName;
212 
213  if(netIdsOfItem.size() == 1)
214  {
215  pythonCommandNetIds = PyCodeProvider::pyCodeNet(netIdsOfItem.at(0));
216  pythonCommandName = PyCodeProvider::pyCodeNetName(netIdsOfItem.at(0));
217  }
218  else if(netIdsOfItem.size() == 2)
219  {
220  pythonCommandNetIds = "netInput = " + PyCodeProvider::pyCodeNet(netIdsOfItem.at(0)) + "\nnetOutput = " + PyCodeProvider::pyCodeNet(netIdsOfItem.at(1));
221  pythonCommandName = "netInputName = " + PyCodeProvider::pyCodeNetName(netIdsOfItem.at(0)) + "\nnetOutputName = " + PyCodeProvider::pyCodeNetName(netIdsOfItem.at(1));
222  }
223 
224  menu.addAction(QIcon(":/icons/python"), "Extract net(s) as python code",
225  [pythonCommandNetIds]()
226  {
227  QApplication::clipboard()->setText(pythonCommandNetIds);
228  });
229 
230  // 2.) DIRECTION
232  menu.addAction(QIcon(":/icons/python"), "Extract pin direction as python code",
233  [pythonCommandDirection]()
234  {
235  QApplication::clipboard()->setText(pythonCommandDirection);
236  });
237 
238 
239  // 3.) type
241  menu.addAction(QIcon(":/icons/python"), "Extract pin type as python code",
242  [pythonCommandType]()
243  {
244  QApplication::clipboard()->setText(pythonCommandType);
245  });
246 
247  }
248 
249  void GatePinTree::buildPythonMenuForPinGroup(QMenu &menu, PinTreeItem *clickedPinIGrouptem)
250  {
251  // 1. PYTHON LIST OF PIN GROUPS
252  QString pythonList = "[";
253  for(auto childPin : clickedPinIGrouptem->getChildren())
254  pythonList += "\"" + childPin->getData(GatePinsTreeModel::sNameColumn).toString() + "\", ";
255  pythonList = pythonList.left(pythonList.size()-2);
256  pythonList += "]";
257 
258  menu.addAction(QIcon(":/icons/python"), "Extract pingroup as python list",
259  [pythonList]()
260  {
261  QApplication::clipboard()->setText(pythonList);
262  });
263 
264  //2. DIRECTION and TYPE(determined by the pin(s) within the group)
265  BaseTreeItem* firstPinItemOfGroup = clickedPinIGrouptem->getChild(0);
266  if(firstPinItemOfGroup)
267  {
268  QString pythonCommandGroupDirection = PyCodeProvider::pyCodeGateTypePinDirection(mPinModel->getCurrentGateID(),
269  firstPinItemOfGroup->getData(GatePinsTreeModel::sNameColumn).toString());
270  menu.addAction(QIcon(":/icons/python"), "Extract direction of pingroup as python code",
271  [pythonCommandGroupDirection]()
272  {
273  QApplication::clipboard()->setText(pythonCommandGroupDirection);
274  });
275 
276  QString pythonCommandGroupType = PyCodeProvider::pyCodeGateTypePinType(mPinModel->getCurrentGateID(),
277  firstPinItemOfGroup->getData(GatePinsTreeModel::sNameColumn).toString());
278  menu.addAction(QIcon(":/icons/python"), "Extract type of pingroup as python code",
279  [pythonCommandGroupType]()
280  {
281  QApplication::clipboard()->setText(pythonCommandGroupType);
282  });
283  }
284  }
285 
286  void GatePinTree::addSourceOurDestinationToSelection(int netId, bool isInputPin)
287  {
288  auto net = gNetlist->get_net_by_id(netId);
289  if(!net) return;
290 
291  auto sourcesOrDesti = isInputPin ? net->get_sources() : net->get_destinations();
292  if(sourcesOrDesti.empty() || net->is_global_input_net() || net->is_global_output_net())
293  {
294  return; //for now, maybe simply add/oberwrite net (check global mClearSelection)?
295  }
296  else if (sourcesOrDesti.size() == 1)
297  {
298  if(mClearSelection)
300  auto ep = *sourcesOrDesti.begin();
301  gSelectionRelay->addGate(ep->get_gate()->get_id());
302  auto pins = isInputPin ? ep->get_gate()->get_type()->get_output_pins() : ep->get_gate()->get_type()->get_input_pins();
303  auto index = std::distance(pins.begin(), std::find(pins.begin(), pins.end(), ep->get_pin()));
306  }
307  else
308  {
309  mNavigationTable->setup(Node(), net, isInputPin ? SelectionRelay::Subfocus::Left : SelectionRelay::Subfocus::Right);
310  if(mNavigationTable->isEmpty())
311  mNavigationTable->closeRequest();
312  else
313  {
314  mNavigationTable->move(QCursor::pos());
315  mNavigationTable->show();
316  mNavigationTable->setFocus();
317  }
318 
319  }
320  }
321 
322  void GatePinTree::handleNavigationCloseRequested()
323  {
324  mNavigationTable->hide();
325  }
326 
327  void GatePinTree::handleNavigationJumpRequested(const Node &origin, const u32 via_net, const QSet<u32> &to_gates, const QSet<u32> &to_modules)
328  {
329  Q_UNUSED(origin)
330  Q_UNUSED(to_modules)
331 
332  mNavigationTable->hide();
333 
334  auto n = gNetlist->get_net_by_id(via_net);
335  if(!n || to_gates.isEmpty())
336  return;
337  for(u32 id : to_gates)
338  if(!gNetlist->get_gate_by_id(id))
339  return;
340 
341  if(mClearSelection)
343  for(u32 id : to_gates)
345 
346  if(to_gates.size()==1)
347  {
348  auto g = gNetlist->get_gate_by_id(*to_gates.begin());
349  u32 index = 0;
350  bool isNavDirLeft = mNavigationTable->direction() == SelectionRelay::Subfocus::Left;
351  auto pins = isNavDirLeft ? g->get_type()->get_output_pins() : g->get_type()->get_input_pins();
352  for(auto pin : pins)
353  {
354  if(isNavDirLeft ? g->get_fan_out_net(pin) == n : g->get_fan_in_net(pin) == n)
355  {
357  break;
358  }
359  index++;
360  }
361  }
363  }
364 
365 }
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)
A model to display the pins of a gate.
static const int sTypeColumn
static const int sDirectionColumn
static const int sNameColumn
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
Type type() const
QVariant getData(int column) const override
QList< u32 > netIds() const
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)