1 #include "traditional_view.hh"
2 #include "tree_scroll_area.hh"
3 #include "layout.hh"
4 #include "structure.hh"
5 #include "node_tree.hh"
6
7 #include <queue>
8 #include <thread>
9 #include <cmath>
10
11 #include <QPainter>
12 #include <QDebug>
13 #include <QTimer>
14 #include <QScrollBar>
15 #include <QMouseEvent>
16 #include <QInputDialog>
17 #include <QLineEdit>
18 #include <QTextEdit>
19 #include <QThread>
20 #include <QVBoxLayout>
21
22 #include "cursors/nodevisitor.hh"
23 #include "cursors/hide_failed_cursor.hh"
24 #include "cursors/hide_not_highlighted_cursor.hh"
25 #include "../utils/std_ext.hh"
26 #include "node_id.hh"
27 #include "shape.hh"
28 #include "../user_data.hh"
29 #include "../solver_data.hh"
30 #include "layout_computer.hh"
31 #include "../config.hh"
32
33 #include "../nogood_dialog.hh"
34
35 #include "../utils/perf_helper.hh"
36 #include "../utils/tree_utils.hh"
37
38 namespace cpprofiler
39 {
40 namespace tree
41 {
42
TraditionalView(const NodeTree & tree,UserData & ud,SolverData & sd)43 TraditionalView::TraditionalView(const NodeTree &tree, UserData &ud, SolverData &sd)
44 : tree_(tree),
45 user_data_(ud),
46 solver_data_(sd),
47 vis_flags_(utils::make_unique<VisualFlags>()),
48 layout_(utils::make_unique<Layout>()),
49 layout_computer_(utils::make_unique<LayoutComputer>(tree, *layout_, *vis_flags_))
50 {
51 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
52
53 scroll_area_.reset(new TreeScrollArea(tree_.getRoot(), tree_, user_data_, *layout_, *vis_flags_));
54
55 // std::cerr << "traditional view thread:" << std::this_thread::get_id() << std::endl;
56
57 // connect(scroll_area_.get(), &TreeScrollArea::nodeClicked, this, &TraditionalView::setCurrentNode);
58 connect(scroll_area_.get(), &TreeScrollArea::nodeClicked, this, &TraditionalView::nodeSelected);
59 connect(scroll_area_.get(), &TreeScrollArea::nodeDoubleClicked, this, &TraditionalView::handleDoubleClick);
60
61 connect(this, &TraditionalView::needsRedrawing, this, &TraditionalView::redraw);
62 connect(this, &TraditionalView::needsLayoutUpdate, this, &TraditionalView::updateLayout);
63
64 connect(&tree, &NodeTree::childrenStructureChanged, [this](NodeID nid) {
65 if (nid == NodeID::NoNode)
66 {
67 return;
68 }
69 layout_computer_->dirtyUpLater(nid);
70 // layout_->setLayoutDone(nid, false);
71 });
72
73 auto autoLayoutTimer = new QTimer(this);
74
75 connect(autoLayoutTimer, &QTimer::timeout, this, &TraditionalView::autoUpdate);
76
77 /// stop this timer up when the tree is finished?
78 autoLayoutTimer->start(100);
79 }
80
81 TraditionalView::~TraditionalView() = default;
82
redraw()83 void TraditionalView::redraw()
84 {
85 scroll_area_->viewport()->update();
86 }
87
node() const88 NodeID TraditionalView::node() const
89 {
90 return user_data_.getSelectedNode();
91 }
92
setNode(NodeID nid)93 void TraditionalView::setNode(NodeID nid)
94 {
95 user_data_.setSelectedNode(nid);
96 }
97
navRoot()98 void TraditionalView::navRoot()
99 {
100 auto root = tree_.getRoot();
101 emit nodeSelected(root);
102 centerCurrentNode(); /// TODO: this should be needed
103 emit needsRedrawing();
104 }
105
navDown()106 void TraditionalView::navDown()
107 {
108
109 const auto nid = node();
110
111 if (nid == NodeID::NoNode)
112 return;
113
114 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
115
116 const auto kids = tree_.childrenCount(nid);
117
118 if (kids == 0 || vis_flags_->isHidden(nid))
119 return;
120
121 auto first_kid = tree_.getChild(nid, 0);
122
123 emit nodeSelected(first_kid);
124 centerCurrentNode();
125 emit needsRedrawing();
126 }
127
navDownAlt()128 void TraditionalView::navDownAlt()
129 {
130 const auto nid = node();
131 if (nid == NodeID::NoNode)
132 return;
133
134 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
135
136 const auto kids = tree_.childrenCount(nid);
137
138 if (kids == 0 || vis_flags_->isHidden(nid))
139 return;
140
141 auto last_kid = tree_.getChild(nid, kids - 1);
142 emit nodeSelected(last_kid);
143 centerCurrentNode();
144 emit needsRedrawing();
145 }
146
navUp()147 void TraditionalView::navUp()
148 {
149 auto nid = node();
150 if (nid == NodeID::NoNode)
151 return;
152
153 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
154
155 auto pid = tree_.getParent(nid);
156
157 if (pid != NodeID::NoNode)
158 {
159 emit nodeSelected(pid);
160 centerCurrentNode();
161 emit needsRedrawing();
162 }
163 }
164
navLeft()165 void TraditionalView::navLeft()
166 {
167 auto nid = node();
168 if (nid == NodeID::NoNode)
169 return;
170
171 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
172
173 auto pid = tree_.getParent(nid);
174 if (pid == NodeID::NoNode)
175 return;
176
177 auto cur_alt = tree_.getAlternative(nid);
178
179 if (cur_alt > 0)
180 {
181 auto kid = tree_.getChild(pid, cur_alt - 1);
182 emit nodeSelected(kid);
183 centerCurrentNode();
184 emit needsRedrawing();
185 }
186 }
187
navRight()188 void TraditionalView::navRight()
189 {
190 /// lock mutex
191 auto nid = node();
192 if (nid == NodeID::NoNode)
193 return;
194
195 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
196
197 auto pid = tree_.getParent(nid);
198
199 if (pid == NodeID::NoNode)
200 return;
201
202 auto cur_alt = tree_.getAlternative(nid);
203
204 auto kids = tree_.childrenCount(pid);
205
206 if (cur_alt + 1 < kids)
207 {
208 const auto kid = tree_.getChild(pid, cur_alt + 1);
209 emit nodeSelected(kid);
210 centerCurrentNode();
211 emit needsRedrawing();
212 }
213 }
214
setLabelShown(NodeID nid,bool val)215 void TraditionalView::setLabelShown(NodeID nid, bool val)
216 {
217 vis_flags_->setLabelShown(nid, val);
218 layout_computer_->dirtyUpLater(nid);
219 }
220
toggleShowLabel()221 void TraditionalView::toggleShowLabel()
222 {
223 auto nid = node();
224 if (nid == NodeID::NoNode)
225 return;
226
227 auto val = !vis_flags_->isLabelShown(nid);
228 setLabelShown(nid, val);
229 emit needsRedrawing();
230 layout_computer_->dirtyUpLater(nid);
231 }
232
showLabelsDown()233 void TraditionalView::showLabelsDown()
234 {
235 auto nid = node();
236 if (nid == NodeID::NoNode)
237 return;
238
239 auto val = !vis_flags_->isLabelShown(nid);
240
241 utils::pre_order_apply(tree_, nid, [val, this](NodeID nid) {
242 setLabelShown(nid, val);
243 });
244
245 emit needsLayoutUpdate();
246 emit needsRedrawing();
247 }
248
showLabelsUp()249 void TraditionalView::showLabelsUp()
250 {
251 auto nid = node();
252 if (nid == NodeID::NoNode)
253 return;
254
255 auto pid = tree_.getParent(nid);
256
257 /// if it is root, toggle for the root only
258 if (pid == NodeID::NoNode)
259 {
260 toggleShowLabel();
261 return;
262 }
263
264 auto val = !vis_flags_->isLabelShown(pid);
265
266 while (nid != NodeID::NoNode)
267 {
268 setLabelShown(nid, val);
269 nid = tree_.getParent(nid);
270 }
271
272 emit needsLayoutUpdate();
273 emit needsRedrawing();
274 }
275
is_leaf(const NodeTree & nt,NodeID nid)276 static bool is_leaf(const NodeTree &nt, NodeID nid)
277 {
278 return nt.childrenCount(nid) == 0;
279 }
280
hideNode(NodeID n,bool delayed)281 void TraditionalView::hideNode(NodeID n, bool delayed)
282 {
283 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
284 utils::DebugMutexLocker layout_lock(&layout_->getMutex());
285
286 if (is_leaf(tree_, n))
287 return;
288
289 vis_flags_->setHidden(n, true);
290
291 dirtyUp(n);
292
293 if (delayed)
294 {
295 setLayoutOutdated();
296 }
297 else
298 {
299 emit needsLayoutUpdate();
300 }
301 emit needsRedrawing();
302 }
303
toggleHidden()304 void TraditionalView::toggleHidden()
305 {
306 auto nid = node();
307 if (nid == NodeID::NoNode)
308 return;
309
310 // do not hide leaf nodes
311 if (is_leaf(tree_, nid))
312 return;
313
314 auto val = !vis_flags_->isHidden(nid);
315 vis_flags_->setHidden(nid, val);
316
317 dirtyUp(nid);
318
319 emit needsLayoutUpdate();
320 emit needsRedrawing();
321 }
322
hideFailedAt(NodeID n,bool onlyDirty)323 void TraditionalView::hideFailedAt(NodeID n, bool onlyDirty)
324 {
325 /// Do nothing if there is no tree
326 if (tree_.nodeCount() == 0)
327 return;
328
329 bool modified = false;
330
331 HideFailedCursor hfc(n, tree_, *vis_flags_, *layout_computer_, onlyDirty, modified);
332 PostorderNodeVisitor<HideFailedCursor>(hfc).run();
333
334 if (modified)
335 {
336 emit needsLayoutUpdate();
337 emit needsRedrawing();
338 }
339 }
340
hideFailed(bool onlyDirty)341 void TraditionalView::hideFailed(bool onlyDirty)
342 {
343 auto nid = node();
344 if (nid == NodeID::NoNode)
345 return;
346
347 hideFailedAt(nid, onlyDirty);
348 }
349
autoUpdate()350 void TraditionalView::autoUpdate()
351 {
352 if (!layout_stale_)
353 return;
354
355 const auto changed = updateLayout();
356 if (changed)
357 {
358 emit needsRedrawing();
359 }
360 }
361
handleDoubleClick()362 void TraditionalView::handleDoubleClick()
363 {
364
365 auto nid = node();
366 if (nid == NodeID::NoNode)
367 return;
368
369 auto status = tree_.getStatus(nid);
370
371 if (status == NodeStatus::BRANCH)
372 {
373 unhideNode(nid);
374 }
375 else if (status == NodeStatus::MERGED)
376 {
377 toggleCollapsePentagon(nid);
378 }
379
380 /// should this happen automatically whenever the layout is changed?
381 centerCurrentNode();
382 }
383
toggleCollapsePentagon(NodeID nid)384 void TraditionalView::toggleCollapsePentagon(NodeID nid)
385 {
386 /// Use the same 'hidden' flag for now
387 auto val = !vis_flags_->isHidden(nid);
388 vis_flags_->setHidden(nid, val);
389 dirtyUp(nid);
390 emit needsLayoutUpdate();
391 emit needsRedrawing();
392 }
393
setNodeHidden(NodeID n,bool val)394 void TraditionalView::setNodeHidden(NodeID n, bool val)
395 {
396 vis_flags_->setHidden(n, false);
397 layout_->setLayoutDone(n, false);
398 }
399
unhideNode(NodeID nid)400 void TraditionalView::unhideNode(NodeID nid)
401 {
402 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
403 utils::DebugMutexLocker layout_lock(&layout_->getMutex());
404
405 auto hidden = vis_flags_->isHidden(nid);
406 if (hidden)
407 {
408 setNodeHidden(nid, false);
409
410 dirtyUp(nid);
411 emit needsLayoutUpdate();
412 emit needsRedrawing();
413 }
414 }
415
bookmarkCurrentNode()416 void TraditionalView::bookmarkCurrentNode()
417 {
418 auto nid = node();
419
420 if (!user_data_.isBookmarked(nid))
421 {
422 /// Add bookmark
423 bool accepted;
424 auto text = QInputDialog::getText(nullptr, "Add bookmark", "Name:", QLineEdit::Normal, "", &accepted);
425 if (!accepted)
426 return;
427
428 user_data_.setBookmark(nid, text.toStdString());
429 }
430 else
431 {
432 /// Remove bookmark
433 user_data_.clearBookmark(nid);
434 }
435
436 emit needsRedrawing();
437 }
438
unhideAllAt(NodeID n)439 void TraditionalView::unhideAllAt(NodeID n)
440 {
441 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
442 utils::DebugMutexLocker layout_lock(&layout_->getMutex());
443
444 if (n == tree_.getRoot())
445 {
446 unhideAll();
447 return;
448 }
449
450 /// indicates if any change was made
451 bool modified = false;
452
453 const auto action = [&](NodeID n) {
454 if (vis_flags_->isHidden(n))
455 {
456 vis_flags_->setHidden(n, false);
457 layout_->setLayoutDone(n, false);
458 dirtyUp(n);
459 modified = true;
460 }
461 };
462
463 utils::apply_below(tree_, n, action);
464
465 if (modified)
466 {
467 emit needsLayoutUpdate();
468 emit needsRedrawing();
469 }
470
471 centerCurrentNode();
472 }
473
unhideAll()474 void TraditionalView::unhideAll()
475 {
476
477 /// faster version for the entire tree
478 if (vis_flags_->hiddenCount() == 0)
479 {
480 return;
481 }
482
483 for (auto n : vis_flags_->hidden_nodes())
484 {
485 dirtyUp(n);
486 layout_->setLayoutDone(n, false);
487 }
488
489 vis_flags_->unhideAll();
490
491 emit needsLayoutUpdate();
492 emit needsRedrawing();
493 centerNode(tree_.getRoot());
494 }
495
unhideAllAtCurrent()496 void TraditionalView::unhideAllAtCurrent()
497 {
498 auto nid = node();
499 if (nid == NodeID::NoNode)
500 return;
501
502 unhideAllAt(nid);
503 }
504
toggleHighlighted()505 void TraditionalView::toggleHighlighted()
506 {
507 auto nid = node();
508 if (nid == NodeID::NoNode)
509 return;
510
511 auto val = !vis_flags_->isHighlighted(nid);
512 vis_flags_->setHighlighted(nid, val);
513
514 emit needsRedrawing();
515 }
516
widget()517 QWidget *TraditionalView::widget()
518 {
519 return scroll_area_.get();
520 }
521
layout() const522 const Layout &TraditionalView::layout() const
523 {
524 return *layout_;
525 }
526
setScale(int val)527 void TraditionalView::setScale(int val)
528 {
529 scroll_area_->setScale(val);
530 }
531
532 /// relative to the root
global_node_x_offset(const NodeTree & tree,const Layout & layout,NodeID nid)533 static int global_node_x_offset(const NodeTree &tree, const Layout &layout, NodeID nid)
534 {
535 auto x_off = 0;
536
537 while (nid != NodeID::NoNode)
538 {
539 x_off += layout.getOffset(nid);
540 nid = tree.getParent(nid);
541 }
542
543 return x_off;
544 }
545
546 /// Does this need any locking?
centerNode(NodeID nid)547 void TraditionalView::centerNode(NodeID nid)
548 {
549
550 const auto x_offset = global_node_x_offset(tree_, *layout_, nid);
551
552 const auto root_nid = tree_.getRoot();
553 const auto bb = layout_->getBoundingBox(root_nid);
554
555 const auto value_x = x_offset - bb.left;
556
557 const auto depth = utils::calculate_depth(tree_, nid);
558 const auto value_y = depth * layout::dist_y;
559
560 scroll_area_->centerPoint(value_x, value_y);
561 }
562
centerCurrentNode()563 void TraditionalView::centerCurrentNode()
564 {
565 centerNode(node());
566 }
567
setCurrentNode(NodeID nid)568 void TraditionalView::setCurrentNode(NodeID nid)
569 {
570 user_data_.setSelectedNode(nid);
571 emit needsRedrawing();
572 }
573
setAndCenterNode(NodeID nid)574 void TraditionalView::setAndCenterNode(NodeID nid)
575 {
576 setCurrentNode(nid);
577 centerNode(nid);
578 }
579
updateLayout()580 bool TraditionalView::updateLayout()
581 {
582 const auto changed = layout_computer_->compute();
583 layout_stale_ = false;
584
585 return changed;
586 }
587
setLayoutOutdated()588 void TraditionalView::setLayoutOutdated()
589 {
590 layout_stale_ = true;
591 }
592
dirtyUp(NodeID nid)593 void TraditionalView::dirtyUp(NodeID nid)
594 {
595 layout_computer_->dirtyUpLater(nid);
596 }
597
dirtyCurrentNodeUp()598 void TraditionalView::dirtyCurrentNodeUp()
599 {
600 const auto nid = node();
601 if (nid == NodeID::NoNode)
602 return;
603
604 dirtyUp(nid);
605 }
606
printNodeInfo()607 void TraditionalView::printNodeInfo()
608 {
609 const auto nid = node();
610 if (nid == NodeID::NoNode)
611 return;
612
613 print("--- Node Info: {} ----", nid);
614 print("offset: {}", layout_->getOffset(nid));
615 auto bb = layout_->getBoundingBox(nid);
616 print("bb:[{},{}]", bb.left, bb.right);
617 print("dirty: {}", layout_->isDirty(nid));
618 print("layout done for node: {}", layout_->getLayoutDone(nid));
619 print("hidden: {}", vis_flags_->isHidden(nid));
620 print("total kids: {}, ", tree_.childrenCount(nid));
621 print("has solved kids: {}, ", tree_.hasSolvedChildren(nid));
622 print("has open kids: {}", tree_.hasOpenChildren(nid));
623
624 const auto &ng = tree_.getNogood(nid);
625
626 if (ng.has_renamed())
627 {
628 print("nogood: {} ({})", ng.renamed(), ng.original());
629 }
630 else
631 {
632 print("nogood: {}", ng.original());
633 }
634 print("alt: {}", tree_.getAlternative(nid));
635 }
636
637 /// Show specified subtrees and hide everyting else
showSubtrees(const NodeTree & tree,VisualFlags & vf,LayoutComputer & lc)638 static void showSubtrees(const NodeTree &tree, VisualFlags &vf, LayoutComputer &lc)
639 {
640 auto root = tree.getRoot();
641
642 HideNotHighlightedCursor hnhc(root, tree, vf, lc);
643 PostorderNodeVisitor<HideNotHighlightedCursor>(hnhc).run();
644 }
645
646 class TreeHighlighter : public QThread
647 {
648
649 const NodeTree &tree_;
650 VisualFlags &vf_;
651 Layout &layout_;
652 LayoutComputer &lc_;
653
654 public:
TreeHighlighter(const NodeTree & tree,VisualFlags & vf,Layout & lo,LayoutComputer & lc)655 TreeHighlighter(const NodeTree &tree, VisualFlags &vf, Layout &lo, LayoutComputer &lc)
656 : tree_(tree), vf_(vf), layout_(lo), lc_(lc) {}
657
run()658 void run() override
659 {
660 utils::DebugMutexLocker t_locker(&tree_.treeMutex());
661 utils::DebugMutexLocker l_locker(&layout_.getMutex());
662
663 auto root = tree_.getRoot();
664
665 HideNotHighlightedCursor hnhc(root, tree_, vf_, lc_);
666 PostorderNodeVisitor<HideNotHighlightedCursor>(hnhc).run();
667 }
668 };
669
revealNode(NodeID n)670 void TraditionalView::revealNode(NodeID n)
671 {
672 utils::DebugMutexLocker t_locker(&tree_.treeMutex());
673 utils::DebugMutexLocker l_locker(&layout_->getMutex());
674
675 layout_computer_->dirtyUpUnconditional(n);
676
677 while (n != NodeID::NoNode)
678 {
679 setNodeHidden(n, false);
680 n = tree_.getParent(n);
681 }
682
683 emit needsLayoutUpdate();
684 emit needsRedrawing();
685 }
686
highlightSubtrees(const std::vector<NodeID> & nodes,bool hide_rest,bool show_outline)687 void TraditionalView::highlightSubtrees(const std::vector<NodeID> &nodes, bool hide_rest, bool show_outline)
688 {
689 vis_flags_->unhighlightAll();
690
691 detail::PerformanceHelper phelper;
692
693 for (auto nid : nodes)
694 {
695 vis_flags_->setHighlighted(nid, true);
696 }
697
698 if (hide_rest)
699 {
700 unhideAll();
701
702 auto root = tree_.getRoot();
703 HideNotHighlightedCursor hnhc(root, tree_, *vis_flags_, *layout_computer_);
704 PostorderNodeVisitor<HideNotHighlightedCursor>(hnhc).run();
705
706 emit needsLayoutUpdate();
707 }
708
709 /// Note: this duplication could probably be avoided
710 if (!show_outline)
711 {
712 for (auto nid : nodes)
713 {
714 vis_flags_->setHighlighted(nid, false);
715 }
716 }
717
718 emit needsRedrawing();
719 }
720
721 /// Lantern Tree Visualisation
hideBySize(int size_limit)722 void TraditionalView::hideBySize(int size_limit)
723 {
724 utils::DebugMutexLocker tree_lock(&tree_.treeMutex());
725
726 unhideAll();
727
728 vis_flags_->resetLanternSizes();
729
730 const int max_lantern = 127;
731
732 const auto sizes = utils::calc_subtree_sizes(tree_);
733
734 const auto root = tree_.getRoot();
735
736 std::stack<NodeID> stack;
737
738 stack.push(root);
739
740 while (!stack.empty())
741 {
742 const auto n = stack.top();
743 stack.pop();
744
745 const auto size = sizes.at(n);
746 const auto nkids = tree_.childrenCount(n);
747
748 if (size > size_limit)
749 {
750 /// visit children
751 for (auto alt = 0u; alt < nkids; ++alt)
752 {
753 stack.push(tree_.getChild(n, alt));
754 }
755 }
756 else
757 {
758 /// turn the node into a "lantern"
759 if (nkids > 0)
760 {
761 vis_flags_->setHidden(n, true);
762 /// lantern size
763 auto lsize = (size * max_lantern) / size_limit;
764 vis_flags_->setLanternSize(n, lsize);
765 layout_->setLayoutDone(n, false);
766 dirtyUp(n);
767 }
768 }
769 }
770
771 emit needsLayoutUpdate();
772 emit needsRedrawing();
773
774 centerCurrentNode();
775 }
776
undoLanterns()777 void TraditionalView::undoLanterns()
778 {
779 vis_flags_->resetLanternSizes();
780 }
781
showNodeInfo() const782 void TraditionalView::showNodeInfo() const
783 {
784
785 if (!solver_data_.hasInfo())
786 return;
787
788 const auto cur_nid = node();
789 if (cur_nid == NodeID::NoNode)
790 return;
791
792 auto info_dialog = new QDialog;
793 auto layout = new QVBoxLayout(info_dialog);
794
795 QTextEdit* te = new QTextEdit;
796 te->append(solver_data_.getInfo(cur_nid).c_str());
797
798 layout->addWidget(te);
799
800 info_dialog->setAttribute(Qt::WA_DeleteOnClose);
801 info_dialog->show();
802 }
803
showNogoods() const804 void TraditionalView::showNogoods() const
805 {
806
807 if (!solver_data_.hasNogoods())
808 return;
809
810 const auto cur_nid = node();
811 if (cur_nid == NodeID::NoNode)
812 return;
813
814 const auto nodes = utils::nodes_below(tree_, cur_nid);
815
816 auto ng_dialog = new NogoodDialog(tree_, nodes);
817 ng_dialog->setAttribute(Qt::WA_DeleteOnClose);
818
819 connect(ng_dialog, &NogoodDialog::nogoodClicked, [this](NodeID nid) {
820 const_cast<TraditionalView *>(this)->revealNode(nid);
821 const_cast<TraditionalView *>(this)->setAndCenterNode(nid);
822 emit nogoodsClicked({nid});
823 });
824
825 ng_dialog->show();
826 }
827
debugCheckLayout() const828 void TraditionalView::debugCheckLayout() const
829 {
830 ///
831 const auto order = utils::any_order(tree_);
832
833 for (const auto n : order)
834 {
835 auto bb = layout_->getBoundingBox(n);
836 // print("bb for {} is fine", n);
837 }
838 }
839
setDebugMode(bool v)840 void TraditionalView::setDebugMode(bool v)
841 {
842 scroll_area_->setDebugMode(true);
843 layout_computer_->setDebugMode(true);
844 emit needsLayoutUpdate();
845 emit needsRedrawing();
846 }
847
848 } // namespace tree
849 } // namespace cpprofiler
850