Paint sampling points on the actual trace, not the center line
[pulseview.git] / pv / view / tracegroup.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2013 Joel Holdsworth <joel@airwebreathe.org.uk>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <extdef.h>
21
22 #include <algorithm>
23 #include <cassert>
24
25 #include <QMenu>
26 #include <QPainter>
27
28 #include "tracegroup.hpp"
29
30 using std::any_of;
31 using std::pair;
32 using std::shared_ptr;
33 using std::vector;
34
35 namespace pv {
36 namespace views {
37 namespace TraceView {
38
39 const int TraceGroup::Padding = 8;
40 const int TraceGroup::Width = 12;
41 const int TraceGroup::LineThickness = 5;
42 const QColor TraceGroup::LineColour(QColor(0x55, 0x57, 0x53));
43
44 TraceGroup::~TraceGroup()
45 {
46         owner_ = nullptr;
47         clear_child_items();
48 }
49
50 bool TraceGroup::enabled() const
51 {
52         return any_of(child_items().begin(), child_items().end(),
53                 [](const shared_ptr<ViewItem> &r) { return r->enabled(); });
54 }
55
56 pv::Session& TraceGroup::session()
57 {
58         assert(owner_);
59         return owner_->session();
60 }
61
62 const pv::Session& TraceGroup::session() const
63 {
64         assert(owner_);
65         return owner_->session();
66 }
67
68 View* TraceGroup::view()
69 {
70         assert(owner_);
71         return owner_->view();
72 }
73
74 const View* TraceGroup::view() const
75 {
76         assert(owner_);
77         return owner_->view();
78 }
79
80 pair<int, int> TraceGroup::v_extents() const
81 {
82         return TraceTreeItemOwner::v_extents();
83 }
84
85 void TraceGroup::paint_label(QPainter &p, const QRect &rect, bool hover)
86 {
87         const QRectF r = label_rect(rect).adjusted(
88                 LineThickness / 2, LineThickness / 2,
89                 -LineThickness / 2, -LineThickness / 2);
90
91         // Paint the label
92         const QPointF points[] = {
93                 r.topRight(),
94                 r.topLeft(),
95                 r.bottomLeft(),
96                 r.bottomRight()
97         };
98
99         if (selected()) {
100                 const QPen pen(highlight_pen());
101                 p.setPen(QPen(pen.brush(), pen.width() + LineThickness,
102                         Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin));
103                 p.setBrush(Qt::transparent);
104                 p.drawPolyline(points, countof(points));
105         }
106
107         p.setPen(QPen(QBrush(LineColour.darker()), LineThickness,
108                 Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin));
109         p.drawPolyline(points, countof(points));
110         p.setPen(QPen(QBrush(hover ? LineColour.lighter() : LineColour),
111                 LineThickness - 2, Qt::SolidLine, Qt::SquareCap,
112                 Qt::RoundJoin));
113         p.drawPolyline(points, countof(points));
114 }
115
116 QRectF TraceGroup::label_rect(const QRectF &rect) const
117 {
118         QRectF child_rect;
119         for (const shared_ptr<ViewItem> r : child_items())
120                 if (r && r->enabled())
121                         child_rect = child_rect.united(r->label_rect(rect));
122
123         return QRectF(child_rect.x() - Width - Padding, child_rect.y(),
124                 Width, child_rect.height());
125 }
126
127 bool TraceGroup::pt_in_label_rect(int left, int right, const QPoint &point)
128 {
129         (void)left;
130         (void)right;
131         (void)point;
132
133         return false;
134 }
135
136 QMenu* TraceGroup::create_context_menu(QWidget *parent)
137 {
138         QMenu *const menu = new QMenu(parent);
139
140         QAction *const ungroup = new QAction(tr("Ungroup"), this);
141         ungroup->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
142         connect(ungroup, SIGNAL(triggered()), this, SLOT(on_ungroup()));
143         menu->addAction(ungroup);
144
145         return menu;
146 }
147
148 pv::widgets::Popup* TraceGroup::create_popup(QWidget *parent)
149 {
150         (void)parent;
151         return nullptr;
152 }
153
154 int TraceGroup::owner_visual_v_offset() const
155 {
156         return owner_ ? visual_v_offset() + owner_->owner_visual_v_offset() : 0;
157 }
158
159 void TraceGroup::restack_items()
160 {
161         vector<shared_ptr<TraceTreeItem>> items(trace_tree_child_items());
162
163         // Sort by the centre line of the extents
164         stable_sort(items.begin(), items.end(),
165                 [](const shared_ptr<TraceTreeItem> &a, const shared_ptr<TraceTreeItem> &b) {
166                         const auto aext = a->v_extents();
167                         const auto bext = b->v_extents();
168                         return a->layout_v_offset() +
169                                         (aext.first + aext.second) / 2 <
170                                 b->layout_v_offset() +
171                                         (bext.first + bext.second) / 2;
172                 });
173
174         int total_offset = 0;
175         for (shared_ptr<TraceTreeItem> r : items) {
176                 const pair<int, int> extents = r->v_extents();
177                 if (extents.first == 0 && extents.second == 0)
178                         continue;
179
180                 // We position disabled traces, so that they are close to the
181                 // animation target positon should they be re-enabled
182                 if (r->enabled())
183                         total_offset += -extents.first;
184
185                 if (!r->dragging())
186                         r->set_layout_v_offset(total_offset);
187
188                 if (r->enabled())
189                         total_offset += extents.second;
190         }
191 }
192
193 unsigned int TraceGroup::depth() const
194 {
195         return owner_ ? owner_->depth() + 1 : 0;
196 }
197
198 void TraceGroup::ungroup()
199 {
200         const vector<shared_ptr<TraceTreeItem>> items(trace_tree_child_items());
201         clear_child_items();
202
203         for (shared_ptr<TraceTreeItem> r : items)
204                 owner_->add_child_item(r);
205
206         owner_->remove_child_item(shared_from_this());
207 }
208
209 void TraceGroup::on_ungroup()
210 {
211         ungroup();
212 }
213
214 void TraceGroup::row_item_appearance_changed(bool label, bool content)
215 {
216         if (owner_)
217                 owner_->row_item_appearance_changed(label, content);
218 }
219
220 void TraceGroup::extents_changed(bool horz, bool vert)
221 {
222         if (owner_)
223                 owner_->extents_changed(horz, vert);
224 }
225
226 } // namespace TraceView
227 } // namespace views
228 } // namespace pv