svgui  1.9
Overview.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "Overview.h"
00017 #include "layer/Layer.h"
00018 #include "data/model/Model.h"
00019 #include "base/ZoomConstraint.h"
00020 
00021 #include <QPaintEvent>
00022 #include <QPainter>
00023 #include <iostream>
00024 
00025 //#define DEBUG_OVERVIEW 1
00026 
00027 
00028 Overview::Overview(QWidget *w) :
00029     View(w, false),
00030     m_clickedInRange(false),
00031     m_dragCentreFrame(0)
00032 {
00033     setObjectName(tr("Overview"));
00034     m_followPan = false;
00035     m_followZoom = false;
00036     setPlaybackFollow(PlaybackIgnore);
00037     m_modelTestTime.start();
00038 }
00039 
00040 void
00041 Overview::modelChangedWithin(int startFrame, int endFrame)
00042 {
00043     bool zoomChanged = false;
00044 
00045     int frameCount = getModelsEndFrame() - getModelsStartFrame();
00046     int zoomLevel = frameCount / width();
00047     if (zoomLevel < 1) zoomLevel = 1;
00048     zoomLevel = getZoomConstraintBlockSize(zoomLevel,
00049                                            ZoomConstraint::RoundUp);
00050     if (zoomLevel != m_zoomLevel) {
00051         zoomChanged = true;
00052     }
00053 
00054     if (!zoomChanged) {
00055         if (m_modelTestTime.elapsed() < 1000) {
00056             for (LayerList::const_iterator i = m_layerStack.begin();
00057                  i != m_layerStack.end(); ++i) {
00058                 if ((*i)->getModel() &&
00059                     (!(*i)->getModel()->isOK() ||
00060                      !(*i)->getModel()->isReady())) {
00061                     return;
00062                 }
00063             }
00064         } else {
00065             m_modelTestTime.restart();
00066         }
00067     }
00068 
00069     View::modelChangedWithin(startFrame, endFrame);
00070 }
00071 
00072 void
00073 Overview::modelReplaced()
00074 {
00075     m_playPointerFrame = getAlignedPlaybackFrame();
00076     View::modelReplaced();
00077 }
00078 
00079 void
00080 Overview::registerView(View *view)
00081 {
00082     m_views.insert(view);
00083     update(); 
00084 }
00085 
00086 void
00087 Overview::unregisterView(View *view)
00088 {
00089     m_views.erase(view);
00090     update();
00091 }
00092 
00093 void
00094 Overview::globalCentreFrameChanged(int 
00095 #ifdef DEBUG_OVERVIEW
00096                                    f
00097 #endif
00098     )
00099 {
00100 #ifdef DEBUG_OVERVIEW
00101     cerr << "Overview::globalCentreFrameChanged: " << f << endl;
00102 #endif
00103     update();
00104 }
00105 
00106 void
00107 Overview::viewCentreFrameChanged(View *v, int
00108 #ifdef DEBUG_OVERVIEW
00109                                  f
00110 #endif
00111     )
00112 {
00113 #ifdef DEBUG_OVERVIEW
00114     cerr << "Overview[" << this << "]::viewCentreFrameChanged(" << v << "): " << f << endl;
00115 #endif
00116     if (m_views.find(v) != m_views.end()) {
00117         update();
00118     }
00119 }    
00120 
00121 void
00122 Overview::viewZoomLevelChanged(View *v, int, bool)
00123 {
00124     if (v == this) return;
00125     if (m_views.find(v) != m_views.end()) {
00126         update();
00127     }
00128 }
00129 
00130 void
00131 Overview::viewManagerPlaybackFrameChanged(int f)
00132 {
00133 #ifdef DEBUG_OVERVIEW
00134     cerr << "Overview[" << this << "]::viewManagerPlaybackFrameChanged(" << f << "): " << f << endl;
00135 #endif
00136 
00137     bool changed = false;
00138 
00139     f = getAlignedPlaybackFrame();
00140 
00141     if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true;
00142     m_playPointerFrame = f;
00143 
00144     if (changed) update();
00145 }
00146 
00147 void
00148 Overview::paintEvent(QPaintEvent *e)
00149 {
00150     // Recalculate zoom in case the size of the widget has changed.
00151 
00152 #ifdef DEBUG_OVERVIEW
00153     cerr << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << endl;
00154 #endif
00155 
00156     int startFrame = getModelsStartFrame();
00157     int frameCount = getModelsEndFrame() - getModelsStartFrame();
00158     int zoomLevel = frameCount / width();
00159     if (zoomLevel < 1) zoomLevel = 1;
00160     zoomLevel = getZoomConstraintBlockSize(zoomLevel,
00161                                            ZoomConstraint::RoundUp);
00162     if (zoomLevel != m_zoomLevel) {
00163         m_zoomLevel = zoomLevel;
00164         emit zoomLevelChanged(m_zoomLevel, m_followZoom);
00165     }
00166 
00167     int centreFrame = startFrame + m_zoomLevel * (width() / 2);
00168     if (centreFrame > (startFrame + getModelsEndFrame())/2) {
00169         centreFrame = (startFrame + getModelsEndFrame())/2;
00170     }
00171     if (centreFrame != m_centreFrame) {
00172 #ifdef DEBUG_OVERVIEW
00173         cerr << "Overview::paintEvent: Centre frame changed from "
00174                   << m_centreFrame << " to " << centreFrame << " and thus start frame from " << getStartFrame();
00175 #endif
00176         m_centreFrame = centreFrame;
00177 #ifdef DEBUG_OVERVIEW
00178         cerr << " to " << getStartFrame() << endl;
00179 #endif
00180         emit centreFrameChanged(m_centreFrame, false, PlaybackIgnore);
00181     }
00182 
00183     View::paintEvent(e);
00184 
00185     QPainter paint;
00186     paint.begin(this);
00187 
00188     QRect r(rect());
00189 
00190     if (e) {
00191         r = e->rect();
00192         paint.setClipRect(r);
00193     }
00194 
00195     paint.setPen(getForeground());
00196 
00197     int y = 0;
00198 
00199     int prevx0 = -10;
00200     int prevx1 = -10;
00201 
00202     for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
00203         if (!*i) continue;
00204 
00205         View *w = (View *)*i;
00206 
00207         int f0 = w->getFrameForX(0);
00208         int f1 = w->getFrameForX(w->width());
00209 
00210         if (f0 >= 0) {
00211             int rf0 = w->alignToReference(f0);
00212             f0 = alignFromReference(rf0);
00213         }
00214         if (f1 >= 0) {
00215             int rf1 = w->alignToReference(f1);
00216             f1 = alignFromReference(rf1);
00217         }
00218 
00219         int x0 = getXForFrame(f0);
00220         int x1 = getXForFrame(f1);
00221 
00222         if (x0 != prevx0 || x1 != prevx1) {
00223             y += height() / 10 + 1;
00224             prevx0 = x0;
00225             prevx1 = x1;
00226         }
00227 
00228         if (x1 <= x0) x1 = x0 + 1;
00229         
00230         paint.drawRect(x0, y, x1 - x0, height() - 2 * y);
00231     }
00232 
00233     paint.end();
00234 }
00235 
00236 void
00237 Overview::mousePressEvent(QMouseEvent *e)
00238 {
00239     m_clickPos = e->pos();
00240     int clickFrame = getFrameForX(m_clickPos.x());
00241     if (clickFrame > 0) m_dragCentreFrame = clickFrame;
00242     else m_dragCentreFrame = 0;
00243     m_clickedInRange = true;
00244 
00245     for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
00246         if (*i && (*i)->getAligningModel() == getAligningModel()) {
00247             m_dragCentreFrame = (*i)->getCentreFrame();
00248             break;
00249         }
00250     }
00251 }
00252 
00253 void
00254 Overview::mouseReleaseEvent(QMouseEvent *e)
00255 {
00256     if (m_clickedInRange) {
00257         mouseMoveEvent(e);
00258     }
00259     m_clickedInRange = false;
00260 }
00261 
00262 void
00263 Overview::mouseMoveEvent(QMouseEvent *e)
00264 {
00265     if (!m_clickedInRange) return;
00266 
00267     int xoff = int(e->x()) - int(m_clickPos.x());
00268     int frameOff = xoff * m_zoomLevel;
00269     
00270     int newCentreFrame = m_dragCentreFrame;
00271     if (frameOff > 0) {
00272         newCentreFrame += frameOff;
00273     } else if (newCentreFrame >= int(-frameOff)) {
00274         newCentreFrame += frameOff;
00275     } else {
00276         newCentreFrame = 0;
00277     }
00278 
00279     if (newCentreFrame >= getModelsEndFrame()) {
00280         newCentreFrame = getModelsEndFrame();
00281         if (newCentreFrame > 0) --newCentreFrame;
00282     }
00283     
00284     if (std::max(m_centreFrame, newCentreFrame) -
00285         std::min(m_centreFrame, newCentreFrame) > int(m_zoomLevel)) {
00286         int rf = alignToReference(newCentreFrame);
00287 #ifdef DEBUG_OVERVIEW
00288         cerr << "Overview::mouseMoveEvent: x " << e->x() << " and click x " << m_clickPos.x() << " -> frame " << newCentreFrame << " -> rf " << rf << endl;
00289 #endif
00290         if (m_followPlay == PlaybackScrollContinuous ||
00291             m_followPlay == PlaybackScrollPageWithCentre) {
00292             emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
00293         } else {
00294             emit centreFrameChanged(rf, true, PlaybackIgnore);
00295         }            
00296     }
00297 }
00298 
00299 void
00300 Overview::mouseDoubleClickEvent(QMouseEvent *e)
00301 {
00302     int frame = getFrameForX(e->x());
00303     int rf = 0;
00304     if (frame > 0) rf = alignToReference(frame);
00305 #ifdef DEBUG_OVERVIEW
00306     cerr << "Overview::mouseDoubleClickEvent: frame " << frame << " -> rf " << rf << endl;
00307 #endif
00308     m_clickedInRange = false; // we're not starting a drag with the second click
00309     emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
00310 }
00311 
00312 void
00313 Overview::enterEvent(QEvent *)
00314 {
00315     emit contextHelpChanged(tr("Click and drag to navigate; double-click to jump"));
00316 }
00317 
00318 void
00319 Overview::leaveEvent(QEvent *)
00320 {
00321     emit contextHelpChanged("");
00322 }
00323 
00324