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