view widgets/Panner.cpp @ 37:21d061e66177

* Make the frequency estimation mode in the spectrogram layer actually useful, and make sure it gets mostly the right results... Still some tidying to do in here.
author Chris Cannam
date Wed, 22 Feb 2006 17:45:18 +0000
parents 38fe0ea9e46e
children 01ab51f72e84
line wrap: on
line source
/* -*- c-basic-offset: 4 -*-  vi:set ts=8 sts=4 sw=4: */

/*
    A waveform viewer and audio annotation editor.
    Chris Cannam, Queen Mary University of London, 2005-2006
    
    This is experimental software.  Not for distribution.
*/

#include "Panner.h"
#include "base/Layer.h"
#include "base/Model.h"
#include "base/ZoomConstraint.h"

#include <QPaintEvent>
#include <QPainter>
#include <iostream>

using std::cerr;
using std::endl;

Panner::Panner(QWidget *w) :
    View(w, false),
    m_clickedInRange(false)
{
    setObjectName(tr("Panner"));
    m_followPan = false;
    m_followZoom = false;
}

void
Panner::modelChanged(size_t startFrame, size_t endFrame)
{
    View::modelChanged(startFrame, endFrame);
}

void
Panner::modelReplaced()
{
    View::modelReplaced();
}

void
Panner::registerView(View *widget)
{
    m_widgets.insert(widget);
    update(); 
}

void
Panner::unregisterView(View *widget)
{
    m_widgets.erase(widget);
    update();
}

void
Panner::viewManagerCentreFrameChanged(void *p, unsigned long f, bool)
{
//    std::cerr << "Panner[" << this << "]::viewManagerCentreFrameChanged(" 
//	      << p << ", " << f << ")" << std::endl;

    if (p == this) return;
    if (m_widgets.find(p) != m_widgets.end()) {
	update();
    }
}

void
Panner::viewManagerZoomLevelChanged(void *p, unsigned long z, bool)
{
    if (p == this) return;
    if (m_widgets.find(p) != m_widgets.end()) {
	update();
    }
}

void
Panner::viewManagerPlaybackFrameChanged(unsigned long f)
{
    bool changed = false;

    if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true;
    m_playPointerFrame = f;

    if (changed) update();
}

void
Panner::paintEvent(QPaintEvent *e)
{
    // Recalculate zoom in case the size of the widget has changed.

    size_t startFrame = getModelsStartFrame();
    size_t frameCount = getModelsEndFrame() - getModelsStartFrame();
    int zoomLevel = frameCount / width();
    if (zoomLevel < 1) zoomLevel = 1;
    zoomLevel = getZoomConstraintBlockSize(zoomLevel,
					   ZoomConstraint::RoundUp);
    if (zoomLevel != m_zoomLevel) {
	m_zoomLevel = zoomLevel;
	emit zoomLevelChanged(this, m_zoomLevel, m_followZoom);
    }
    size_t centreFrame = startFrame + m_zoomLevel * (width() / 2);
    if (centreFrame > (startFrame + getModelsEndFrame())/2) {
	centreFrame = (startFrame + getModelsEndFrame())/2;
    }
    if (centreFrame != m_centreFrame) {
	m_centreFrame = centreFrame;
	emit centreFrameChanged(this, m_centreFrame, false);
    }

    View::paintEvent(e);

    QPainter paint;
    paint.begin(this);

    QRect r(rect());

    if (e) {
	r = e->rect();
	paint.setClipRect(r);
    }

    paint.setPen(Qt::black);

    int y = 0;

    int prevx0 = -10;
    int prevx1 = -10;

    for (WidgetSet::iterator i = m_widgets.begin(); i != m_widgets.end(); ++i) {
	if (!*i) continue;

	View *w = (View *)*i;

	long f0 = w->getFrameForX(0);
	long f1 = w->getFrameForX(w->width());

	int x0 = getXForFrame(f0);
	int x1 = getXForFrame(f1);

	if (x0 != prevx0 || x1 != prevx1) {
	    y += height() / 10 + 1;
	    prevx0 = x0;
	    prevx1 = x1;
	}

	if (x1 <= x0) x1 = x0 + 1;
	
	paint.drawRect(x0, y, x1 - x0, height() - 2 * y);
    }

    paint.end();
}

void
Panner::mousePressEvent(QMouseEvent *e)
{
    m_clickPos = e->pos();
    for (WidgetSet::iterator i = m_widgets.begin(); i != m_widgets.end(); ++i) {
	if (*i) {
	    m_clickedInRange = true;
	    m_dragCentreFrame = ((View *)*i)->getCentreFrame();
	    break;
	}
    }
}

void
Panner::mouseReleaseEvent(QMouseEvent *e)
{
    if (m_clickedInRange) {
	mouseMoveEvent(e);
    }
    m_clickedInRange = false;
}

void
Panner::mouseMoveEvent(QMouseEvent *e)
{
    if (!m_clickedInRange) return;

    long xoff = int(e->x()) - int(m_clickPos.x());
    long frameOff = xoff * m_zoomLevel;
    
    size_t newCentreFrame = m_dragCentreFrame;
    if (frameOff > 0) {
	newCentreFrame += frameOff;
    } else if (newCentreFrame >= size_t(-frameOff)) {
	newCentreFrame += frameOff;
    } else {
	newCentreFrame = 0;
    }

    if (newCentreFrame >= getModelsEndFrame()) {
	newCentreFrame = getModelsEndFrame();
	if (newCentreFrame > 0) --newCentreFrame;
    }
    
    if (std::max(m_centreFrame, newCentreFrame) -
	std::min(m_centreFrame, newCentreFrame) > size_t(m_zoomLevel)) {
	emit centreFrameChanged(this, newCentreFrame, true);
    }
}

#ifdef INCLUDE_MOCFILES
#include "Panner.moc.cpp"
#endif