Chris@173: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@173: Chris@173: /* Chris@173: Sonic Visualiser Chris@173: An audio file viewer and annotation editor. Chris@173: Centre for Digital Music, Queen Mary, University of London. Chris@182: This file copyright 2006 Chris Cannam and QMUL. Chris@173: Chris@173: This program is free software; you can redistribute it and/or Chris@173: modify it under the terms of the GNU General Public License as Chris@173: published by the Free Software Foundation; either version 2 of the Chris@173: License, or (at your option) any later version. See the file Chris@173: COPYING included with this distribution for more information. Chris@173: */ Chris@173: Chris@173: #include "Overview.h" Chris@173: #include "layer/Layer.h" Chris@173: #include "data/model/Model.h" Chris@173: #include "base/ZoomConstraint.h" Chris@173: Chris@173: #include Chris@173: #include Chris@173: #include Chris@173: Chris@173: using std::cerr; Chris@173: using std::endl; Chris@173: Chris@173: Overview::Overview(QWidget *w) : Chris@173: View(w, false), Chris@173: m_clickedInRange(false) Chris@173: { Chris@173: setObjectName(tr("Overview")); Chris@173: m_followPan = false; Chris@173: m_followZoom = false; Chris@211: setPlaybackFollow(PlaybackIgnore); Chris@274: m_modelTestTime.start(); Chris@173: } Chris@173: Chris@173: void Chris@173: Overview::modelChanged(size_t startFrame, size_t endFrame) Chris@173: { Chris@253: bool zoomChanged = false; Chris@253: Chris@253: size_t frameCount = getModelsEndFrame() - getModelsStartFrame(); Chris@253: int zoomLevel = frameCount / width(); Chris@253: if (zoomLevel < 1) zoomLevel = 1; Chris@253: zoomLevel = getZoomConstraintBlockSize(zoomLevel, Chris@253: ZoomConstraint::RoundUp); Chris@253: if (zoomLevel != m_zoomLevel) { Chris@253: zoomChanged = true; Chris@253: } Chris@253: Chris@253: if (!zoomChanged) { Chris@274: if (m_modelTestTime.elapsed() < 1000) { Chris@274: for (LayerList::const_iterator i = m_layers.begin(); Chris@274: i != m_layers.end(); ++i) { Chris@274: if ((*i)->getModel() && Chris@389: (!(*i)->getModel()->isOK() || Chris@389: !(*i)->getModel()->isReady())) { Chris@274: return; Chris@274: } Chris@253: } Chris@274: } else { Chris@274: m_modelTestTime.restart(); Chris@253: } Chris@253: } Chris@253: Chris@173: View::modelChanged(startFrame, endFrame); Chris@173: } Chris@173: Chris@173: void Chris@173: Overview::modelReplaced() Chris@173: { Chris@339: m_playPointerFrame = getAlignedPlaybackFrame(); Chris@173: View::modelReplaced(); Chris@173: } Chris@173: Chris@173: void Chris@211: Overview::registerView(View *view) Chris@173: { Chris@211: m_views.insert(view); Chris@173: update(); Chris@173: } Chris@173: Chris@173: void Chris@211: Overview::unregisterView(View *view) Chris@173: { Chris@211: m_views.erase(view); Chris@173: update(); Chris@173: } Chris@173: Chris@173: void Chris@248: Overview::globalCentreFrameChanged(unsigned long) Chris@173: { Chris@211: update(); Chris@211: } Chris@173: Chris@211: void Chris@248: Overview::viewCentreFrameChanged(View *v, unsigned long) Chris@211: { Chris@211: if (m_views.find(v) != m_views.end()) { Chris@173: update(); Chris@173: } Chris@211: } Chris@173: Chris@173: void Chris@248: Overview::viewZoomLevelChanged(View *v, unsigned long, bool) Chris@173: { Chris@222: if (v == this) return; Chris@211: if (m_views.find(v) != m_views.end()) { Chris@173: update(); Chris@173: } Chris@173: } Chris@173: Chris@173: void Chris@173: Overview::viewManagerPlaybackFrameChanged(unsigned long f) Chris@173: { Chris@173: bool changed = false; Chris@173: Chris@339: f = getAlignedPlaybackFrame(); Chris@339: Chris@173: if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true; Chris@173: m_playPointerFrame = f; Chris@173: Chris@173: if (changed) update(); Chris@173: } Chris@173: Chris@173: void Chris@173: Overview::paintEvent(QPaintEvent *e) Chris@173: { Chris@173: // Recalculate zoom in case the size of the widget has changed. Chris@173: Chris@587: // SVDEBUG << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << endl; Chris@214: Chris@173: size_t startFrame = getModelsStartFrame(); Chris@173: size_t frameCount = getModelsEndFrame() - getModelsStartFrame(); Chris@173: int zoomLevel = frameCount / width(); Chris@173: if (zoomLevel < 1) zoomLevel = 1; Chris@173: zoomLevel = getZoomConstraintBlockSize(zoomLevel, Chris@173: ZoomConstraint::RoundUp); Chris@173: if (zoomLevel != m_zoomLevel) { Chris@173: m_zoomLevel = zoomLevel; Chris@222: emit zoomLevelChanged(m_zoomLevel, m_followZoom); Chris@173: } Chris@253: Chris@173: size_t centreFrame = startFrame + m_zoomLevel * (width() / 2); Chris@173: if (centreFrame > (startFrame + getModelsEndFrame())/2) { Chris@173: centreFrame = (startFrame + getModelsEndFrame())/2; Chris@173: } Chris@173: if (centreFrame != m_centreFrame) { Chris@587: // SVDEBUG << "Overview::paintEvent: Centre frame changed from " Chris@214: // << m_centreFrame << " to " << centreFrame << " and thus start frame from " << getStartFrame(); Chris@173: m_centreFrame = centreFrame; Chris@587: // SVDEBUG << " to " << getStartFrame() << endl; Chris@211: emit centreFrameChanged(m_centreFrame, false, PlaybackIgnore); Chris@173: } Chris@173: Chris@173: View::paintEvent(e); Chris@173: Chris@173: QPainter paint; Chris@173: paint.begin(this); Chris@173: Chris@173: QRect r(rect()); Chris@173: Chris@173: if (e) { Chris@173: r = e->rect(); Chris@173: paint.setClipRect(r); Chris@173: } Chris@173: Chris@287: paint.setPen(getForeground()); Chris@173: Chris@173: int y = 0; Chris@173: Chris@173: int prevx0 = -10; Chris@173: int prevx1 = -10; Chris@173: Chris@211: for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) { Chris@173: if (!*i) continue; Chris@173: Chris@173: View *w = (View *)*i; Chris@173: Chris@173: long f0 = w->getFrameForX(0); Chris@173: long f1 = w->getFrameForX(w->width()); Chris@173: Chris@339: if (f0 >= 0) { Chris@339: size_t rf0 = w->alignToReference(f0); Chris@339: f0 = alignFromReference(rf0); Chris@339: } Chris@339: if (f1 >= 0) { Chris@339: size_t rf1 = w->alignToReference(f1); Chris@339: f1 = alignFromReference(rf1); Chris@339: } Chris@339: Chris@173: int x0 = getXForFrame(f0); Chris@173: int x1 = getXForFrame(f1); Chris@173: Chris@173: if (x0 != prevx0 || x1 != prevx1) { Chris@173: y += height() / 10 + 1; Chris@173: prevx0 = x0; Chris@173: prevx1 = x1; Chris@173: } Chris@173: Chris@173: if (x1 <= x0) x1 = x0 + 1; Chris@173: Chris@173: paint.drawRect(x0, y, x1 - x0, height() - 2 * y); Chris@173: } Chris@173: Chris@173: paint.end(); Chris@173: } Chris@173: Chris@173: void Chris@173: Overview::mousePressEvent(QMouseEvent *e) Chris@173: { Chris@173: m_clickPos = e->pos(); Chris@339: long clickFrame = getFrameForX(m_clickPos.x()); Chris@339: if (clickFrame > 0) m_dragCentreFrame = clickFrame; Chris@339: else m_dragCentreFrame = 0; Chris@339: m_clickedInRange = true; Chris@339: Chris@211: for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) { Chris@339: if (*i && (*i)->getAligningModel() == getAligningModel()) { Chris@339: m_dragCentreFrame = (*i)->getCentreFrame(); Chris@339: break; Chris@339: } Chris@173: } Chris@173: } Chris@173: Chris@173: void Chris@173: Overview::mouseReleaseEvent(QMouseEvent *e) Chris@173: { Chris@173: if (m_clickedInRange) { Chris@173: mouseMoveEvent(e); Chris@173: } Chris@173: m_clickedInRange = false; Chris@173: } Chris@173: Chris@173: void Chris@173: Overview::mouseMoveEvent(QMouseEvent *e) Chris@173: { Chris@173: if (!m_clickedInRange) return; Chris@173: Chris@173: long xoff = int(e->x()) - int(m_clickPos.x()); Chris@173: long frameOff = xoff * m_zoomLevel; Chris@173: Chris@173: size_t newCentreFrame = m_dragCentreFrame; Chris@173: if (frameOff > 0) { Chris@173: newCentreFrame += frameOff; Chris@173: } else if (newCentreFrame >= size_t(-frameOff)) { Chris@173: newCentreFrame += frameOff; Chris@173: } else { Chris@173: newCentreFrame = 0; Chris@173: } Chris@173: Chris@173: if (newCentreFrame >= getModelsEndFrame()) { Chris@173: newCentreFrame = getModelsEndFrame(); Chris@173: if (newCentreFrame > 0) --newCentreFrame; Chris@173: } Chris@173: Chris@173: if (std::max(m_centreFrame, newCentreFrame) - Chris@173: std::min(m_centreFrame, newCentreFrame) > size_t(m_zoomLevel)) { Chris@339: size_t rf = alignToReference(newCentreFrame); Chris@339: emit centreFrameChanged(rf, true, PlaybackScrollContinuous); Chris@173: } Chris@173: } Chris@173: Chris@189: void Chris@189: Overview::mouseDoubleClickEvent(QMouseEvent *e) Chris@189: { Chris@189: long frame = getFrameForX(e->x()); Chris@339: size_t rf = 0; Chris@339: if (frame > 0) rf = alignToReference(frame); Chris@339: emit centreFrameChanged(rf, true, PlaybackScrollContinuous); Chris@189: } Chris@173: Chris@189: void Chris@189: Overview::enterEvent(QEvent *) Chris@189: { Chris@189: emit contextHelpChanged(tr("Click and drag to navigate; double-click to jump")); Chris@189: } Chris@189: Chris@189: void Chris@189: Overview::leaveEvent(QEvent *) Chris@189: { Chris@189: emit contextHelpChanged(""); Chris@189: } Chris@189: Chris@189: