Overview.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "Overview.h"
17 #include "layer/Layer.h"
18 #include "data/model/Model.h"
19 #include "base/ZoomConstraint.h"
20 
21 #include <QPaintEvent>
22 #include <QPainter>
23 #include <QPainterPath>
24 #include <iostream>
25 
26 //#define DEBUG_OVERVIEW 1
27 
28 
29 Overview::Overview(QWidget *w) :
30  View(w, false),
31  m_clickedInRange(false),
32  m_dragCentreFrame(0)
33 {
34  setObjectName(tr("Overview"));
35  m_followPan = false;
36  m_followZoom = false;
38  m_modelTestTimer.start();
39 
40  bool light = hasLightBackground();
41  if (light) m_boxColour = Qt::darkGray;
42  else m_boxColour = Qt::lightGray;
43 }
44 
45 void
46 Overview::modelChangedWithin(ModelId modelId, sv_frame_t startFrame, sv_frame_t endFrame)
47 {
48  using namespace std::rel_ops;
49 
50  bool zoomChanged = false;
51 
52  sv_frame_t frameCount = getModelsEndFrame() - getModelsStartFrame();
53  ZoomLevel zoomLevel { ZoomLevel::FramesPerPixel, int(frameCount / width()) };
54  if (zoomLevel.level < 1) zoomLevel.level = 1;
55  zoomLevel = getZoomConstraintLevel(zoomLevel, ZoomConstraint::RoundUp);
56  if (zoomLevel != m_zoomLevel) {
57  zoomChanged = true;
58  }
59 
60  if (!zoomChanged) {
61  if (m_modelTestTimer.elapsed() < 1000) {
62  for (LayerList::const_iterator i = m_layerStack.begin();
63  i != m_layerStack.end(); ++i) {
64  auto model = ModelById::get((*i)->getModel());
65  if (model && (!model->isOK() || !model->isReady())) {
66  return;
67  }
68  }
69  } else {
70  m_modelTestTimer.restart();
71  }
72  }
73 
74  View::modelChangedWithin(modelId, startFrame, endFrame);
75 }
76 
77 void
79 {
82 }
83 
84 void
86 {
87  m_views.insert(view);
88  update();
89 }
90 
91 void
93 {
94  m_views.erase(view);
95  update();
96 }
97 
98 void
100 #ifdef DEBUG_OVERVIEW
101  f
102 #endif
103  )
104 {
105 #ifdef DEBUG_OVERVIEW
106  cerr << "Overview::globalCentreFrameChanged: " << f << endl;
107 #endif
108  update();
109 }
110 
111 void
113 #ifdef DEBUG_OVERVIEW
114  f
115 #endif
116  )
117 {
118 #ifdef DEBUG_OVERVIEW
119  cerr << "Overview[" << this << "]::viewCentreFrameChanged(" << v << "): " << f << endl;
120 #endif
121  if (m_views.find(v) != m_views.end()) {
122  update();
123  }
124 }
125 
126 void
128 {
129  if (v == this) return;
130  if (m_views.find(v) != m_views.end()) {
131  update();
132  }
133 }
134 
135 void
137 {
138 #ifdef DEBUG_OVERVIEW
139  cerr << "Overview[" << this << "]::viewManagerPlaybackFrameChanged(" << f << "): " << f << endl;
140 #endif
141 
142  bool changed = false;
143 
145 
146  if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true;
147  m_playPointerFrame = f;
148 
149  if (changed) update();
150 }
151 
152 QColor
154 {
155  return Qt::transparent;
156 }
157 
158 QColor
160 {
161  QColor c = palette().window().color();
162  c.setAlpha(100);
163  return c;
164 }
165 
166 void
168 {
169  m_boxColour = c;
170 }
171 
172 void
173 Overview::paintEvent(QPaintEvent *e)
174 {
175  using namespace std::rel_ops;
176 
177  // Recalculate zoom in case the size of the widget has changed.
178 
179 #ifdef DEBUG_OVERVIEW
180  cerr << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << endl;
181 #endif
182 
183  sv_frame_t startFrame = getModelsStartFrame();
184  sv_frame_t frameCount = getModelsEndFrame() - getModelsStartFrame();
185  ZoomLevel zoomLevel { ZoomLevel::FramesPerPixel, int(frameCount / width()) };
186  if (zoomLevel.level < 1) zoomLevel.level = 1;
187  zoomLevel = getZoomConstraintLevel(zoomLevel, ZoomConstraint::RoundUp);
188  if (zoomLevel != m_zoomLevel) {
189  m_zoomLevel = zoomLevel;
191  }
192 
193  sv_frame_t centreFrame = startFrame +
194  sv_frame_t(round(m_zoomLevel.pixelsToFrames(width()/2)));
195 
196  if (centreFrame > (startFrame + getModelsEndFrame())/2) {
197  centreFrame = (startFrame + getModelsEndFrame())/2;
198  }
199  if (centreFrame != m_centreFrame) {
200 #ifdef DEBUG_OVERVIEW
201  cerr << "Overview::paintEvent: Centre frame changed from "
202  << m_centreFrame << " to " << centreFrame << " and thus start frame from " << getStartFrame();
203 #endif
204  m_centreFrame = centreFrame;
205 #ifdef DEBUG_OVERVIEW
206  cerr << " to " << getStartFrame() << endl;
207 #endif
209  }
210 
211  View::paintEvent(e);
212 
213  QPainter paint;
214  paint.begin(this);
215  paint.setClipRegion(e->region());
216  paint.setRenderHints(QPainter::Antialiasing);
217 
218  // We paint a rounded rect for each distinct set of view extents,
219  // and we colour in the inside and outside of the rect that
220  // corresponds to the current view. (One small caveat -- we don't
221  // know which rect that is yet. We'll have to figure it out
222  // somehow...)
223 
224  std::set<std::pair<int, int> > extents;
225  std::vector<QRect> rects;
226  QRect primary;
227 
228  int y = 0;
229 
230  for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
231  if (!*i) continue;
232 
233  View *w = (View *)*i;
234 
235  sv_frame_t f0 = w->getFrameForX(0);
236  sv_frame_t f1 = w->getFrameForX(w->width());
237 
238  if (f0 >= 0) {
239  sv_frame_t rf0 = w->alignToReference(f0);
240  f0 = alignFromReference(rf0);
241  }
242  if (f1 >= 0) {
243  sv_frame_t rf1 = w->alignToReference(f1);
244  f1 = alignFromReference(rf1);
245  }
246 
247  int x0 = getXForFrame(f0);
248  int x1 = getXForFrame(f1);
249 
250  if (x1 <= x0) x1 = x0 + 1;
251 
252  std::pair<int, int> extent(x0, x1);
253 
254  if (extents.find(extent) == extents.end()) {
255 
256  y += height() / 10 + 1;
257  extents.insert(extent);
258 
259  QRect vr(x0, y, x1 - x0, height() - 2 * y);
260  rects.push_back(vr);
261  primary = vr;
262  }
263  }
264 
265  QPainterPath without;
266  without.addRoundedRect(primary, 4, 4);
267  without.addRect(rect());
268  paint.setPen(Qt::NoPen);
269  paint.setBrush(getFillWithout());
270  paint.drawPath(without);
271 
272  paint.setBrush(getFillWithin());
273  paint.drawRoundedRect(primary, 4, 4);
274 
275  foreach (QRect vr, rects) {
276  paint.setBrush(Qt::NoBrush);
277  paint.setPen(QPen(m_boxColour, 2));
278  paint.drawRoundedRect(vr, 4, 4);
279  }
280 
281  paint.end();
282 }
283 
284 void
286 {
287  m_clickPos = e->pos();
288  sv_frame_t clickFrame = getFrameForX(m_clickPos.x());
289  if (clickFrame > 0) m_dragCentreFrame = clickFrame;
290  else m_dragCentreFrame = 0;
291  m_clickedInRange = true;
292 
293  for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
294  if (*i && (*i)->getAligningModel() == getAligningModel()) {
295  m_dragCentreFrame = (*i)->getCentreFrame();
296  break;
297  }
298  }
299 }
300 
301 void
303 {
304  if (m_clickedInRange) {
305  mouseMoveEvent(e);
306  }
307  m_clickedInRange = false;
308 }
309 
310 void
312 {
313  if (!m_clickedInRange) return;
314 
315  int xoff = int(e->x()) - int(m_clickPos.x());
316  sv_frame_t frameOff = sv_frame_t(round(m_zoomLevel.pixelsToFrames(xoff)));
317 
318  sv_frame_t newCentreFrame = m_dragCentreFrame;
319  if (frameOff > 0) {
320  newCentreFrame += frameOff;
321  } else if (newCentreFrame >= -frameOff) {
322  newCentreFrame += frameOff;
323  } else {
324  newCentreFrame = 0;
325  }
326 
327  if (newCentreFrame >= getModelsEndFrame()) {
328  newCentreFrame = getModelsEndFrame();
329  if (newCentreFrame > 0) --newCentreFrame;
330  }
331 
332  sv_frame_t pixel = sv_frame_t(round(m_zoomLevel.pixelsToFrames(1)));
333 
334  if (std::max(m_centreFrame, newCentreFrame) -
335  std::min(m_centreFrame, newCentreFrame) >
336  pixel) {
337  sv_frame_t rf = alignToReference(newCentreFrame);
338 #ifdef DEBUG_OVERVIEW
339  cerr << "Overview::mouseMoveEvent: x " << e->x() << " and click x " << m_clickPos.x() << " -> frame " << newCentreFrame << " -> rf " << rf << endl;
340 #endif
344  } else {
345  emit centreFrameChanged(rf, true, PlaybackIgnore);
346  }
347  }
348 }
349 
350 void
352 {
353  sv_frame_t frame = getFrameForX(e->x());
354  sv_frame_t rf = 0;
355  if (frame > 0) rf = alignToReference(frame);
356 #ifdef DEBUG_OVERVIEW
357  cerr << "Overview::mouseDoubleClickEvent: frame " << frame << " -> rf " << rf << endl;
358 #endif
359  m_clickedInRange = false; // we're not starting a drag with the second click
361 }
362 
363 void
365 {
366  emit contextHelpChanged(tr("Click and drag to navigate; double-click to jump"));
367 }
368 
369 void
371 {
372  emit contextHelpChanged("");
373 }
374 
375 
QElapsedTimer m_modelTestTimer
Definition: Overview.h:71
void paintEvent(QPaintEvent *e) override
Definition: View.cpp:2225
sv_frame_t m_dragCentreFrame
Definition: Overview.h:70
ZoomLevel m_zoomLevel
Definition: View.h:541
QColor m_boxColour
Definition: Overview.h:72
void viewCentreFrameChanged(View *, sv_frame_t) override
Definition: Overview.cpp:112
sv_frame_t alignFromReference(sv_frame_t) const
Definition: View.cpp:1597
sv_frame_t m_playPointerFrame
Definition: View.h:546
virtual void modelChangedWithin(ModelId, sv_frame_t startFrame, sv_frame_t endFrame)
Definition: View.cpp:1137
View scrolls continuously during playback, keeping the playback position at the centre.
Definition: ViewManager.h:44
bool m_followZoom
Definition: View.h:543
ZoomLevel getZoomConstraintLevel(ZoomLevel level, ZoomConstraint::RoundingDirection dir=ZoomConstraint::RoundNearest) const
Definition: View.cpp:1708
virtual void modelReplaced()
Definition: View.cpp:1202
sv_frame_t alignToReference(sv_frame_t) const
Definition: View.cpp:1606
ViewSet m_views
Definition: Overview.h:75
QPoint m_clickPos
Definition: Overview.h:67
LayerList m_layerStack
Definition: View.h:559
void mouseMoveEvent(QMouseEvent *e) override
Definition: Overview.cpp:311
void leaveEvent(QEvent *) override
Definition: Overview.cpp:370
void centreFrameChanged(sv_frame_t frame, bool globalScroll, PlaybackFollowMode followMode)
void mouseReleaseEvent(QMouseEvent *e) override
Definition: Overview.cpp:302
void mousePressEvent(QMouseEvent *e) override
Definition: Overview.cpp:285
View follows playback page-by-page, but dragging the view relocates playback to the centre frame...
Definition: ViewManager.h:51
void enterEvent(QEvent *) override
Definition: Overview.cpp:364
sv_frame_t getFrameForX(int x) const override
Return the closest frame to the given pixel x-coordinate.
Definition: View.cpp:600
sv_frame_t getAlignedPlaybackFrame() const
Definition: View.cpp:1615
void viewManagerPlaybackFrameChanged(sv_frame_t) override
Definition: Overview.cpp:136
void mouseDoubleClickEvent(QMouseEvent *e) override
Definition: Overview.cpp:351
QColor getFillWithout() const
Definition: Overview.cpp:159
bool m_clickedInRange
Definition: Overview.h:69
View is detached from playback.
Definition: ViewManager.h:64
ModelId getAligningModel() const
!!
Definition: View.cpp:1542
void viewZoomLevelChanged(View *, ZoomLevel, bool) override
Definition: Overview.cpp:127
QColor getFillWithin() const
Definition: Overview.cpp:153
sv_frame_t m_centreFrame
Definition: View.h:540
void globalCentreFrameChanged(sv_frame_t) override
Definition: Overview.cpp:99
Overview(QWidget *parent=0)
Definition: Overview.cpp:29
PlaybackFollowMode m_followPlay
Definition: View.h:544
void contextHelpChanged(const QString &)
sv_frame_t getModelsStartFrame() const override
Definition: View.cpp:1451
bool hasLightBackground() const override
Definition: View.cpp:774
void unregisterView(View *view)
Definition: Overview.cpp:92
virtual void setPlaybackFollow(PlaybackFollowMode m)
Definition: View.cpp:1097
bool m_followPan
Definition: View.h:542
View is the base class of widgets that display one or more overlaid views of data against a horizonta...
Definition: View.h:55
void paintEvent(QPaintEvent *e) override
Definition: Overview.cpp:173
void modelReplaced() override
Definition: Overview.cpp:78
sv_frame_t getStartFrame() const override
Retrieve the first visible sample frame on the widget.
Definition: View.cpp:445
void modelChangedWithin(ModelId, sv_frame_t startFrame, sv_frame_t endFrame) override
Definition: Overview.cpp:46
sv_frame_t getModelsEndFrame() const override
Definition: View.cpp:1475
virtual void setBoxColour(QColor)
Definition: Overview.cpp:167
void registerView(View *view)
Definition: Overview.cpp:85
void zoomLevelChanged(ZoomLevel level, bool locked)
int getXForFrame(sv_frame_t frame) const override
Return the pixel x-coordinate corresponding to a given sample frame.
Definition: View.cpp:527