Chris@0: /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@0: A waveform viewer and audio annotation editor. Chris@5: Chris Cannam, Queen Mary University of London, 2005-2006 Chris@0: Chris@0: This is experimental software. Not for distribution. Chris@0: */ Chris@0: Chris@0: #include "Panner.h" Chris@0: #include "base/Layer.h" Chris@0: #include "base/Model.h" Chris@0: #include "base/ZoomConstraint.h" Chris@0: Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: Chris@0: using std::cerr; Chris@0: using std::endl; Chris@0: Chris@0: Panner::Panner(QWidget *w) : Chris@0: View(w, false), Chris@0: m_clickedInRange(false) Chris@0: { Chris@0: setObjectName(tr("Panner")); Chris@0: m_followPan = false; Chris@0: m_followZoom = false; Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::modelChanged(size_t startFrame, size_t endFrame) Chris@0: { Chris@0: View::modelChanged(startFrame, endFrame); Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::modelReplaced() Chris@0: { Chris@0: View::modelReplaced(); Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::registerView(View *widget) Chris@0: { Chris@0: m_widgets[widget] = WidgetRec(0, -1); Chris@0: update(); Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::unregisterView(View *widget) Chris@0: { Chris@0: m_widgets.erase(widget); Chris@0: update(); Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::viewManagerCentreFrameChanged(void *p, unsigned long f, bool) Chris@0: { Chris@0: // std::cerr << "Panner[" << this << "]::viewManagerCentreFrameChanged(" Chris@0: // << p << ", " << f << ")" << std::endl; Chris@0: Chris@0: if (p == this) return; Chris@0: if (m_widgets.find(p) != m_widgets.end()) { Chris@0: m_widgets[p].first = f; Chris@0: update(); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::viewManagerZoomLevelChanged(void *p, unsigned long z, bool) Chris@0: { Chris@0: if (p == this) return; Chris@0: if (m_widgets.find(p) != m_widgets.end()) { Chris@0: m_widgets[p].second = z; Chris@0: update(); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::viewManagerPlaybackFrameChanged(unsigned long f) Chris@0: { Chris@0: bool changed = false; Chris@0: Chris@0: if (m_playPointerFrame / m_zoomLevel != f / m_zoomLevel) changed = true; Chris@0: m_playPointerFrame = f; Chris@0: Chris@0: for (WidgetMap::iterator i = m_widgets.begin(); i != m_widgets.end(); ++i) { Chris@0: unsigned long of = i->second.first; Chris@0: i->second.first = f; Chris@0: if (of / m_zoomLevel != f / m_zoomLevel) changed = true; Chris@0: } Chris@0: Chris@0: if (changed) update(); Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::paintEvent(QPaintEvent *e) Chris@0: { Chris@0: /*!!! Chris@0: // Force View to recalculate zoom in case the size of the Chris@0: // widget has changed. (We need a better name/mechanism for this) Chris@0: m_newModel = true; Chris@0: */ Chris@0: Chris@0: // Recalculate zoom in case the size of the widget has changed. Chris@0: Chris@0: size_t startFrame = getModelsStartFrame(); Chris@0: size_t frameCount = getModelsEndFrame() - getModelsStartFrame(); Chris@0: int zoomLevel = frameCount / width(); Chris@0: if (zoomLevel < 1) zoomLevel = 1; Chris@0: zoomLevel = getZoomConstraintBlockSize(zoomLevel, Chris@0: ZoomConstraint::RoundUp); Chris@0: if (zoomLevel != m_zoomLevel) { Chris@0: m_zoomLevel = zoomLevel; Chris@0: emit zoomLevelChanged(this, m_zoomLevel, m_followZoom); Chris@0: } Chris@0: size_t centreFrame = startFrame + m_zoomLevel * (width() / 2); Chris@0: if (centreFrame > (startFrame + getModelsEndFrame())/2) { Chris@0: centreFrame = (startFrame + getModelsEndFrame())/2; Chris@0: } Chris@0: if (centreFrame != m_centreFrame) { Chris@0: m_centreFrame = centreFrame; Chris@0: emit centreFrameChanged(this, m_centreFrame, false); Chris@0: } Chris@0: Chris@0: View::paintEvent(e); Chris@0: Chris@0: QPainter paint; Chris@0: paint.begin(this); Chris@0: Chris@0: QRect r(rect()); Chris@0: Chris@0: if (e) { Chris@0: r = e->rect(); Chris@0: paint.setClipRect(r); Chris@0: } Chris@0: Chris@0: paint.setPen(Qt::black); Chris@0: Chris@0: int y = 0; Chris@0: long prevCentre = 0; Chris@0: long prevZoom = -1; Chris@0: Chris@0: for (WidgetMap::iterator i = m_widgets.begin(); i != m_widgets.end(); ++i) { Chris@0: if (!i->first) continue; Chris@0: Chris@0: View *w = (View *)i->first; Chris@0: if (i->second.second < 0) i->second.second = w->getZoomLevel(); Chris@0: if (i->second.second < 0) continue; Chris@0: Chris@0: long c = (long)i->second.first; Chris@0: long z = (long)i->second.second; Chris@0: Chris@0: long f0 = c - (w->width() / 2) * z; Chris@0: long f1 = c + (w->width() / 2) * z; Chris@0: Chris@0: int x0 = (f0 - long(getCentreFrame())) / getZoomLevel() + width()/2; Chris@0: int x1 = (f1 - long(getCentreFrame())) / getZoomLevel() + width()/2 - 1; Chris@0: Chris@0: if (c != prevCentre || z != prevZoom) { Chris@0: y += height() / 10 + 1; Chris@0: prevCentre = c; Chris@0: prevZoom = z; Chris@0: } Chris@0: Chris@0: paint.drawRect(x0, y, x1 - x0, height() - 2 * y); Chris@0: } Chris@0: Chris@0: paint.end(); Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::mousePressEvent(QMouseEvent *e) Chris@0: { Chris@0: m_clickPos = e->pos(); Chris@0: for (WidgetMap::iterator i = m_widgets.begin(); i != m_widgets.end(); ++i) { Chris@0: if (i->first && i->second.second >= 0) { Chris@0: m_clickedInRange = true; Chris@0: m_dragCentreFrame = i->second.first; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::mouseReleaseEvent(QMouseEvent *e) Chris@0: { Chris@0: if (m_clickedInRange) { Chris@0: mouseMoveEvent(e); Chris@0: } Chris@0: m_clickedInRange = false; Chris@0: } Chris@0: Chris@0: void Chris@0: Panner::mouseMoveEvent(QMouseEvent *e) Chris@0: { Chris@0: if (!m_clickedInRange) return; Chris@0: Chris@0: /*!!! Chris@0: long newFrame = getStartFrame() + e->x() * m_zoomLevel; Chris@0: Chris@0: if (newFrame < 0) newFrame = 0; Chris@0: if (newFrame >= getModelsEndFrame()) { Chris@0: newFrame = getModelsEndFrame(); Chris@0: if (newFrame > 0) --newFrame; Chris@0: } Chris@0: emit centreFrameChanged(this, newFrame, true); Chris@0: */ Chris@0: Chris@0: long xoff = int(e->x()) - int(m_clickPos.x()); Chris@0: long frameOff = xoff * m_zoomLevel; Chris@0: Chris@0: size_t newCentreFrame = m_dragCentreFrame; Chris@0: if (frameOff > 0) { Chris@0: newCentreFrame += frameOff; Chris@0: } else if (newCentreFrame >= size_t(-frameOff)) { Chris@0: newCentreFrame += frameOff; Chris@0: } else { Chris@0: newCentreFrame = 0; Chris@0: } Chris@0: Chris@0: if (newCentreFrame >= getModelsEndFrame()) { Chris@0: newCentreFrame = getModelsEndFrame(); Chris@0: if (newCentreFrame > 0) --newCentreFrame; Chris@0: } Chris@0: Chris@0: if (std::max(m_centreFrame, newCentreFrame) - Chris@0: std::min(m_centreFrame, newCentreFrame) > size_t(m_zoomLevel)) { Chris@0: emit centreFrameChanged(this, newCentreFrame, true); Chris@0: } Chris@0: } Chris@0: Chris@0: #ifdef INCLUDE_MOCFILES Chris@0: #include "Panner.moc.cpp" Chris@0: #endif Chris@0: