2 * This file is part of the PulseView project.
4 * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
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.
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.
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/>.
24 #include "tracegroup.hpp"
29 #include <boost/iterator/filter_iterator.hpp>
31 #include <QApplication>
33 #include <QMouseEvent>
37 #include <pv/session.hpp>
38 #include <pv/widgets/popup.hpp>
40 using boost::make_filter_iterator
;
43 using std::dynamic_pointer_cast
;
44 using std::shared_ptr
;
45 using std::stable_sort
;
52 const int Header::Padding
= 12;
53 const int Header::BaselineOffset
= 5;
55 static bool item_selected(shared_ptr
<TraceTreeItem
> r
)
60 Header::Header(View
&parent
) :
65 QSize
Header::sizeHint() const
67 QRectF
max_rect(-Padding
, 0, Padding
, 0);
68 const vector
<shared_ptr
<TraceTreeItem
>> items(
69 view_
.list_by_type
<TraceTreeItem
>());
72 max_rect
= max_rect
.united(i
->label_rect(QRect()));
73 return QSize(max_rect
.width() + Padding
+ BaselineOffset
, 0);
76 QSize
Header::extended_size_hint() const
78 return sizeHint() + QSize(ViewItem::HighlightRadius
, 0);
81 vector
< shared_ptr
<ViewItem
> > Header::items()
83 const vector
<shared_ptr
<TraceTreeItem
>> items(
84 view_
.list_by_type
<TraceTreeItem
>());
85 return vector
< shared_ptr
<ViewItem
> >(items
.begin(), items
.end());
88 shared_ptr
<ViewItem
> Header::get_mouse_over_item(const QPoint
&pt
)
90 const QRect
r(0, 0, width() - BaselineOffset
, height());
91 const vector
<shared_ptr
<TraceTreeItem
>> items(
92 view_
.list_by_type
<TraceTreeItem
>());
93 for (auto i
= items
.rbegin(); i
!= items
.rend(); i
++)
94 if ((*i
)->enabled() && (*i
)->label_rect(r
).contains(pt
))
96 return shared_ptr
<TraceTreeItem
>();
99 void Header::paintEvent(QPaintEvent
*)
101 // The trace labels are not drawn with the arrows exactly on the
102 // left edge of the widget, because then the selection shadow
103 // would be clipped away.
104 const QRect
rect(0, 0, width() - BaselineOffset
, height());
106 vector
< shared_ptr
<RowItem
> > items(
107 view_
.list_by_type
<RowItem
>());
109 stable_sort(items
.begin(), items
.end(),
110 [](const shared_ptr
<RowItem
> &a
, const shared_ptr
<RowItem
> &b
) {
111 return a
->point(QRect()).y() < b
->point(QRect()).y(); });
113 QPainter
painter(this);
114 painter
.setRenderHint(QPainter::Antialiasing
);
116 for (const shared_ptr
<RowItem
> r
: items
) {
119 const bool highlight
= !item_dragging_
&&
120 r
->label_rect(rect
).contains(mouse_point_
);
121 r
->paint_label(painter
, rect
, highlight
);
127 void Header::contextMenuEvent(QContextMenuEvent
*event
)
129 const shared_ptr
<ViewItem
> r
= get_mouse_over_item(mouse_point_
);
133 QMenu
*menu
= r
->create_context_menu(this);
135 menu
= new QMenu(this);
137 const vector
< shared_ptr
<TraceTreeItem
> > items(
138 view_
.list_by_type
<TraceTreeItem
>());
139 if (count_if(items
.begin(), items
.end(), item_selected
) > 1) {
140 menu
->addSeparator();
142 QAction
*const group
= new QAction(tr("Group"), this);
143 QList
<QKeySequence
> shortcuts
;
144 shortcuts
.append(QKeySequence(Qt::ControlModifier
| Qt::Key_G
));
145 group
->setShortcuts(shortcuts
);
146 connect(group
, SIGNAL(triggered()), this, SLOT(on_group()));
147 menu
->addAction(group
);
150 menu
->exec(event
->globalPos());
153 void Header::keyPressEvent(QKeyEvent
*event
)
157 MarginWidget::keyPressEvent(event
);
159 if (event
->key() == Qt::Key_G
&& event
->modifiers() == Qt::ControlModifier
)
161 else if (event
->key() == Qt::Key_U
&& event
->modifiers() == Qt::ControlModifier
)
165 void Header::on_group()
167 const vector
< shared_ptr
<TraceTreeItem
> > items(
168 view_
.list_by_type
<TraceTreeItem
>());
169 vector
< shared_ptr
<TraceTreeItem
> > selected_items(
170 make_filter_iterator(item_selected
, items
.begin(), items
.end()),
171 make_filter_iterator(item_selected
, items
.end(), items
.end()));
172 stable_sort(selected_items
.begin(), selected_items
.end(),
173 [](const shared_ptr
<TraceTreeItem
> &a
, const shared_ptr
<TraceTreeItem
> &b
) {
174 return a
->visual_v_offset() < b
->visual_v_offset(); });
176 shared_ptr
<TraceGroup
> group(new TraceGroup());
177 shared_ptr
<TraceTreeItem
> mouse_down_item(
178 dynamic_pointer_cast
<TraceTreeItem
>(mouse_down_item_
));
179 shared_ptr
<TraceTreeItem
> focus_item(
180 mouse_down_item
? mouse_down_item
: selected_items
.front());
183 assert(focus_item
->owner());
184 focus_item
->owner()->add_child_item(group
);
186 // Set the group v_offset here before reparenting
187 group
->force_to_v_offset(focus_item
->layout_v_offset() +
188 focus_item
->v_extents().first
);
190 for (size_t i
= 0; i
< selected_items
.size(); i
++) {
191 const shared_ptr
<TraceTreeItem
> &r
= selected_items
[i
];
193 r
->owner()->remove_child_item(r
);
194 group
->add_child_item(r
);
196 // Put the items at 1-pixel offsets, so that restack will
197 // stack them in the right order
198 r
->set_layout_v_offset(i
);
202 void Header::on_ungroup()
207 const vector
< shared_ptr
<TraceGroup
> > groups(
208 view_
.list_by_type
<TraceGroup
>());
209 for (const shared_ptr
<TraceGroup
> tg
: groups
)
210 if (tg
->selected()) {
218 } // namespace TraceView