Mercurial > hg > svgui
changeset 133:9e6b3e239b9d
* Add zoom thumbwheels to Pane. Implement horizontal thumbwheel, and
vertical depending on layer type (supported for waveform and spectrogram,
though wrong for log-scale spectrogram at the moment).
* Add bare bones of a spectrum layer.
* Add window icon
* Add shortcut for "insert time instant" on laptops without keypad enter (";")
* Delete FFT processing thread when it exits (at least, next time we're asked
for something interesting)
* Get audio file extensions from the file readers, and thus from libsndfile for
the wave file reader -- leads to rather a wide combo box in file dialog though
* Better refresh order for spectrogram (redraw centre section first)
author | Chris Cannam |
---|---|
date | Fri, 04 Aug 2006 17:01:37 +0000 |
parents | 5d3a483856ff |
children | 13949a6970ab |
files | layer/Layer.h layer/LayerFactory.cpp layer/LayerFactory.h layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h layer/SpectrumLayer.cpp layer/SpectrumLayer.h layer/WaveformLayer.cpp layer/WaveformLayer.h layer/layer.pro view/Pane.cpp view/Pane.h view/View.cpp view/View.h view/ViewManager.cpp view/ViewManager.h widgets/Thumbwheel.cpp widgets/Thumbwheel.h |
diffstat | 18 files changed, 764 insertions(+), 73 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/Layer.h Thu Aug 03 15:40:11 2006 +0000 +++ b/layer/Layer.h Fri Aug 04 17:01:37 2006 +0000 @@ -280,6 +280,34 @@ return false; } + /** + * Get the number of vertical zoom steps available for this layer. + * If vertical zooming is not available, return 0. The meaning of + * "zooming" is entirely up to the layer -- changing the zoom + * level may cause the layer to reset its display extents or + * change another property such as display gain. + * Layers that provide this facility should also emit the + * verticalZoomChanged signal if their vertical zoom changes + * due to factors other than setVerticalZoomStep being called. + */ + virtual int getVerticalZoomSteps(int &defaultStep) const { return 0; } + + /** + * Get the current vertical zoom step. A layer may support finer + * control over ranges etc than is available through the integer + * zoom step mechanism; if this one does, it should just return + * the nearest of the available zoom steps to the current settings. + */ + virtual int getCurrentVerticalZoomStep() const { return 0; } + + /** + * Set the vertical zoom step. The meaning of "zooming" is + * entirely up to the layer -- changing the zoom level may cause + * the layer to reset its display extents or change another + * property such as display gain. + */ + virtual void setVerticalZoomStep(int) { } + public slots: void showLayer(View *, bool show); @@ -292,6 +320,8 @@ void layerParametersChanged(); void layerNameChanged(); + void verticalZoomChanged(); + private: mutable QMutex m_dormancyMutex; mutable std::map<const void *, bool> m_dormancy;
--- a/layer/LayerFactory.cpp Thu Aug 03 15:40:11 2006 +0000 +++ b/layer/LayerFactory.cpp Fri Aug 04 17:01:37 2006 +0000 @@ -23,6 +23,7 @@ #include "NoteLayer.h" #include "TextLayer.h" #include "Colour3DPlotLayer.h" +#include "SpectrumLayer.h" #include "data/model/RangeSummarisableTimeValueModel.h" #include "data/model/DenseTimeValueModel.h" @@ -57,6 +58,7 @@ case Notes: return Layer::tr("Notes"); case Text: return Layer::tr("Text"); case Colour3DPlot: return Layer::tr("Colour 3D Plot"); + case Spectrum: return Layer::tr("Spectrum"); case MelodicRangeSpectrogram: // The user can change all the parameters of this after the @@ -109,6 +111,10 @@ types.insert(Text); } + if (dynamic_cast<DenseTimeValueModel *>(model)) { + types.insert(Spectrum); + } + // We don't count TimeRuler here as it doesn't actually display // the data, although it can be backed by any model @@ -138,6 +144,7 @@ if (dynamic_cast<const NoteLayer *>(layer)) return Notes; if (dynamic_cast<const TextLayer *>(layer)) return Text; if (dynamic_cast<const Colour3DPlotLayer *>(layer)) return Colour3DPlot; + if (dynamic_cast<const SpectrumLayer *>(layer)) return Spectrum; return UnknownLayer; } @@ -153,6 +160,7 @@ case Notes: return "notes"; case Text: return "text"; case Colour3DPlot: return "colour3d"; + case Spectrum: return "spectrum"; default: return "unknown"; } } @@ -169,6 +177,7 @@ case Notes: return "notes"; case Text: return "text"; case Colour3DPlot: return "colour3dplot"; + case Spectrum: return "spectrum"; default: return "unknown"; } } @@ -184,6 +193,7 @@ if (name == "notes") return Notes; if (name == "text") return Text; if (name == "colour3dplot") return Colour3DPlot; + if (name == "spectrum") return Spectrum; return UnknownLayer; } @@ -216,6 +226,9 @@ if (trySetModel<SpectrogramLayer, DenseTimeValueModel>(layer, model)) return; + + if (trySetModel<SpectrumLayer, DenseTimeValueModel>(layer, model)) + return; } Model * @@ -300,6 +313,10 @@ layer = new Colour3DPlotLayer; break; + case Spectrum: + layer = new SpectrumLayer; + break; + case MelodicRangeSpectrogram: layer = new SpectrogramLayer(SpectrogramLayer::MelodicRange); break;
--- a/layer/LayerFactory.h Thu Aug 03 15:40:11 2006 +0000 +++ b/layer/LayerFactory.h Fri Aug 04 17:01:37 2006 +0000 @@ -36,6 +36,7 @@ Notes, Text, Colour3DPlot, + Spectrum, // Layers with different initial parameters MelodicRangeSpectrogram,
--- a/layer/SpectrogramLayer.cpp Thu Aug 03 15:40:11 2006 +0000 +++ b/layer/SpectrogramLayer.cpp Fri Aug 04 17:01:37 2006 +0000 @@ -35,7 +35,7 @@ #include <cassert> #include <cmath> -//#define DEBUG_SPECTROGRAM_REPAINT 1 +#define DEBUG_SPECTROGRAM_REPAINT 1 SpectrogramLayer::SpectrogramLayer(Configuration config) : Layer(), @@ -57,6 +57,7 @@ m_binDisplay(AllBins), m_normalizeColumns(false), m_normalizeVisibleArea(false), + m_lastEmittedZoomStep(-1), m_updateTimer(0), m_candidateFillStartFrame(0), m_exiting(false) @@ -487,6 +488,11 @@ case 8: setMinFrequency(4000); break; case 9: setMinFrequency(10000); break; } + int vs = getCurrentVerticalZoomStep(); + if (vs != m_lastEmittedZoomStep) { + emit verticalZoomChanged(); + m_lastEmittedZoomStep = vs; + } } else if (name == "Max Frequency") { switch (value) { case 0: setMaxFrequency(500); break; @@ -501,6 +507,11 @@ default: case 9: setMaxFrequency(0); break; } + int vs = getCurrentVerticalZoomStep(); + if (vs != m_lastEmittedZoomStep) { + emit verticalZoomChanged(); + m_lastEmittedZoomStep = vs; + } } else if (name == "Colour Scale") { switch (value) { default: @@ -1159,7 +1170,12 @@ //!!! experiment with normalizing the visible area this way. //In any case, we need to have some indication of what the dB //scale is relative to. - input = 10.f * log10f(input / max); + input = input / max; + if (input > 0.f) { + input = 10.f * log10f(input); + } else { + input = thresh; + } if (min > 0.f) { thresh = 10.f * log10f(min); if (thresh < -80.f) thresh = -80.f; @@ -1173,7 +1189,12 @@ case OtherColourScale: //!!! the "Other" scale is just where our current experiments go //!!! power rather than v - input = 10.f * log10f((input * input) / (max * max)); + input = (input * input) / (max * max); + if (input > 0.f) { + input = 10.f * log10f(input); + } else { + input = thresh; + } if (min > 0.f) { thresh = 10.f * log10f(min * min); if (thresh < -80.f) thresh = -80.f; @@ -1657,9 +1678,9 @@ std::cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << std::endl; #endif - long sf = v->getStartFrame(); - if (sf < 0) m_candidateFillStartFrame = 0; - else m_candidateFillStartFrame = sf; + long startFrame = v->getStartFrame(); + if (startFrame < 0) m_candidateFillStartFrame = 0; + else m_candidateFillStartFrame = startFrame; if (!m_model || !m_model->isOK() || !m_model->isReady()) { return; @@ -1695,7 +1716,6 @@ std::cerr << "SpectrogramLayer::paint(): Still cacheing = " << stillCacheing << std::endl; #endif - long startFrame = v->getStartFrame(); int zoomLevel = v->getZoomLevel(); int x0 = 0; @@ -1824,17 +1844,18 @@ } */ + if (updateViewMagnitudes(v)) { + std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; + recreateWholePixmapCache = true; + } else { + std::cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; + } + if (recreateWholePixmapCache) { x0 = 0; x1 = v->width(); } - if (updateViewMagnitudes(v)) { - std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; - } else { - std::cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; - } - int paintBlockWidth = (300000 / zoomLevel); if (paintBlockWidth < 20) paintBlockWidth = 20; @@ -1875,7 +1896,16 @@ } else { if (x1 > x0 + paintBlockWidth) { - x1 = x0 + paintBlockWidth; + int sfx = x1; + if (startFrame < 0) sfx = v->getXForFrame(0); + if (sfx >= x0 && sfx + paintBlockWidth <= x1) { + x0 = sfx; + x1 = x0 + paintBlockWidth; + } else { + int mid = (x1 + x0) / 2; + x0 = mid - paintBlockWidth/2; + x1 = x0 + paintBlockWidth; + } } cache.validArea = QRect(x0, 0, x1 - x0, v->height()); } @@ -2156,6 +2186,9 @@ << x0 << "," << y1 << " -> " << x1 << "," << y0 << std::endl; paint.setPen(Qt::white); + + //!!! should we be using paintCrosshairs for this? + paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1); } } @@ -2193,8 +2226,16 @@ SpectrogramLayer::getValueExtents(float &min, float &max, bool &logarithmic, QString &unit) const { - min = getEffectiveMinFrequency(); - max = getEffectiveMaxFrequency(); +//!!! +// min = getEffectiveMinFrequency(); +// max = getEffectiveMaxFrequency(); + + if (!m_model) return false; + + int sr = m_model->getSampleRate(); + min = float(sr) / m_fftSize; + max = float(sr) / 2; + logarithmic = (m_frequencyScale == LogFrequencyScale); unit = "Hz"; return true; @@ -2228,6 +2269,12 @@ emit layerParametersChanged(); + int vs = getCurrentVerticalZoomStep(); + if (vs != m_lastEmittedZoomStep) { + emit verticalZoomChanged(); + m_lastEmittedZoomStep = vs; + } + return true; } @@ -2712,6 +2759,72 @@ } } +int +SpectrogramLayer::getVerticalZoomSteps(int &defaultStep) const +{ + defaultStep = 0; + return 20; //!!! +} + +int +SpectrogramLayer::getCurrentVerticalZoomStep() const +{ + if (!m_model) return 0; + + float dmin, dmax; + getDisplayExtents(dmin, dmax); + + float mmin, mmax; + int sr = m_model->getSampleRate(); + mmin = float(sr) / m_fftSize; + mmax = float(sr) / 2; + + float mdist = mmax - mmin; + float ddist = dmax - dmin; + + int n = 0; + float s2 = sqrtf(2); + while (mdist > ddist) { + if (++n > 20) break; + mdist /= s2; + } + + return n; +} + +void +SpectrogramLayer::setVerticalZoomStep(int step) +{ + //!!! does not do the right thing for log scale + + float dmin, dmax; + getDisplayExtents(dmin, dmax); + + float mmin, mmax; + int sr = m_model->getSampleRate(); + mmin = float(sr) / m_fftSize; + mmax = float(sr) / 2; + + float ddist = mmax - mmin; + + int n = 0; + float s2 = sqrtf(2); + while (n < step) { + ddist /= s2; + ++n; + } + + float dmid = (dmax + dmin) / 2; + float newmin = dmid - ddist / 2; + float newmax = dmid + ddist / 2; + + if (newmin < mmin) newmin = mmin; + if (newmax > mmax) newmax = mmax; + + setMinFrequency(newmin); + setMaxFrequency(newmax); +} + QString SpectrogramLayer::toXmlString(QString indent, QString extraAttributes) const { @@ -2815,8 +2928,3 @@ setNormalizeColumns(normalizeColumns); } - -#ifdef INCLUDE_MOCFILES -#include "SpectrogramLayer.moc.cpp" -#endif -
--- a/layer/SpectrogramLayer.h Thu Aug 03 15:40:11 2006 +0000 +++ b/layer/SpectrogramLayer.h Fri Aug 04 17:01:37 2006 +0000 @@ -208,6 +208,10 @@ virtual bool isLayerScrollable(const View *v) const { return false; } + virtual int getVerticalZoomSteps(int &defaultStep) const; + virtual int getCurrentVerticalZoomStep() const; + virtual void setVerticalZoomStep(int); + protected slots: void cacheInvalid(); void cacheInvalid(size_t startFrame, size_t endFrame); @@ -237,6 +241,7 @@ BinDisplay m_binDisplay; bool m_normalizeColumns; bool m_normalizeVisibleArea; + int m_lastEmittedZoomStep; enum { NO_VALUE = 0 }; // colour index for unused pixels
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layer/SpectrumLayer.cpp Fri Aug 04 17:01:37 2006 +0000 @@ -0,0 +1,112 @@ + +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "SpectrumLayer.h" + +#include "data/model/FFTModel.h" +#include "view/View.h" + +#include <QPainter> +#include <QPainterPath> + +SpectrumLayer::SpectrumLayer() : + m_model(0), + m_fft(0), + m_colour(Qt::blue) +{ +} + +SpectrumLayer::~SpectrumLayer() +{ + delete m_fft; +} + +void +SpectrumLayer::setModel(DenseTimeValueModel *model) +{ + m_model = model; + delete m_fft; + m_fft = new FFTModel(m_model, + -1, + HanningWindow, + 1024, + 256, + 1024, + true); + m_fft->resume(); +} + +void +SpectrumLayer::paint(View *v, QPainter &paint, QRect rect) const +{ + if (!m_fft) return; + + int fftSize = 1024; //!!! ... + int windowIncrement = 256; + int windowSize = 1024; + + size_t f = v->getCentreFrame(); + + int w = (v->width() * 2) / 3; + int xorigin = (v->width() / 2) - (w / 2); + + int h = (v->height() * 2) / 3; + int yorigin = (v->height() / 2) + (h / 2); + + size_t column = f / windowIncrement; + + paint.save(); + paint.setPen(m_colour); + paint.setRenderHint(QPainter::Antialiasing, false); + + QPainterPath path; + float thresh = -80.f; + + for (size_t bin = 0; bin < m_fft->getHeight(); ++bin) { + + float mag = m_fft->getMagnitudeAt(column, bin); + float db = thresh; + if (mag > 0.f) db = 10.f * log10f(mag); + if (db < thresh) db = thresh; + float val = (db - thresh) / -thresh; + float x = xorigin + (float(w) * bin) / m_fft->getHeight(); + float y = yorigin - (float(h) * val); + + if (bin == 0) { + path.moveTo(x, y); + } else { + path.lineTo(x, y); + } + } + + paint.drawPath(path); +// paint.setRenderHint(QPainter::Antialiasing, false); + paint.restore(); + +} + +void +SpectrumLayer::setProperties(const QXmlAttributes &attr) +{ +} + +bool +SpectrumLayer::getValueExtents(float &min, float &max, bool &logarithmic, + QString &units) const +{ + return false; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layer/SpectrumLayer.h Fri Aug 04 17:01:37 2006 +0000 @@ -0,0 +1,55 @@ + +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _SPECTRUM_LAYER_H_ +#define _SPECTRUM_LAYER_H_ + +#include "Layer.h" + +#include "data/model/DenseTimeValueModel.h" + +#include <QColor> + +class FFTModel; + +class SpectrumLayer : public Layer +{ + Q_OBJECT + +public: + SpectrumLayer(); + ~SpectrumLayer(); + + void setModel(DenseTimeValueModel *model); + virtual const Model *getModel() const { return m_model; } + virtual void paint(View *v, QPainter &paint, QRect rect) const; + + virtual void setProperties(const QXmlAttributes &); + + virtual bool getValueExtents(float &min, float &max, + bool &logarithmic, QString &unit) const; + + virtual bool isLayerScrollable(const View *v) const { return false; } + + virtual QString getPropertyLabel(const PropertyName &) const { return ""; } + +protected: + DenseTimeValueModel *m_model; + FFTModel *m_fft; + QColor m_colour; +}; + +#endif
--- a/layer/WaveformLayer.cpp Thu Aug 03 15:40:11 2006 +0000 +++ b/layer/WaveformLayer.cpp Fri Aug 04 17:01:37 2006 +0000 @@ -262,6 +262,7 @@ m_gain = gain; m_cacheValid = false; emit layerParametersChanged(); + emit verticalZoomChanged(); } void @@ -1194,7 +1195,25 @@ setAutoNormalize(autoNormalize); } -#ifdef INCLUDE_MOCFILES -#include "WaveformLayer.moc.cpp" -#endif +int +WaveformLayer::getVerticalZoomSteps(int &defaultStep) const +{ + defaultStep = 50; + return 100; +} +int +WaveformLayer::getCurrentVerticalZoomStep() const +{ + int val = lrint(log10(m_gain) * 20.0) + 50; + if (val < 0) val = 0; + if (val > 100) val = 100; + return val; +} + +void +WaveformLayer::setVerticalZoomStep(int step) +{ + setGain(pow(10, float(step - 50) / 20.0)); +} +
--- a/layer/WaveformLayer.h Thu Aug 03 15:40:11 2006 +0000 +++ b/layer/WaveformLayer.h Fri Aug 04 17:01:37 2006 +0000 @@ -181,6 +181,10 @@ void setProperties(const QXmlAttributes &attributes); + virtual int getVerticalZoomSteps(int &defaultStep) const; + virtual int getCurrentVerticalZoomStep() const; + virtual void setVerticalZoomStep(int); + protected: int dBscale(float sample, int m) const;
--- a/layer/layer.pro Thu Aug 03 15:40:11 2006 +0000 +++ b/layer/layer.pro Fri Aug 04 17:01:37 2006 +0000 @@ -19,6 +19,7 @@ LayerFactory.h \ NoteLayer.h \ SpectrogramLayer.h \ + SpectrumLayer.h \ TextLayer.h \ TimeInstantLayer.h \ TimeRulerLayer.h \ @@ -29,6 +30,7 @@ LayerFactory.cpp \ NoteLayer.cpp \ SpectrogramLayer.cpp \ + SpectrumLayer.cpp \ TextLayer.cpp \ TimeInstantLayer.cpp \ TimeRulerLayer.cpp \
--- a/view/Pane.cpp Thu Aug 03 15:40:11 2006 +0000 +++ b/view/Pane.cpp Fri Aug 04 17:01:37 2006 +0000 @@ -22,13 +22,18 @@ #include "ViewManager.h" #include "base/CommandHistory.h" #include "layer/WaveformLayer.h" -#include "widgets/Thumbwheel.h" #include <QPaintEvent> #include <QPainter> #include <iostream> #include <cmath> +//!!! for HUD -- pull out into a separate class +#include <QFrame> +#include <QGridLayout> +#include <QPushButton> +#include "widgets/Thumbwheel.h" + using std::cerr; using std::endl; @@ -40,10 +45,18 @@ m_ctrlPressed(false), m_navigating(false), m_resizing(false), - m_centreLineVisible(true) + m_centreLineVisible(true), + m_headsUpDisplay(0) { setObjectName("Pane"); setMouseTracking(true); + + updateHeadsUpDisplay(); +} + +void +Pane::updateHeadsUpDisplay() +{ /* int count = 0; int currentLevel = 1; @@ -60,13 +73,102 @@ std::cerr << "Have " << count+1 << " zoom levels" << std::endl; */ -/* - Thumbwheel *thumbwheel = new Thumbwheel(0, 40, 5, - Qt::Vertical, this); - thumbwheel->move(10, 10); - connect(thumbwheel, SIGNAL(valueChanged(int)), this, - SLOT(horizontalThumbwheelMoved(int))); -*/ + + if (!m_headsUpDisplay) { + + m_headsUpDisplay = new QFrame(this); + + QGridLayout *layout = new QGridLayout; + layout->setMargin(0); + layout->setSpacing(0); + m_headsUpDisplay->setLayout(layout); + + m_hthumb = new Thumbwheel(Qt::Horizontal); + layout->addWidget(m_hthumb, 1, 0); + m_hthumb->setFixedWidth(70); + m_hthumb->setFixedHeight(16); + m_hthumb->setDefaultValue(0); + connect(m_hthumb, SIGNAL(valueChanged(int)), this, + SLOT(horizontalThumbwheelMoved(int))); + + m_vthumb = new Thumbwheel(Qt::Vertical); + layout->addWidget(m_vthumb, 0, 1); + m_vthumb->setFixedWidth(16); + m_vthumb->setFixedHeight(70); + connect(m_vthumb, SIGNAL(valueChanged(int)), this, + SLOT(verticalThumbwheelMoved(int))); + + QPushButton *reset = new QPushButton; + reset->setFixedHeight(16); + reset->setFixedWidth(16); + layout->addWidget(reset, 1, 1); + connect(reset, SIGNAL(clicked()), m_hthumb, SLOT(resetToDefault())); + connect(reset, SIGNAL(clicked()), m_vthumb, SLOT(resetToDefault())); + } + + int count = 0; + int current = 0; + int level = 1; + + while (true) { + if (getZoomLevel() == level) current = count; + int newLevel = getZoomConstraintBlockSize(level + 1, + ZoomConstraint::RoundUp); + if (newLevel == level) break; + level = newLevel; + if (++count == 50) break; + } + +// std::cerr << "Have " << count << " zoom levels" << std::endl; + + m_hthumb->setMinimumValue(0); + m_hthumb->setMaximumValue(count); + m_hthumb->setValue(count - current); + +// std::cerr << "set value to " << count-current << std::endl; + +// std::cerr << "default value is " << m_hthumb->getDefaultValue() << std::endl; + + if (count != 50 && m_hthumb->getDefaultValue() == 0) { + m_hthumb->setDefaultValue(count - current); +// std::cerr << "set default value to " << m_hthumb->getDefaultValue() << std::endl; + } + + Layer *layer = 0; + if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1); + if (layer) { + int defaultStep = 0; + int max = layer->getVerticalZoomSteps(defaultStep); + if (max == 0) { + m_vthumb->hide(); + } else { + m_vthumb->show(); + m_vthumb->setMinimumValue(0); + m_vthumb->setMaximumValue(max); + m_vthumb->setDefaultValue(defaultStep); + m_vthumb->setValue(layer->getCurrentVerticalZoomStep()); + } + } + + if (m_manager && m_manager->getZoomWheelsEnabled() && + width() > 120 && height() > 100) { + if (m_vthumb->isVisible()) { + m_headsUpDisplay->move(width() - 86, height() - 86); + } else { + m_headsUpDisplay->move(width() - 86, height() - 51); + } + if (!m_headsUpDisplay->isVisible()) { + m_headsUpDisplay->show(); + connect(m_manager, SIGNAL(zoomLevelChanged()), + this, SLOT(zoomLevelChanged())); + } + } else { + m_headsUpDisplay->hide(); + if (m_manager) { + disconnect(m_manager, SIGNAL(zoomLevelChanged()), + this, SLOT(zoomLevelChanged())); + } + } } bool @@ -409,8 +511,14 @@ } int lly = height() - 6; + int llx = width() - maxTextWidth - 5; - if (r.x() + r.width() >= width() - maxTextWidth - 5) { + if (m_manager->getZoomWheelsEnabled()) { + lly -= 20; + llx -= 20; + } + + if (r.x() + r.width() >= llx) { for (int i = 0; i < texts.size(); ++i) { @@ -418,7 +526,7 @@ paint.setPen(Qt::black); } - drawVisibleText(paint, width() - maxTextWidth - 5, + drawVisibleText(paint, llx, lly - fontHeight + fontAscent, texts[i], OutlinedText); @@ -930,6 +1038,12 @@ } void +Pane::resizeEvent(QResizeEvent *) +{ + updateHeadsUpDisplay(); +} + +void Pane::wheelEvent(QWheelEvent *e) { //std::cerr << "wheelEvent, delta " << e->delta() << std::endl; @@ -999,7 +1113,7 @@ int count = 0; int level = 1; while (true) { - if (value == count) break; + if (m_hthumb->getMaximumValue() - value == count) break; int newLevel = getZoomConstraintBlockSize(level + 1, ZoomConstraint::RoundUp); if (newLevel == level) break; @@ -1007,13 +1121,27 @@ ++count; } - std::cerr << "new level is " << level << std::endl; +// std::cerr << "new level is " << level << std::endl; setZoomLevel(level); } void Pane::verticalThumbwheelMoved(int value) { + Layer *layer = 0; + if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1); + if (layer) { + int defaultStep = 0; + int max = layer->getVerticalZoomSteps(defaultStep); + if (max == 0) { + updateHeadsUpDisplay(); + return; + } + if (value > max) { + value = max; + } + layer->setVerticalZoomStep(value); + } } bool @@ -1126,6 +1254,57 @@ } } +void +Pane::zoomWheelsEnabledChanged() +{ + updateHeadsUpDisplay(); + update(); +} + +void +Pane::zoomLevelChanged() +{ + if (m_manager && m_manager->getZoomWheelsEnabled()) { + updateHeadsUpDisplay(); + } +} + +void +Pane::propertyContainerSelected(View *v, PropertyContainer *pc) +{ + Layer *layer = 0; + + if (getLayerCount() > 0) { + layer = getLayer(getLayerCount() - 1); + disconnect(layer, SIGNAL(verticalZoomChanged()), + this, SLOT(verticalZoomChanged())); + } + + View::propertyContainerSelected(v, pc); + updateHeadsUpDisplay(); + + if (getLayerCount() > 0) { + layer = getLayer(getLayerCount() - 1); + connect(layer, SIGNAL(verticalZoomChanged()), + this, SLOT(verticalZoomChanged())); + } +} + +void +Pane::verticalZoomChanged() +{ + Layer *layer = 0; + + if (getLayerCount() > 0) { + + layer = getLayer(getLayerCount() - 1); + + if (m_vthumb && m_vthumb->isVisible()) { + m_vthumb->setValue(layer->getCurrentVerticalZoomStep()); + } + } +} + QString Pane::toXmlString(QString indent, QString extraAttributes) const {
--- a/view/Pane.h Thu Aug 03 15:40:11 2006 +0000 +++ b/view/Pane.h Fri Aug 04 17:01:37 2006 +0000 @@ -27,6 +27,7 @@ class QWidget; class QPaintEvent; class Layer; +class Thumbwheel; class Pane : public View { @@ -54,9 +55,14 @@ public slots: virtual void toolModeChanged(); + virtual void zoomWheelsEnabledChanged(); + virtual void zoomLevelChanged(); virtual void horizontalThumbwheelMoved(int value); virtual void verticalThumbwheelMoved(int value); + virtual void verticalZoomChanged(); + + virtual void propertyContainerSelected(View *, PropertyContainer *pc); protected: virtual void paintEvent(QPaintEvent *e); @@ -66,6 +72,7 @@ virtual void mouseDoubleClickEvent(QMouseEvent *e); virtual void leaveEvent(QEvent *e); virtual void wheelEvent(QWheelEvent *e); + virtual void resizeEvent(QResizeEvent *e); Selection getSelectionAt(int x, bool &closeToLeft, bool &closeToRight) const; @@ -74,6 +81,8 @@ bool editSelectionEnd(QMouseEvent *e); bool selectionIsBeingEdited() const; + void updateHeadsUpDisplay(); + bool m_identifyFeatures; QPoint m_identifyPoint; QPoint m_clickPos; @@ -88,6 +97,10 @@ size_t m_selectionStartFrame; Selection m_editingSelection; int m_editingSelectionEdge; + + QWidget *m_headsUpDisplay; + Thumbwheel *m_hthumb; + Thumbwheel *m_vthumb; }; #endif
--- a/view/View.cpp Thu Aug 03 15:40:11 2006 +0000 +++ b/view/View.cpp Fri Aug 04 17:01:37 2006 +0000 @@ -262,6 +262,18 @@ // std::cerr << "View::toolModeChanged(" << m_manager->getToolMode() << ")" << std::endl; } +void +View::overlayModeChanged() +{ + update(); +} + +void +View::zoomWheelsEnabledChanged() +{ + // subclass might override this +} + long View::getStartFrame() const { @@ -525,7 +537,9 @@ connect(m_manager, SIGNAL(inProgressSelectionChanged()), this, SLOT(selectionChanged())); connect(m_manager, SIGNAL(overlayModeChanged()), - this, SLOT(update())); + this, SLOT(overlayModeChanged())); + connect(m_manager, SIGNAL(zoomWheelsEnabledChanged()), + this, SLOT(zoomWheelsEnabledChanged())); connect(this, SIGNAL(centreFrameChanged(void *, unsigned long, bool)), m_manager, SIGNAL(centreFrameChanged(void *, unsigned long, bool)));
--- a/view/View.h Thu Aug 03 15:40:11 2006 +0000 +++ b/view/View.h Fri Aug 04 17:01:37 2006 +0000 @@ -258,6 +258,8 @@ virtual void selectionChanged(); virtual void toolModeChanged(); + virtual void overlayModeChanged(); + virtual void zoomWheelsEnabledChanged(); protected: View(QWidget *, bool showProgress);
--- a/view/ViewManager.cpp Thu Aug 03 15:40:11 2006 +0000 +++ b/view/ViewManager.cpp Fri Aug 04 17:01:37 2006 +0000 @@ -18,6 +18,8 @@ #include "data/model/Model.h" #include "base/CommandHistory.h" +#include <QSettings> + #include <iostream> // #define DEBUG_VIEW_MANAGER 1 @@ -34,8 +36,17 @@ m_toolMode(NavigateMode), m_playLoopMode(false), m_playSelectionMode(false), - m_overlayMode(BasicOverlays) + m_overlayMode(BasicOverlays), + m_zoomWheelsEnabled(true) { + QSettings settings; + settings.beginGroup("MainWindow"); + m_overlayMode = OverlayMode + (settings.value("overlay-mode", int(m_overlayMode)).toInt()); + m_zoomWheelsEnabled = + settings.value("zoom-wheels-enabled", m_zoomWheelsEnabled).toBool(); + settings.endGroup(); + connect(this, SIGNAL(centreFrameChanged(void *, unsigned long, bool)), SLOT(considerSeek(void *, unsigned long, bool))); @@ -337,6 +348,8 @@ void ViewManager::considerZoomChange(void *p, unsigned long z, bool locked) { + emit zoomLevelChanged(); + if (locked) { m_globalZoom = z; } @@ -353,9 +366,24 @@ m_overlayMode = mode; emit overlayModeChanged(); } + + QSettings settings; + settings.beginGroup("MainWindow"); + settings.setValue("overlay-mode", int(m_overlayMode)); + settings.endGroup(); } -#ifdef INCLUDE_MOCFILES -#include "ViewManager.moc.cpp" -#endif +void +ViewManager::setZoomWheelsEnabled(bool enabled) +{ + if (m_zoomWheelsEnabled != enabled) { + m_zoomWheelsEnabled = enabled; + emit zoomWheelsEnabledChanged(); + } + QSettings settings; + settings.beginGroup("MainWindow"); + settings.setValue("zoom-wheels-enabled", m_zoomWheelsEnabled); + settings.endGroup(); +} +
--- a/view/ViewManager.h Thu Aug 03 15:40:11 2006 +0000 +++ b/view/ViewManager.h Fri Aug 04 17:01:37 2006 +0000 @@ -105,6 +105,9 @@ void setOverlayMode(OverlayMode mode); OverlayMode getOverlayMode() const { return m_overlayMode; } + void setZoomWheelsEnabled(bool enable); + bool getZoomWheelsEnabled() const { return m_zoomWheelsEnabled; } + signals: /** Emitted when a widget pans. The originator identifies the widget. */ void centreFrameChanged(void *originator, unsigned long frame, bool locked); @@ -112,6 +115,9 @@ /** Emitted when a widget zooms. The originator identifies the widget. */ void zoomLevelChanged(void *originator, unsigned long zoom, bool locked); + /** Emitted when a widget zooms. */ + void zoomLevelChanged(); + /** Emitted when the playback frame changes. */ void playbackFrameChanged(unsigned long frame); @@ -136,6 +142,9 @@ /** Emitted when the overlay mode has been changed. */ void overlayModeChanged(); + /** Emitted when the zoom wheels have been toggled. */ + void zoomWheelsEnabledChanged(); + protected slots: void checkPlayStatus(); void playStatusChanged(bool playing); @@ -182,6 +191,7 @@ }; OverlayMode m_overlayMode; + bool m_zoomWheelsEnabled; }; #endif
--- a/widgets/Thumbwheel.cpp Thu Aug 03 15:40:11 2006 +0000 +++ b/widgets/Thumbwheel.cpp Fri Aug 04 17:01:37 2006 +0000 @@ -23,22 +23,21 @@ #include <cmath> #include <iostream> -Thumbwheel::Thumbwheel(int min, int max, int defaultValue, - Qt::Orientation orientation, +Thumbwheel::Thumbwheel(Qt::Orientation orientation, QWidget *parent) : QWidget(parent), - m_min(min), - m_max(max), - m_default(defaultValue), - m_value((min + max) / 2), + m_min(0), + m_max(100), + m_default(50), + m_value(50), m_orientation(orientation), + m_speed(0.25), m_tracking(true), m_showScale(true), m_clicked(false), + m_atDefault(true), m_clickValue(m_value) { - if (max <= min) max = min + 1; - m_speed = float(max - min) / 300.f; } Thumbwheel::~Thumbwheel() @@ -46,14 +45,78 @@ } void +Thumbwheel::setMinimumValue(int min) +{ + if (m_min == min) return; + + m_min = min; + if (m_max <= m_min) m_max = m_min + 1; + if (m_value < m_min) m_value = m_min; + if (m_value > m_max) m_value = m_max; +} + +int +Thumbwheel::getMinimumValue() const +{ + return m_min; +} + +void +Thumbwheel::setMaximumValue(int max) +{ + if (m_max == max) return; + + m_max = max; + if (m_min >= m_max) m_min = m_max - 1; + if (m_value < m_min) m_value = m_min; + if (m_value > m_max) m_value = m_max; +} + +int +Thumbwheel::getMaximumValue() const +{ + return m_max; +} + +void +Thumbwheel::setDefaultValue(int deft) +{ + if (m_default == deft) return; + + m_default = deft; + if (m_atDefault) { + setValue(m_default); + emit valueChanged(getValue()); + } +} + +int +Thumbwheel::getDefaultValue() const +{ + return m_default; +} + +void Thumbwheel::setValue(int value) { + if (m_value == value) return; + m_atDefault = false; + if (value < m_min) value = m_min; if (value > m_max) value = m_max; m_value = value; update(); } +void +Thumbwheel::resetToDefault() +{ + if (m_default == m_value) return; + setValue(m_default); + m_atDefault = true; + emit valueChanged(getValue()); +} + int Thumbwheel::getValue() const { @@ -99,21 +162,25 @@ void Thumbwheel::mousePressEvent(QMouseEvent *e) { - m_clicked = true; - m_clickPos = e->pos(); - m_clickValue = m_value; + if (e->button() == Qt::LeftButton) { + m_clicked = true; + m_clickPos = e->pos(); + m_clickValue = m_value; + } else if (e->button() == Qt::MidButton) { + resetToDefault(); + } } void Thumbwheel::mouseDoubleClickEvent(QMouseEvent *) { - setValue(m_default); - emit valueChanged(getValue()); + resetToDefault(); } void Thumbwheel::mouseMoveEvent(QMouseEvent *e) { + if (!m_clicked) return; int dist = 0; if (m_orientation == Qt::Horizontal) { dist = e->x() - m_clickPos.x(); @@ -132,10 +199,12 @@ void Thumbwheel::mouseReleaseEvent(QMouseEvent *e) { + if (!m_clicked) return; bool reallyTracking = m_tracking; m_tracking = true; mouseMoveEvent(e); m_tracking = reallyTracking; + m_clicked = false; } void @@ -156,12 +225,27 @@ void Thumbwheel::paintEvent(QPaintEvent *) { + QPainter paint(this); + paint.fillRect(rect(), palette().background().color()); + paint.setRenderHint(QPainter::Antialiasing, false); + + int bw = 3; + + for (int i = 0; i < bw; ++i) { + int grey = (i + 1) * (256 / (bw + 1)); + QColor fc = QColor(grey, grey, grey); + paint.setPen(fc); + paint.drawRect(i, i, width() - i*2 - 1, height() - i*2 - 1); + } + + paint.setClipRect(QRect(bw, bw, width() - bw*2, height() - bw*2)); + float distance = float(m_value - m_min) / float(m_max - m_min); float rotation = distance * 1.5f * M_PI; // std::cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << std::endl; - int w = (m_orientation == Qt::Horizontal ? width() : height()); + int w = (m_orientation == Qt::Horizontal ? width() : height()) - bw*2; // total number of notches on the entire wheel int notches = 25; @@ -169,8 +253,6 @@ // radius of the wheel including invisible part int radius = w / 2 + 2; - QPainter paint(this); - paint.fillRect(rect(), palette().background().color()); paint.setRenderHint(QPainter::Antialiasing, true); for (int i = 0; i < notches; ++i) { @@ -190,6 +272,10 @@ if (x0 < 0) x0 = 0; if (x2 > w) x2 = w; + x0 += bw; + x1 += bw; + x2 += bw; + int grey = lrintf(255 * depth); QColor fc = QColor(grey, grey, grey); QColor oc = palette().dark().color(); @@ -198,9 +284,9 @@ paint.setBrush(fc); if (m_orientation == Qt::Horizontal) { - paint.drawRect(QRectF(x1, 0, x2 - x1, height())); + paint.drawRect(QRectF(x1, bw, x2 - x1, height() - bw*2)); } else { - paint.drawRect(QRectF(0, x1, width(), x2 - x1)); + paint.drawRect(QRectF(bw, x1, width() - bw*2, x2 - x1)); } if (m_showScale) { @@ -216,10 +302,10 @@ } if (m_orientation == Qt::Horizontal) { - paint.drawRect(QRectF(x1, height() - height() * prop, + paint.drawRect(QRectF(x1, height() - (height() - bw*2) * prop - bw, x2 - x1, height() * prop)); } else { - paint.drawRect(QRectF(0, x1, width() * prop, x2 - x1)); + paint.drawRect(QRectF(bw, x1, (width() - bw*2) * prop, x2 - x1)); } } @@ -227,9 +313,9 @@ paint.setBrush(palette().background().color()); if (m_orientation == Qt::Horizontal) { - paint.drawRect(QRectF(x0, 0, x1 - x0, height())); + paint.drawRect(QRectF(x0, bw, x1 - x0, height() - bw*2)); } else { - paint.drawRect(QRectF(0, x0, width(), x1 - x0)); + paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0)); } } }
--- a/widgets/Thumbwheel.h Thu Aug 03 15:40:11 2006 +0000 +++ b/widgets/Thumbwheel.h Fri Aug 04 17:01:37 2006 +0000 @@ -23,20 +23,15 @@ Q_OBJECT public: - Thumbwheel(int min, int max, int defaultValue, - Qt::Orientation orientation, QWidget *parent = 0); + Thumbwheel(Qt::Orientation orientation, QWidget *parent = 0); virtual ~Thumbwheel(); - void setSpeed(float speed); + int getMinimumValue() const; + int getMaximumValue() const; + int getDefaultValue() const; float getSpeed() const; - - void setTracking(bool tracking); bool getTracking() const; - - void setShowScale(bool show); bool getShowScale() const; - - void setValue(int value); int getValue() const; virtual void mousePressEvent(QMouseEvent *e); @@ -51,6 +46,16 @@ signals: void valueChanged(int); +public slots: + void setMinimumValue(int min); + void setMaximumValue(int max); + void setDefaultValue(int deft); + void setSpeed(float speed); + void setTracking(bool tracking); + void setShowScale(bool show); + void setValue(int value); + void resetToDefault(); + private: int m_min; int m_max; @@ -61,6 +66,7 @@ bool m_tracking; bool m_showScale; bool m_clicked; + bool m_atDefault; QPoint m_clickPos; int m_clickValue; };