svgui  1.9
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 <iostream>
24 
25 //#define DEBUG_OVERVIEW 1
26 
27 
28 Overview::Overview(QWidget *w) :
29  View(w, false),
30  m_clickedInRange(false),
31  m_dragCentreFrame(0)
32 {
33  setObjectName(tr("Overview"));
34  m_followPan = false;
35  m_followZoom = false;
37  m_modelTestTime.start();
38 }
39 
40 void
41 Overview::modelChangedWithin(int startFrame, int endFrame)
42 {
43  bool zoomChanged = false;
44 
45  int frameCount = getModelsEndFrame() - getModelsStartFrame();
46  int zoomLevel = frameCount / width();
47  if (zoomLevel < 1) zoomLevel = 1;
48  zoomLevel = getZoomConstraintBlockSize(zoomLevel,
49  ZoomConstraint::RoundUp);
50  if (zoomLevel != m_zoomLevel) {
51  zoomChanged = true;
52  }
53 
54  if (!zoomChanged) {
55  if (m_modelTestTime.elapsed() < 1000) {
56  for (LayerList::const_iterator i = m_layerStack.begin();
57  i != m_layerStack.end(); ++i) {
58  if ((*i)->getModel() &&
59  (!(*i)->getModel()->isOK() ||
60  !(*i)->getModel()->isReady())) {
61  return;
62  }
63  }
64  } else {
65  m_modelTestTime.restart();
66  }
67  }
68 
69  View::modelChangedWithin(startFrame, endFrame);
70 }
71 
72 void
74 {
77 }
78 
79 void
81 {
82  m_views.insert(view);
83  update();
84 }
85 
86 void
88 {
89  m_views.erase(view);
90  update();
91 }
92 
93 void
95 #ifdef DEBUG_OVERVIEW
96  f
97 #endif
98  )
99 {
100 #ifdef DEBUG_OVERVIEW
101  cerr << "Overview::globalCentreFrameChanged: " << f << endl;
102 #endif
103  update();
104 }
105 
106 void
108 #ifdef DEBUG_OVERVIEW
109  f
110 #endif
111  )
112 {
113 #ifdef DEBUG_OVERVIEW
114  cerr << "Overview[" << this << "]::viewCentreFrameChanged(" << v << "): " << f << endl;
115 #endif
116  if (m_views.find(v) != m_views.end()) {
117  update();
118  }
119 }
120 
121 void
123 {
124  if (v == this) return;
125  if (m_views.find(v) != m_views.end()) {
126  update();
127  }
128 }
129 
130 void
132 {
133 #ifdef DEBUG_OVERVIEW
134  cerr << "Overview[" << this << "]::viewManagerPlaybackFrameChanged(" << f << "): " << f << endl;
135 #endif
136 
137  bool changed = false;
138 
140 
141  if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true;
142  m_playPointerFrame = f;
143 
144  if (changed) update();
145 }
146 
147 void
148 Overview::paintEvent(QPaintEvent *e)
149 {
150  // Recalculate zoom in case the size of the widget has changed.
151 
152 #ifdef DEBUG_OVERVIEW
153  cerr << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << endl;
154 #endif
155 
156  int startFrame = getModelsStartFrame();
157  int frameCount = getModelsEndFrame() - getModelsStartFrame();
158  int zoomLevel = frameCount / width();
159  if (zoomLevel < 1) zoomLevel = 1;
160  zoomLevel = getZoomConstraintBlockSize(zoomLevel,
161  ZoomConstraint::RoundUp);
162  if (zoomLevel != m_zoomLevel) {
163  m_zoomLevel = zoomLevel;
165  }
166 
167  int centreFrame = startFrame + m_zoomLevel * (width() / 2);
168  if (centreFrame > (startFrame + getModelsEndFrame())/2) {
169  centreFrame = (startFrame + getModelsEndFrame())/2;
170  }
171  if (centreFrame != m_centreFrame) {
172 #ifdef DEBUG_OVERVIEW
173  cerr << "Overview::paintEvent: Centre frame changed from "
174  << m_centreFrame << " to " << centreFrame << " and thus start frame from " << getStartFrame();
175 #endif
176  m_centreFrame = centreFrame;
177 #ifdef DEBUG_OVERVIEW
178  cerr << " to " << getStartFrame() << endl;
179 #endif
181  }
182 
183  View::paintEvent(e);
184 
185  QPainter paint;
186  paint.begin(this);
187 
188  QRect r(rect());
189 
190  if (e) {
191  r = e->rect();
192  paint.setClipRect(r);
193  }
194 
195  paint.setPen(getForeground());
196 
197  int y = 0;
198 
199  int prevx0 = -10;
200  int prevx1 = -10;
201 
202  for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
203  if (!*i) continue;
204 
205  View *w = (View *)*i;
206 
207  int f0 = w->getFrameForX(0);
208  int f1 = w->getFrameForX(w->width());
209 
210  if (f0 >= 0) {
211  int rf0 = w->alignToReference(f0);
212  f0 = alignFromReference(rf0);
213  }
214  if (f1 >= 0) {
215  int rf1 = w->alignToReference(f1);
216  f1 = alignFromReference(rf1);
217  }
218 
219  int x0 = getXForFrame(f0);
220  int x1 = getXForFrame(f1);
221 
222  if (x0 != prevx0 || x1 != prevx1) {
223  y += height() / 10 + 1;
224  prevx0 = x0;
225  prevx1 = x1;
226  }
227 
228  if (x1 <= x0) x1 = x0 + 1;
229 
230  paint.drawRect(x0, y, x1 - x0, height() - 2 * y);
231  }
232 
233  paint.end();
234 }
235 
236 void
238 {
239  m_clickPos = e->pos();
240  int clickFrame = getFrameForX(m_clickPos.x());
241  if (clickFrame > 0) m_dragCentreFrame = clickFrame;
242  else m_dragCentreFrame = 0;
243  m_clickedInRange = true;
244 
245  for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
246  if (*i && (*i)->getAligningModel() == getAligningModel()) {
247  m_dragCentreFrame = (*i)->getCentreFrame();
248  break;
249  }
250  }
251 }
252 
253 void
255 {
256  if (m_clickedInRange) {
257  mouseMoveEvent(e);
258  }
259  m_clickedInRange = false;
260 }
261 
262 void
264 {
265  if (!m_clickedInRange) return;
266 
267  int xoff = int(e->x()) - int(m_clickPos.x());
268  int frameOff = xoff * m_zoomLevel;
269 
270  int newCentreFrame = m_dragCentreFrame;
271  if (frameOff > 0) {
272  newCentreFrame += frameOff;
273  } else if (newCentreFrame >= int(-frameOff)) {
274  newCentreFrame += frameOff;
275  } else {
276  newCentreFrame = 0;
277  }
278 
279  if (newCentreFrame >= getModelsEndFrame()) {
280  newCentreFrame = getModelsEndFrame();
281  if (newCentreFrame > 0) --newCentreFrame;
282  }
283 
284  if (std::max(m_centreFrame, newCentreFrame) -
285  std::min(m_centreFrame, newCentreFrame) > int(m_zoomLevel)) {
286  int rf = alignToReference(newCentreFrame);
287 #ifdef DEBUG_OVERVIEW
288  cerr << "Overview::mouseMoveEvent: x " << e->x() << " and click x " << m_clickPos.x() << " -> frame " << newCentreFrame << " -> rf " << rf << endl;
289 #endif
293  } else {
294  emit centreFrameChanged(rf, true, PlaybackIgnore);
295  }
296  }
297 }
298 
299 void
301 {
302  int frame = getFrameForX(e->x());
303  int rf = 0;
304  if (frame > 0) rf = alignToReference(frame);
305 #ifdef DEBUG_OVERVIEW
306  cerr << "Overview::mouseDoubleClickEvent: frame " << frame << " -> rf " << rf << endl;
307 #endif
308  m_clickedInRange = false; // we're not starting a drag with the second click
310 }
311 
312 void
314 {
315  emit contextHelpChanged(tr("Click and drag to navigate; double-click to jump"));
316 }
317 
318 void
320 {
321  emit contextHelpChanged("");
322 }
323 
324 
int getFrameForX(int x) const
Return the closest frame to the given pixel x-coordinate.
Definition: View.cpp:363
int getZoomConstraintBlockSize(int blockSize, ZoomConstraint::RoundingDirection dir=ZoomConstraint::RoundNearest) const
Definition: View.cpp:1424
virtual void modelReplaced()
Definition: Overview.cpp:73
View scrolls continuously during playback, keeping the playback position at the centre.
Definition: ViewManager.h:39
int m_zoomLevel
Definition: View.h:409
bool m_followZoom
Definition: View.h:411
virtual void viewCentreFrameChanged(View *, int)
Definition: Overview.cpp:107
virtual QColor getForeground() const
Definition: View.cpp:513
int getModelsStartFrame() const
Definition: View.cpp:1190
virtual void modelReplaced()
Definition: View.cpp:947
virtual void mouseMoveEvent(QMouseEvent *e)
Definition: Overview.cpp:263
virtual void viewManagerPlaybackFrameChanged(int)
Definition: Overview.cpp:131
virtual void enterEvent(QEvent *)
Definition: Overview.cpp:313
ViewSet m_views
Definition: Overview.h:69
int getAlignedPlaybackFrame() const
Definition: View.cpp:1331
void zoomLevelChanged(int, bool)
QPoint m_clickPos
Definition: Overview.h:62
virtual void paintEvent(QPaintEvent *e)
Definition: View.cpp:1662
virtual void globalCentreFrameChanged(int)
Definition: Overview.cpp:94
LayerList m_layerStack
Definition: View.h:425
int alignToReference(int) const
Definition: View.cpp:1322
View follows playback page-by-page, but dragging the view relocates playback to the centre frame.
Definition: ViewManager.h:46
int m_dragCentreFrame
Definition: Overview.h:65
Model * getAligningModel() const
!!
Definition: View.cpp:1273
virtual void paintEvent(QPaintEvent *e)
Definition: Overview.cpp:148
int getStartFrame() const
Retrieve the first visible sample frame on the widget.
Definition: View.cpp:302
int alignFromReference(int) const
Definition: View.cpp:1313
bool m_clickedInRange
Definition: Overview.h:64
View is detached from playback.
Definition: ViewManager.h:59
virtual void modelChangedWithin(int startFrame, int endFrame)
Definition: View.cpp:880
int m_centreFrame
Definition: View.h:408
QTime m_modelTestTime
Definition: Overview.h:66
virtual void mouseReleaseEvent(QMouseEvent *e)
Definition: Overview.cpp:254
Overview(QWidget *parent=0)
Definition: Overview.cpp:28
virtual void leaveEvent(QEvent *)
Definition: Overview.cpp:319
PlaybackFollowMode m_followPlay
Definition: View.h:412
void contextHelpChanged(const QString &)
int m_playPointerFrame
Definition: View.h:414
int getModelsEndFrame() const
Definition: View.cpp:1211
void unregisterView(View *view)
Definition: Overview.cpp:87
virtual void modelChangedWithin(int startFrame, int endFrame)
Definition: Overview.cpp:41
virtual void setPlaybackFollow(PlaybackFollowMode m)
Definition: View.cpp:837
bool m_followPan
Definition: View.h:410
View is the base class of widgets that display one or more overlaid views of data against a horizonta...
Definition: View.h:50
virtual void mousePressEvent(QMouseEvent *e)
Definition: Overview.cpp:237
void registerView(View *view)
Definition: Overview.cpp:80
int getXForFrame(int frame) const
Return the pixel x-coordinate corresponding to a given sample frame (which may be negative).
Definition: View.cpp:357
virtual void mouseDoubleClickEvent(QMouseEvent *e)
Definition: Overview.cpp:300
virtual void viewZoomLevelChanged(View *, int, bool)
Definition: Overview.cpp:122
void centreFrameChanged(int frame, bool globalScroll, PlaybackFollowMode followMode)