1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (c) 2021, The Regents of the University of California
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice, this
11 //   list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright notice,
14 //   this list of conditions and the following disclaimer in the documentation
15 //   and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the copyright holder nor the names of its
18 //   contributors may be used to endorse or promote products derived from
19 //   this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 
33 #include "gui/gui.h"
34 
35 #include <QApplication>
36 #include <QDebug>
37 #include <boost/algorithm/string/predicate.hpp>
38 #include <stdexcept>
39 #include <string>
40 
41 #include "db.h"
42 #include "dbDescriptors.h"
43 #include "dbShape.h"
44 #include "defin.h"
45 #include "displayControls.h"
46 #include "geom.h"
47 #include "lefin.h"
48 #include "mainWindow.h"
49 #include "ord/OpenRoad.hh"
50 
51 namespace gui {
52 
getBlock(odb::dbDatabase * db)53 static odb::dbBlock* getBlock(odb::dbDatabase* db)
54 {
55   if (!db) {
56     return nullptr;
57   }
58 
59   auto chip = db->getChip();
60   if (!chip) {
61     return nullptr;
62   }
63 
64   return chip->getBlock();
65 }
66 
67 // This provides the link for Gui::redraw to the widget
68 static gui::MainWindow* main_window = nullptr;
69 
70 Gui* Gui::singleton_ = nullptr;
71 
get()72 Gui* Gui::get()
73 {
74   if (main_window == nullptr) {
75     return nullptr;  // batch mode
76   }
77 
78   if (!singleton_) {
79     singleton_ = new Gui();
80   }
81 
82   return singleton_;
83 }
84 
registerRenderer(Renderer * renderer)85 void Gui::registerRenderer(Renderer* renderer)
86 {
87   renderers_.insert(renderer);
88   redraw();
89 }
90 
unregisterRenderer(Renderer * renderer)91 void Gui::unregisterRenderer(Renderer* renderer)
92 {
93   renderers_.erase(renderer);
94   redraw();
95 }
96 
redraw()97 void Gui::redraw()
98 {
99   main_window->redraw();
100 }
101 
status(const std::string & message)102 void Gui::status(const std::string& message)
103 {
104   main_window->status(message);
105 }
106 
pause()107 void Gui::pause()
108 {
109   main_window->pause();
110 }
111 
makeSelected(std::any object,void * additional_data)112 Selected Gui::makeSelected(std::any object, void* additional_data)
113 {
114   return main_window->makeSelected(object, additional_data);
115 }
116 
setSelected(Selected selection)117 void Gui::setSelected(Selected selection)
118 {
119   main_window->setSelected(selection);
120 }
121 
addSelectedNet(const char * name)122 void Gui::addSelectedNet(const char* name)
123 {
124   auto block = getBlock(main_window->getDb());
125   if (!block) {
126     return;
127   }
128 
129   auto net = block->findNet(name);
130   if (!net) {
131     return;
132   }
133 
134   main_window->addSelected(makeSelected(net));
135 }
136 
addSelectedNets(const char * pattern,bool match_case,bool match_reg_ex,bool add_to_highlight_set,int highlight_group)137 void Gui::addSelectedNets(const char* pattern,
138                           bool match_case,
139                           bool match_reg_ex,
140                           bool add_to_highlight_set,
141                           int highlight_group)
142 {
143   auto block = getBlock(main_window->getDb());
144   if (!block) {
145     return;
146   }
147 
148   QRegExp re(pattern, Qt::CaseSensitive, QRegExp::Wildcard);
149   SelectionSet nets;
150   if (match_reg_ex == true) {
151     QRegExp re(pattern,
152                match_case == true ? Qt::CaseSensitive : Qt::CaseInsensitive,
153                QRegExp::Wildcard);
154 
155     for (auto* net : block->getNets()) {
156       if (re.exactMatch(net->getConstName())) {
157         nets.insert(makeSelected(net));
158       }
159     }
160   } else if (match_case == false) {
161     for (auto* net : block->getNets()) {
162       if (boost::iequals(pattern, net->getConstName()))
163         nets.insert(makeSelected(net));
164     }
165   } else {
166     for (auto* net : block->getNets()) {
167       if (pattern == net->getConstName()) {
168         nets.insert(makeSelected(net));
169       }
170     }
171   }
172 
173   main_window->addSelected(nets);
174   if (add_to_highlight_set == true)
175     main_window->addHighlighted(nets, highlight_group);
176 }  // namespace gui
177 
addSelectedInst(const char * name)178 void Gui::addSelectedInst(const char* name)
179 {
180   auto block = getBlock(main_window->getDb());
181   if (!block) {
182     return;
183   }
184 
185   auto inst = block->findInst(name);
186   if (!inst) {
187     return;
188   }
189 
190   main_window->addSelected(makeSelected(inst));
191 }
192 
addSelectedInsts(const char * pattern,bool match_case,bool match_reg_ex,bool add_to_highlight_set,int highlight_group)193 void Gui::addSelectedInsts(const char* pattern,
194                            bool match_case,
195                            bool match_reg_ex,
196                            bool add_to_highlight_set,
197                            int highlight_group)
198 {
199   auto block = getBlock(main_window->getDb());
200   if (!block) {
201     return;
202   }
203 
204   SelectionSet insts;
205   if (match_reg_ex) {
206     QRegExp re(pattern,
207                match_case == true ? Qt::CaseSensitive : Qt::CaseInsensitive,
208                QRegExp::Wildcard);
209     for (auto* inst : block->getInsts()) {
210       if (re.exactMatch(inst->getConstName())) {
211         insts.insert(makeSelected(inst));
212       }
213     }
214   } else if (match_case == false) {
215     for (auto* inst : block->getInsts()) {
216       if (boost::iequals(inst->getConstName(), pattern))
217         insts.insert(makeSelected(inst));
218     }
219   } else {
220     for (auto* inst : block->getInsts()) {
221       if (pattern == inst->getConstName()) {
222         insts.insert(makeSelected(inst));
223         break;  // There can't be two insts with the same name
224       }
225     }
226   }
227 
228   main_window->addSelected(insts);
229   if (add_to_highlight_set == true)
230     main_window->addHighlighted(insts, highlight_group);
231 }
232 
anyObjectInSet(bool selection_set,odb::dbObjectType obj_type) const233 bool Gui::anyObjectInSet(bool selection_set, odb::dbObjectType obj_type) const
234 {
235   return main_window->anyObjectInSet(selection_set, obj_type);
236 }
237 
selectHighlightConnectedInsts(bool select_flag,int highlight_group)238 void Gui::selectHighlightConnectedInsts(bool select_flag, int highlight_group)
239 {
240   return main_window->selectHighlightConnectedInsts(select_flag,
241                                                     highlight_group);
242 }
selectHighlightConnectedNets(bool select_flag,bool output,bool input,int highlight_group)243 void Gui::selectHighlightConnectedNets(bool select_flag,
244                                        bool output,
245                                        bool input,
246                                        int highlight_group)
247 {
248   return main_window->selectHighlightConnectedNets(
249       select_flag, output, input, highlight_group);
250 }
251 
addInstToHighlightSet(const char * name,int highlight_group)252 void Gui::addInstToHighlightSet(const char* name, int highlight_group)
253 {
254   auto block = getBlock(main_window->getDb());
255   if (!block) {
256     return;
257   }
258 
259   auto inst = block->findInst(name);
260   if (!inst) {
261     return;
262   }
263   SelectionSet sel_inst_set;
264   sel_inst_set.insert(makeSelected(inst));
265   main_window->addHighlighted(sel_inst_set, highlight_group);
266 }
267 
addNetToHighlightSet(const char * name,int highlight_group)268 void Gui::addNetToHighlightSet(const char* name, int highlight_group)
269 {
270   auto block = getBlock(main_window->getDb());
271   if (!block) {
272     return;
273   }
274 
275   auto net = block->findNet(name);
276   if (!net) {
277     return;
278   }
279   SelectionSet selection_set;
280   selection_set.insert(makeSelected(net));
281   main_window->addHighlighted(selection_set, highlight_group);
282 }
283 
addRuler(int x0,int y0,int x1,int y1)284 void Gui::addRuler(int x0, int y0, int x1, int y1)
285 {
286   main_window->addRuler(x0, y0, x1, y1);
287 }
288 
clearSelections()289 void Gui::clearSelections()
290 {
291   main_window->setSelected(Selected());
292 }
293 
clearHighlights(int highlight_group)294 void Gui::clearHighlights(int highlight_group)
295 {
296   main_window->clearHighlighted(highlight_group);
297 }
298 
clearRulers()299 void Gui::clearRulers()
300 {
301   main_window->clearRulers();
302 }
303 
addCustomVisibilityControl(const std::string & name,bool initially_visible)304 void Gui::addCustomVisibilityControl(const std::string& name,
305                                      bool initially_visible)
306 {
307   main_window->getControls()->addCustomVisibilityControl(name,
308                                                          initially_visible);
309 }
310 
checkCustomVisibilityControl(const std::string & name)311 bool Gui::checkCustomVisibilityControl(const std::string& name)
312 {
313   return main_window->getControls()->checkCustomVisibilityControl(name);
314 }
315 
zoomTo(const odb::Rect & rect_dbu)316 void Gui::zoomTo(const odb::Rect& rect_dbu)
317 {
318   main_window->zoomTo(rect_dbu);
319 }
320 
~Renderer()321 Renderer::~Renderer()
322 {
323   gui::Gui::get()->unregisterRenderer(this);
324 }
325 
load_design()326 void Gui::load_design()
327 {
328   main_window->postReadDb(main_window->getDb());
329 }
330 
fit()331 void Gui::fit()
332 {
333   main_window->fit();
334 }
335 
registerDescriptor(const std::type_info & type,const Descriptor * descriptor)336 void Gui::registerDescriptor(const std::type_info& type,
337                              const Descriptor* descriptor)
338 {
339   main_window->registerDescriptor(type, descriptor);
340 }
341 
342 //////////////////////////////////////////////////
343 
344 // This is the main entry point to start the GUI.  It only
345 // returns when the GUI is done.
startGui(int argc,char * argv[])346 int startGui(int argc, char* argv[])
347 {
348   QApplication app(argc, argv);
349 
350   // Default to 12 point for easier reading
351   QFont font = QApplication::font();
352   font.setPointSize(12);
353   QApplication::setFont(font);
354 
355   gui::MainWindow win;
356   main_window = &win;
357   auto* open_road = ord::OpenRoad::openRoad();
358   win.setDb(open_road->getDb());
359   open_road->addObserver(&win);
360   win.show();
361 
362   // Exit the app if someone chooses exit from the menu in the window
363   QObject::connect(&win, SIGNAL(exit()), &app, SLOT(quit()));
364 
365   // Save the window's status into the settings when quitting.
366   QObject::connect(&app, SIGNAL(aboutToQuit()), &win, SLOT(saveSettings()));
367 
368   return app.exec();
369 }
370 
highlight(Painter & painter,bool select_flag,int highlight_group) const371 void Selected::highlight(Painter& painter,
372                          bool select_flag,
373                          int highlight_group) const
374 {
375   if (select_flag) {
376     painter.setPen(Painter::highlight, true);
377     painter.setBrush(Painter::transparent);
378   } else if (highlight_group >= 0 && highlight_group < 7) {
379     auto highlight_color = Painter::highlightColors[highlight_group];
380     highlight_color.a = 100;
381     painter.setPen(highlight_color, true);
382     painter.setBrush(highlight_color);
383   } else {
384     painter.setPen(Painter::persistHighlight);
385     painter.setBrush(Painter::transparent);
386   }
387 
388   return descriptor_->highlight(object_, painter, additional_data_);
389 }
390 
391 }  // namespace gui
392 
393 extern "C" {
394 struct Tcl_Interp;
395 }
396 
397 namespace ord {
398 
399 extern "C" {
400 extern int Gui_Init(Tcl_Interp* interp);
401 }
402 
initGui(OpenRoad * openroad)403 void initGui(OpenRoad* openroad)
404 {
405   // Define swig TCL commands.
406   Gui_Init(openroad->tclInterp());
407   if (gui::main_window) {
408     using namespace gui;
409     main_window->setLogger(openroad->getLogger());
410     Gui::get()->registerDescriptor<odb::dbInst*>(new DbInstDescriptor);
411     Gui::get()->registerDescriptor<odb::dbNet*>(new DbNetDescriptor);
412     Gui::get()->registerDescriptor<odb::dbITerm*>(new DbITermDescriptor);
413     Gui::get()->registerDescriptor<odb::dbBTerm*>(new DbBTermDescriptor);
414   }
415 }
416 
417 }  // namespace ord
418