annotate view/Overview.cpp @ 959:2633a1d73e39

Address #1214, layer import produces wrong layer type. We needed a more principled approach to making sure the format gets updated properly and the dialog elements are consistent (basically separating making the dialog elements consistent from subsequently updating the format). This change should provide that, though there may be gotchas still.
author Chris Cannam
date Tue, 12 May 2015 12:31:37 +0100
parents 1c529a22a6a7
children 73b0dc7d6ec1
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@173 28 Overview::Overview(QWidget *w) :
Chris@173 29 View(w, false),
Chris@854 30 m_clickedInRange(false),
Chris@854 31 m_dragCentreFrame(0)
Chris@173 32 {
Chris@173 33 setObjectName(tr("Overview"));
Chris@173 34 m_followPan = false;
Chris@173 35 m_followZoom = false;
Chris@211 36 setPlaybackFollow(PlaybackIgnore);
Chris@274 37 m_modelTestTime.start();
Chris@173 38 }
Chris@173 39
Chris@173 40 void
Chris@908 41 Overview::modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame)
Chris@173 42 {
Chris@253 43 bool zoomChanged = false;
Chris@253 44
Chris@908 45 sv_frame_t frameCount = getModelsEndFrame() - getModelsStartFrame();
Chris@908 46 int zoomLevel = int(frameCount / width());
Chris@253 47 if (zoomLevel < 1) zoomLevel = 1;
Chris@253 48 zoomLevel = getZoomConstraintBlockSize(zoomLevel,
Chris@253 49 ZoomConstraint::RoundUp);
Chris@253 50 if (zoomLevel != m_zoomLevel) {
Chris@253 51 zoomChanged = true;
Chris@253 52 }
Chris@253 53
Chris@253 54 if (!zoomChanged) {
Chris@274 55 if (m_modelTestTime.elapsed() < 1000) {
Chris@835 56 for (LayerList::const_iterator i = m_layerStack.begin();
Chris@835 57 i != m_layerStack.end(); ++i) {
Chris@274 58 if ((*i)->getModel() &&
Chris@389 59 (!(*i)->getModel()->isOK() ||
Chris@389 60 !(*i)->getModel()->isReady())) {
Chris@274 61 return;
Chris@274 62 }
Chris@253 63 }
Chris@274 64 } else {
Chris@274 65 m_modelTestTime.restart();
Chris@253 66 }
Chris@253 67 }
Chris@253 68
Chris@806 69 View::modelChangedWithin(startFrame, endFrame);
Chris@173 70 }
Chris@173 71
Chris@173 72 void
Chris@173 73 Overview::modelReplaced()
Chris@173 74 {
Chris@339 75 m_playPointerFrame = getAlignedPlaybackFrame();
Chris@173 76 View::modelReplaced();
Chris@173 77 }
Chris@173 78
Chris@173 79 void
Chris@211 80 Overview::registerView(View *view)
Chris@173 81 {
Chris@211 82 m_views.insert(view);
Chris@173 83 update();
Chris@173 84 }
Chris@173 85
Chris@173 86 void
Chris@211 87 Overview::unregisterView(View *view)
Chris@173 88 {
Chris@211 89 m_views.erase(view);
Chris@173 90 update();
Chris@173 91 }
Chris@173 92
Chris@173 93 void
Chris@908 94 Overview::globalCentreFrameChanged(sv_frame_t
Chris@806 95 #ifdef DEBUG_OVERVIEW
Chris@806 96 f
Chris@806 97 #endif
Chris@806 98 )
Chris@173 99 {
Chris@642 100 #ifdef DEBUG_OVERVIEW
Chris@682 101 cerr << "Overview::globalCentreFrameChanged: " << f << endl;
Chris@642 102 #endif
Chris@211 103 update();
Chris@211 104 }
Chris@173 105
Chris@211 106 void
Chris@908 107 Overview::viewCentreFrameChanged(View *v, sv_frame_t
Chris@806 108 #ifdef DEBUG_OVERVIEW
Chris@806 109 f
Chris@806 110 #endif
Chris@806 111 )
Chris@211 112 {
Chris@642 113 #ifdef DEBUG_OVERVIEW
Chris@682 114 cerr << "Overview[" << this << "]::viewCentreFrameChanged(" << v << "): " << f << endl;
Chris@642 115 #endif
Chris@211 116 if (m_views.find(v) != m_views.end()) {
Chris@173 117 update();
Chris@173 118 }
Chris@211 119 }
Chris@173 120
Chris@173 121 void
Chris@806 122 Overview::viewZoomLevelChanged(View *v, int, bool)
Chris@173 123 {
Chris@222 124 if (v == this) return;
Chris@211 125 if (m_views.find(v) != m_views.end()) {
Chris@173 126 update();
Chris@173 127 }
Chris@173 128 }
Chris@173 129
Chris@173 130 void
Chris@908 131 Overview::viewManagerPlaybackFrameChanged(sv_frame_t f)
Chris@173 132 {
Chris@642 133 #ifdef DEBUG_OVERVIEW
Chris@682 134 cerr << "Overview[" << this << "]::viewManagerPlaybackFrameChanged(" << f << "): " << f << endl;
Chris@642 135 #endif
Chris@642 136
Chris@173 137 bool changed = false;
Chris@173 138
Chris@339 139 f = getAlignedPlaybackFrame();
Chris@339 140
Chris@173 141 if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true;
Chris@173 142 m_playPointerFrame = f;
Chris@173 143
Chris@173 144 if (changed) update();
Chris@173 145 }
Chris@173 146
Chris@871 147 QColor
Chris@871 148 Overview::getFillWithin() const
Chris@871 149 {
Chris@871 150 return Qt::transparent;
Chris@871 151 }
Chris@871 152
Chris@871 153 QColor
Chris@871 154 Overview::getFillWithout() const
Chris@871 155 {
Chris@871 156 QColor c = palette().window().color();
Chris@871 157 c.setAlpha(100);
Chris@871 158 return c;
Chris@871 159 }
Chris@871 160
Chris@173 161 void
Chris@173 162 Overview::paintEvent(QPaintEvent *e)
Chris@173 163 {
Chris@173 164 // Recalculate zoom in case the size of the widget has changed.
Chris@173 165
Chris@642 166 #ifdef DEBUG_OVERVIEW
Chris@682 167 cerr << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << endl;
Chris@642 168 #endif
Chris@214 169
Chris@908 170 sv_frame_t startFrame = getModelsStartFrame();
Chris@908 171 sv_frame_t frameCount = getModelsEndFrame() - getModelsStartFrame();
Chris@908 172 int zoomLevel = int(frameCount / width());
Chris@173 173 if (zoomLevel < 1) zoomLevel = 1;
Chris@173 174 zoomLevel = getZoomConstraintBlockSize(zoomLevel,
Chris@173 175 ZoomConstraint::RoundUp);
Chris@173 176 if (zoomLevel != m_zoomLevel) {
Chris@173 177 m_zoomLevel = zoomLevel;
Chris@222 178 emit zoomLevelChanged(m_zoomLevel, m_followZoom);
Chris@173 179 }
Chris@253 180
Chris@908 181 sv_frame_t centreFrame = startFrame + m_zoomLevel * (width() / 2);
Chris@173 182 if (centreFrame > (startFrame + getModelsEndFrame())/2) {
Chris@173 183 centreFrame = (startFrame + getModelsEndFrame())/2;
Chris@173 184 }
Chris@173 185 if (centreFrame != m_centreFrame) {
Chris@642 186 #ifdef DEBUG_OVERVIEW
Chris@682 187 cerr << "Overview::paintEvent: Centre frame changed from "
Chris@642 188 << m_centreFrame << " to " << centreFrame << " and thus start frame from " << getStartFrame();
Chris@642 189 #endif
Chris@173 190 m_centreFrame = centreFrame;
Chris@642 191 #ifdef DEBUG_OVERVIEW
Chris@682 192 cerr << " to " << getStartFrame() << endl;
Chris@642 193 #endif
Chris@211 194 emit centreFrameChanged(m_centreFrame, false, PlaybackIgnore);
Chris@173 195 }
Chris@173 196
Chris@173 197 View::paintEvent(e);
Chris@173 198
Chris@173 199 QPainter paint;
Chris@173 200 paint.begin(this);
Chris@871 201 paint.setClipRegion(e->region());
Chris@871 202 paint.setRenderHints(QPainter::Antialiasing);
Chris@871 203
Chris@173 204 QRect r(rect());
Chris@173 205
Chris@871 206 // We paint a rounded rect for each distinct set of view extents,
Chris@871 207 // and we colour in the inside and outside of the rect that
Chris@871 208 // corresponds to the current view. (One small caveat -- we don't
Chris@871 209 // know which rect that is yet. We'll have to figure it out
Chris@871 210 // somehow...)
Chris@173 211
Chris@871 212 std::set<std::pair<int, int> > extents;
Chris@871 213 std::vector<QRect> rects;
Chris@871 214 QRect primary;
Chris@173 215
Chris@173 216 int y = 0;
Chris@173 217
Chris@211 218 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
Chris@173 219 if (!*i) continue;
Chris@173 220
Chris@173 221 View *w = (View *)*i;
Chris@173 222
Chris@908 223 sv_frame_t f0 = w->getFrameForX(0);
Chris@908 224 sv_frame_t f1 = w->getFrameForX(w->width());
Chris@173 225
Chris@339 226 if (f0 >= 0) {
Chris@908 227 sv_frame_t rf0 = w->alignToReference(f0);
Chris@339 228 f0 = alignFromReference(rf0);
Chris@339 229 }
Chris@339 230 if (f1 >= 0) {
Chris@908 231 sv_frame_t rf1 = w->alignToReference(f1);
Chris@339 232 f1 = alignFromReference(rf1);
Chris@339 233 }
Chris@339 234
Chris@173 235 int x0 = getXForFrame(f0);
Chris@173 236 int x1 = getXForFrame(f1);
Chris@173 237
matthiasm@935 238
Chris@871 239 if (x1 <= x0) x1 = x0 + 1;
Chris@871 240
Chris@871 241 std::pair<int, int> extent(x0, x1);
Chris@871 242
Chris@871 243 if (extents.find(extent) == extents.end()) {
Chris@871 244
matthiasm@935 245 y += height() / 10 + 1;
Chris@871 246 extents.insert(extent);
Chris@173 247
Chris@871 248 QRect vr(x0, y, x1 - x0, height() - 2 * y);
Chris@871 249 rects.push_back(vr);
Chris@871 250 primary = vr; //!!! for now
Chris@871 251 }
Chris@871 252 }
Chris@871 253
Chris@871 254 QPainterPath without;
matthiasm@935 255 without.addRoundedRect(primary, 4, 4);
Chris@871 256 without.addRect(rect());
Chris@871 257 paint.setPen(Qt::NoPen);
Chris@871 258 paint.setBrush(getFillWithout());
Chris@871 259 paint.drawPath(without);
Chris@871 260
Chris@871 261 paint.setBrush(getFillWithin());
matthiasm@935 262 paint.drawRoundedRect(primary, 4, 4);
Chris@871 263
Chris@871 264 foreach (QRect vr, rects) {
Chris@871 265 paint.setBrush(Qt::NoBrush);
matthiasm@935 266 paint.setPen(QPen(Qt::gray, 2));
matthiasm@935 267 paint.drawRoundedRect(vr, 4, 4);
Chris@173 268 }
Chris@173 269
Chris@173 270 paint.end();
Chris@173 271 }
Chris@173 272
Chris@173 273 void
Chris@173 274 Overview::mousePressEvent(QMouseEvent *e)
Chris@173 275 {
Chris@173 276 m_clickPos = e->pos();
Chris@908 277 sv_frame_t clickFrame = getFrameForX(m_clickPos.x());
Chris@339 278 if (clickFrame > 0) m_dragCentreFrame = clickFrame;
Chris@339 279 else m_dragCentreFrame = 0;
Chris@339 280 m_clickedInRange = true;
Chris@339 281
Chris@211 282 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
Chris@339 283 if (*i && (*i)->getAligningModel() == getAligningModel()) {
Chris@339 284 m_dragCentreFrame = (*i)->getCentreFrame();
Chris@339 285 break;
Chris@339 286 }
Chris@173 287 }
Chris@173 288 }
Chris@173 289
Chris@173 290 void
Chris@173 291 Overview::mouseReleaseEvent(QMouseEvent *e)
Chris@173 292 {
Chris@173 293 if (m_clickedInRange) {
Chris@173 294 mouseMoveEvent(e);
Chris@173 295 }
Chris@173 296 m_clickedInRange = false;
Chris@173 297 }
Chris@173 298
Chris@173 299 void
Chris@173 300 Overview::mouseMoveEvent(QMouseEvent *e)
Chris@173 301 {
Chris@173 302 if (!m_clickedInRange) return;
Chris@173 303
Chris@806 304 int xoff = int(e->x()) - int(m_clickPos.x());
Chris@908 305 sv_frame_t frameOff = xoff * m_zoomLevel;
Chris@173 306
Chris@908 307 sv_frame_t newCentreFrame = m_dragCentreFrame;
Chris@173 308 if (frameOff > 0) {
Chris@173 309 newCentreFrame += frameOff;
Chris@908 310 } else if (newCentreFrame >= -frameOff) {
Chris@173 311 newCentreFrame += frameOff;
Chris@173 312 } else {
Chris@173 313 newCentreFrame = 0;
Chris@173 314 }
Chris@173 315
Chris@173 316 if (newCentreFrame >= getModelsEndFrame()) {
Chris@173 317 newCentreFrame = getModelsEndFrame();
Chris@173 318 if (newCentreFrame > 0) --newCentreFrame;
Chris@173 319 }
Chris@173 320
Chris@173 321 if (std::max(m_centreFrame, newCentreFrame) -
Chris@908 322 std::min(m_centreFrame, newCentreFrame) > m_zoomLevel) {
Chris@908 323 sv_frame_t rf = alignToReference(newCentreFrame);
Chris@643 324 #ifdef DEBUG_OVERVIEW
Chris@682 325 cerr << "Overview::mouseMoveEvent: x " << e->x() << " and click x " << m_clickPos.x() << " -> frame " << newCentreFrame << " -> rf " << rf << endl;
Chris@643 326 #endif
Chris@817 327 if (m_followPlay == PlaybackScrollContinuous ||
Chris@817 328 m_followPlay == PlaybackScrollPageWithCentre) {
Chris@817 329 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
Chris@817 330 } else {
Chris@817 331 emit centreFrameChanged(rf, true, PlaybackIgnore);
Chris@817 332 }
Chris@173 333 }
Chris@173 334 }
Chris@173 335
Chris@189 336 void
Chris@189 337 Overview::mouseDoubleClickEvent(QMouseEvent *e)
Chris@189 338 {
Chris@908 339 sv_frame_t frame = getFrameForX(e->x());
Chris@908 340 sv_frame_t rf = 0;
Chris@339 341 if (frame > 0) rf = alignToReference(frame);
Chris@643 342 #ifdef DEBUG_OVERVIEW
Chris@682 343 cerr << "Overview::mouseDoubleClickEvent: frame " << frame << " -> rf " << rf << endl;
Chris@643 344 #endif
Chris@643 345 m_clickedInRange = false; // we're not starting a drag with the second click
Chris@339 346 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
Chris@189 347 }
Chris@173 348
Chris@189 349 void
Chris@189 350 Overview::enterEvent(QEvent *)
Chris@189 351 {
Chris@189 352 emit contextHelpChanged(tr("Click and drag to navigate; double-click to jump"));
Chris@189 353 }
Chris@189 354
Chris@189 355 void
Chris@189 356 Overview::leaveEvent(QEvent *)
Chris@189 357 {
Chris@189 358 emit contextHelpChanged("");
Chris@189 359 }
Chris@189 360
Chris@189 361