annotate view/Overview.cpp @ 643:77fa3fdbfc7e sv_v2.1

Fix bug that caused overview to jump back to its original position after moving on double-click
author Chris Cannam
date Thu, 16 May 2013 13:11:13 +0100
parents 2c35737cd3f8
children 1a0dfcbffaf1
rev   line source
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@173 27 using std::cerr;
Chris@173 28 using std::endl;
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@173 42 Overview::modelChanged(size_t startFrame, size_t endFrame)
Chris@173 43 {
Chris@253 44 bool zoomChanged = false;
Chris@253 45
Chris@253 46 size_t 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@173 70 View::modelChanged(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@642 95 Overview::globalCentreFrameChanged(unsigned long f)
Chris@173 96 {
Chris@642 97 #ifdef DEBUG_OVERVIEW
Chris@642 98 std::cerr << "Overview::globalCentreFrameChanged: " << f << std::endl;
Chris@642 99 #endif
Chris@211 100 update();
Chris@211 101 }
Chris@173 102
Chris@211 103 void
Chris@642 104 Overview::viewCentreFrameChanged(View *v, unsigned long f)
Chris@211 105 {
Chris@642 106 #ifdef DEBUG_OVERVIEW
Chris@642 107 std::cerr << "Overview[" << this << "]::viewCentreFrameChanged(" << v << "): " << f << std::endl;
Chris@642 108 #endif
Chris@211 109 if (m_views.find(v) != m_views.end()) {
Chris@173 110 update();
Chris@173 111 }
Chris@211 112 }
Chris@173 113
Chris@173 114 void
Chris@248 115 Overview::viewZoomLevelChanged(View *v, unsigned long, bool)
Chris@173 116 {
Chris@222 117 if (v == this) return;
Chris@211 118 if (m_views.find(v) != m_views.end()) {
Chris@173 119 update();
Chris@173 120 }
Chris@173 121 }
Chris@173 122
Chris@173 123 void
Chris@173 124 Overview::viewManagerPlaybackFrameChanged(unsigned long f)
Chris@173 125 {
Chris@642 126 #ifdef DEBUG_OVERVIEW
Chris@642 127 std::cerr << "Overview[" << this << "]::viewManagerPlaybackFrameChanged(" << f << "): " << f << std::endl;
Chris@642 128 #endif
Chris@642 129
Chris@173 130 bool changed = false;
Chris@173 131
Chris@339 132 f = getAlignedPlaybackFrame();
Chris@339 133
Chris@173 134 if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true;
Chris@173 135 m_playPointerFrame = f;
Chris@173 136
Chris@173 137 if (changed) update();
Chris@173 138 }
Chris@173 139
Chris@173 140 void
Chris@173 141 Overview::paintEvent(QPaintEvent *e)
Chris@173 142 {
Chris@173 143 // Recalculate zoom in case the size of the widget has changed.
Chris@173 144
Chris@642 145 #ifdef DEBUG_OVERVIEW
Chris@642 146 std::cerr << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << std::endl;
Chris@642 147 #endif
Chris@214 148
Chris@173 149 size_t startFrame = getModelsStartFrame();
Chris@173 150 size_t frameCount = getModelsEndFrame() - getModelsStartFrame();
Chris@173 151 int zoomLevel = frameCount / width();
Chris@173 152 if (zoomLevel < 1) zoomLevel = 1;
Chris@173 153 zoomLevel = getZoomConstraintBlockSize(zoomLevel,
Chris@173 154 ZoomConstraint::RoundUp);
Chris@173 155 if (zoomLevel != m_zoomLevel) {
Chris@173 156 m_zoomLevel = zoomLevel;
Chris@222 157 emit zoomLevelChanged(m_zoomLevel, m_followZoom);
Chris@173 158 }
Chris@253 159
Chris@173 160 size_t centreFrame = startFrame + m_zoomLevel * (width() / 2);
Chris@173 161 if (centreFrame > (startFrame + getModelsEndFrame())/2) {
Chris@173 162 centreFrame = (startFrame + getModelsEndFrame())/2;
Chris@173 163 }
Chris@173 164 if (centreFrame != m_centreFrame) {
Chris@642 165 #ifdef DEBUG_OVERVIEW
Chris@642 166 std::cerr << "Overview::paintEvent: Centre frame changed from "
Chris@642 167 << m_centreFrame << " to " << centreFrame << " and thus start frame from " << getStartFrame();
Chris@642 168 #endif
Chris@173 169 m_centreFrame = centreFrame;
Chris@642 170 #ifdef DEBUG_OVERVIEW
Chris@642 171 std::cerr << " to " << getStartFrame() << std::endl;
Chris@642 172 #endif
Chris@211 173 emit centreFrameChanged(m_centreFrame, false, PlaybackIgnore);
Chris@173 174 }
Chris@173 175
Chris@173 176 View::paintEvent(e);
Chris@173 177
Chris@173 178 QPainter paint;
Chris@173 179 paint.begin(this);
Chris@173 180
Chris@173 181 QRect r(rect());
Chris@173 182
Chris@173 183 if (e) {
Chris@173 184 r = e->rect();
Chris@173 185 paint.setClipRect(r);
Chris@173 186 }
Chris@173 187
Chris@287 188 paint.setPen(getForeground());
Chris@173 189
Chris@173 190 int y = 0;
Chris@173 191
Chris@173 192 int prevx0 = -10;
Chris@173 193 int prevx1 = -10;
Chris@173 194
Chris@211 195 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
Chris@173 196 if (!*i) continue;
Chris@173 197
Chris@173 198 View *w = (View *)*i;
Chris@173 199
Chris@173 200 long f0 = w->getFrameForX(0);
Chris@173 201 long f1 = w->getFrameForX(w->width());
Chris@173 202
Chris@339 203 if (f0 >= 0) {
Chris@339 204 size_t rf0 = w->alignToReference(f0);
Chris@339 205 f0 = alignFromReference(rf0);
Chris@339 206 }
Chris@339 207 if (f1 >= 0) {
Chris@339 208 size_t rf1 = w->alignToReference(f1);
Chris@339 209 f1 = alignFromReference(rf1);
Chris@339 210 }
Chris@339 211
Chris@173 212 int x0 = getXForFrame(f0);
Chris@173 213 int x1 = getXForFrame(f1);
Chris@173 214
Chris@173 215 if (x0 != prevx0 || x1 != prevx1) {
Chris@173 216 y += height() / 10 + 1;
Chris@173 217 prevx0 = x0;
Chris@173 218 prevx1 = x1;
Chris@173 219 }
Chris@173 220
Chris@173 221 if (x1 <= x0) x1 = x0 + 1;
Chris@173 222
Chris@173 223 paint.drawRect(x0, y, x1 - x0, height() - 2 * y);
Chris@173 224 }
Chris@173 225
Chris@173 226 paint.end();
Chris@173 227 }
Chris@173 228
Chris@173 229 void
Chris@173 230 Overview::mousePressEvent(QMouseEvent *e)
Chris@173 231 {
Chris@173 232 m_clickPos = e->pos();
Chris@339 233 long clickFrame = getFrameForX(m_clickPos.x());
Chris@339 234 if (clickFrame > 0) m_dragCentreFrame = clickFrame;
Chris@339 235 else m_dragCentreFrame = 0;
Chris@339 236 m_clickedInRange = true;
Chris@339 237
Chris@211 238 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
Chris@339 239 if (*i && (*i)->getAligningModel() == getAligningModel()) {
Chris@339 240 m_dragCentreFrame = (*i)->getCentreFrame();
Chris@339 241 break;
Chris@339 242 }
Chris@173 243 }
Chris@173 244 }
Chris@173 245
Chris@173 246 void
Chris@173 247 Overview::mouseReleaseEvent(QMouseEvent *e)
Chris@173 248 {
Chris@173 249 if (m_clickedInRange) {
Chris@173 250 mouseMoveEvent(e);
Chris@173 251 }
Chris@173 252 m_clickedInRange = false;
Chris@173 253 }
Chris@173 254
Chris@173 255 void
Chris@173 256 Overview::mouseMoveEvent(QMouseEvent *e)
Chris@173 257 {
Chris@173 258 if (!m_clickedInRange) return;
Chris@173 259
Chris@173 260 long xoff = int(e->x()) - int(m_clickPos.x());
Chris@173 261 long frameOff = xoff * m_zoomLevel;
Chris@173 262
Chris@173 263 size_t newCentreFrame = m_dragCentreFrame;
Chris@173 264 if (frameOff > 0) {
Chris@173 265 newCentreFrame += frameOff;
Chris@173 266 } else if (newCentreFrame >= size_t(-frameOff)) {
Chris@173 267 newCentreFrame += frameOff;
Chris@173 268 } else {
Chris@173 269 newCentreFrame = 0;
Chris@173 270 }
Chris@173 271
Chris@173 272 if (newCentreFrame >= getModelsEndFrame()) {
Chris@173 273 newCentreFrame = getModelsEndFrame();
Chris@173 274 if (newCentreFrame > 0) --newCentreFrame;
Chris@173 275 }
Chris@173 276
Chris@173 277 if (std::max(m_centreFrame, newCentreFrame) -
Chris@173 278 std::min(m_centreFrame, newCentreFrame) > size_t(m_zoomLevel)) {
Chris@339 279 size_t rf = alignToReference(newCentreFrame);
Chris@643 280 #ifdef DEBUG_OVERVIEW
Chris@643 281 std::cerr << "Overview::mouseMoveEvent: x " << e->x() << " and click x " << m_clickPos.x() << " -> frame " << newCentreFrame << " -> rf " << rf << std::endl;
Chris@643 282 #endif
Chris@339 283 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
Chris@173 284 }
Chris@173 285 }
Chris@173 286
Chris@189 287 void
Chris@189 288 Overview::mouseDoubleClickEvent(QMouseEvent *e)
Chris@189 289 {
Chris@189 290 long frame = getFrameForX(e->x());
Chris@339 291 size_t rf = 0;
Chris@339 292 if (frame > 0) rf = alignToReference(frame);
Chris@643 293 #ifdef DEBUG_OVERVIEW
Chris@643 294 std::cerr << "Overview::mouseDoubleClickEvent: frame " << frame << " -> rf " << rf << std::endl;
Chris@643 295 #endif
Chris@643 296 m_clickedInRange = false; // we're not starting a drag with the second click
Chris@339 297 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
Chris@189 298 }
Chris@173 299
Chris@189 300 void
Chris@189 301 Overview::enterEvent(QEvent *)
Chris@189 302 {
Chris@189 303 emit contextHelpChanged(tr("Click and drag to navigate; double-click to jump"));
Chris@189 304 }
Chris@189 305
Chris@189 306 void
Chris@189 307 Overview::leaveEvent(QEvent *)
Chris@189 308 {
Chris@189 309 emit contextHelpChanged("");
Chris@189 310 }
Chris@189 311
Chris@189 312