]> sigrok.org Git - pulseview.git/blob - pv/view/viewwidget.cpp
TraceTreeItemOwner: Removed non-const item_list accessor
[pulseview.git] / pv / view / viewwidget.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2014 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #include <QApplication>
22 #include <QMouseEvent>
23 #include <QTouchEvent>
24
25 #include "tracetreeitem.hpp"
26 #include "view.hpp"
27 #include "viewwidget.hpp"
28
29 using std::any_of;
30 using std::shared_ptr;
31 using std::vector;
32
33 namespace pv {
34 namespace view {
35
36 ViewWidget::ViewWidget(View &parent) :
37         QWidget(&parent),
38         view_(parent),
39         item_dragging_(false)
40 {
41         setFocusPolicy(Qt::ClickFocus);
42         setAttribute(Qt::WA_AcceptTouchEvents, true);
43         setMouseTracking(true);
44 }
45
46 void ViewWidget::clear_selection()
47 {
48         const auto items = this->items();
49         for (auto &i : items)
50                 i->select(false);
51         update();
52 }
53
54 void ViewWidget::item_hover(const shared_ptr<ViewItem> &item)
55 {
56         (void)item;
57 }
58
59 void ViewWidget::item_clicked(const shared_ptr<ViewItem> &item)
60 {
61         (void)item;
62 }
63
64 bool ViewWidget::accept_drag() const
65 {
66         const vector< shared_ptr<TimeItem> > items(view_.time_items());
67         const vector< shared_ptr<TraceTreeItem> > trace_tree_items(
68                 view_.list_by_type<TraceTreeItem>());
69
70         const bool any_row_items_selected = any_of(
71                 trace_tree_items.begin(), trace_tree_items.end(),
72                 [](const shared_ptr<TraceTreeItem> &r) { return r->selected(); });
73
74         const bool any_time_items_selected = any_of(items.begin(), items.end(),
75                 [](const shared_ptr<TimeItem> &i) { return i->selected(); });
76
77         if (any_row_items_selected && !any_time_items_selected)
78         {
79                 // Check all the drag items share a common owner
80                 TraceTreeItemOwner *item_owner = nullptr;
81                 for (shared_ptr<TraceTreeItem> r : trace_tree_items)
82                         if (r->dragging()) {
83                                 if (!item_owner)
84                                         item_owner = r->owner();
85                                 else if (item_owner != r->owner())
86                                         return false;
87                         }
88
89                 return true;
90         }
91         else if (any_time_items_selected && !any_row_items_selected)
92         {
93                 return true;
94         }
95
96         // A background drag is beginning
97         return true;
98 }
99
100 bool ViewWidget::mouse_down() const
101 {
102         return mouse_down_point_.x() != INT_MIN &&
103                 mouse_down_point_.y() != INT_MIN;
104 }
105
106 void ViewWidget::drag_items(const QPoint &delta)
107 {
108         bool item_dragged = false;
109
110         // Drag the row items
111         TraceTreeItemOwner *item_owner = nullptr;
112         const vector< shared_ptr<TraceTreeItem> > trace_tree_items(
113                 view_.list_by_type<TraceTreeItem>());
114         for (shared_ptr<TraceTreeItem> r : trace_tree_items)
115                 if (r->dragging()) {
116                         item_owner = r->owner();
117                         r->drag_by(delta);
118
119                         // Ensure the trace is selected
120                         r->select();
121                 }
122
123         if (item_owner) {
124                 item_dragged = true;
125                 item_owner->restack_items();
126                 for (shared_ptr<TraceTreeItem> r : trace_tree_items)
127                         r->animate_to_layout_v_offset();
128         }
129
130         // Drag the time items
131         const vector< shared_ptr<TimeItem> > items(view_.time_items());
132         for (auto &i : items)
133                 if (i->dragging()) {
134                         i->drag_by(delta);
135                         item_dragged = true;
136                 }
137
138         // Do the background drag
139         if (!item_dragged)
140                 drag_by(delta);
141 }
142
143 void ViewWidget::drag()
144 {
145 }
146
147 void ViewWidget::drag_by(const QPoint &delta)
148 {
149         (void)delta;
150 }
151
152 void ViewWidget::drag_release()
153 {
154 }
155
156 void ViewWidget::mouse_left_press_event(QMouseEvent *event)
157 {
158         (void)event;
159
160         const bool ctrl_pressed =
161                 QApplication::keyboardModifiers() & Qt::ControlModifier;
162
163         // Clear selection if control is not pressed and this item is unselected
164         if ((!mouse_down_item_ || !mouse_down_item_->selected()) &&
165                 !ctrl_pressed)
166                 clear_selection();
167
168         // Set the signal selection state if the item has been clicked
169         if (mouse_down_item_) {
170                 if (ctrl_pressed)
171                         mouse_down_item_->select(!mouse_down_item_->selected());
172                 else
173                         mouse_down_item_->select(true);
174         }
175
176         // Save the offsets of any signals which will be dragged
177         bool item_dragged = false;
178         const auto items = this->items();
179         for (auto &i : items)
180                 if (i->selected()) {
181                         item_dragged = true;
182                         i->drag();
183                 }
184
185         // Do the background drag
186         if (!item_dragged)
187                 drag();
188
189         selection_changed();
190         update();
191 }
192
193 void ViewWidget::mouse_left_release_event(QMouseEvent *event)
194 {
195         assert(event);
196
197         auto items = this->items();
198         const bool ctrl_pressed =
199                 QApplication::keyboardModifiers() & Qt::ControlModifier;
200
201         // Unselect everything if control is not pressed
202         const shared_ptr<ViewItem> mouse_over =
203                 get_mouse_over_item(event->pos());
204
205         for (auto &i : items)
206                 i->drag_release();
207
208         if (item_dragging_)
209                 view_.restack_all_trace_tree_items();
210         else
211         {
212                 if (!ctrl_pressed) {
213                         for (shared_ptr<ViewItem> i : items)
214                                 if (mouse_down_item_ != i)
215                                         i->select(false);
216
217                         if (mouse_down_item_)
218                                 item_clicked(mouse_down_item_);
219                 }
220         }
221
222         item_dragging_ = false;
223 }
224
225 bool ViewWidget::touch_event(QTouchEvent *e)
226 {
227         (void)e;
228         return false;
229 }
230
231 bool ViewWidget::event(QEvent *event)
232 {
233         switch (event->type()) {
234         case QEvent::TouchBegin:
235         case QEvent::TouchUpdate:
236         case QEvent::TouchEnd:
237                 if (touch_event(static_cast<QTouchEvent *>(event)))
238                         return true;
239                 break;
240
241         default:
242                 break;
243         }
244
245         return QWidget::event(event);
246 }
247
248 void ViewWidget::mousePressEvent(QMouseEvent *event)
249 {
250         assert(event);
251
252         mouse_down_point_ = event->pos();
253         mouse_down_item_ = get_mouse_over_item(event->pos());
254
255         if (event->button() & Qt::LeftButton)
256                 mouse_left_press_event(event);
257 }
258
259 void ViewWidget::mouseReleaseEvent(QMouseEvent *event)
260 {
261         assert(event);
262         if (event->button() & Qt::LeftButton)
263                 mouse_left_release_event(event);
264
265         mouse_down_point_ = QPoint(INT_MIN, INT_MIN);
266         mouse_down_item_ = nullptr;
267 }
268
269 void ViewWidget::mouseMoveEvent(QMouseEvent *e)
270 {
271         assert(e);
272         mouse_point_ = e->pos();
273
274         if (!e->buttons())
275                 item_hover(get_mouse_over_item(e->pos()));
276         else if (e->buttons() & Qt::LeftButton)
277         {
278                 if (!item_dragging_)
279                 {
280                         if ((e->pos() - mouse_down_point_).manhattanLength() <
281                                 QApplication::startDragDistance())
282                                 return;
283
284                         if (!accept_drag())
285                                 return;
286
287                         item_dragging_ = true;
288                 }
289
290                 // Do the drag
291                 drag_items(e->pos() - mouse_down_point_);
292
293                 update();
294         }
295 }
296
297 void ViewWidget::leaveEvent(QEvent*)
298 {
299         mouse_point_ = QPoint(-1, -1);
300         update();
301 }
302
303 } // namespace view
304 } // namespace pv