Chris@173
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@173
|
2
|
Chris@173
|
3 /*
|
Chris@173
|
4 Sonic Visualiser
|
Chris@173
|
5 An audio file viewer and annotation editor.
|
Chris@173
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@182
|
7 This file copyright 2006 Chris Cannam and QMUL.
|
Chris@173
|
8
|
Chris@173
|
9 This program is free software; you can redistribute it and/or
|
Chris@173
|
10 modify it under the terms of the GNU General Public License as
|
Chris@173
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@173
|
12 License, or (at your option) any later version. See the file
|
Chris@173
|
13 COPYING included with this distribution for more information.
|
Chris@173
|
14 */
|
Chris@173
|
15
|
Chris@173
|
16 #include "Overview.h"
|
Chris@173
|
17 #include "layer/Layer.h"
|
Chris@173
|
18 #include "data/model/Model.h"
|
Chris@173
|
19 #include "base/ZoomConstraint.h"
|
Chris@173
|
20
|
Chris@173
|
21 #include <QPaintEvent>
|
Chris@173
|
22 #include <QPainter>
|
Chris@173
|
23 #include <iostream>
|
Chris@173
|
24
|
Chris@643
|
25 //#define DEBUG_OVERVIEW 1
|
Chris@642
|
26
|
Chris@682
|
27
|
Chris@682
|
28
|
Chris@173
|
29
|
Chris@173
|
30 Overview::Overview(QWidget *w) :
|
Chris@173
|
31 View(w, false),
|
Chris@173
|
32 m_clickedInRange(false)
|
Chris@173
|
33 {
|
Chris@173
|
34 setObjectName(tr("Overview"));
|
Chris@173
|
35 m_followPan = false;
|
Chris@173
|
36 m_followZoom = false;
|
Chris@211
|
37 setPlaybackFollow(PlaybackIgnore);
|
Chris@274
|
38 m_modelTestTime.start();
|
Chris@173
|
39 }
|
Chris@173
|
40
|
Chris@173
|
41 void
|
Chris@806
|
42 Overview::modelChangedWithin(int startFrame, int endFrame)
|
Chris@173
|
43 {
|
Chris@253
|
44 bool zoomChanged = false;
|
Chris@253
|
45
|
Chris@806
|
46 int frameCount = getModelsEndFrame() - getModelsStartFrame();
|
Chris@253
|
47 int zoomLevel = frameCount / width();
|
Chris@253
|
48 if (zoomLevel < 1) zoomLevel = 1;
|
Chris@253
|
49 zoomLevel = getZoomConstraintBlockSize(zoomLevel,
|
Chris@253
|
50 ZoomConstraint::RoundUp);
|
Chris@253
|
51 if (zoomLevel != m_zoomLevel) {
|
Chris@253
|
52 zoomChanged = true;
|
Chris@253
|
53 }
|
Chris@253
|
54
|
Chris@253
|
55 if (!zoomChanged) {
|
Chris@274
|
56 if (m_modelTestTime.elapsed() < 1000) {
|
Chris@274
|
57 for (LayerList::const_iterator i = m_layers.begin();
|
Chris@274
|
58 i != m_layers.end(); ++i) {
|
Chris@274
|
59 if ((*i)->getModel() &&
|
Chris@389
|
60 (!(*i)->getModel()->isOK() ||
|
Chris@389
|
61 !(*i)->getModel()->isReady())) {
|
Chris@274
|
62 return;
|
Chris@274
|
63 }
|
Chris@253
|
64 }
|
Chris@274
|
65 } else {
|
Chris@274
|
66 m_modelTestTime.restart();
|
Chris@253
|
67 }
|
Chris@253
|
68 }
|
Chris@253
|
69
|
Chris@806
|
70 View::modelChangedWithin(startFrame, endFrame);
|
Chris@173
|
71 }
|
Chris@173
|
72
|
Chris@173
|
73 void
|
Chris@173
|
74 Overview::modelReplaced()
|
Chris@173
|
75 {
|
Chris@339
|
76 m_playPointerFrame = getAlignedPlaybackFrame();
|
Chris@173
|
77 View::modelReplaced();
|
Chris@173
|
78 }
|
Chris@173
|
79
|
Chris@173
|
80 void
|
Chris@211
|
81 Overview::registerView(View *view)
|
Chris@173
|
82 {
|
Chris@211
|
83 m_views.insert(view);
|
Chris@173
|
84 update();
|
Chris@173
|
85 }
|
Chris@173
|
86
|
Chris@173
|
87 void
|
Chris@211
|
88 Overview::unregisterView(View *view)
|
Chris@173
|
89 {
|
Chris@211
|
90 m_views.erase(view);
|
Chris@173
|
91 update();
|
Chris@173
|
92 }
|
Chris@173
|
93
|
Chris@173
|
94 void
|
Chris@806
|
95 Overview::globalCentreFrameChanged(int
|
Chris@806
|
96 #ifdef DEBUG_OVERVIEW
|
Chris@806
|
97 f
|
Chris@806
|
98 #endif
|
Chris@806
|
99 )
|
Chris@173
|
100 {
|
Chris@642
|
101 #ifdef DEBUG_OVERVIEW
|
Chris@682
|
102 cerr << "Overview::globalCentreFrameChanged: " << f << endl;
|
Chris@642
|
103 #endif
|
Chris@211
|
104 update();
|
Chris@211
|
105 }
|
Chris@173
|
106
|
Chris@211
|
107 void
|
Chris@806
|
108 Overview::viewCentreFrameChanged(View *v, int
|
Chris@806
|
109 #ifdef DEBUG_OVERVIEW
|
Chris@806
|
110 f
|
Chris@806
|
111 #endif
|
Chris@806
|
112 )
|
Chris@211
|
113 {
|
Chris@642
|
114 #ifdef DEBUG_OVERVIEW
|
Chris@682
|
115 cerr << "Overview[" << this << "]::viewCentreFrameChanged(" << v << "): " << f << endl;
|
Chris@642
|
116 #endif
|
Chris@211
|
117 if (m_views.find(v) != m_views.end()) {
|
Chris@173
|
118 update();
|
Chris@173
|
119 }
|
Chris@211
|
120 }
|
Chris@173
|
121
|
Chris@173
|
122 void
|
Chris@806
|
123 Overview::viewZoomLevelChanged(View *v, int, bool)
|
Chris@173
|
124 {
|
Chris@222
|
125 if (v == this) return;
|
Chris@211
|
126 if (m_views.find(v) != m_views.end()) {
|
Chris@173
|
127 update();
|
Chris@173
|
128 }
|
Chris@173
|
129 }
|
Chris@173
|
130
|
Chris@173
|
131 void
|
Chris@806
|
132 Overview::viewManagerPlaybackFrameChanged(int f)
|
Chris@173
|
133 {
|
Chris@642
|
134 #ifdef DEBUG_OVERVIEW
|
Chris@682
|
135 cerr << "Overview[" << this << "]::viewManagerPlaybackFrameChanged(" << f << "): " << f << endl;
|
Chris@642
|
136 #endif
|
Chris@642
|
137
|
Chris@173
|
138 bool changed = false;
|
Chris@173
|
139
|
Chris@339
|
140 f = getAlignedPlaybackFrame();
|
Chris@339
|
141
|
Chris@173
|
142 if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true;
|
Chris@173
|
143 m_playPointerFrame = f;
|
Chris@173
|
144
|
Chris@173
|
145 if (changed) update();
|
Chris@173
|
146 }
|
Chris@173
|
147
|
Chris@173
|
148 void
|
Chris@173
|
149 Overview::paintEvent(QPaintEvent *e)
|
Chris@173
|
150 {
|
Chris@173
|
151 // Recalculate zoom in case the size of the widget has changed.
|
Chris@173
|
152
|
Chris@642
|
153 #ifdef DEBUG_OVERVIEW
|
Chris@682
|
154 cerr << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << endl;
|
Chris@642
|
155 #endif
|
Chris@214
|
156
|
Chris@806
|
157 int startFrame = getModelsStartFrame();
|
Chris@806
|
158 int frameCount = getModelsEndFrame() - getModelsStartFrame();
|
Chris@173
|
159 int zoomLevel = frameCount / width();
|
Chris@173
|
160 if (zoomLevel < 1) zoomLevel = 1;
|
Chris@173
|
161 zoomLevel = getZoomConstraintBlockSize(zoomLevel,
|
Chris@173
|
162 ZoomConstraint::RoundUp);
|
Chris@173
|
163 if (zoomLevel != m_zoomLevel) {
|
Chris@173
|
164 m_zoomLevel = zoomLevel;
|
Chris@222
|
165 emit zoomLevelChanged(m_zoomLevel, m_followZoom);
|
Chris@173
|
166 }
|
Chris@253
|
167
|
Chris@806
|
168 int centreFrame = startFrame + m_zoomLevel * (width() / 2);
|
Chris@173
|
169 if (centreFrame > (startFrame + getModelsEndFrame())/2) {
|
Chris@173
|
170 centreFrame = (startFrame + getModelsEndFrame())/2;
|
Chris@173
|
171 }
|
Chris@173
|
172 if (centreFrame != m_centreFrame) {
|
Chris@642
|
173 #ifdef DEBUG_OVERVIEW
|
Chris@682
|
174 cerr << "Overview::paintEvent: Centre frame changed from "
|
Chris@642
|
175 << m_centreFrame << " to " << centreFrame << " and thus start frame from " << getStartFrame();
|
Chris@642
|
176 #endif
|
Chris@173
|
177 m_centreFrame = centreFrame;
|
Chris@642
|
178 #ifdef DEBUG_OVERVIEW
|
Chris@682
|
179 cerr << " to " << getStartFrame() << endl;
|
Chris@642
|
180 #endif
|
Chris@211
|
181 emit centreFrameChanged(m_centreFrame, false, PlaybackIgnore);
|
Chris@173
|
182 }
|
Chris@173
|
183
|
Chris@173
|
184 View::paintEvent(e);
|
Chris@173
|
185
|
Chris@173
|
186 QPainter paint;
|
Chris@173
|
187 paint.begin(this);
|
Chris@173
|
188
|
Chris@173
|
189 QRect r(rect());
|
Chris@173
|
190
|
Chris@173
|
191 if (e) {
|
Chris@173
|
192 r = e->rect();
|
Chris@173
|
193 paint.setClipRect(r);
|
Chris@173
|
194 }
|
Chris@173
|
195
|
Chris@287
|
196 paint.setPen(getForeground());
|
Chris@173
|
197
|
Chris@173
|
198 int y = 0;
|
Chris@173
|
199
|
Chris@173
|
200 int prevx0 = -10;
|
Chris@173
|
201 int prevx1 = -10;
|
Chris@173
|
202
|
Chris@211
|
203 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
|
Chris@173
|
204 if (!*i) continue;
|
Chris@173
|
205
|
Chris@173
|
206 View *w = (View *)*i;
|
Chris@173
|
207
|
Chris@806
|
208 int f0 = w->getFrameForX(0);
|
Chris@806
|
209 int f1 = w->getFrameForX(w->width());
|
Chris@173
|
210
|
Chris@339
|
211 if (f0 >= 0) {
|
Chris@806
|
212 int rf0 = w->alignToReference(f0);
|
Chris@339
|
213 f0 = alignFromReference(rf0);
|
Chris@339
|
214 }
|
Chris@339
|
215 if (f1 >= 0) {
|
Chris@806
|
216 int rf1 = w->alignToReference(f1);
|
Chris@339
|
217 f1 = alignFromReference(rf1);
|
Chris@339
|
218 }
|
Chris@339
|
219
|
Chris@173
|
220 int x0 = getXForFrame(f0);
|
Chris@173
|
221 int x1 = getXForFrame(f1);
|
Chris@173
|
222
|
Chris@173
|
223 if (x0 != prevx0 || x1 != prevx1) {
|
Chris@173
|
224 y += height() / 10 + 1;
|
Chris@173
|
225 prevx0 = x0;
|
Chris@173
|
226 prevx1 = x1;
|
Chris@173
|
227 }
|
Chris@173
|
228
|
Chris@173
|
229 if (x1 <= x0) x1 = x0 + 1;
|
Chris@173
|
230
|
Chris@173
|
231 paint.drawRect(x0, y, x1 - x0, height() - 2 * y);
|
Chris@173
|
232 }
|
Chris@173
|
233
|
Chris@173
|
234 paint.end();
|
Chris@173
|
235 }
|
Chris@173
|
236
|
Chris@173
|
237 void
|
Chris@173
|
238 Overview::mousePressEvent(QMouseEvent *e)
|
Chris@173
|
239 {
|
Chris@173
|
240 m_clickPos = e->pos();
|
Chris@806
|
241 int clickFrame = getFrameForX(m_clickPos.x());
|
Chris@339
|
242 if (clickFrame > 0) m_dragCentreFrame = clickFrame;
|
Chris@339
|
243 else m_dragCentreFrame = 0;
|
Chris@339
|
244 m_clickedInRange = true;
|
Chris@339
|
245
|
Chris@211
|
246 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
|
Chris@339
|
247 if (*i && (*i)->getAligningModel() == getAligningModel()) {
|
Chris@339
|
248 m_dragCentreFrame = (*i)->getCentreFrame();
|
Chris@339
|
249 break;
|
Chris@339
|
250 }
|
Chris@173
|
251 }
|
Chris@173
|
252 }
|
Chris@173
|
253
|
Chris@173
|
254 void
|
Chris@173
|
255 Overview::mouseReleaseEvent(QMouseEvent *e)
|
Chris@173
|
256 {
|
Chris@173
|
257 if (m_clickedInRange) {
|
Chris@173
|
258 mouseMoveEvent(e);
|
Chris@173
|
259 }
|
Chris@173
|
260 m_clickedInRange = false;
|
Chris@173
|
261 }
|
Chris@173
|
262
|
Chris@173
|
263 void
|
Chris@173
|
264 Overview::mouseMoveEvent(QMouseEvent *e)
|
Chris@173
|
265 {
|
Chris@173
|
266 if (!m_clickedInRange) return;
|
Chris@173
|
267
|
Chris@806
|
268 int xoff = int(e->x()) - int(m_clickPos.x());
|
Chris@806
|
269 int frameOff = xoff * m_zoomLevel;
|
Chris@173
|
270
|
Chris@806
|
271 int newCentreFrame = m_dragCentreFrame;
|
Chris@173
|
272 if (frameOff > 0) {
|
Chris@173
|
273 newCentreFrame += frameOff;
|
Chris@806
|
274 } else if (newCentreFrame >= int(-frameOff)) {
|
Chris@173
|
275 newCentreFrame += frameOff;
|
Chris@173
|
276 } else {
|
Chris@173
|
277 newCentreFrame = 0;
|
Chris@173
|
278 }
|
Chris@173
|
279
|
Chris@173
|
280 if (newCentreFrame >= getModelsEndFrame()) {
|
Chris@173
|
281 newCentreFrame = getModelsEndFrame();
|
Chris@173
|
282 if (newCentreFrame > 0) --newCentreFrame;
|
Chris@173
|
283 }
|
Chris@173
|
284
|
Chris@173
|
285 if (std::max(m_centreFrame, newCentreFrame) -
|
Chris@806
|
286 std::min(m_centreFrame, newCentreFrame) > int(m_zoomLevel)) {
|
Chris@806
|
287 int rf = alignToReference(newCentreFrame);
|
Chris@643
|
288 #ifdef DEBUG_OVERVIEW
|
Chris@682
|
289 cerr << "Overview::mouseMoveEvent: x " << e->x() << " and click x " << m_clickPos.x() << " -> frame " << newCentreFrame << " -> rf " << rf << endl;
|
Chris@643
|
290 #endif
|
Chris@339
|
291 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
|
Chris@173
|
292 }
|
Chris@173
|
293 }
|
Chris@173
|
294
|
Chris@189
|
295 void
|
Chris@189
|
296 Overview::mouseDoubleClickEvent(QMouseEvent *e)
|
Chris@189
|
297 {
|
Chris@806
|
298 int frame = getFrameForX(e->x());
|
Chris@806
|
299 int rf = 0;
|
Chris@339
|
300 if (frame > 0) rf = alignToReference(frame);
|
Chris@643
|
301 #ifdef DEBUG_OVERVIEW
|
Chris@682
|
302 cerr << "Overview::mouseDoubleClickEvent: frame " << frame << " -> rf " << rf << endl;
|
Chris@643
|
303 #endif
|
Chris@643
|
304 m_clickedInRange = false; // we're not starting a drag with the second click
|
Chris@339
|
305 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
|
Chris@189
|
306 }
|
Chris@173
|
307
|
Chris@189
|
308 void
|
Chris@189
|
309 Overview::enterEvent(QEvent *)
|
Chris@189
|
310 {
|
Chris@189
|
311 emit contextHelpChanged(tr("Click and drag to navigate; double-click to jump"));
|
Chris@189
|
312 }
|
Chris@189
|
313
|
Chris@189
|
314 void
|
Chris@189
|
315 Overview::leaveEvent(QEvent *)
|
Chris@189
|
316 {
|
Chris@189
|
317 emit contextHelpChanged("");
|
Chris@189
|
318 }
|
Chris@189
|
319
|
Chris@189
|
320
|