annotate view/Overview.cpp @ 789:9fd1bdf214dd tonioni

Play pointer: when user drags pane during playback such that the pointer is no longer visible, accept that and stop trying to track it until pointer naturally comes back within visible area
author Chris Cannam
date Thu, 12 Jun 2014 12:48:11 +0100
parents cf1e8a1abb7b
children 0ba792bb235b
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@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@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@682 98 cerr << "Overview::globalCentreFrameChanged: " << f << 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@682 107 cerr << "Overview[" << this << "]::viewCentreFrameChanged(" << v << "): " << f << 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@682 127 cerr << "Overview[" << this << "]::viewManagerPlaybackFrameChanged(" << f << "): " << f << 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@682 146 cerr << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << 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@682 166 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@682 171 cerr << " to " << getStartFrame() << 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@682 281 cerr << "Overview::mouseMoveEvent: x " << e->x() << " and click x " << m_clickPos.x() << " -> frame " << newCentreFrame << " -> rf " << rf << endl;
Chris@643 282 #endif
Chris@788 283 emit centreFrameChanged(rf, true, PlaybackIgnore);
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@682 294 cerr << "Overview::mouseDoubleClickEvent: frame " << frame << " -> rf " << rf << 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