Mercurial > hg > svgui
changeset 1045:f535f6e5dbb0 alignment-simple
Merge in from SV 3.0-integration branches
author | Chris Cannam |
---|---|
date | Wed, 02 Mar 2016 17:25:27 +0000 |
parents | f2c63ec85901 (current diff) 4e5c1c326794 (diff) |
children | 834e94eb1bca |
files | svgui.pro view/View.h |
diffstat | 62 files changed, 2768 insertions(+), 1940 deletions(-) [+] |
line wrap: on
line diff
--- a/acinclude.m4 Mon Jun 15 09:15:55 2015 +0100 +++ b/acinclude.m4 Wed Mar 02 17:25:27 2016 +0000 @@ -69,6 +69,9 @@ AC_CHECK_PROG(QMAKE, qmake-qt5, $QTDIR/bin/qmake-qt5,,$QTDIR/bin/) fi if test x$QMAKE = x ; then + AC_CHECK_PROG(QMAKE, qt5-qmake, $QTDIR/bin/qt5-qmake,,$QTDIR/bin/) +fi +if test x$QMAKE = x ; then AC_CHECK_PROG(QMAKE, qmake, $QTDIR/bin/qmake,,$QTDIR/bin/) fi if test x$QMAKE = x ; then @@ -78,6 +81,9 @@ AC_CHECK_PROG(QMAKE, qmake-qt5, qmake-qt5,,$PATH) fi if test x$QMAKE = x ; then + AC_CHECK_PROG(QMAKE, qt5-qmake, qt5-qmake,,$PATH) +fi +if test x$QMAKE = x ; then AC_CHECK_PROG(QMAKE, qmake, qmake,,$PATH) fi if test x$QMAKE = x ; then
--- a/configure Mon Jun 15 09:15:55 2015 +0100 +++ b/configure Wed Mar 02 17:25:27 2016 +0000 @@ -4137,6 +4137,45 @@ fi if test x$QMAKE = x ; then + # Extract the first word of "qt5-qmake", so it can be a program name with args. +set dummy qt5-qmake; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_QMAKE+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$QMAKE"; then + ac_cv_prog_QMAKE="$QMAKE" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $QTDIR/bin/ +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_QMAKE="$QTDIR/bin/qt5-qmake" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +QMAKE=$ac_cv_prog_QMAKE +if test -n "$QMAKE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $QMAKE" >&5 +$as_echo "$QMAKE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test x$QMAKE = x ; then # Extract the first word of "qmake", so it can be a program name with args. set dummy qmake; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -4254,6 +4293,45 @@ fi if test x$QMAKE = x ; then + # Extract the first word of "qt5-qmake", so it can be a program name with args. +set dummy qt5-qmake; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_QMAKE+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$QMAKE"; then + ac_cv_prog_QMAKE="$QMAKE" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_QMAKE="qt5-qmake" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +QMAKE=$ac_cv_prog_QMAKE +if test -n "$QMAKE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $QMAKE" >&5 +$as_echo "$QMAKE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test x$QMAKE = x ; then # Extract the first word of "qmake", so it can be a program name with args. set dummy qmake; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
--- a/configure.ac Mon Jun 15 09:15:55 2015 +0100 +++ b/configure.ac Wed Mar 02 17:25:27 2016 +0000 @@ -88,7 +88,7 @@ SV_MODULE_REQUIRED([rubberband],[rubberband],[rubberband/RubberBandStretcher.h],[rubberband],[rubberband_new]) SV_MODULE_OPTIONAL([liblo],[],[lo/lo.h],[lo],[lo_address_new]) -SV_MODULE_OPTIONAL([portaudio_2_0],[portaudio-2.0 >= 19],[portaudio.h],[portaudio],[Pa_IsFormatSupported]) +SV_MODULE_OPTIONAL([portaudio],[portaudio-2.0 >= 19],[portaudio.h],[portaudio],[Pa_IsFormatSupported]) SV_MODULE_OPTIONAL([JACK],[jack >= 0.100],[jack/jack.h],[jack],[jack_client_open]) SV_MODULE_OPTIONAL([libpulse],[libpulse >= 0.9],[pulse/pulseaudio.h],[pulse],[pa_stream_new]) SV_MODULE_OPTIONAL([lrdf],[lrdf >= 0.2],[lrdf.h],[lrdf],[lrdf_init])
--- a/layer/Colour3DPlotLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/Colour3DPlotLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -25,6 +25,7 @@ #include <QImage> #include <QRect> #include <QTextStream> +#include <QSettings> #include <iostream> @@ -54,14 +55,16 @@ m_normalizeVisibleArea(false), m_normalizeHybrid(false), m_invertVertical(false), - m_rectified(false), m_opaque(false), m_smooth(false), m_peakResolution(256), m_miny(0), m_maxy(0) { - + QSettings settings; + settings.beginGroup("Preferences"); + setColourMap(settings.value("colour-3d-plot-colour", ColourMapper::Green).toInt()); + settings.endGroup(); } Colour3DPlotLayer::~Colour3DPlotLayer() @@ -163,7 +166,6 @@ list.push_back("Gain"); list.push_back("Bin Scale"); list.push_back("Invert Vertical Scale"); - list.push_back("Show Rectified"); list.push_back("Opaque"); list.push_back("Smooth"); return list; @@ -177,7 +179,6 @@ if (name == "Normalize Columns") return tr("Normalize Columns"); if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale"); - if (name == "Show Rectified") return tr("Half-Wave Rectify"); if (name == "Gain") return tr("Gain"); if (name == "Opaque") return tr("Always Opaque"); if (name == "Smooth") return tr("Smooth"); @@ -191,7 +192,6 @@ if (name == "Normalize Columns") return "normalise-columns"; if (name == "Normalize Visible Area") return "normalise"; if (name == "Invert Vertical Scale") return "invert-vertical"; - if (name == "Show Rectified") return "derivative"; if (name == "Opaque") return "opaque"; if (name == "Smooth") return "smooth"; return ""; @@ -204,7 +204,6 @@ if (name == "Normalize Columns") return ToggleProperty; if (name == "Normalize Visible Area") return ToggleProperty; if (name == "Invert Vertical Scale") return ToggleProperty; - if (name == "Show Rectified") return ToggleProperty; if (name == "Opaque") return ToggleProperty; if (name == "Smooth") return ToggleProperty; return ValueProperty; @@ -216,7 +215,6 @@ if (name == "Normalize Columns" || name == "Normalize Visible Area" || name == "Colour Scale" || - name == "Show Rectified" || name == "Gain") return tr("Scale"); if (name == "Bin Scale" || name == "Invert Vertical Scale") return tr("Bins"); @@ -281,13 +279,6 @@ *deflt = 0; val = (m_invertVertical ? 1 : 0); - } else if (name == "Show Rectified") { - - if (min) *min = 0; - if (max) *max = 0; - if (deflt) *deflt = 0; - val = (m_rectified ? 1.0 : 0.0); - } else if (name == "Bin Scale") { *min = 0; @@ -368,8 +359,6 @@ setNormalizeVisibleArea(value ? true : false); } else if (name == "Invert Vertical Scale") { setInvertVertical(value ? true : false); - } else if (name == "Show Rectified") { - setShowRectified(value > 0.5); } else if (name == "Opaque") { setOpaque(value ? true : false); } else if (name == "Smooth") { @@ -487,15 +476,6 @@ } void -Colour3DPlotLayer::setShowRectified(bool show) -{ - if (m_rectified == show) return; - m_rectified = show; - cacheInvalid(); - emit layerParametersChanged(); -} - -void Colour3DPlotLayer::setOpaque(bool n) { if (m_opaque == n) return; @@ -530,7 +510,7 @@ } void -Colour3DPlotLayer::setLayerDormant(const View *v, bool dormant) +Colour3DPlotLayer::setLayerDormant(const LayerGeometryProvider *v, bool dormant) { if (dormant) { @@ -554,7 +534,7 @@ } bool -Colour3DPlotLayer::isLayerScrollable(const View *v) const +Colour3DPlotLayer::isLayerScrollable(const LayerGeometryProvider *v) const { if (m_normalizeVisibleArea) { return false; @@ -613,7 +593,7 @@ } bool -Colour3DPlotLayer::getYScaleValue(const View *, int, +Colour3DPlotLayer::getYScaleValue(const LayerGeometryProvider *, int, double &, QString &) const { return false;//!!! @@ -669,13 +649,13 @@ } double -Colour3DPlotLayer::getYForBin(View *v, double bin) const +Colour3DPlotLayer::getYForBin(LayerGeometryProvider *v, double bin) const { double y = bin; if (!m_model) return y; double mn = 0, mx = m_model->getHeight(); getDisplayExtents(mn, mx); - double h = v->height(); + double h = v->getPaintHeight(); if (m_binScale == LinearBinScale) { y = h - (((bin - mn) * h) / (mx - mn)); } else { @@ -687,19 +667,19 @@ } int -Colour3DPlotLayer::getIYForBin(View *v, int bin) const +Colour3DPlotLayer::getIYForBin(LayerGeometryProvider *v, int bin) const { return int(round(getYForBin(v, bin))); } double -Colour3DPlotLayer::getBinForY(View *v, double y) const +Colour3DPlotLayer::getBinForY(LayerGeometryProvider *v, double y) const { double bin = y; if (!m_model) return bin; double mn = 0, mx = m_model->getHeight(); getDisplayExtents(mn, mx); - double h = v->height(); + double h = v->getPaintHeight(); if (m_binScale == LinearBinScale) { bin = mn + ((h - y) * (mx - mn)) / h; } else { @@ -711,13 +691,13 @@ } int -Colour3DPlotLayer::getIBinForY(View *v, int y) const +Colour3DPlotLayer::getIBinForY(LayerGeometryProvider *v, int y) const { return int(floor(getBinForY(v, y))); } QString -Colour3DPlotLayer::getFeatureDescription(View *v, QPoint &pos) const +Colour3DPlotLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { if (!m_model) return ""; @@ -748,8 +728,8 @@ if (symin < 0) symin = 0; if (symax > sh) symax = sh; - // double binHeight = double(v->height()) / (symax - symin); -// int sy = int((v->height() - y) / binHeight) + symin; + // double binHeight = double(v->getPaintHeight()) / (symax - symin); +// int sy = int((v->getPaintHeight() - y) / binHeight) + symin; int sy = getIBinForY(v, y); @@ -779,14 +759,15 @@ } int -Colour3DPlotLayer::getColourScaleWidth(QPainter &) const +Colour3DPlotLayer::getColourScaleWidth(QPainter &p) const { - int cw = 20; + // Font is rotated + int cw = p.fontMetrics().height(); return cw; } int -Colour3DPlotLayer::getVerticalScaleWidth(View *, bool, QPainter &paint) const +Colour3DPlotLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const { if (!m_model) return 0; @@ -808,7 +789,7 @@ } void -Colour3DPlotLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const +Colour3DPlotLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const { if (!m_model) return; @@ -868,7 +849,7 @@ paint.save(); QFont font = paint.font(); - font.setPixelSize(10); + font.setPixelSize(int(font.pixelSize() * 0.65)); paint.setFont(font); int msw = paint.fontMetrics().width(maxstr); @@ -906,6 +887,8 @@ int py = h; + int defaultFontHeight = paint.fontMetrics().height(); + for (int i = symin; i <= symax; ++i) { int y0; @@ -915,9 +898,9 @@ if (i > symin) { if (paint.fontMetrics().height() >= h) { - if (h >= 8) { + if (h >= defaultFontHeight * 0.8) { QFont tf = paint.font(); - tf.setPixelSize(h-2); + tf.setPixelSize(int(h * 0.8)); paint.setFont(tf); } else { continue; @@ -954,36 +937,25 @@ { Profiler profiler("Colour3DPlotLayer::getColumn"); - DenseThreeDimensionalModel::Column prev; - if (m_rectified && (col > m_model->getStartFrame())) { - prev = m_model->getColumn(col - 1); - } - DenseThreeDimensionalModel::Column values = m_model->getColumn(col); - - if (m_rectified && !prev.empty()) { - for (int y = 0; y < values.size(); ++y) { - if (values[y] < prev[y]) values[y] = 0; - else values[y] -= prev[y]; - } - } - - while (values.size() < m_model->getHeight()) values.push_back(0.f); + values.resize(m_model->getHeight(), 0.f); if (!m_normalizeColumns && !m_normalizeHybrid) return values; double colMax = 0.f, colMin = 0.f; double min = 0.f, max = 0.f; + int nv = int(values.size()); + min = m_model->getMinimumLevel(); max = m_model->getMaximumLevel(); - for (int y = 0; y < values.size(); ++y) { + for (int y = 0; y < nv; ++y) { if (y == 0 || values.at(y) > colMax) colMax = values.at(y); if (y == 0 || values.at(y) < colMin) colMin = values.at(y); } if (colMin == colMax) colMax = colMin + 1; - for (int y = 0; y < values.size(); ++y) { + for (int y = 0; y < nv; ++y) { double value = values.at(y); double norm = (value - colMin) / (colMax - colMin); @@ -994,7 +966,7 @@ if (m_normalizeHybrid && (colMax > 0.0)) { double logmax = log10(colMax); - for (int y = 0; y < values.size(); ++y) { + for (int y = 0; y < nv; ++y) { values[y] = float(values[y] * logmax); } } @@ -1166,7 +1138,7 @@ double colMax = 0.f, colMin = 0.f; for (int y = 0; y < cacheHeight; ++y) { - if (y >= values.size()) break; + if (!in_range_for(values, y)) break; if (y == 0 || values[y] > colMax) colMax = values[y]; if (y == 0 || values[y] < colMin) colMin = values[y]; } @@ -1216,7 +1188,7 @@ for (int y = 0; y < cacheHeight; ++y) { double value = min; - if (y < values.size()) { + if (in_range_for(values, y)) { value = values.at(y); } @@ -1283,7 +1255,7 @@ } bool -Colour3DPlotLayer::shouldPaintDenseIn(const View *v) const +Colour3DPlotLayer::shouldPaintDenseIn(const LayerGeometryProvider *v) const { if (!m_model || !v || !(v->getViewManager())) { return false; @@ -1292,7 +1264,7 @@ v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate(); if (m_opaque || m_smooth || - m_model->getHeight() >= v->height() || + m_model->getHeight() >= v->getPaintHeight() || ((m_model->getResolution() * srRatio) / v->getZoomLevel()) < 2) { return true; } @@ -1300,7 +1272,7 @@ } void -Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const +Colour3DPlotLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { /* if (m_model) { @@ -1315,13 +1287,13 @@ int completion = 0; if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) { if (completion > 0) { - paint.fillRect(0, 10, v->width() * completion / 100, + paint.fillRect(0, 10, v->getPaintWidth() * completion / 100, 10, QColor(120, 120, 120)); } return; } - if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect(); + if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->getPaintRect(); sv_frame_t modelStart = m_model->getStartFrame(); sv_frame_t modelEnd = m_model->getEndFrame(); @@ -1339,7 +1311,7 @@ int x0 = rect.left(); int x1 = rect.right() + 1; - int h = v->height(); + int h = v->getPaintHeight(); double srRatio = v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate(); @@ -1461,7 +1433,7 @@ } void -Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const +Colour3DPlotLayer::paintDense(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { Profiler profiler("Colour3DPlotLayer::paintDense", true); if (!m_cache) return; @@ -1477,7 +1449,7 @@ int x1 = rect.right() + 1; const int w = x1 - x0; // const so it can be used as array size below - int h = v->height(); // we always paint full height + int h = v->getPaintHeight(); // we always paint full height int sh = m_model->getHeight(); int symin = m_miny; @@ -1692,7 +1664,7 @@ } bool -Colour3DPlotLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, +Colour3DPlotLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const {
--- a/layer/Colour3DPlotLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/Colour3DPlotLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -49,20 +49,20 @@ return m_model ? m_model->getZoomConstraint() : 0; } virtual const Model *getModel() const { return m_model; } - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; - virtual int getVerticalScaleWidth(View *v, bool, QPainter &) const; - virtual void paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const; + virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &) const; + virtual void paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; - virtual bool snapToFeatureFrame(View *v, sv_frame_t &frame, + virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual void setLayerDormant(const View *v, bool dormant); + virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant); - virtual bool isLayerScrollable(const View *v) const; + virtual bool isLayerScrollable(const LayerGeometryProvider *v) const; virtual ColourSignificance getLayerColourSignificance() const { return ColourHasMeaningfulValue; @@ -70,7 +70,7 @@ void setModel(const DenseThreeDimensionalModel *model); - virtual int getCompletion(View *) const { return m_model->getCompletion(); } + virtual int getCompletion(LayerGeometryProvider *) const { return m_model->getCompletion(); } virtual PropertyList getProperties() const; virtual PropertyType getPropertyType(const PropertyName &) const; @@ -139,9 +139,6 @@ void setInvertVertical(bool i); bool getInvertVertical() const; - void setShowRectified(bool); - bool getShowRectified() const { return m_rectified; } - void setOpaque(bool i); bool getOpaque() const; @@ -154,7 +151,7 @@ virtual bool getDisplayExtents(double &min, double &max) const; virtual bool setDisplayExtents(double min, double max); - virtual bool getYScaleValue(const View *, int /* y */, + virtual bool getYScaleValue(const LayerGeometryProvider *, int /* y */, double &/* value */, QString &/* unit */) const; virtual int getVerticalZoomSteps(int &defaultStep) const; @@ -190,7 +187,6 @@ bool m_normalizeVisibleArea; bool m_normalizeHybrid; bool m_invertVertical; - bool m_rectified; bool m_opaque; bool m_smooth; int m_peakResolution; @@ -206,12 +202,12 @@ * and the vertical scale is the usual way up). Bin number may be * fractional, to obtain a position part-way through a bin. */ - double getYForBin(View *, double bin) const; + double getYForBin(LayerGeometryProvider *, double bin) const; /** * As getYForBin, but rounding to integer values. */ - int getIYForBin(View *, int bin) const; + int getIYForBin(LayerGeometryProvider *, int bin) const; /** * Return the bin number, possibly fractional, at the given y @@ -219,12 +215,12 @@ * at which the bins "start" (i.e. the bottom of the visible bin, * if the vertical scale is the usual way up). */ - double getBinForY(View *, double y) const; + double getBinForY(LayerGeometryProvider *, double y) const; /** * As getBinForY, but rounding to integer values. */ - int getIBinForY(View *, int y) const; + int getIBinForY(LayerGeometryProvider *, int y) const; DenseThreeDimensionalModel::Column getColumn(int col) const; @@ -233,11 +229,11 @@ * are so small you can't see their borders. False for big, * translucent cells. */ - bool shouldPaintDenseIn(const View *) const; + bool shouldPaintDenseIn(const LayerGeometryProvider *) const; int getColourScaleWidth(QPainter &) const; void fillCache(int firstBin, int lastBin) const; - void paintDense(View *v, QPainter &paint, QRect rect) const; + void paintDense(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; }; #endif
--- a/layer/ColourMapper.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/ColourMapper.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -21,6 +21,44 @@ #include "base/Debug.h" +#include <vector> + +using namespace std; + +static vector<QColor> convertStrings(const vector<QString> &strs) +{ + vector<QColor> converted; + for (const auto &s: strs) converted.push_back(QColor(s)); + reverse(converted.begin(), converted.end()); + return converted; +} + +static vector<QColor> ice = convertStrings({ + // Based on ColorBrewer ylGnBu + "#ffffff", "#ffff00", "#f7fcf0", "#e0f3db", "#ccebc5", "#a8ddb5", + "#7bccc4", "#4eb3d3", "#2b8cbe", "#0868ac", "#084081", "#042040" + }); + +static vector<QColor> cherry = convertStrings({ + "#f7f7f7", "#fddbc7", "#f4a582", "#d6604d", "#b2182b", "#dd3497", + "#ae017e", "#7a0177", "#49006a" + }); + +static void +mapDiscrete(double norm, vector<QColor> &colours, double &r, double &g, double &b) +{ + int n = int(colours.size()); + double m = norm * (n-1); + if (m >= n-1) { colours[n-1].getRgbF(&r, &g, &b, 0); return; } + if (m <= 0) { colours[0].getRgbF(&r, &g, &b, 0); return; } + int base(int(floor(m))); + double prop0 = (base + 1.0) - m, prop1 = m - base; + QColor c0(colours[base]), c1(colours[base+1]); + r = c0.redF() * prop0 + c1.redF() * prop1; + g = c0.greenF() * prop0 + c1.greenF() * prop1; + b = c0.blueF() * prop0 + c1.blueF() * prop1; +} + ColourMapper::ColourMapper(int map, double min, double max) : QObject(), m_map(map), @@ -51,12 +89,12 @@ StandardMap map = (StandardMap)n; switch (map) { - case DefaultColours: return tr("Default"); + case Green: return tr("Green"); case WhiteOnBlack: return tr("White on Black"); case BlackOnWhite: return tr("Black on White"); - case RedOnBlue: return tr("Red on Blue"); - case YellowOnBlack: return tr("Yellow on Black"); - case BlueOnBlack: return tr("Blue on Black"); + case Cherry: return tr("Cherry"); + case Wasp: return tr("Wasp"); + case Ice: return tr("Ice"); case Sunset: return tr("Sunset"); case FruitSalad: return tr("Fruit Salad"); case Banded: return tr("Banded"); @@ -85,7 +123,7 @@ switch (map) { - case DefaultColours: + case Green: h = blue - norm * 2.0 * pieslice; s = 0.5f + norm/2.0; v = norm; @@ -101,30 +139,17 @@ hsv = false; break; - case RedOnBlue: - h = blue - pieslice/4.0 + norm * (pieslice + pieslice/4.0); - s = 1.0; - v = norm; + case Cherry: + hsv = false; + mapDiscrete(norm, cherry, r, g, b); break; - case YellowOnBlack: + case Wasp: h = 0.15; s = 1.0; v = norm; break; - case BlueOnBlack: - h = blue; - s = 1.0; - v = norm * 2.0; - if (v > 1.0) { - v = 1.0; - s = 1.0 - (sqrt(norm) - 0.707) * 3.413; - if (s < 0.0) s = 0.0; - if (s > 1.0) s = 1.0; - } - break; - case Sunset: r = (norm - 0.24) * 2.38; if (r > 1.0) r = 1.0; @@ -207,6 +232,10 @@ hsv = false; */ break; + + case Ice: + hsv = false; + mapDiscrete(norm, ice, r, g, b); } if (hsv) { @@ -224,7 +253,7 @@ switch (map) { - case DefaultColours: + case Green: return QColor(255, 150, 50); case WhiteOnBlack: @@ -233,13 +262,13 @@ case BlackOnWhite: return Qt::darkGreen; - case RedOnBlue: + case Cherry: return Qt::green; - case YellowOnBlack: + case Wasp: return QColor::fromHsv(240, 255, 255); - case BlueOnBlack: + case Ice: return Qt::red; case Sunset: @@ -277,12 +306,12 @@ case HighGain: return true; - case DefaultColours: + case Green: case Sunset: case WhiteOnBlack: - case RedOnBlue: - case YellowOnBlack: - case BlueOnBlack: + case Cherry: + case Wasp: + case Ice: case FruitSalad: case Banded: case Highlight:
--- a/layer/ColourMapper.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/ColourMapper.h Wed Mar 02 17:25:27 2016 +0000 @@ -33,13 +33,13 @@ virtual ~ColourMapper(); enum StandardMap { - DefaultColours, + Green, Sunset, WhiteOnBlack, BlackOnWhite, - RedOnBlue, - YellowOnBlack, - BlueOnBlack, + Cherry, + Wasp, + Ice, FruitSalad, Banded, Highlight,
--- a/layer/ColourScaleLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/ColourScaleLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -19,11 +19,13 @@ #include <QString> #include <QColor> +class LayerGeometryProvider; + class ColourScaleLayer { public: virtual QString getScaleUnits() const = 0; - virtual QColor getColourForValue(View *v, double value) const = 0; + virtual QColor getColourForValue(LayerGeometryProvider *v, double value) const = 0; }; #endif
--- a/layer/FlexiNoteLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/FlexiNoteLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -204,7 +204,7 @@ } bool -FlexiNoteLayer::isLayerScrollable(const View *v) const +FlexiNoteLayer::isLayerScrollable(const LayerGeometryProvider *v) const { QPoint discard; return !v->shouldIlluminateLocalFeatures(this, discard); @@ -405,7 +405,7 @@ } FlexiNoteModel::PointList -FlexiNoteLayer::getLocalPoints(View *v, int x) const +FlexiNoteLayer::getLocalPoints(LayerGeometryProvider *v, int x) const { if (!m_model) return FlexiNoteModel::PointList(); @@ -448,7 +448,7 @@ } bool -FlexiNoteLayer::getPointToDrag(View *v, int x, int y, FlexiNoteModel::Point &p) const +FlexiNoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, FlexiNoteModel::Point &p) const { if (!m_model) return false; @@ -476,7 +476,7 @@ } bool -FlexiNoteLayer::getNoteToEdit(View *v, int x, int y, FlexiNoteModel::Point &p) const +FlexiNoteLayer::getNoteToEdit(LayerGeometryProvider *v, int x, int y, FlexiNoteModel::Point &p) const { // GF: find the note that is closest to the cursor if (!m_model) return false; @@ -505,7 +505,7 @@ } QString -FlexiNoteLayer::getFeatureDescription(View *v, QPoint &pos) const +FlexiNoteLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { int x = pos.x(); @@ -593,7 +593,7 @@ } bool -FlexiNoteLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, +FlexiNoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { @@ -673,7 +673,7 @@ } void -FlexiNoteLayer::getScaleExtents(View *v, double &min, double &max, bool &log) const +FlexiNoteLayer::getScaleExtents(LayerGeometryProvider *v, double &min, double &max, bool &log) const { min = 0.0; max = 0.0; @@ -730,11 +730,11 @@ } int -FlexiNoteLayer::getYForValue(View *v, double val) const +FlexiNoteLayer::getYForValue(LayerGeometryProvider *v, double val) const { double min = 0.0, max = 0.0; bool logarithmic = false; - int h = v->height(); + int h = v->getPaintHeight(); getScaleExtents(v, min, max, logarithmic); @@ -765,11 +765,11 @@ } double -FlexiNoteLayer::getValueForY(View *v, int y) const +FlexiNoteLayer::getValueForY(LayerGeometryProvider *v, int y) const { double min = 0.0, max = 0.0; bool logarithmic = false; - int h = v->height(); + int h = v->getPaintHeight(); getScaleExtents(v, min, max, logarithmic); @@ -794,7 +794,7 @@ } void -FlexiNoteLayer::paint(View *v, QPainter &paint, QRect rect) const +FlexiNoteLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { if (!m_model || !m_model->isOK()) return; @@ -860,8 +860,8 @@ !FlexiNoteModel::Point::Comparator()(illuminatePoint, p) && !FlexiNoteModel::Point::Comparator()(p, illuminatePoint)) { - paint.drawLine(x, -1, x, v->height() + 1); - paint.drawLine(x+w, -1, x+w, v->height() + 1); + paint.drawLine(x, -1, x, v->getPaintHeight() + 1); + paint.drawLine(x+w, -1, x+w, v->getPaintHeight() + 1); paint.setPen(v->getForeground()); // paint.setBrush(v->getForeground()); @@ -904,7 +904,7 @@ } int -FlexiNoteLayer::getVerticalScaleWidth(View *v, bool, QPainter &paint) const +FlexiNoteLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const { if (!m_model || shouldAutoAlign()) { return 0; @@ -918,7 +918,7 @@ } void -FlexiNoteLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect) const +FlexiNoteLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const { if (!m_model || m_model->getPoints().empty()) return; @@ -927,7 +927,7 @@ bool logarithmic; int w = getVerticalScaleWidth(v, false, paint); - int h = v->height(); + int h = v->getPaintHeight(); getScaleExtents(v, min, max, logarithmic); @@ -956,7 +956,7 @@ } void -FlexiNoteLayer::drawStart(View *v, QMouseEvent *e) +FlexiNoteLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "FlexiNoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; @@ -980,7 +980,7 @@ } void -FlexiNoteLayer::drawDrag(View *v, QMouseEvent *e) +FlexiNoteLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "FlexiNoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; @@ -1009,7 +1009,7 @@ } void -FlexiNoteLayer::drawEnd(View *, QMouseEvent *) +FlexiNoteLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) { // SVDEBUG << "FlexiNoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl; if (!m_model || !m_editing) return; @@ -1019,7 +1019,7 @@ } void -FlexiNoteLayer::eraseStart(View *v, QMouseEvent *e) +FlexiNoteLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return; @@ -1034,12 +1034,12 @@ } void -FlexiNoteLayer::eraseDrag(View *, QMouseEvent *) +FlexiNoteLayer::eraseDrag(LayerGeometryProvider *, QMouseEvent *) { } void -FlexiNoteLayer::eraseEnd(View *v, QMouseEvent *e) +FlexiNoteLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -1059,7 +1059,7 @@ } void -FlexiNoteLayer::editStart(View *v, QMouseEvent *e) +FlexiNoteLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "FlexiNoteLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; std::cerr << "FlexiNoteLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl; @@ -1110,7 +1110,7 @@ } void -FlexiNoteLayer::editDrag(View *v, QMouseEvent *e) +FlexiNoteLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "FlexiNoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl; std::cerr << "FlexiNoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl; @@ -1190,7 +1190,7 @@ } void -FlexiNoteLayer::editEnd(View *v, QMouseEvent *e) +FlexiNoteLayer::editEnd(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "FlexiNoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl; std::cerr << "FlexiNoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl; @@ -1229,7 +1229,7 @@ } void -FlexiNoteLayer::splitStart(View *v, QMouseEvent *e) +FlexiNoteLayer::splitStart(LayerGeometryProvider *v, QMouseEvent *e) { // GF: note splitting starts (!! remove printing soon) std::cerr << "splitStart (n.b. editStart will be called later, if the user drags the mouse)" << std::endl; @@ -1252,7 +1252,7 @@ } void -FlexiNoteLayer::splitEnd(View *v, QMouseEvent *e) +FlexiNoteLayer::splitEnd(LayerGeometryProvider *v, QMouseEvent *e) { // GF: note splitting ends. (!! remove printing soon) std::cerr << "splitEnd" << std::endl; @@ -1271,13 +1271,13 @@ } void -FlexiNoteLayer::splitNotesAt(View *v, sv_frame_t frame) +FlexiNoteLayer::splitNotesAt(LayerGeometryProvider *v, sv_frame_t frame) { splitNotesAt(v, frame, 0); } void -FlexiNoteLayer::splitNotesAt(View *v, sv_frame_t frame, QMouseEvent *e) +FlexiNoteLayer::splitNotesAt(LayerGeometryProvider *v, sv_frame_t frame, QMouseEvent *e) { FlexiNoteModel::PointList onPoints = m_model->getPoints(frame); if (onPoints.empty()) return; @@ -1317,7 +1317,7 @@ } void -FlexiNoteLayer::addNote(View *v, QMouseEvent *e) +FlexiNoteLayer::addNote(LayerGeometryProvider *v, QMouseEvent *e) { std::cerr << "addNote" << std::endl; if (!m_model) return; @@ -1356,14 +1356,14 @@ } SparseTimeValueModel * -FlexiNoteLayer::getAssociatedPitchModel(View *v) const +FlexiNoteLayer::getAssociatedPitchModel(LayerGeometryProvider *v) const { // Better than we used to do, but still not very satisfactory // cerr << "FlexiNoteLayer::getAssociatedPitchModel()" << endl; - for (int i = 0; i < v->getLayerCount(); ++i) { - Layer *layer = v->getLayer(i); + for (int i = 0; i < v->getView()->getLayerCount(); ++i) { + Layer *layer = v->getView()->getLayer(i); if (layer && layer->getLayerPresentationName() != "candidate") { // cerr << "FlexiNoteLayer::getAssociatedPitchModel: looks like our layer is " << layer << endl; @@ -1381,7 +1381,7 @@ } void -FlexiNoteLayer::snapSelectedNotesToPitchTrack(View *v, Selection s) +FlexiNoteLayer::snapSelectedNotesToPitchTrack(LayerGeometryProvider *v, Selection s) { if (!m_model) return; @@ -1419,7 +1419,7 @@ } void -FlexiNoteLayer::mergeNotes(View *v, Selection s, bool inclusive) +FlexiNoteLayer::mergeNotes(LayerGeometryProvider *v, Selection s, bool inclusive) { FlexiNoteModel::PointList points = m_model->getPoints(s.getStartFrame(), s.getEndFrame()); @@ -1462,8 +1462,7 @@ } bool -FlexiNoteLayer::updateNoteValueFromPitchCurve(View *v, - FlexiNoteModel::Point ¬e) const +FlexiNoteLayer::updateNoteValueFromPitchCurve(LayerGeometryProvider *v, FlexiNoteModel::Point ¬e) const { SparseTimeValueModel *model = getAssociatedPitchModel(v); if (!model) return false; @@ -1507,13 +1506,13 @@ } void -FlexiNoteLayer::mouseMoveEvent(View *v, QMouseEvent *e) +FlexiNoteLayer::mouseMoveEvent(LayerGeometryProvider *v, QMouseEvent *e) { // GF: context sensitive cursors - // v->setCursor(Qt::ArrowCursor); + // v->getView()->setCursor(Qt::ArrowCursor); FlexiNoteModel::Point note(0); if (!getNoteToEdit(v, e->x(), e->y(), note)) { - // v->setCursor(Qt::UpArrowCursor); + // v->getView()->setCursor(Qt::UpArrowCursor); return; } @@ -1524,28 +1523,28 @@ closeToTop, closeToBottom); if (closeToLeft) { - v->setCursor(Qt::SizeHorCursor); + v->getView()->setCursor(Qt::SizeHorCursor); m_editMode = LeftBoundary; cerr << "edit mode -> LeftBoundary" << endl; } else if (closeToRight) { - v->setCursor(Qt::SizeHorCursor); + v->getView()->setCursor(Qt::SizeHorCursor); m_editMode = RightBoundary; cerr << "edit mode -> RightBoundary" << endl; } else if (closeToTop) { - v->setCursor(Qt::CrossCursor); + v->getView()->setCursor(Qt::CrossCursor); m_editMode = DragNote; cerr << "edit mode -> DragNote" << endl; } else if (closeToBottom) { - v->setCursor(Qt::UpArrowCursor); + v->getView()->setCursor(Qt::UpArrowCursor); m_editMode = SplitNote; cerr << "edit mode -> SplitNote" << endl; } else { - v->setCursor(Qt::ArrowCursor); + v->getView()->setCursor(Qt::ArrowCursor); } } void -FlexiNoteLayer::getRelativeMousePosition(View *v, FlexiNoteModel::Point ¬e, int x, int y, bool &closeToLeft, bool &closeToRight, bool &closeToTop, bool &closeToBottom) const +FlexiNoteLayer::getRelativeMousePosition(LayerGeometryProvider *v, FlexiNoteModel::Point ¬e, int x, int y, bool &closeToLeft, bool &closeToRight, bool &closeToTop, bool &closeToBottom) const { // GF: TODO: consoloidate the tolerance values if (!m_model) return; @@ -1574,7 +1573,7 @@ bool -FlexiNoteLayer::editOpen(View *v, QMouseEvent *e) +FlexiNoteLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) { std::cerr << "Opening note editor dialog" << std::endl; if (!m_model) return false; @@ -1728,7 +1727,7 @@ } void -FlexiNoteLayer::copy(View *v, Selection s, Clipboard &to) +FlexiNoteLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -1746,7 +1745,7 @@ } bool -FlexiNoteLayer::paste(View *v, const Clipboard &from, sv_frame_t /*frameOffset */, bool /* interactive */) +FlexiNoteLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /*frameOffset */, bool /* interactive */) { if (!m_model) return false; @@ -1757,7 +1756,7 @@ if (clipboardHasDifferentAlignment(v, from)) { QMessageBox::StandardButton button = - QMessageBox::question(v, tr("Re-align pasted items?"), + QMessageBox::question(v->getView(), tr("Re-align pasted items?"), tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes); @@ -1894,7 +1893,7 @@ } void -FlexiNoteLayer::setVerticalRangeToNoteRange(View *v) +FlexiNoteLayer::setVerticalRangeToNoteRange(LayerGeometryProvider *v) { double minf = std::numeric_limits<double>::max(); double maxf = 0; @@ -1910,7 +1909,7 @@ std::cerr << "min frequency:" << minf << ", max frequency: " << maxf << std::endl; if (hasNotes) { - v->getLayer(1)->setDisplayExtents(minf*0.66,maxf*1.5); + v->getView()->getLayer(1)->setDisplayExtents(minf*0.66,maxf*1.5); // MM: this is a hack because we rely on // * this layer being automatically aligned to layer 1 // * layer one is a log frequency layer.
--- a/layer/FlexiNoteLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/FlexiNoteLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -38,50 +38,50 @@ public: FlexiNoteLayer(); - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; - virtual int getVerticalScaleWidth(View *v, bool, QPainter &) const; - virtual void paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const; + virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &) const; + virtual void paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; - virtual bool snapToFeatureFrame(View *v, sv_frame_t &frame, + virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual void drawStart(View *v, QMouseEvent *); - virtual void drawDrag(View *v, QMouseEvent *); - virtual void drawEnd(View *v, QMouseEvent *); + virtual void drawStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void eraseStart(View *v, QMouseEvent *); - virtual void eraseDrag(View *v, QMouseEvent *); - virtual void eraseEnd(View *v, QMouseEvent *); + virtual void eraseStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void editStart(View *v, QMouseEvent *); - virtual void editDrag(View *v, QMouseEvent *); - virtual void editEnd(View *v, QMouseEvent *); + virtual void editStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void editDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void editEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void splitStart(View *v, QMouseEvent *); - virtual void splitEnd(View *v, QMouseEvent *); + virtual void splitStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void splitEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void addNote(View *v, QMouseEvent *e); + virtual void addNote(LayerGeometryProvider *v, QMouseEvent *e); - virtual void mouseMoveEvent(View *v, QMouseEvent *); + virtual void mouseMoveEvent(LayerGeometryProvider *v, QMouseEvent *); - virtual bool editOpen(View *v, QMouseEvent *); + virtual bool editOpen(LayerGeometryProvider *v, QMouseEvent *); virtual void moveSelection(Selection s, sv_frame_t newStartFrame); virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); virtual void deleteSelectionInclusive(Selection s); - virtual void copy(View *v, Selection s, Clipboard &to); - virtual bool paste(View *v, const Clipboard &from, sv_frame_t frameOffset, + virtual void copy(LayerGeometryProvider *v, Selection s, Clipboard &to); + virtual bool paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool interactive); - void splitNotesAt(View *v, sv_frame_t frame); - void snapSelectedNotesToPitchTrack(View *v, Selection s); - void mergeNotes(View *v, Selection s, bool inclusive); + void splitNotesAt(LayerGeometryProvider *v, sv_frame_t frame); + void snapSelectedNotesToPitchTrack(LayerGeometryProvider *v, Selection s); + void mergeNotes(LayerGeometryProvider *v, Selection s, bool inclusive); virtual const Model *getModel() const { return m_model; } void setModel(FlexiNoteModel *model); @@ -116,11 +116,11 @@ void setVerticalScale(VerticalScale scale); VerticalScale getVerticalScale() const { return m_verticalScale; } - virtual bool isLayerScrollable(const View *v) const; + virtual bool isLayerScrollable(const LayerGeometryProvider *v) const; virtual bool isLayerEditable() const { return true; } - virtual int getCompletion(View *) const { return m_model->getCompletion(); } + virtual int getCompletion(LayerGeometryProvider *) const { return m_model->getCompletion(); } virtual bool getValueExtents(double &min, double &max, bool &log, QString &unit) const; @@ -156,11 +156,11 @@ void setProperties(const QXmlAttributes &attributes); - void setVerticalRangeToNoteRange(View *v); + void setVerticalRangeToNoteRange(LayerGeometryProvider *v); /// VerticalScaleLayer methods - virtual int getYForValue(View *v, double value) const; - virtual double getValueForY(View *v, int y) const; + virtual int getYForValue(LayerGeometryProvider *v, double value) const; + virtual double getValueForY(LayerGeometryProvider *v, int y) const; virtual QString getScaleUnits() const; signals: @@ -168,23 +168,19 @@ void materialiseReAnalysis(); protected: - void getScaleExtents(View *, double &min, double &max, bool &log) const; + void getScaleExtents(LayerGeometryProvider *, double &min, double &max, bool &log) const; bool shouldConvertMIDIToHz() const; virtual int getDefaultColourHint(bool dark, bool &impose); - FlexiNoteModel::PointList getLocalPoints(View *v, int) const; + FlexiNoteModel::PointList getLocalPoints(LayerGeometryProvider *v, int) const; - bool getPointToDrag(View *v, int x, int y, FlexiNoteModel::Point &) const; - bool getNoteToEdit(View *v, int x, int y, FlexiNoteModel::Point &) const; - void getRelativeMousePosition(View *v, FlexiNoteModel::Point ¬e, - int x, int y, - bool &closeToLeft, bool &closeToRight, - bool &closeToTop, bool &closeToBottom) const; - SparseTimeValueModel *getAssociatedPitchModel(View *v) const; - bool updateNoteValueFromPitchCurve(View *v, - FlexiNoteModel::Point ¬e) const; - void splitNotesAt(View *v, sv_frame_t frame, QMouseEvent *e); + bool getPointToDrag(LayerGeometryProvider *v, int x, int y, FlexiNoteModel::Point &) const; + bool getNoteToEdit(LayerGeometryProvider *v, int x, int y, FlexiNoteModel::Point &) const; + void getRelativeMousePosition(LayerGeometryProvider *v, FlexiNoteModel::Point ¬e, int x, int y, bool &closeToLeft, bool &closeToRight, bool &closeToTop, bool &closeToBottom) const; + SparseTimeValueModel *getAssociatedPitchModel(LayerGeometryProvider *v) const; + bool updateNoteValueFromPitchCurve(LayerGeometryProvider *v, FlexiNoteModel::Point ¬e) const; + void splitNotesAt(LayerGeometryProvider *v, sv_frame_t frame, QMouseEvent *e); FlexiNoteModel *m_model; bool m_editing;
--- a/layer/ImageLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/ImageLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -116,14 +116,14 @@ } bool -ImageLayer::isLayerScrollable(const View *) const +ImageLayer::isLayerScrollable(const LayerGeometryProvider *) const { return true; } ImageModel::PointList -ImageLayer::getLocalPoints(View *v, int x, int ) const +ImageLayer::getLocalPoints(LayerGeometryProvider *v, int x, int ) const { if (!m_model) return ImageModel::PointList(); @@ -169,7 +169,7 @@ } QString -ImageLayer::getFeatureDescription(View *v, QPoint &pos) const +ImageLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { int x = pos.x(); @@ -208,7 +208,7 @@ //!!! too much overlap with TimeValueLayer/TimeInstantLayer/TextLayer bool -ImageLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, +ImageLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { @@ -280,7 +280,7 @@ } void -ImageLayer::paint(View *v, QPainter &paint, QRect rect) const +ImageLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { if (!m_model || !m_model->isOK()) return; @@ -290,7 +290,7 @@ // Profiler profiler("ImageLayer::paint", true); // int x0 = rect.left(), x1 = rect.right(); - int x0 = 0, x1 = v->width(); + int x0 = 0, x1 = v->getPaintWidth(); sv_frame_t frame0 = v->getFrameForX(x0); sv_frame_t frame1 = v->getFrameForX(x1); @@ -299,7 +299,7 @@ if (points.empty()) return; paint.save(); - paint.setClipRect(rect.x(), 0, rect.width(), v->height()); + paint.setClipRect(rect.x(), 0, rect.width(), v->getPaintHeight()); QColor penColour; penColour = v->getForeground(); @@ -338,7 +338,7 @@ } void -ImageLayer::drawImage(View *v, QPainter &paint, const ImageModel::Point &p, +ImageLayer::drawImage(LayerGeometryProvider *v, QPainter &paint, const ImageModel::Point &p, int x, int nx) const { QString label = p.label; @@ -358,12 +358,12 @@ int bottomMargin = 10; int spacing = 5; - if (v->height() < 100) { + if (v->getPaintHeight() < 100) { topMargin = 5; bottomMargin = 5; } - int maxBoxHeight = v->height() - topMargin - bottomMargin; + int maxBoxHeight = v->getPaintHeight() - topMargin - bottomMargin; int availableWidth = nx - x - 3; if (availableWidth < 20) availableWidth = 20; @@ -372,7 +372,7 @@ if (label != "") { - int likelyHeight = v->height() / 4; + int likelyHeight = v->getPaintHeight() / 4; int likelyWidth = // available height times image aspect ((maxBoxHeight - likelyHeight) * imageSize.width()) @@ -435,10 +435,10 @@ division += paint.fontMetrics().height(); } - bottomMargin = v->height() - topMargin - boxHeight; - if (bottomMargin > topMargin + v->height()/7) { - topMargin += v->height()/8; - bottomMargin -= v->height()/8; + bottomMargin = v->getPaintHeight() - topMargin - boxHeight; + if (bottomMargin > topMargin + v->getPaintHeight()/7) { + topMargin += v->getPaintHeight()/8; + bottomMargin -= v->getPaintHeight()/8; } paint.drawRect(x - 1, @@ -480,7 +480,7 @@ } void -ImageLayer::setLayerDormant(const View *v, bool dormant) +ImageLayer::setLayerDormant(const LayerGeometryProvider *v, bool dormant) { if (dormant) { // Delete the images named in the view's scaled map from the @@ -517,7 +517,7 @@ } QImage -ImageLayer::getImage(View *v, QString name, QSize maxSize) const +ImageLayer::getImage(LayerGeometryProvider *v, QString name, QSize maxSize) const { // SVDEBUG << "ImageLayer::getImage(" << v << ", " << name << ", (" // << maxSize.width() << "x" << maxSize.height() << "))" << endl; @@ -554,7 +554,7 @@ } void -ImageLayer::drawStart(View *v, QMouseEvent *e) +ImageLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "ImageLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; @@ -578,7 +578,7 @@ } void -ImageLayer::drawDrag(View *v, QMouseEvent *e) +ImageLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "ImageLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; @@ -594,7 +594,7 @@ } void -ImageLayer::drawEnd(View *, QMouseEvent *) +ImageLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) { // SVDEBUG << "ImageLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl; if (!m_model || !m_editing) return; @@ -638,7 +638,7 @@ } void -ImageLayer::editStart(View *v, QMouseEvent *e) +ImageLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "ImageLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; @@ -660,7 +660,7 @@ } void -ImageLayer::editDrag(View *v, QMouseEvent *e) +ImageLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -680,7 +680,7 @@ } void -ImageLayer::editEnd(View *, QMouseEvent *) +ImageLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) { // SVDEBUG << "ImageLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl; if (!m_model || !m_editing) return; @@ -694,7 +694,7 @@ } bool -ImageLayer::editOpen(View *v, QMouseEvent *e) +ImageLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return false; @@ -801,7 +801,7 @@ } void -ImageLayer::copy(View *v, Selection s, Clipboard &to) +ImageLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -819,7 +819,7 @@ } bool -ImageLayer::paste(View *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) +ImageLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) { if (!m_model) return false; @@ -830,7 +830,7 @@ if (clipboardHasDifferentAlignment(v, from)) { QMessageBox::StandardButton button = - QMessageBox::question(v, tr("Re-align pasted items?"), + QMessageBox::question(v->getView(), tr("Re-align pasted items?"), tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
--- a/layer/ImageLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/ImageLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -38,31 +38,31 @@ ImageLayer(); virtual ~ImageLayer(); - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; - virtual bool snapToFeatureFrame(View *v, sv_frame_t &frame, + virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual void drawStart(View *v, QMouseEvent *); - virtual void drawDrag(View *v, QMouseEvent *); - virtual void drawEnd(View *v, QMouseEvent *); + virtual void drawStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void editStart(View *v, QMouseEvent *); - virtual void editDrag(View *v, QMouseEvent *); - virtual void editEnd(View *v, QMouseEvent *); + virtual void editStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void editDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void editEnd(LayerGeometryProvider *v, QMouseEvent *); virtual void moveSelection(Selection s, sv_frame_t newStartFrame); virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(View *v, Selection s, Clipboard &to); - virtual bool paste(View *v, const Clipboard &from, sv_frame_t frameOffset, + virtual void copy(LayerGeometryProvider *v, Selection s, Clipboard &to); + virtual bool paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool interactive); - virtual bool editOpen(View *, QMouseEvent *); // on double-click + virtual bool editOpen(LayerGeometryProvider *, QMouseEvent *); // on double-click virtual const Model *getModel() const { return m_model; } void setModel(ImageModel *model); @@ -80,11 +80,11 @@ return ColourAbsent; } - virtual bool isLayerScrollable(const View *v) const; + virtual bool isLayerScrollable(const LayerGeometryProvider *v) const; virtual bool isLayerEditable() const { return true; } - virtual int getCompletion(View *) const { return m_model->getCompletion(); } + virtual int getCompletion(LayerGeometryProvider *) const { return m_model->getCompletion(); } virtual bool getValueExtents(double &min, double &max, bool &logarithmic, QString &unit) const; @@ -92,9 +92,9 @@ virtual void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const; - virtual int getVerticalScaleWidth(View *, bool, QPainter &) const { return 0; } + virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &) const { return 0; } - virtual void setLayerDormant(const View *v, bool dormant); + virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant); void setProperties(const QXmlAttributes &attributes); @@ -105,18 +105,18 @@ void fileSourceReady(); protected: - ImageModel::PointList getLocalPoints(View *v, int x, int y) const; + ImageModel::PointList getLocalPoints(LayerGeometryProvider *v, int x, int y) const; bool getImageOriginalSize(QString name, QSize &size) const; - QImage getImage(View *v, QString name, QSize maxSize) const; + QImage getImage(LayerGeometryProvider *v, QString name, QSize maxSize) const; - void drawImage(View *v, QPainter &paint, const ImageModel::Point &p, + void drawImage(LayerGeometryProvider *v, QPainter &paint, const ImageModel::Point &p, int x, int nx) const; //!!! how to reap no-longer-used images? typedef std::map<QString, QImage> ImageMap; - typedef std::map<const View *, ImageMap> ViewImageMap; + typedef std::map<const LayerGeometryProvider *, ImageMap> ViewImageMap; typedef std::map<QString, FileSource *> FileSourceMap; static ImageMap m_images;
--- a/layer/Layer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/Layer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -115,7 +115,7 @@ } void -Layer::setLayerDormant(const View *v, bool dormant) +Layer::setLayerDormant(const LayerGeometryProvider *v, bool dormant) { const void *vv = (const void *)v; QMutexLocker locker(&m_dormancyMutex); @@ -123,7 +123,7 @@ } bool -Layer::isLayerDormant(const View *v) const +Layer::isLayerDormant(const LayerGeometryProvider *v) const { const void *vv = (const void *)v; QMutexLocker locker(&m_dormancyMutex); @@ -132,14 +132,14 @@ } void -Layer::showLayer(View *view, bool show) +Layer::showLayer(LayerGeometryProvider *view, bool show) { setLayerDormant(view, !show); emit layerParametersChanged(); } bool -Layer::getXScaleValue(const View *v, int x, double &value, QString &unit) const +Layer::getXScaleValue(const LayerGeometryProvider *v, int x, double &value, QString &unit) const { if (!hasTimeXAxis()) return false; @@ -152,7 +152,7 @@ } bool -Layer::getYScaleDifference(const View *v, int y0, int y1, +Layer::getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1, double &diff, QString &unit) const { double v0, v1; @@ -166,31 +166,31 @@ } sv_frame_t -Layer::alignToReference(View *v, sv_frame_t frame) const +Layer::alignToReference(LayerGeometryProvider *v, sv_frame_t frame) const { const Model *m = getModel(); SVDEBUG << "Layer::alignToReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << endl; if (m && m->getAlignmentReference()) { return m->alignToReference(frame); } else { - return v->alignToReference(frame); + return v->getView()->alignToReference(frame); } } sv_frame_t -Layer::alignFromReference(View *v, sv_frame_t frame) const +Layer::alignFromReference(LayerGeometryProvider *v, sv_frame_t frame) const { const Model *m = getModel(); SVDEBUG << "Layer::alignFromReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << endl; if (m && m->getAlignmentReference()) { return m->alignFromReference(frame); } else { - return v->alignFromReference(frame); + return v->getView()->alignFromReference(frame); } } bool -Layer::clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const +Layer::clipboardHasDifferentAlignment(LayerGeometryProvider *v, const Clipboard &clip) const { // Notes on pasting to an aligned layer: // @@ -371,7 +371,7 @@ } void -Layer::measureStart(View *v, QMouseEvent *e) +Layer::measureStart(LayerGeometryProvider *v, QMouseEvent *e) { setMeasureRectFromPixrect(v, m_draggingRect, QRect(e->x(), e->y(), 0, 0)); @@ -379,7 +379,7 @@ } void -Layer::measureDrag(View *v, QMouseEvent *e) +Layer::measureDrag(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_haveDraggingRect) return; @@ -391,7 +391,7 @@ } void -Layer::measureEnd(View *v, QMouseEvent *e) +Layer::measureEnd(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_haveDraggingRect) return; measureDrag(v, e); @@ -405,7 +405,7 @@ } void -Layer::measureDoubleClick(View *, QMouseEvent *) +Layer::measureDoubleClick(LayerGeometryProvider *, QMouseEvent *) { // nothing, in the base class } @@ -425,7 +425,7 @@ } void -Layer::paintMeasurementRects(View *v, QPainter &paint, +Layer::paintMeasurementRects(LayerGeometryProvider *v, QPainter &paint, bool showFocus, QPoint focusPoint) const { updateMeasurePixrects(v); @@ -457,7 +457,7 @@ } bool -Layer::nearestMeasurementRectChanged(View *v, QPoint prev, QPoint now) const +Layer::nearestMeasurementRectChanged(LayerGeometryProvider *v, QPoint prev, QPoint now) const { updateMeasurePixrects(v); @@ -468,7 +468,7 @@ } void -Layer::updateMeasurePixrects(View *v) const +Layer::updateMeasurePixrects(LayerGeometryProvider *v) const { sv_frame_t sf = v->getStartFrame(); sv_frame_t ef = v->getEndFrame(); @@ -507,26 +507,26 @@ } void -Layer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const +Layer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const { - int y0 = int(lrint(r.startY * v->height())); - int y1 = int(lrint(r.endY * v->height())); + int y0 = int(lrint(r.startY * v->getPaintHeight())); + int y1 = int(lrint(r.endY * v->getPaintHeight())); r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0); } void -Layer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const +Layer::setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const { if (start) { - r.startY = double(y) / double(v->height()); + r.startY = double(y) / double(v->getPaintHeight()); r.endY = r.startY; } else { - r.endY = double(y) / double(v->height()); + r.endY = double(y) / double(v->getPaintHeight()); } } void -Layer::setMeasureRectFromPixrect(View *v, MeasureRect &r, QRect pixrect) const +Layer::setMeasureRectFromPixrect(LayerGeometryProvider *v, MeasureRect &r, QRect pixrect) const { r.pixrect = pixrect; r.haveFrames = hasTimeXAxis(); @@ -566,13 +566,13 @@ } void -Layer::paintMeasurementRect(View *v, QPainter &paint, +Layer::paintMeasurementRect(LayerGeometryProvider *v, QPainter &paint, const MeasureRect &r, bool focus) const { if (r.haveFrames) { int x0 = -1; - int x1 = v->width() + 1; + int x1 = v->getPaintWidth() + 1; if (r.startFrame >= v->getStartFrame()) { x0 = v->getXForFrame(r.startFrame);
--- a/layer/Layer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/Layer.h Wed Mar 02 17:25:27 2016 +0000 @@ -39,6 +39,7 @@ class Model; class QPainter; class View; +class LayerGeometryProvider; class QMouseEvent; class Clipboard; class RangeMapper; @@ -83,12 +84,13 @@ /** * Paint the given rectangle of this layer onto the given view * using the given painter, superimposing it on top of any - * existing material in that view. The view is provided here - * because it is possible for one layer to exist in more than one - * view, so the dimensions of the view may vary from one paint - * call to another (without any view having been resized). + * existing material in that view. The LayerGeometryProvider (an + * interface implemented by View) is provided here because it is + * possible for one layer to exist in more than one view, so the + * dimensions of the view may vary from one paint call to another + * (without any view having been resized). */ - virtual void paint(View *, QPainter &, QRect) const = 0; + virtual void paint(LayerGeometryProvider *, QPainter &, QRect) const = 0; /** * Enable or disable synchronous painting. If synchronous @@ -128,25 +130,25 @@ virtual QString getLayerPresentationName() const; virtual QPixmap getLayerPresentationPixmap(QSize) const { return QPixmap(); } - virtual int getVerticalScaleWidth(View *, bool detailed, + virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool detailed, QPainter &) const = 0; - virtual void paintVerticalScale(View *, bool /* detailed */, + virtual void paintVerticalScale(LayerGeometryProvider *, bool /* detailed */, QPainter &, QRect) const { } - virtual bool getCrosshairExtents(View *, QPainter &, QPoint /* cursorPos */, + virtual bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint /* cursorPos */, std::vector<QRect> &) const { return false; } - virtual void paintCrosshairs(View *, QPainter &, QPoint) const { } + virtual void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const { } - virtual void paintMeasurementRects(View *, QPainter &, + virtual void paintMeasurementRects(LayerGeometryProvider *, QPainter &, bool showFocus, QPoint focusPoint) const; - virtual bool nearestMeasurementRectChanged(View *, QPoint prev, + virtual bool nearestMeasurementRectChanged(LayerGeometryProvider *, QPoint prev, QPoint now) const; - virtual QString getFeatureDescription(View *, QPoint &) const { + virtual QString getFeatureDescription(LayerGeometryProvider *, QPoint &) const { return ""; } @@ -180,7 +182,7 @@ * (and leave frame unmodified). If returning true, also return * the resolution of the model in this layer in sample frames. */ - virtual bool snapToFeatureFrame(View * /* v */, + virtual bool snapToFeatureFrame(LayerGeometryProvider * /* v */, sv_frame_t & /* frame */, int &resolution, SnapType /* snap */) const { @@ -204,7 +206,7 @@ * (and leave frame unmodified). If returning true, also return * the resolution of the model in this layer in sample frames. */ - virtual bool snapToSimilarFeature(View * /* v */, + virtual bool snapToSimilarFeature(LayerGeometryProvider * /* v */, sv_frame_t & /* source frame */, int &resolution, SnapType /* snap */) const { @@ -217,30 +219,30 @@ // Layer needs to get actual mouse events, I guess. Draw mode is // probably the easier. - virtual void drawStart(View *, QMouseEvent *) { } - virtual void drawDrag(View *, QMouseEvent *) { } - virtual void drawEnd(View *, QMouseEvent *) { } + virtual void drawStart(LayerGeometryProvider *, QMouseEvent *) { } + virtual void drawDrag(LayerGeometryProvider *, QMouseEvent *) { } + virtual void drawEnd(LayerGeometryProvider *, QMouseEvent *) { } - virtual void eraseStart(View *, QMouseEvent *) { } - virtual void eraseDrag(View *, QMouseEvent *) { } - virtual void eraseEnd(View *, QMouseEvent *) { } + virtual void eraseStart(LayerGeometryProvider *, QMouseEvent *) { } + virtual void eraseDrag(LayerGeometryProvider *, QMouseEvent *) { } + virtual void eraseEnd(LayerGeometryProvider *, QMouseEvent *) { } - virtual void editStart(View *, QMouseEvent *) { } - virtual void editDrag(View *, QMouseEvent *) { } - virtual void editEnd(View *, QMouseEvent *) { } + virtual void editStart(LayerGeometryProvider *, QMouseEvent *) { } + virtual void editDrag(LayerGeometryProvider *, QMouseEvent *) { } + virtual void editEnd(LayerGeometryProvider *, QMouseEvent *) { } - virtual void splitStart(View *, QMouseEvent *) { } - virtual void splitEnd(View *, QMouseEvent *) { } - virtual void addNote(View *, QMouseEvent *) { }; + virtual void splitStart(LayerGeometryProvider *, QMouseEvent *) { } + virtual void splitEnd(LayerGeometryProvider *, QMouseEvent *) { } + virtual void addNote(LayerGeometryProvider *, QMouseEvent *) { }; // Measurement rectangle (or equivalent). Unlike draw and edit, // the base Layer class can provide working implementations of // these for most situations. // - virtual void measureStart(View *, QMouseEvent *); - virtual void measureDrag(View *, QMouseEvent *); - virtual void measureEnd(View *, QMouseEvent *); - virtual void measureDoubleClick(View *, QMouseEvent *); + virtual void measureStart(LayerGeometryProvider *, QMouseEvent *); + virtual void measureDrag(LayerGeometryProvider *, QMouseEvent *); + virtual void measureEnd(LayerGeometryProvider *, QMouseEvent *); + virtual void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *); virtual bool haveCurrentMeasureRect() const { return m_haveCurrentMeasureRect; @@ -252,13 +254,13 @@ * double-click). If there is no item or editing is not * supported, return false. */ - virtual bool editOpen(View *, QMouseEvent *) { return false; } + virtual bool editOpen(LayerGeometryProvider *, QMouseEvent *) { return false; } virtual void moveSelection(Selection, sv_frame_t /* newStartFrame */) { } virtual void resizeSelection(Selection, Selection /* newSize */) { } virtual void deleteSelection(Selection) { } - virtual void copy(View *, Selection, Clipboard & /* to */) { } + virtual void copy(LayerGeometryProvider *, Selection, Clipboard & /* to */) { } /** * Paste from the given clipboard onto the layer at the given @@ -267,7 +269,7 @@ * return false if the user cancelled the paste operation. This * function should return true if a paste actually occurred. */ - virtual bool paste(View *, + virtual bool paste(LayerGeometryProvider *, const Clipboard & /* from */, sv_frame_t /* frameOffset */, bool /* interactive */) { return false; } @@ -289,7 +291,7 @@ * scrolling better if it is known that individual views can be * scrolled safely in this way. */ - virtual bool isLayerScrollable(const View *) const { return true; } + virtual bool isLayerScrollable(const LayerGeometryProvider *) const { return true; } /** * This should return true if the layer completely obscures any @@ -344,14 +346,14 @@ * isReady(int *) call. The view may choose to show a progress * meter if it finds that this returns < 100 at any given moment. */ - virtual int getCompletion(View *) const { return 100; } + virtual int getCompletion(LayerGeometryProvider *) const { return 100; } /** * Return an error string if any errors have occurred while * loading or processing data for the given view. Return the * empty string if no error has occurred. */ - virtual QString getError(View *) const { return ""; } + virtual QString getError(LayerGeometryProvider *) const { return ""; } virtual void setObjectName(const QString &name); @@ -400,13 +402,13 @@ * A layer class that overrides this function must also call this * class's implementation. */ - virtual void setLayerDormant(const View *v, bool dormant); + virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant); /** * Return whether the layer is dormant (i.e. hidden) in the given * view. */ - virtual bool isLayerDormant(const View *v) const; + virtual bool isLayerDormant(const LayerGeometryProvider *v) const; virtual PlayParameters *getPlayParameters(); @@ -457,14 +459,14 @@ * measurement tool. The default implementation works correctly * if the layer hasTimeXAxis(). */ - virtual bool getXScaleValue(const View *v, int x, + virtual bool getXScaleValue(const LayerGeometryProvider *v, int x, double &value, QString &unit) const; /** * Return the value and unit at the given y coordinate in the * given view. */ - virtual bool getYScaleValue(const View *, int /* y */, + virtual bool getYScaleValue(const LayerGeometryProvider *, int /* y */, double &/* value */, QString &/* unit */) const { return false; } @@ -475,7 +477,7 @@ * The default implementation just calls getYScaleValue twice and * returns the difference, with the same unit. */ - virtual bool getYScaleDifference(const View *v, int y0, int y1, + virtual bool getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1, double &diff, QString &unit) const; /** @@ -526,7 +528,7 @@ virtual bool canExistWithoutModel() const { return false; } public slots: - void showLayer(View *, bool show); + void showLayer(LayerGeometryProvider *, bool show); signals: void modelChanged(); @@ -545,9 +547,9 @@ protected: void connectSignals(const Model *); - virtual sv_frame_t alignToReference(View *v, sv_frame_t frame) const; - virtual sv_frame_t alignFromReference(View *v, sv_frame_t frame) const; - bool clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const; + virtual sv_frame_t alignToReference(LayerGeometryProvider *v, sv_frame_t frame) const; + virtual sv_frame_t alignFromReference(LayerGeometryProvider *v, sv_frame_t frame) const; + bool clipboardHasDifferentAlignment(LayerGeometryProvider *v, const Clipboard &clip) const; struct MeasureRect { @@ -612,16 +614,16 @@ // Note that pixrects are only correct for a single view. // So we should update them at the start of the paint procedure // (painting is single threaded) and only use them after that. - void updateMeasurePixrects(View *v) const; + void updateMeasurePixrects(LayerGeometryProvider *v) const; - virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const; - virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const; - virtual void setMeasureRectFromPixrect(View *v, MeasureRect &r, QRect pixrect) const; + virtual void updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const; + virtual void setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const; + virtual void setMeasureRectFromPixrect(LayerGeometryProvider *v, MeasureRect &r, QRect pixrect) const; // This assumes updateMeasurementPixrects has been called MeasureRectSet::const_iterator findFocusedMeasureRect(QPoint) const; - void paintMeasurementRect(View *v, QPainter &paint, + void paintMeasurementRect(LayerGeometryProvider *v, QPainter &paint, const MeasureRect &r, bool focus) const; QString m_presentationName;
--- a/layer/LayerFactory.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/LayerFactory.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -289,6 +289,7 @@ if (name == "timeruler") return TimeRuler; if (name == "timeinstants") return TimeInstants; if (name == "timevalues") return TimeValues; + if (name == "notes") return Notes; if (name == "flexinotes") return FlexiNotes; if (name == "regions") return Regions; if (name == "text") return Text;
--- a/layer/LinearColourScale.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/LinearColourScale.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -20,24 +20,24 @@ #include <cmath> -#include "view/View.h" +#include "view/LayerGeometryProvider.h" int -LinearColourScale::getWidth(View *, +LinearColourScale::getWidth(LayerGeometryProvider *, QPainter &paint) { return paint.fontMetrics().width("-000.00") + 15; } void -LinearColourScale::paintVertical(View *v, +LinearColourScale::paintVertical(LayerGeometryProvider *v, const ColourScaleLayer *layer, QPainter &paint, int /* x0 */, double min, double max) { - int h = v->height(); + int h = v->getPaintHeight(); int n = 10;
--- a/layer/LinearColourScale.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/LinearColourScale.h Wed Mar 02 17:25:27 2016 +0000 @@ -19,16 +19,16 @@ #include <QRect> class QPainter; -class View; +class LayerGeometryProvider; class ColourScaleLayer; class LinearColourScale { public: - int getWidth(View *v, QPainter &paint); + int getWidth(LayerGeometryProvider *v, QPainter &paint); void paintVertical - (View *v, const ColourScaleLayer *layer, QPainter &paint, int x0, + (LayerGeometryProvider *v, const ColourScaleLayer *layer, QPainter &paint, int x0, double minf, double maxf); };
--- a/layer/LinearNumericalScale.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/LinearNumericalScale.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -23,14 +23,14 @@ #include "view/View.h" int -LinearNumericalScale::getWidth(View *, +LinearNumericalScale::getWidth(LayerGeometryProvider *, QPainter &paint) { return paint.fontMetrics().width("-000.00") + 10; } void -LinearNumericalScale::paintVertical(View *v, +LinearNumericalScale::paintVertical(LayerGeometryProvider *v, const VerticalScaleLayer *layer, QPainter &paint, int x0, @@ -69,7 +69,7 @@ double dispval = val; if (i == n-1 && - v->height() < paint.fontMetrics().height() * (n*2)) { + v->getPaintHeight() < paint.fontMetrics().height() * (n*2)) { if (layer->getScaleUnits() != "") drawText = false; } dispval = int(rint(val / round) * round);
--- a/layer/LinearNumericalScale.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/LinearNumericalScale.h Wed Mar 02 17:25:27 2016 +0000 @@ -19,17 +19,17 @@ #include <QRect> class QPainter; -class View; +class LayerGeometryProvider; class VerticalScaleLayer; class LinearNumericalScale { public: - int getWidth(View *v, QPainter &paint); + int getWidth(LayerGeometryProvider *v, QPainter &paint); void paintVertical - (View *v, const VerticalScaleLayer *layer, QPainter &paint, int x0, - double minf, double maxf); + (LayerGeometryProvider *v, const VerticalScaleLayer *layer, + QPainter &paint, int x0, double minf, double maxf); }; #endif
--- a/layer/LogColourScale.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/LogColourScale.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -25,21 +25,21 @@ #include "view/View.h" int -LogColourScale::getWidth(View *, +LogColourScale::getWidth(LayerGeometryProvider *, QPainter &paint) { return paint.fontMetrics().width("-000.00") + 15; } void -LogColourScale::paintVertical(View *v, +LogColourScale::paintVertical(LayerGeometryProvider *v, const ColourScaleLayer *layer, QPainter &paint, int /* x0 */, double minlog, double maxlog) { - int h = v->height(); + int h = v->getPaintHeight(); int n = 10;
--- a/layer/LogColourScale.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/LogColourScale.h Wed Mar 02 17:25:27 2016 +0000 @@ -19,16 +19,16 @@ #include <QRect> class QPainter; -class View; +class LayerGeometryProvider; class ColourScaleLayer; class LogColourScale { public: - int getWidth(View *v, QPainter &paint); + int getWidth(LayerGeometryProvider *v, QPainter &paint); void paintVertical - (View *v, const ColourScaleLayer *layer, QPainter &paint, int x0, + (LayerGeometryProvider *v, const ColourScaleLayer *layer, QPainter &paint, int x0, double minf, double maxf); };
--- a/layer/LogNumericalScale.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/LogNumericalScale.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -27,14 +27,14 @@ //#define DEBUG_TIME_VALUE_LAYER 1 int -LogNumericalScale::getWidth(View *, +LogNumericalScale::getWidth(LayerGeometryProvider *, QPainter &paint) { return paint.fontMetrics().width("-000.00") + 10; } void -LogNumericalScale::paintVertical(View *v, +LogNumericalScale::paintVertical(LayerGeometryProvider *v, const VerticalScaleLayer *layer, QPainter &paint, int x0, @@ -79,7 +79,7 @@ bool drawText = true; if (i == n-1 && - v->height() < paint.fontMetrics().height() * (n*2)) { + v->getPaintHeight() < paint.fontMetrics().height() * (n*2)) { if (layer->getScaleUnits() != "") drawText = false; }
--- a/layer/LogNumericalScale.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/LogNumericalScale.h Wed Mar 02 17:25:27 2016 +0000 @@ -19,16 +19,16 @@ #include <QRect> class QPainter; -class View; +class LayerGeometryProvider; class VerticalScaleLayer; class LogNumericalScale { public: - int getWidth(View *v, QPainter &paint); + int getWidth(LayerGeometryProvider *v, QPainter &paint); void paintVertical - (View *v, const VerticalScaleLayer *layer, QPainter &paint, int x0, + (LayerGeometryProvider *v, const VerticalScaleLayer *layer, QPainter &paint, int x0, double minlog, double maxlog); };
--- a/layer/NoteLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/NoteLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -191,7 +191,7 @@ } bool -NoteLayer::isLayerScrollable(const View *v) const +NoteLayer::isLayerScrollable(const LayerGeometryProvider *v) const { QPoint discard; return !v->shouldIlluminateLocalFeatures(this, discard); @@ -389,7 +389,7 @@ } NoteModel::PointList -NoteLayer::getLocalPoints(View *v, int x) const +NoteLayer::getLocalPoints(LayerGeometryProvider *v, int x) const { if (!m_model) return NoteModel::PointList(); @@ -432,7 +432,7 @@ } bool -NoteLayer::getPointToDrag(View *v, int x, int y, NoteModel::Point &p) const +NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, NoteModel::Point &p) const { if (!m_model) return false; @@ -460,7 +460,7 @@ } QString -NoteLayer::getFeatureDescription(View *v, QPoint &pos) const +NoteLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { int x = pos.x(); @@ -547,7 +547,7 @@ } bool -NoteLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, +NoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { @@ -619,7 +619,7 @@ } void -NoteLayer::getScaleExtents(View *v, double &min, double &max, bool &log) const +NoteLayer::getScaleExtents(LayerGeometryProvider *v, double &min, double &max, bool &log) const { min = 0.0; max = 0.0; @@ -677,11 +677,11 @@ } int -NoteLayer::getYForValue(View *v, double val) const +NoteLayer::getYForValue(LayerGeometryProvider *v, double val) const { double min = 0.0, max = 0.0; bool logarithmic = false; - int h = v->height(); + int h = v->getPaintHeight(); getScaleExtents(v, min, max, logarithmic); @@ -712,11 +712,11 @@ } double -NoteLayer::getValueForY(View *v, int y) const +NoteLayer::getValueForY(LayerGeometryProvider *v, int y) const { double min = 0.0, max = 0.0; bool logarithmic = false; - int h = v->height(); + int h = v->getPaintHeight(); getScaleExtents(v, min, max, logarithmic); @@ -741,7 +741,7 @@ } void -NoteLayer::paint(View *v, QPainter &paint, QRect rect) const +NoteLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { if (!m_model || !m_model->isOK()) return; @@ -830,7 +830,7 @@ } int -NoteLayer::getVerticalScaleWidth(View *v, bool, QPainter &paint) const +NoteLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const { if (!m_model || shouldAutoAlign()) { return 0; @@ -844,7 +844,7 @@ } void -NoteLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect) const +NoteLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const { if (!m_model || m_model->getPoints().empty()) return; @@ -853,7 +853,7 @@ bool logarithmic; int w = getVerticalScaleWidth(v, false, paint); - int h = v->height(); + int h = v->getPaintHeight(); getScaleExtents(v, min, max, logarithmic); @@ -882,7 +882,7 @@ } void -NoteLayer::drawStart(View *v, QMouseEvent *e) +NoteLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "NoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; @@ -906,7 +906,7 @@ } void -NoteLayer::drawDrag(View *v, QMouseEvent *e) +NoteLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "NoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; @@ -935,7 +935,7 @@ } void -NoteLayer::drawEnd(View *, QMouseEvent *) +NoteLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) { // SVDEBUG << "NoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl; if (!m_model || !m_editing) return; @@ -945,7 +945,7 @@ } void -NoteLayer::eraseStart(View *v, QMouseEvent *e) +NoteLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return; @@ -960,12 +960,12 @@ } void -NoteLayer::eraseDrag(View *, QMouseEvent *) +NoteLayer::eraseDrag(LayerGeometryProvider *, QMouseEvent *) { } void -NoteLayer::eraseEnd(View *v, QMouseEvent *e) +NoteLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -985,7 +985,7 @@ } void -NoteLayer::editStart(View *v, QMouseEvent *e) +NoteLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "NoteLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; @@ -1008,7 +1008,7 @@ } void -NoteLayer::editDrag(View *v, QMouseEvent *e) +NoteLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "NoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl; @@ -1037,7 +1037,7 @@ } void -NoteLayer::editEnd(View *, QMouseEvent *) +NoteLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) { // SVDEBUG << "NoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl; if (!m_model || !m_editing) return; @@ -1065,7 +1065,7 @@ } bool -NoteLayer::editOpen(View *v, QMouseEvent *e) +NoteLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return false; @@ -1193,7 +1193,7 @@ } void -NoteLayer::copy(View *v, Selection s, Clipboard &to) +NoteLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -1211,7 +1211,7 @@ } bool -NoteLayer::paste(View *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) +NoteLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) { if (!m_model) return false; @@ -1222,7 +1222,7 @@ if (clipboardHasDifferentAlignment(v, from)) { QMessageBox::StandardButton button = - QMessageBox::question(v, tr("Re-align pasted items?"), + QMessageBox::question(v->getView(), tr("Re-align pasted items?"), tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
--- a/layer/NoteLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/NoteLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -35,37 +35,37 @@ public: NoteLayer(); - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; - virtual int getVerticalScaleWidth(View *v, bool, QPainter &) const; - virtual void paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const; + virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &) const; + virtual void paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; - virtual bool snapToFeatureFrame(View *v, sv_frame_t &frame, + virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual void drawStart(View *v, QMouseEvent *); - virtual void drawDrag(View *v, QMouseEvent *); - virtual void drawEnd(View *v, QMouseEvent *); + virtual void drawStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void eraseStart(View *v, QMouseEvent *); - virtual void eraseDrag(View *v, QMouseEvent *); - virtual void eraseEnd(View *v, QMouseEvent *); + virtual void eraseStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void editStart(View *v, QMouseEvent *); - virtual void editDrag(View *v, QMouseEvent *); - virtual void editEnd(View *v, QMouseEvent *); + virtual void editStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void editDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void editEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual bool editOpen(View *v, QMouseEvent *); + virtual bool editOpen(LayerGeometryProvider *v, QMouseEvent *); virtual void moveSelection(Selection s, sv_frame_t newStartFrame); virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(View *v, Selection s, Clipboard &to); - virtual bool paste(View *v, const Clipboard &from, sv_frame_t frameOffset, + virtual void copy(LayerGeometryProvider *v, Selection s, Clipboard &to); + virtual bool paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool interactive); virtual const Model *getModel() const { return m_model; } @@ -91,11 +91,11 @@ void setVerticalScale(VerticalScale scale); VerticalScale getVerticalScale() const { return m_verticalScale; } - virtual bool isLayerScrollable(const View *v) const; + virtual bool isLayerScrollable(const LayerGeometryProvider *v) const; virtual bool isLayerEditable() const { return true; } - virtual int getCompletion(View *) const { return m_model->getCompletion(); } + virtual int getCompletion(LayerGeometryProvider *) const { return m_model->getCompletion(); } virtual bool getValueExtents(double &min, double &max, bool &log, QString &unit) const; @@ -132,19 +132,19 @@ void setProperties(const QXmlAttributes &attributes); /// VerticalScaleLayer methods - virtual int getYForValue(View *v, double value) const; - virtual double getValueForY(View *v, int y) const; + virtual int getYForValue(LayerGeometryProvider *v, double value) const; + virtual double getValueForY(LayerGeometryProvider *v, int y) const; virtual QString getScaleUnits() const; protected: - void getScaleExtents(View *, double &min, double &max, bool &log) const; + void getScaleExtents(LayerGeometryProvider *, double &min, double &max, bool &log) const; bool shouldConvertMIDIToHz() const; virtual int getDefaultColourHint(bool dark, bool &impose); - NoteModel::PointList getLocalPoints(View *v, int) const; + NoteModel::PointList getLocalPoints(LayerGeometryProvider *v, int) const; - bool getPointToDrag(View *v, int x, int y, NoteModel::Point &) const; + bool getPointToDrag(LayerGeometryProvider *v, int x, int y, NoteModel::Point &) const; NoteModel *m_model; bool m_editing;
--- a/layer/PianoScale.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/PianoScale.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -21,10 +21,10 @@ #include "base/Pitch.h" -#include "view/View.h" +#include "view/LayerGeometryProvider.h" void -PianoScale::paintPianoVertical(View *v, +PianoScale::paintPianoVertical(LayerGeometryProvider *v, QPainter &paint, QRect r, double minf,
--- a/layer/PianoScale.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/PianoScale.h Wed Mar 02 17:25:27 2016 +0000 @@ -19,13 +19,13 @@ #include <QRect> class QPainter; -class View; +class LayerGeometryProvider; class PianoScale { public: void paintPianoVertical - (View *v, QPainter &paint, QRect rect, double minf, double maxf); + (LayerGeometryProvider *v, QPainter &paint, QRect rect, double minf, double maxf); }; #endif
--- a/layer/RegionLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/RegionLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -244,7 +244,7 @@ } bool -RegionLayer::isLayerScrollable(const View *v) const +RegionLayer::isLayerScrollable(const LayerGeometryProvider *v) const { QPoint discard; return !v->shouldIlluminateLocalFeatures(this, discard); @@ -302,11 +302,11 @@ } RegionModel::PointList -RegionLayer::getLocalPoints(View *v, int x) const +RegionLayer::getLocalPoints(LayerGeometryProvider *v, int x) const { if (!m_model) return RegionModel::PointList(); - long frame = v->getFrameForX(x); + sv_frame_t frame = v->getFrameForX(x); RegionModel::PointList onPoints = m_model->getPoints(frame); @@ -345,11 +345,11 @@ } bool -RegionLayer::getPointToDrag(View *v, int x, int y, RegionModel::Point &p) const +RegionLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, RegionModel::Point &p) const { if (!m_model) return false; - long frame = v->getFrameForX(x); + sv_frame_t frame = v->getFrameForX(x); RegionModel::PointList onPoints = m_model->getPoints(frame); if (onPoints.empty()) return false; @@ -383,7 +383,7 @@ } QString -RegionLayer::getFeatureDescription(View *v, QPoint &pos) const +RegionLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { int x = pos.x(); @@ -453,7 +453,7 @@ } bool -RegionLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, +RegionLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { @@ -536,7 +536,7 @@ } bool -RegionLayer::snapToSimilarFeature(View *v, sv_frame_t &frame, +RegionLayer::snapToSimilarFeature(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { @@ -624,7 +624,7 @@ } void -RegionLayer::getScaleExtents(View *v, double &min, double &max, bool &log) const +RegionLayer::getScaleExtents(LayerGeometryProvider *v, double &min, double &max, bool &log) const { min = 0.0; max = 0.0; @@ -676,9 +676,9 @@ } int -RegionLayer::spacingIndexToY(View *v, int i) const +RegionLayer::spacingIndexToY(LayerGeometryProvider *v, int i) const { - int h = v->height(); + int h = v->getPaintHeight(); int n = int(m_spacingMap.size()); // this maps from i (spacing of the value from the spacing // map) and n (number of region types) to y @@ -687,10 +687,10 @@ } double -RegionLayer::yToSpacingIndex(View *v, int y) const +RegionLayer::yToSpacingIndex(LayerGeometryProvider *v, int y) const { // we return an inexact result here (double rather than int) - int h = v->height(); + int h = v->getPaintHeight(); int n = int(m_spacingMap.size()); // from y = h - ((h * i) / n) + (h / (2 * n)) as above (vh taking place of i) double vh = double(2*h*n - h - 2*n*y) / double(2*h); @@ -698,11 +698,11 @@ } int -RegionLayer::getYForValue(View *v, double val) const +RegionLayer::getYForValue(LayerGeometryProvider *v, double val) const { double min = 0.0, max = 0.0; bool logarithmic = false; - int h = v->height(); + int h = v->getPaintHeight(); if (m_verticalScale == EqualSpaced) { @@ -733,17 +733,17 @@ } double -RegionLayer::getValueForY(View *v, int y) const +RegionLayer::getValueForY(LayerGeometryProvider *v, int y) const { return getValueForY(v, y, -1); } double -RegionLayer::getValueForY(View *v, int y, int avoid) const +RegionLayer::getValueForY(LayerGeometryProvider *v, int y, int avoid) const { double min = 0.0, max = 0.0; bool logarithmic = false; - int h = v->height(); + int h = v->getPaintHeight(); if (m_verticalScale == EqualSpaced) { @@ -836,7 +836,7 @@ } QColor -RegionLayer::getColourForValue(View *v, double val) const +RegionLayer::getColourForValue(LayerGeometryProvider *v, double val) const { double min, max; bool log; @@ -866,7 +866,7 @@ } void -RegionLayer::paint(View *v, QPainter &paint, QRect rect) const +RegionLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { if (!m_model || !m_model->isOK()) return; @@ -942,7 +942,7 @@ if (w < 1) w = 1; if (m_plotStyle == PlotSegmentation) { - paint.setPen(getForegroundQColor(v)); + paint.setPen(getForegroundQColor(v->getView())); paint.setBrush(getColourForValue(v, p.value)); } else { paint.setPen(getBaseQColor()); @@ -958,15 +958,15 @@ RegionModel::Point::Comparator()(illuminatePoint, p) || RegionModel::Point::Comparator()(p, illuminatePoint)) { - paint.setPen(QPen(getForegroundQColor(v), 1)); - paint.drawLine(x, 0, x, v->height()); + paint.setPen(QPen(getForegroundQColor(v->getView()), 1)); + paint.drawLine(x, 0, x, v->getPaintHeight()); paint.setPen(Qt::NoPen); } else { - paint.setPen(QPen(getForegroundQColor(v), 2)); + paint.setPen(QPen(getForegroundQColor(v->getView()), 2)); } - paint.drawRect(x, -1, ex - x, v->height() + 2); + paint.drawRect(x, -1, ex - x, v->getPaintHeight() + 2); } else { @@ -1040,7 +1040,7 @@ labelX = x + 5; labelY = v->getTextLabelHeight(this, paint); if (labelX < nextLabelMinX) { - if (lastLabelY < v->height()/2) { + if (lastLabelY < v->getPaintHeight()/2) { labelY = lastLabelY + fontHeight; } } @@ -1056,7 +1056,7 @@ } int -RegionLayer::getVerticalScaleWidth(View *v, bool, QPainter &paint) const +RegionLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const { if (!m_model || m_verticalScale == AutoAlignScale || @@ -1078,7 +1078,7 @@ } void -RegionLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect) const +RegionLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const { if (!m_model || m_model->getPoints().empty()) return; @@ -1121,11 +1121,11 @@ } void -RegionLayer::drawStart(View *v, QMouseEvent *e) +RegionLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return; - long frame = v->getFrameForX(e->x()); + sv_frame_t frame = v->getFrameForX(e->x()); if (frame < 0) frame = 0; frame = frame / m_model->getResolution() * m_model->getResolution(); @@ -1145,7 +1145,7 @@ } void -RegionLayer::drawDrag(View *v, QMouseEvent *e) +RegionLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -1175,7 +1175,7 @@ } void -RegionLayer::drawEnd(View *, QMouseEvent *) +RegionLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) { if (!m_model || !m_editing) return; finish(m_editingCommand); @@ -1186,7 +1186,7 @@ } void -RegionLayer::eraseStart(View *v, QMouseEvent *e) +RegionLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return; @@ -1202,12 +1202,12 @@ } void -RegionLayer::eraseDrag(View *, QMouseEvent *) +RegionLayer::eraseDrag(LayerGeometryProvider *, QMouseEvent *) { } void -RegionLayer::eraseEnd(View *v, QMouseEvent *e) +RegionLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -1229,7 +1229,7 @@ } void -RegionLayer::editStart(View *v, QMouseEvent *e) +RegionLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return; @@ -1254,7 +1254,7 @@ } void -RegionLayer::editDrag(View *v, QMouseEvent *e) +RegionLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -1263,7 +1263,7 @@ int newx = m_dragPointX + xdist; int newy = m_dragPointY + ydist; - long frame = v->getFrameForX(newx); + sv_frame_t frame = v->getFrameForX(newx); if (frame < 0) frame = 0; frame = frame / m_model->getResolution() * m_model->getResolution(); @@ -1289,7 +1289,7 @@ } void -RegionLayer::editEnd(View *, QMouseEvent *) +RegionLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) { if (!m_model || !m_editing) return; @@ -1317,7 +1317,7 @@ } bool -RegionLayer::editOpen(View *v, QMouseEvent *e) +RegionLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return false; @@ -1447,7 +1447,7 @@ } void -RegionLayer::copy(View *v, Selection s, Clipboard &to) +RegionLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -1465,7 +1465,7 @@ } bool -RegionLayer::paste(View *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) +RegionLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) { if (!m_model) return false; @@ -1476,7 +1476,7 @@ if (clipboardHasDifferentAlignment(v, from)) { QMessageBox::StandardButton button = - QMessageBox::question(v, tr("Re-align pasted items?"), + QMessageBox::question(v->getView(), tr("Re-align pasted items?"), tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
--- a/layer/RegionLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/RegionLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -39,41 +39,41 @@ public: RegionLayer(); - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; - virtual int getVerticalScaleWidth(View *v, bool, QPainter &) const; - virtual void paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const; + virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &) const; + virtual void paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; virtual QString getLabelPreceding(sv_frame_t) const; - virtual bool snapToFeatureFrame(View *v, sv_frame_t &frame, + virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual bool snapToSimilarFeature(View *v, sv_frame_t &frame, + virtual bool snapToSimilarFeature(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual void drawStart(View *v, QMouseEvent *); - virtual void drawDrag(View *v, QMouseEvent *); - virtual void drawEnd(View *v, QMouseEvent *); + virtual void drawStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void eraseStart(View *v, QMouseEvent *); - virtual void eraseDrag(View *v, QMouseEvent *); - virtual void eraseEnd(View *v, QMouseEvent *); + virtual void eraseStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void editStart(View *v, QMouseEvent *); - virtual void editDrag(View *v, QMouseEvent *); - virtual void editEnd(View *v, QMouseEvent *); + virtual void editStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void editDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void editEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual bool editOpen(View *v, QMouseEvent *); + virtual bool editOpen(LayerGeometryProvider *v, QMouseEvent *); virtual void moveSelection(Selection s, sv_frame_t newStartFrame); virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(View *v, Selection s, Clipboard &to); - virtual bool paste(View *v, const Clipboard &from, sv_frame_t frameOffset, + virtual void copy(LayerGeometryProvider *v, Selection s, Clipboard &to); + virtual bool paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool interactive); virtual const Model *getModel() const { return m_model; } @@ -110,11 +110,11 @@ void setPlotStyle(PlotStyle style); PlotStyle getPlotStyle() const { return m_plotStyle; } - virtual bool isLayerScrollable(const View *v) const; + virtual bool isLayerScrollable(const LayerGeometryProvider *v) const; virtual bool isLayerEditable() const { return true; } - virtual int getCompletion(View *) const { return m_model->getCompletion(); } + virtual int getCompletion(LayerGeometryProvider *) const { return m_model->getCompletion(); } virtual bool getValueExtents(double &min, double &max, bool &log, QString &unit) const; @@ -127,23 +127,23 @@ void setProperties(const QXmlAttributes &attributes); /// VerticalScaleLayer and ColourScaleLayer methods - int getYForValue(View *v, double value) const; - double getValueForY(View *v, int y) const; + int getYForValue(LayerGeometryProvider *v, double value) const; + double getValueForY(LayerGeometryProvider *v, int y) const; virtual QString getScaleUnits() const; - QColor getColourForValue(View *v, double value) const; + QColor getColourForValue(LayerGeometryProvider *v, double value) const; protected slots: void recalcSpacing(); protected: - double getValueForY(View *v, int y, int avoid) const; - void getScaleExtents(View *, double &min, double &max, bool &log) const; + double getValueForY(LayerGeometryProvider *v, int y, int avoid) const; + void getScaleExtents(LayerGeometryProvider *, double &min, double &max, bool &log) const; virtual int getDefaultColourHint(bool dark, bool &impose); - RegionModel::PointList getLocalPoints(View *v, int x) const; + RegionModel::PointList getLocalPoints(LayerGeometryProvider *v, int x) const; - bool getPointToDrag(View *v, int x, int y, RegionModel::Point &) const; + bool getPointToDrag(LayerGeometryProvider *v, int x, int y, RegionModel::Point &) const; RegionModel *m_model; bool m_editing; @@ -166,8 +166,8 @@ // region value -> number of regions with this value SpacingMap m_distributionMap; - int spacingIndexToY(View *v, int i) const; - double yToSpacingIndex(View *v, int y) const; + int spacingIndexToY(LayerGeometryProvider *v, int i) const; + double yToSpacingIndex(LayerGeometryProvider *v, int y) const; void finish(RegionModel::EditCommand *command) { Command *c = command->finish();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layer/ScrollableImageCache.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -0,0 +1,206 @@ +/* -*- 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 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 "ScrollableImageCache.h" + +#include <iostream> +using namespace std; + +//#define DEBUG_SCROLLABLE_IMAGE_CACHE 1 + +void +ScrollableImageCache::scrollTo(sv_frame_t newStartFrame) +{ + if (!m_v) throw std::logic_error("ScrollableImageCache: not associated with a LayerGeometryProvider"); + + int dx = (m_v->getXForFrame(m_startFrame) - + m_v->getXForFrame(newStartFrame)); + +#ifdef DEBUG_SCROLLABLE_IMAGE_CACHE + cerr << "ScrollableImageCache::scrollTo: start frame " << m_startFrame + << " -> " << newStartFrame << ", dx = " << dx << endl; +#endif + + m_startFrame = newStartFrame; + + if (!isValid()) { + return; + } + + int w = m_image.width(); + + if (dx == 0) { + // haven't moved + return; + } + + if (dx <= -w || dx >= w) { + // scrolled entirely off + invalidate(); + return; + } + + // dx is in range, cache is scrollable + + int dxp = dx; + if (dxp < 0) dxp = -dxp; + + int copylen = (w - dxp) * int(sizeof(QRgb)); + for (int y = 0; y < m_image.height(); ++y) { + QRgb *line = (QRgb *)m_image.scanLine(y); + if (dx < 0) { + memmove(line, line + dxp, copylen); + } else { + memmove(line + dxp, line, copylen); + } + } + + // update valid area + + int px = m_left; + int pw = m_width; + + px += dx; + + if (dx < 0) { + // we scrolled left + if (px < 0) { + pw += px; + px = 0; + if (pw < 0) { + pw = 0; + } + } + } else { + // we scrolled right + if (px + pw > w) { + pw = w - px; + if (pw < 0) { + pw = 0; + } + } + } + + m_left = px; + m_width = pw; +} + +void +ScrollableImageCache::adjustToTouchValidArea(int &left, int &width, + bool &isLeftOfValidArea) const +{ +#ifdef DEBUG_SCROLLABLE_IMAGE_CACHE + cerr << "ScrollableImageCache::adjustToTouchValidArea: left " << left + << ", width " << width << endl; + cerr << "ScrollableImageCache: my left " << m_left + << ", width " << m_width << " so right " << (m_left + m_width) << endl; +#endif + if (left < m_left) { + isLeftOfValidArea = true; + if (left + width <= m_left + m_width) { + width = m_left - left; + } +#ifdef DEBUG_SCROLLABLE_IMAGE_CACHE + cerr << "ScrollableImageCache: we're left of valid area, adjusted width to " << width << endl; +#endif + } else { + isLeftOfValidArea = false; + width = left + width - (m_left + m_width); + left = m_left + m_width; + if (width < 0) width = 0; +#ifdef DEBUG_SCROLLABLE_IMAGE_CACHE + cerr << "ScrollableImageCache: we're right of valid area, adjusted left to " << left << ", width to " << width << endl; +#endif + } +} + +void +ScrollableImageCache::drawImage(int left, + int width, + QImage image, + int imageLeft, + int imageWidth) +{ + if (image.height() != m_image.height()) { + cerr << "ScrollableImageCache::drawImage: ERROR: Supplied image height " + << image.height() << " does not match cache height " + << m_image.height() << endl; + throw std::logic_error("Image height must match cache height in ScrollableImageCache::drawImage"); + } + if (left < 0 || width < 0 || left + width > m_image.width()) { + cerr << "ScrollableImageCache::drawImage: ERROR: Target area (left = " + << left << ", width = " << width << ", so right = " << left + width + << ") out of bounds for cache of width " << m_image.width() << endl; + throw std::logic_error("Target area out of bounds in ScrollableImageCache::drawImage"); + } + if (imageLeft < 0 || imageWidth < 0 || + imageLeft + imageWidth > image.width()) { + cerr << "ScrollableImageCache::drawImage: ERROR: Source area (left = " + << imageLeft << ", width = " << imageWidth << ", so right = " + << imageLeft + imageWidth << ") out of bounds for image of " + << "width " << image.width() << endl; + throw std::logic_error("Source area out of bounds in ScrollableImageCache::drawImage"); + } + + QPainter painter(&m_image); + painter.drawImage(QRect(left, 0, width, m_image.height()), + image, + QRect(imageLeft, 0, imageWidth, image.height())); + painter.end(); + + if (!isValid()) { + m_left = left; + m_width = width; + return; + } + + if (left < m_left) { + if (left + width > m_left + m_width) { + // new image completely contains the old valid area -- + // use the new area as is + m_left = left; + m_width = width; + } else if (left + width < m_left) { + // new image completely off left of old valid area -- + // we can't extend the valid area because the bit in + // between is not valid, so must use the new area only + m_left = left; + m_width = width; + } else { + // new image overlaps old valid area on left side -- + // use new left edge, and extend width to existing + // right edge + m_width = (m_left + m_width) - left; + m_left = left; + } + } else { + if (left > m_left + m_width) { + // new image completely off right of old valid area -- + // we can't extend the valid area because the bit in + // between is not valid, so must use the new area only + m_left = left; + m_width = width; + } else if (left + width > m_left + m_width) { + // new image overlaps old valid area on right side -- + // use existing left edge, and extend width to new + // right edge + m_width = (left + width) - m_left; + // (m_left unchanged) + } else { + // new image completely contained within old valid + // area -- leave the old area unchanged + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layer/ScrollableImageCache.h Wed Mar 02 17:25:27 2016 +0000 @@ -0,0 +1,145 @@ +/* -*- 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 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 SCROLLABLE_IMAGE_CACHE_H +#define SCROLLABLE_IMAGE_CACHE_H + +#include "base/BaseTypes.h" + +#include "view/LayerGeometryProvider.h" + +#include <QImage> +#include <QRect> +#include <QPainter> + +/** + * A cached image for a view that scrolls horizontally, primarily the + * spectrogram. The cache object holds an image, reports the size of + * the image (likely the same as the underlying view, but it's the + * caller's responsibility to set the size appropriately), can scroll + * the image, and can report and update which contiguous horizontal + * range of the image is valid. + * + * The only way to *update* the valid area in a cache is to draw to it + * using the drawImage call. + */ +class ScrollableImageCache +{ +public: + ScrollableImageCache(const LayerGeometryProvider *v = 0) : + m_v(v), + m_left(0), + m_width(0), + m_startFrame(0), + m_zoomLevel(0) + {} + + void invalidate() { + m_width = 0; + } + + bool isValid() const { + return m_width > 0; + } + + QSize getSize() const { + return m_image.size(); + } + + void resize(QSize newSize) { + m_image = QImage(newSize, QImage::Format_ARGB32_Premultiplied); + invalidate(); + } + + int getValidLeft() const { + return m_left; + } + + int getValidWidth() const { + return m_width; + } + + int getValidRight() const { + return m_left + m_width; + } + + QRect getValidArea() const { + return QRect(m_left, 0, m_width, m_image.height()); + } + + int getZoomLevel() const { + return m_zoomLevel; + } + + void setZoomLevel(int zoom) { + m_zoomLevel = zoom; + invalidate(); + } + + sv_frame_t getStartFrame() const { + return m_startFrame; + } + + /** + * Set the start frame and invalidate the cache. To scroll, + * i.e. to set the start frame while retaining cache validity + * where possible, use scrollTo() instead. + */ + void setStartFrame(sv_frame_t frame) { + m_startFrame = frame; + invalidate(); + } + + const QImage &getImage() const { + return m_image; + } + + /** + * Set the new start frame for the cache, if possible also moving + * along any existing valid data within the cache so that it + * continues to be valid for the new start frame. + */ + void scrollTo(sv_frame_t newStartFrame); + + /** + * Take a left coordinate and width describing a region, and + * adjust them so that they are contiguous with the cache valid + * region and so that the union of the adjusted region with the + * cache valid region contains the supplied region. + */ + void adjustToTouchValidArea(int &left, int &width, + bool &isLeftOfValidArea) const; + /** + * Draw from an image onto the cache. The supplied image must have + * the same height as the cache and the full height is always + * drawn. The left and width parameters determine the target + * region of the cache, the imageLeft and imageWidth parameters + * the source region of the image. + */ + void drawImage(int left, + int width, + QImage image, + int imageLeft, + int imageWidth); + +private: + const LayerGeometryProvider *m_v; + QImage m_image; + int m_left; // of valid region + int m_width; // of valid region + sv_frame_t m_startFrame; + int m_zoomLevel; +}; + +#endif
--- a/layer/SingleColourLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/SingleColourLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -137,7 +137,7 @@ } void -SingleColourLayer::setDefaultColourFor(View *v) +SingleColourLayer::setDefaultColourFor(LayerGeometryProvider *v) { #ifdef DEBUG_COLOUR_SELECTION SVDEBUG << "SingleColourLayer::setDefaultColourFor: m_colourExplicitlySet = " << m_colourExplicitlySet << ", m_defaultColourSet " << m_defaultColourSet << endl; @@ -244,19 +244,19 @@ } QColor -SingleColourLayer::getBackgroundQColor(View *v) const +SingleColourLayer::getBackgroundQColor(LayerGeometryProvider *v) const { return v->getBackground(); } QColor -SingleColourLayer::getForegroundQColor(View *v) const +SingleColourLayer::getForegroundQColor(LayerGeometryProvider *v) const { return v->getForeground(); } std::vector<QColor> -SingleColourLayer::getPartialShades(View *v) const +SingleColourLayer::getPartialShades(LayerGeometryProvider *v) const { std::vector<QColor> s; QColor base = getBaseQColor();
--- a/layer/SingleColourLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/SingleColourLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -71,16 +71,16 @@ virtual void setProperties(const QXmlAttributes &attributes); - virtual void setDefaultColourFor(View *v); + virtual void setDefaultColourFor(LayerGeometryProvider *v); protected: SingleColourLayer(); virtual ~SingleColourLayer(); virtual QColor getBaseQColor() const; - virtual QColor getBackgroundQColor(View *v) const; - virtual QColor getForegroundQColor(View *v) const; - std::vector<QColor> getPartialShades(View *v) const; + virtual QColor getBackgroundQColor(LayerGeometryProvider *v) const; + virtual QColor getForegroundQColor(LayerGeometryProvider *v) const; + std::vector<QColor> getPartialShades(LayerGeometryProvider *v) const; virtual void flagBaseColourChanged() { } virtual int getDefaultColourHint(bool /* darkBackground */,
--- a/layer/SliceLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/SliceLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -92,14 +92,14 @@ } QString -SliceLayer::getFeatureDescription(View *v, QPoint &p) const +SliceLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &p) const { int minbin, maxbin, range; return getFeatureDescriptionAux(v, p, true, minbin, maxbin, range); } QString -SliceLayer::getFeatureDescriptionAux(View *v, QPoint &p, +SliceLayer::getFeatureDescriptionAux(LayerGeometryProvider *v, QPoint &p, bool includeBinDescription, int &minbin, int &maxbin, int &range) const { @@ -108,7 +108,7 @@ if (!m_sliceableModel) return ""; int xorigin = m_xorigins[v]; - int w = v->width() - xorigin - 1; + int w = v->getPaintWidth() - xorigin - 1; int mh = m_sliceableModel->getHeight(); minbin = getBinForX(p.x() - xorigin, mh, w); @@ -226,7 +226,7 @@ } double -SliceLayer::getYForValue(double value, const View *v, double &norm) const +SliceLayer::getYForValue(double value, const LayerGeometryProvider *v, double &norm) const { norm = 0.0; @@ -276,7 +276,7 @@ } double -SliceLayer::getValueForY(double y, const View *v) const +SliceLayer::getValueForY(double y, const LayerGeometryProvider *v) const { double value = 0.0; @@ -313,7 +313,7 @@ } void -SliceLayer::paint(View *v, QPainter &paint, QRect rect) const +SliceLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { if (!m_sliceableModel || !m_sliceableModel->isOK() || !m_sliceableModel->isReady()) return; @@ -334,11 +334,11 @@ paint.setPen(getBaseQColor()); int xorigin = getVerticalScaleWidth(v, true, paint) + 1; - int w = v->width() - xorigin - 1; + int w = v->getPaintWidth() - xorigin - 1; m_xorigins[v] = xorigin; // for use in getFeatureDescription - int yorigin = v->height() - 20 - paint.fontMetrics().height() - 7; + int yorigin = v->getPaintHeight() - 20 - paint.fontMetrics().height() - 7; int h = yorigin - paint.fontMetrics().height() - 8; m_yorigins[v] = yorigin; // for getYForValue etc @@ -501,7 +501,7 @@ } int -SliceLayer::getVerticalScaleWidth(View *, bool, QPainter &paint) const +SliceLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const { if (m_energyScale == LinearScale || m_energyScale == AbsoluteScale) { return std::max(paint.fontMetrics().width("0.0") + 13, @@ -513,7 +513,7 @@ } void -SliceLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const +SliceLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const { double thresh = m_threshold; if (m_energyScale != LinearScale && m_energyScale != AbsoluteScale) { @@ -523,7 +523,7 @@ // int h = (rect.height() * 3) / 4; // int y = (rect.height() / 2) - (h / 2); - int yorigin = v->height() - 20 - paint.fontMetrics().height() - 6; + int yorigin = v->getPaintHeight() - 20 - paint.fontMetrics().height() - 6; int h = yorigin - paint.fontMetrics().height() - 8; if (h < 0) return;
--- a/layer/SliceLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/SliceLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -38,12 +38,12 @@ void setSliceableModel(const Model *model); - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; - virtual int getVerticalScaleWidth(View *v, bool, QPainter &) const; - virtual void paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const; + virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &) const; + virtual void paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const; virtual ColourSignificance getLayerColourSignificance() const { return ColourAndBackgroundSignificant; @@ -67,7 +67,7 @@ virtual bool hasTimeXAxis() const { return false; } - virtual bool isLayerScrollable(const View *) const { return false; } + virtual bool isLayerScrollable(const LayerGeometryProvider *) const { return false; } enum EnergyScale { LinearScale, MeterScale, dBScale, AbsoluteScale }; @@ -112,10 +112,10 @@ virtual double getXForBin(int bin, int totalBins, double w) const; virtual int getBinForX(double x, int totalBins, double w) const; - virtual double getYForValue(double value, const View *v, double &norm) const; - virtual double getValueForY(double y, const View *v) const; + virtual double getYForValue(double value, const LayerGeometryProvider *v, double &norm) const; + virtual double getValueForY(double y, const LayerGeometryProvider *v) const; - virtual QString getFeatureDescriptionAux(View *v, QPoint &, + virtual QString getFeatureDescriptionAux(LayerGeometryProvider *v, QPoint &, bool includeBinDescription, int &minbin, int &maxbin, int &range) const; @@ -141,9 +141,9 @@ float m_initialThreshold; float m_gain; mutable std::vector<int> m_scalePoints; - mutable std::map<const View *, int> m_xorigins; - mutable std::map<const View *, int> m_yorigins; - mutable std::map<const View *, int> m_heights; + mutable std::map<const LayerGeometryProvider *, int> m_xorigins; + mutable std::map<const LayerGeometryProvider *, int> m_yorigins; + mutable std::map<const LayerGeometryProvider *, int> m_heights; mutable sv_frame_t m_currentf0; mutable sv_frame_t m_currentf1; mutable std::vector<float> m_values;
--- a/layer/SpectrogramLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/SpectrogramLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -33,11 +33,11 @@ #include <QImage> #include <QPixmap> #include <QRect> -#include <QTimer> #include <QApplication> #include <QMessageBox> #include <QMouseEvent> #include <QTextStream> +#include <QSettings> #include <iostream> @@ -48,9 +48,9 @@ #include <alloca.h> #endif -//#define DEBUG_SPECTROGRAM_REPAINT 1 - -using std::vector; +#define DEBUG_SPECTROGRAM_REPAINT 1 + +using namespace std; SpectrogramLayer::SpectrogramLayer(Configuration config) : m_model(0), @@ -73,18 +73,16 @@ m_colourMap(0), m_frequencyScale(LinearFrequencyScale), m_binDisplay(AllBins), - m_normalizeColumns(false), - m_normalizeVisibleArea(false), - m_normalizeHybrid(false), + m_normalization(NoNormalization), m_lastEmittedZoomStep(-1), m_synchronous(false), m_haveDetailedScale(false), - m_lastPaintBlockWidth(0), - m_updateTimer(0), - m_candidateFillStartFrame(0), m_exiting(false), m_sliceableModel(0) { + QString colourConfigName = "spectrogram-colour"; + int colourConfigDefault = int(ColourMapper::Green); + if (config == FullRangeDb) { m_initialMaxFrequency = 0; setMaxFrequency(0); @@ -97,6 +95,8 @@ setColourScale(LinearColourScale); setColourMap(ColourMapper::Sunset); setFrequencyScale(LogFrequencyScale); + colourConfigName = "spectrogram-melodic-colour"; + colourConfigDefault = int(ColourMapper::Sunset); // setGain(20); } else if (config == MelodicPeaks) { setWindowSize(4096); @@ -107,9 +107,16 @@ setFrequencyScale(LogFrequencyScale); setColourScale(LinearColourScale); setBinDisplay(PeakFrequencies); - setNormalizeColumns(true); + setNormalization(NormalizeColumns); + colourConfigName = "spectrogram-melodic-colour"; + colourConfigDefault = int(ColourMapper::Sunset); } + QSettings settings; + settings.beginGroup("Preferences"); + setColourMap(settings.value(colourConfigName, colourConfigDefault).toInt()); + settings.endGroup(); + Preferences *prefs = Preferences::getInstance(); connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)), this, SLOT(preferenceChanged(PropertyContainer::PropertyName))); @@ -120,9 +127,6 @@ SpectrogramLayer::~SpectrogramLayer() { - delete m_updateTimer; - m_updateTimer = 0; - invalidateFFTModels(); } @@ -155,8 +159,7 @@ list.push_back("Colour Scale"); list.push_back("Window Size"); list.push_back("Window Increment"); - list.push_back("Normalize Columns"); - list.push_back("Normalize Visible Area"); + list.push_back("Normalization"); list.push_back("Bin Display"); list.push_back("Threshold"); list.push_back("Gain"); @@ -175,8 +178,7 @@ if (name == "Colour Scale") return tr("Colour Scale"); if (name == "Window Size") return tr("Window Size"); if (name == "Window Increment") return tr("Window Overlap"); - if (name == "Normalize Columns") return tr("Normalize Columns"); - if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); + if (name == "Normalization") return tr("Normalization"); if (name == "Bin Display") return tr("Bin Display"); if (name == "Threshold") return tr("Threshold"); if (name == "Gain") return tr("Gain"); @@ -189,10 +191,8 @@ } QString -SpectrogramLayer::getPropertyIconName(const PropertyName &name) const +SpectrogramLayer::getPropertyIconName(const PropertyName &) const { - if (name == "Normalize Columns") return "normalise-columns"; - if (name == "Normalize Visible Area") return "normalise"; return ""; } @@ -201,8 +201,6 @@ { if (name == "Gain") return RangeProperty; if (name == "Colour Rotation") return RangeProperty; - if (name == "Normalize Columns") return ToggleProperty; - if (name == "Normalize Visible Area") return ToggleProperty; if (name == "Threshold") return RangeProperty; if (name == "Zero Padding") return ToggleProperty; return ValueProperty; @@ -219,8 +217,7 @@ if (name == "Colour" || name == "Threshold" || name == "Colour Rotation") return tr("Colour"); - if (name == "Normalize Columns" || - name == "Normalize Visible Area" || + if (name == "Normalization" || name == "Gain" || name == "Colour Scale") return tr("Scale"); return QString(); @@ -365,15 +362,12 @@ *deflt = int(AllBins); val = (int)m_binDisplay; - } else if (name == "Normalize Columns") { + } else if (name == "Normalization") { - *deflt = 0; - val = (m_normalizeColumns ? 1 : 0); - - } else if (name == "Normalize Visible Area") { - - *deflt = 0; - val = (m_normalizeVisibleArea ? 1 : 0); + *min = 0; + *max = 3; + *deflt = int(NoNormalization); + val = (int)m_normalization; } else { val = Layer::getPropertyRangeAndValue(name, min, max, deflt); @@ -399,6 +393,9 @@ case 4: return tr("Phase"); } } + if (name == "Normalization") { + return ""; // icon only + } if (name == "Window Size") { return QString("%1").arg(32 << value); } @@ -465,6 +462,22 @@ return tr("<unknown>"); } +QString +SpectrogramLayer::getPropertyValueIconName(const PropertyName &name, + int value) const +{ + if (name == "Normalization") { + switch(value) { + default: + case 0: return "normalise-none"; + case 1: return "normalise-columns"; + case 2: return "normalise"; + case 3: return "normalise-hybrid"; + } + } + return ""; +} + RangeMapper * SpectrogramLayer::getNewPropertyRangeMapper(const PropertyName &name) const { @@ -555,86 +568,26 @@ case 1: setBinDisplay(PeakBins); break; case 2: setBinDisplay(PeakFrequencies); break; } - } else if (name == "Normalize Columns") { - setNormalizeColumns(value ? true : false); - } else if (name == "Normalize Visible Area") { - setNormalizeVisibleArea(value ? true : false); + } else if (name == "Normalization") { + switch (value) { + default: + case 0: setNormalization(NoNormalization); break; + case 1: setNormalization(NormalizeColumns); break; + case 2: setNormalization(NormalizeVisibleArea); break; + case 3: setNormalization(NormalizeHybrid); break; + } } } void SpectrogramLayer::invalidateImageCaches() { +#ifdef DEBUG_SPECTROGRAM + cerr << "SpectrogramLayer::invalidateImageCaches called" << endl; +#endif for (ViewImageCache::iterator i = m_imageCaches.begin(); i != m_imageCaches.end(); ++i) { - i->second.validArea = QRect(); - } -} - -void -SpectrogramLayer::invalidateImageCaches(sv_frame_t startFrame, sv_frame_t endFrame) -{ - for (ViewImageCache::iterator i = m_imageCaches.begin(); - i != m_imageCaches.end(); ++i) { - - //!!! when are views removed from the map? on setLayerDormant? - const View *v = i->first; - -#ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::invalidateImageCaches(" - << startFrame << ", " << endFrame << "): view range is " - << v->getStartFrame() << ", " << v->getEndFrame() - << endl; - - cerr << "Valid area was: " << i->second.validArea.x() << ", " - << i->second.validArea.y() << " " - << i->second.validArea.width() << "x" - << i->second.validArea.height() << endl; -#endif - - if (int(startFrame) > v->getStartFrame()) { - if (startFrame >= v->getEndFrame()) { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Modified start frame is off right of view" << endl; -#endif - return; - } - int x = v->getXForFrame(startFrame); -#ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "clipping from 0 to " << x-1 << endl; -#endif - if (x > 1) { - i->second.validArea &= - QRect(0, 0, x-1, v->height()); - } else { - i->second.validArea = QRect(); - } - } else { - if (int(endFrame) < v->getStartFrame()) { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Modified end frame is off left of view" << endl; -#endif - return; - } - int x = v->getXForFrame(endFrame); -#ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "clipping from " << x+1 << " to " << v->width() - << endl; -#endif - if (x < v->width()) { - i->second.validArea &= - QRect(x+1, 0, v->width()-(x+1), v->height()); - } else { - i->second.validArea = QRect(); - } - } - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Valid area is now: " << i->second.validArea.x() << ", " - << i->second.validArea.y() << " " - << i->second.validArea.width() << "x" - << i->second.validArea.height() << endl; -#endif + i->second.invalidate(); } } @@ -934,69 +887,30 @@ } void -SpectrogramLayer::setNormalizeColumns(bool n) +SpectrogramLayer::setNormalization(Normalization n) { - if (m_normalizeColumns == n) return; + if (m_normalization == n) return; invalidateImageCaches(); invalidateMagnitudes(); - m_normalizeColumns = n; + m_normalization = n; emit layerParametersChanged(); } -bool -SpectrogramLayer::getNormalizeColumns() const +SpectrogramLayer::Normalization +SpectrogramLayer::getNormalization() const { - return m_normalizeColumns; + return m_normalization; } void -SpectrogramLayer::setNormalizeHybrid(bool n) -{ - if (m_normalizeHybrid == n) return; - - invalidateImageCaches(); - invalidateMagnitudes(); - m_normalizeHybrid = n; - - emit layerParametersChanged(); -} - -bool -SpectrogramLayer::getNormalizeHybrid() const -{ - return m_normalizeHybrid; -} - -void -SpectrogramLayer::setNormalizeVisibleArea(bool n) -{ - SVDEBUG << "SpectrogramLayer::setNormalizeVisibleArea(" << n - << ") (from " << m_normalizeVisibleArea << ")" << endl; - - if (m_normalizeVisibleArea == n) return; - - invalidateImageCaches(); - invalidateMagnitudes(); - m_normalizeVisibleArea = n; - - emit layerParametersChanged(); -} - -bool -SpectrogramLayer::getNormalizeVisibleArea() const -{ - return m_normalizeVisibleArea; -} - -void -SpectrogramLayer::setLayerDormant(const View *v, bool dormant) +SpectrogramLayer::setLayerDormant(const LayerGeometryProvider *v, bool dormant) { if (dormant) { #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::setLayerDormant(" << dormant << ")" + cerr << "SpectrogramLayer::setLayerDormant(" << dormant << ")" << endl; #endif @@ -1006,17 +920,20 @@ Layer::setLayerDormant(v, true); + const View *view = v->getView(); + invalidateImageCaches(); - m_imageCaches.erase(v); - - if (m_fftModels.find(v) != m_fftModels.end()) { - - if (m_sliceableModel == m_fftModels[v].first) { + + m_imageCaches.erase(view->getId()); + + if (m_fftModels.find(view->getId()) != m_fftModels.end()) { + + if (m_sliceableModel == m_fftModels[view->getId()]) { bool replaced = false; for (ViewFFTMap::iterator i = m_fftModels.begin(); i != m_fftModels.end(); ++i) { - if (i->second.first != m_sliceableModel) { - emit sliceableModelReplaced(m_sliceableModel, i->second.first); + if (i->second != m_sliceableModel) { + emit sliceableModelReplaced(m_sliceableModel, i->second); replaced = true; break; } @@ -1024,11 +941,11 @@ if (!replaced) emit sliceableModelReplaced(m_sliceableModel, 0); } - delete m_fftModels[v].first; - m_fftModels.erase(v); - - delete m_peakCaches[v]; - m_peakCaches.erase(v); + delete m_fftModels[view->getId()]; + m_fftModels.erase(view->getId()); + + delete m_peakCaches[view->getId()]; + m_peakCaches.erase(view->getId()); } } else { @@ -1041,7 +958,7 @@ SpectrogramLayer::cacheInvalid() { #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::cacheInvalid()" << endl; + cerr << "SpectrogramLayer::cacheInvalid()" << endl; #endif invalidateImageCaches(); @@ -1049,84 +966,28 @@ } void -SpectrogramLayer::cacheInvalid(sv_frame_t from, sv_frame_t to) +SpectrogramLayer::cacheInvalid( +#ifdef DEBUG_SPECTROGRAM_REPAINT + sv_frame_t from, sv_frame_t to +#else + sv_frame_t , sv_frame_t +#endif + ) { #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::cacheInvalid(" << from << ", " << to << ")" << endl; + cerr << "SpectrogramLayer::cacheInvalid(" << from << ", " << to << ")" << endl; #endif - invalidateImageCaches(from, to); + // We used to call invalidateMagnitudes(from, to) to invalidate + // only those caches whose views contained some of the (from, to) + // range. That's the right thing to do; it has been lost in + // pulling out the image cache code, but it might not matter very + // much, since the underlying models for spectrogram layers don't + // change very often. Let's see. + invalidateImageCaches(); invalidateMagnitudes(); } -void -SpectrogramLayer::fillTimerTimedOut() -{ - if (!m_model) return; - - bool allDone = true; - -#ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::fillTimerTimedOut: have " << m_fftModels.size() << " FFT models associated with views" << endl; -#endif - - for (ViewFFTMap::iterator i = m_fftModels.begin(); - i != m_fftModels.end(); ++i) { - - const FFTModel *model = i->second.first; - sv_frame_t lastFill = i->second.second; - - if (model) { - - sv_frame_t fill = model->getFillExtent(); - -#ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::fillTimerTimedOut: extent for " << model << ": " << fill << ", last " << lastFill << ", total " << m_model->getEndFrame() << endl; -#endif - - if (fill >= lastFill) { - if (fill >= m_model->getEndFrame() && lastFill > 0) { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "complete!" << endl; -#endif - invalidateImageCaches(); - i->second.second = -1; - emit modelChanged(); - - } else if (fill > lastFill) { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "SpectrogramLayer: emitting modelChanged(" - << lastFill << "," << fill << ")" << endl; -#endif - invalidateImageCaches(lastFill, fill); - i->second.second = fill; - emit modelChangedWithin(lastFill, fill); - } - } else { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "SpectrogramLayer: going backwards, emitting modelChanged(" - << m_model->getStartFrame() << "," << m_model->getEndFrame() << ")" << endl; -#endif - invalidateImageCaches(); - i->second.second = fill; - emit modelChangedWithin(m_model->getStartFrame(), m_model->getEndFrame()); - } - - if (i->second.second >= 0) { - allDone = false; - } - } - } - - if (allDone) { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "SpectrogramLayer: all complete!" << endl; -#endif - delete m_updateTimer; - m_updateTimer = 0; - } -} - bool SpectrogramLayer::hasLightBackground() const { @@ -1181,17 +1042,17 @@ } unsigned char -SpectrogramLayer::getDisplayValue(View *v, double input) const +SpectrogramLayer::getDisplayValue(LayerGeometryProvider *v, double input) const { int value; double min = 0.0; double max = 1.0; - if (m_normalizeVisibleArea) { - min = m_viewMags[v].getMin(); - max = m_viewMags[v].getMax(); - } else if (!m_normalizeColumns) { + if (m_normalization == NormalizeVisibleArea) { + min = m_viewMags[v->getId()].getMin(); + max = m_viewMags[v->getId()].getMax(); + } else if (m_normalization != NormalizeColumns) { if (m_colourScale == LinearColourScale //|| // m_colourScale == MeterColourScale) { ) { @@ -1294,11 +1155,11 @@ } bool -SpectrogramLayer::getYBinRange(View *v, int y, double &q0, double &q1) const +SpectrogramLayer::getYBinRange(LayerGeometryProvider *v, int y, double &q0, double &q1) const { Profiler profiler("SpectrogramLayer::getYBinRange"); - int h = v->height(); + int h = v->getPaintHeight(); if (y < 0 || y >= h) return false; sv_samplerate_t sr = m_model->getSampleRate(); @@ -1320,11 +1181,11 @@ } bool -SpectrogramLayer::getSmoothedYBinRange(View *v, int y, double &q0, double &q1) const +SpectrogramLayer::getSmoothedYBinRange(LayerGeometryProvider *v, int y, double &q0, double &q1) const { Profiler profiler("SpectrogramLayer::getSmoothedYBinRange"); - int h = v->height(); + int h = v->getPaintHeight(); if (y < 0 || y >= h) return false; sv_samplerate_t sr = m_model->getSampleRate(); @@ -1346,7 +1207,7 @@ } bool -SpectrogramLayer::getXBinRange(View *v, int x, double &s0, double &s1) const +SpectrogramLayer::getXBinRange(LayerGeometryProvider *v, int x, double &s0, double &s1) const { sv_frame_t modelStart = m_model->getStartFrame(); sv_frame_t modelEnd = m_model->getEndFrame(); @@ -1370,7 +1231,7 @@ } bool -SpectrogramLayer::getXBinSourceRange(View *v, int x, RealTime &min, RealTime &max) const +SpectrogramLayer::getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &min, RealTime &max) const { double s0 = 0, s1 = 0; if (!getXBinRange(v, x, s0, s1)) return false; @@ -1389,7 +1250,7 @@ } bool -SpectrogramLayer::getYBinSourceRange(View *v, int y, double &freqMin, double &freqMax) +SpectrogramLayer::getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) const { double q0 = 0, q1 = 0; @@ -1408,7 +1269,7 @@ } bool -SpectrogramLayer::getAdjustedYBinSourceRange(View *v, int x, int y, +SpectrogramLayer::getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &freqMin, double &freqMax, double &adjFreqMin, double &adjFreqMax) const @@ -1443,8 +1304,6 @@ for (int s = s0i; s <= s1i; ++s) { - if (!fft->isColumnAvailable(s)) continue; - double binfreq = (double(sr) * q) / m_windowSize; if (q == q0i) freqMin = binfreq; if (q == q1i) freqMax = binfreq; @@ -1475,7 +1334,7 @@ } bool -SpectrogramLayer::getXYBinSourceRange(View *v, int x, int y, +SpectrogramLayer::getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &min, double &max, double &phaseMin, double &phaseMax) const { @@ -1518,8 +1377,6 @@ for (int s = s0i; s <= s1i; ++s) { if (s >= 0 && q >= 0 && s < cw && q < ch) { - if (!fft->isColumnAvailable(s)) continue; - double value; value = fft->getPhaseAt(s, q); @@ -1544,7 +1401,7 @@ } int -SpectrogramLayer::getZeroPadLevel(const View *v) const +SpectrogramLayer::getZeroPadLevel(const LayerGeometryProvider *v) const { //!!! tidy all this stuff @@ -1574,7 +1431,7 @@ } double perPixel = - double(v->height()) / + double(v->getPaintHeight()) / double((maxbin - minbin) / (m_zeroPadLevel + 1)); if (perPixel > 2.8) { @@ -1587,42 +1444,44 @@ } int -SpectrogramLayer::getFFTSize(const View *v) const +SpectrogramLayer::getFFTSize(const LayerGeometryProvider *v) const { return m_fftSize * (getZeroPadLevel(v) + 1); } FFTModel * -SpectrogramLayer::getFFTModel(const View *v) const +SpectrogramLayer::getFFTModel(const LayerGeometryProvider *v) const { if (!m_model) return 0; int fftSize = getFFTSize(v); - if (m_fftModels.find(v) != m_fftModels.end()) { - if (m_fftModels[v].first == 0) { + const View *view = v->getView(); + + if (m_fftModels.find(view->getId()) != m_fftModels.end()) { + if (m_fftModels[view->getId()] == 0) { #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found null model" << endl; + cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found null model" << endl; #endif return 0; } - if (m_fftModels[v].first->getHeight() != fftSize / 2 + 1) { + if (m_fftModels[view->getId()]->getHeight() != fftSize / 2 + 1) { #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found a model with the wrong height (" << m_fftModels[v].first->getHeight() << ", wanted " << (fftSize / 2 + 1) << ")" << endl; + cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found a model with the wrong height (" << m_fftModels[view->getId()]->getHeight() << ", wanted " << (fftSize / 2 + 1) << ")" << endl; #endif - delete m_fftModels[v].first; - m_fftModels.erase(v); - delete m_peakCaches[v]; - m_peakCaches.erase(v); + delete m_fftModels[view->getId()]; + m_fftModels.erase(view->getId()); + delete m_peakCaches[view->getId()]; + m_peakCaches.erase(view->getId()); } else { #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found a good model of height " << m_fftModels[v].first->getHeight() << endl; + cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found a good model of height " << m_fftModels[view->getId()]->getHeight() << endl; #endif - return m_fftModels[v].first; + return m_fftModels[view->getId()]; } } - if (m_fftModels.find(v) == m_fftModels.end()) { + if (m_fftModels.find(view->getId()) == m_fftModels.end()) { FFTModel *model = new FFTModel(m_model, m_channel, @@ -1637,7 +1496,7 @@ tr("Failed to create the FFT model for this spectrogram.\n" "There may be insufficient memory or disc space to continue.")); delete model; - m_fftModels[v] = FFTFillPair(0, 0); + m_fftModels[view->getId()] = 0; return 0; } @@ -1649,27 +1508,22 @@ m_sliceableModel = model; } - m_fftModels[v] = FFTFillPair(model, 0); - - delete m_updateTimer; - m_updateTimer = new QTimer((SpectrogramLayer *)this); - connect(m_updateTimer, SIGNAL(timeout()), - this, SLOT(fillTimerTimedOut())); - m_updateTimer->start(200); + m_fftModels[view->getId()] = model; } - return m_fftModels[v].first; + return m_fftModels[view->getId()]; } Dense3DModelPeakCache * -SpectrogramLayer::getPeakCache(const View *v) const +SpectrogramLayer::getPeakCache(const LayerGeometryProvider *v) const { - if (!m_peakCaches[v]) { + const View *view = v->getView(); + if (!m_peakCaches[view->getId()]) { FFTModel *f = getFFTModel(v); if (!f) return 0; - m_peakCaches[v] = new Dense3DModelPeakCache(f, 8); + m_peakCaches[view->getId()] = new Dense3DModelPeakCache(f, 8); } - return m_peakCaches[v]; + return m_peakCaches[view->getId()]; } const Model * @@ -1677,16 +1531,19 @@ { if (m_sliceableModel) return m_sliceableModel; if (m_fftModels.empty()) return 0; - m_sliceableModel = m_fftModels.begin()->second.first; + m_sliceableModel = m_fftModels.begin()->second; return m_sliceableModel; } void SpectrogramLayer::invalidateFFTModels() { +#ifdef DEBUG_SPECTROGRAM + cerr << "SpectrogramLayer::invalidateFFTModels called" << endl; +#endif for (ViewFFTMap::iterator i = m_fftModels.begin(); i != m_fftModels.end(); ++i) { - delete i->second.first; + delete i->second; } for (PeakCacheMap::iterator i = m_peakCaches.begin(); i != m_peakCaches.end(); ++i) { @@ -1706,19 +1563,22 @@ void SpectrogramLayer::invalidateMagnitudes() { +#ifdef DEBUG_SPECTROGRAM + cerr << "SpectrogramLayer::invalidateMagnitudes called" << endl; +#endif m_viewMags.clear(); - for (std::vector<MagnitudeRange>::iterator i = m_columnMags.begin(); + for (vector<MagnitudeRange>::iterator i = m_columnMags.begin(); i != m_columnMags.end(); ++i) { *i = MagnitudeRange(); } } bool -SpectrogramLayer::updateViewMagnitudes(View *v) const +SpectrogramLayer::updateViewMagnitudes(LayerGeometryProvider *v) const { MagnitudeRange mag; - int x0 = 0, x1 = v->width(); + int x0 = 0, x1 = v->getPaintWidth(); double s00 = 0, s01 = 0, s10 = 0, s11 = 0; if (!getXBinRange(v, x0, s00, s01)) { @@ -1729,8 +1589,8 @@ s10 = s11 = double(m_model->getEndFrame()) / getWindowIncrement(); } - int s0 = int(std::min(s00, s10) + 0.0001); - int s1 = int(std::max(s01, s11) + 0.0001); + int s0 = int(min(s00, s10) + 0.0001); + int s1 = int(max(s01, s11) + 0.0001); // SVDEBUG << "SpectrogramLayer::updateViewMagnitudes: x0 = " << x0 << ", x1 = " << x1 << ", s00 = " << s00 << ", s11 = " << s11 << " s0 = " << s0 << ", s1 = " << s1 << endl; @@ -1745,13 +1605,15 @@ } #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::updateViewMagnitudes returning from cols " - << s0 << " -> " << s1 << " inclusive" << endl; + cerr << "SpectrogramLayer::updateViewMagnitudes returning from cols " + << s0 << " -> " << s1 << " inclusive" << endl; + cerr << "SpectrogramLayer::updateViewMagnitudes: for view id " << v->getId() + << ": min is " << mag.getMin() << ", max is " << mag.getMax() << endl; #endif if (!mag.isSet()) return false; - if (mag == m_viewMags[v]) return false; - m_viewMags[v] = mag; + if (mag == m_viewMags[v->getId()]) return false; + m_viewMags[v->getId()] = mag; return true; } @@ -1761,23 +1623,27 @@ m_synchronous = synchronous; } +ScrollableImageCache & +SpectrogramLayer::getImageCacheReference(const LayerGeometryProvider *view) const +{ + if (m_imageCaches.find(view->getId()) == m_imageCaches.end()) { + m_imageCaches[view->getId()] = ScrollableImageCache(view); + } + return m_imageCaches.at(view->getId()); +} + void -SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const +SpectrogramLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { - // What a lovely, old-fashioned function this is. - // It's practically FORTRAN 77 in its clarity and linearity. - Profiler profiler("SpectrogramLayer::paint", false); #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", m_updateTimer " << m_updateTimer << endl; + cerr << "SpectrogramLayer::paint() entering: m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << endl; - cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl; + cerr << "SpectrogramLayer::paint(): rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl; #endif sv_frame_t startFrame = v->getStartFrame(); - if (startFrame < 0) m_candidateFillStartFrame = 0; - else m_candidateFillStartFrame = startFrame; if (!m_model || !m_model->isOK() || !m_model->isReady()) { return; @@ -1795,310 +1661,135 @@ const_cast<SpectrogramLayer *>(this)->Layer::setLayerDormant(v, false); int fftSize = getFFTSize(v); -/* - FFTModel *fft = getFFTModel(v); - if (!fft) { - cerr << "ERROR: SpectrogramLayer::paint(): No FFT model, returning" << endl; - return; + + const View *view = v->getView(); + ScrollableImageCache &cache = getImageCacheReference(view); + +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer::paint(): image cache valid area from " << cache.getValidLeft() << " width " << cache.getValidWidth() << ", height " << cache.getSize().height() << endl; + if (rect.x() + rect.width() + 1 < cache.getValidLeft() || + rect.x() > cache.getValidRight()) { + cerr << "SpectrogramLayer: NOTE: requested rect is not contiguous with cache valid area" << endl; } -*/ - ImageCache &cache = m_imageCaches[v]; - -#ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::paint(): image cache valid area " << cache. - -validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << endl; #endif -#ifdef DEBUG_SPECTROGRAM_REPAINT - bool stillCacheing = (m_updateTimer != 0); - SVDEBUG << "SpectrogramLayer::paint(): Still cacheing = " << stillCacheing << endl; -#endif - int zoomLevel = v->getZoomLevel(); - int x0 = 0; - int x1 = v->width(); - - bool recreateWholeImageCache = true; - - x0 = rect.left(); - x1 = rect.right() + 1; -/* - double xPixelRatio = double(fft->getResolution()) / double(zoomLevel); - cerr << "xPixelRatio = " << xPixelRatio << endl; - if (xPixelRatio < 1.f) xPixelRatio = 1.f; -*/ - if (cache.validArea.width() > 0) { - - int cw = cache.image.width(); - int ch = cache.image.height(); - - if (int(cache.zoomLevel) == zoomLevel && - cw == v->width() && - ch == v->height()) { - - if (v->getXForFrame(cache.startFrame) == - v->getXForFrame(startFrame) && - cache.validArea.x() <= x0 && - cache.validArea.x() + cache.validArea.width() >= x1) { - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "SpectrogramLayer: image cache good" << endl; -#endif - - paint.drawImage(rect, cache.image, rect); - //!!! -// paint.drawImage(v->rect(), cache.image, -// QRect(QPoint(0, 0), cache.image.size())); - - illuminateLocalFeatures(v, paint); - return; - - } else { - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "SpectrogramLayer: image cache partially OK" << endl; -#endif - - recreateWholeImageCache = false; - - int dx = v->getXForFrame(cache.startFrame) - - v->getXForFrame(startFrame); - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "SpectrogramLayer: dx = " << dx << " (image cache " << cw << "x" << ch << ")" << endl; -#endif - - if (dx != 0 && - dx > -cw && - dx < cw) { - - int dxp = dx; - if (dxp < 0) dxp = -dxp; - size_t copy = (cw - dxp) * sizeof(QRgb); - for (int y = 0; y < ch; ++y) { - QRgb *line = (QRgb *)cache.image.scanLine(y); - if (dx < 0) { - memmove(line, line + dxp, copy); - } else { - memmove(line + dxp, line, copy); - } - } - - int px = cache.validArea.x(); - int pw = cache.validArea.width(); - - if (dx < 0) { - x0 = cw + dx; - x1 = cw; - px += dx; - if (px < 0) { - pw += px; - px = 0; - if (pw < 0) pw = 0; - } - } else { - x0 = 0; - x1 = dx; - px += dx; - if (px + pw > cw) { - pw = int(cw) - px; - if (pw < 0) pw = 0; - } - } - - cache.validArea = - QRect(px, cache.validArea.y(), - pw, cache.validArea.height()); - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "valid area now " - << px << "," << cache.validArea.y() - << " " << pw << "x" << cache.validArea.height() - << endl; -#endif -/* - paint.drawImage(rect & cache.validArea, - cache.image, - rect & cache.validArea); -*/ - } else if (dx != 0) { - - // we scrolled too far to be of use - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "dx == " << dx << ": scrolled too far for cache to be useful" << endl; -#endif - - cache.validArea = QRect(); - recreateWholeImageCache = true; - } - } - } else { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "SpectrogramLayer: image cache useless" << endl; - if (int(cache.zoomLevel) != zoomLevel) { - cerr << "(cache zoomLevel " << cache.zoomLevel - << " != " << zoomLevel << ")" << endl; - } - if (cw != v->width()) { - cerr << "(cache width " << cw - << " != " << v->width(); - } - if (ch != v->height()) { - cerr << "(cache height " << ch - << " != " << v->height(); - } -#endif - cache.validArea = QRect(); -// recreateWholeImageCache = true; - } - } + int x0 = v->getXForViewX(rect.x()); + int x1 = v->getXForViewX(rect.x() + rect.width()); + if (x0 < 0) x0 = 0; + if (x1 > v->getPaintWidth()) x1 = v->getPaintWidth(); if (updateViewMagnitudes(v)) { #ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << endl; + cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v->getId()].getMin() << "->" << m_viewMags[v->getId()].getMax() << "]" << endl; #endif - if (m_normalizeVisibleArea) { - cache.validArea = QRect(); - recreateWholeImageCache = true; + if (m_normalization == NormalizeVisibleArea) { + cache.invalidate(); + } + } + + if (cache.getZoomLevel() != zoomLevel || + cache.getSize() != v->getPaintSize()) { +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer: resizing image cache from " + << cache.getSize().width() << "x" << cache.getSize().height() + << " to " + << v->getPaintSize().width() << "x" << v->getPaintSize().height() + << " and updating zoom level from " << cache.getZoomLevel() + << " to " << zoomLevel + << endl; +#endif + cache.resize(v->getPaintSize()); + cache.setZoomLevel(zoomLevel); + cache.setStartFrame(startFrame); + } + + if (cache.isValid()) { + + if (v->getXForFrame(cache.getStartFrame()) == + v->getXForFrame(startFrame) && + cache.getValidLeft() <= x0 && + cache.getValidRight() >= x1) { + +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer: image cache hit!" << endl; +#endif + + paint.drawImage(rect, cache.getImage(), rect); + + illuminateLocalFeatures(v, paint); + return; + + } else { + + // cache doesn't begin at the right frame or doesn't + // contain the complete view, but might be scrollable or + // partially usable + +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer: scrolling the image cache if applicable" << endl; +#endif + + cache.scrollTo(startFrame); + +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer: after scrolling, cache valid from " + << cache.getValidLeft() << " width " << cache.getValidWidth() + << endl; +#endif + } + } + + bool rightToLeft = false; + + if (!cache.isValid()) { + if (!m_synchronous) { + // When rendering the whole thing, start from somewhere near + // the middle so that the region of interest appears first + + //!!! (perhaps we should have some cunning test to avoid + //!!! doing this if past repaints have appeared fast + //!!! enough to do the whole width in one shot) + if (x0 == 0 && x1 == v->getPaintWidth()) { + x0 = int(x1 * 0.3); + } } } else { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << endl; -#endif + // When rendering only a part of the cache, we need to make + // sure that the part we're rendering is adjacent to (or + // overlapping) a valid area of cache, if we have one. The + // alternative is to ditch the valid area of cache and render + // only the requested area, but that's risky because this can + // happen when just waving the pointer over a small part of + // the view -- if we lose the partly-built cache every time + // the user does that, we'll never finish building it. + int left = x0; + int width = x1 - x0; + bool isLeftOfValidArea = false; + cache.adjustToTouchValidArea(left, width, isLeftOfValidArea); + x0 = left; + x1 = x0 + width; + + // That call also told us whether we should be painting + // sub-regions of our target region in right-to-left order in + // order to ensure contiguity + rightToLeft = isLeftOfValidArea; } - - if (recreateWholeImageCache) { - x0 = 0; - x1 = v->width(); - } - - struct timeval tv; - (void)gettimeofday(&tv, 0); - RealTime mainPaintStart = RealTime::fromTimeval(tv); - - int paintBlockWidth = m_lastPaintBlockWidth; - - if (m_synchronous) { - if (paintBlockWidth < x1 - x0) { - // always paint full width - paintBlockWidth = x1 - x0; - } - } else { - if (paintBlockWidth == 0) { - paintBlockWidth = (300000 / zoomLevel); - } else { - RealTime lastTime = m_lastPaintTime; - while (lastTime > RealTime::fromMilliseconds(200) && - paintBlockWidth > 50) { - paintBlockWidth /= 2; - lastTime = lastTime / 2; - } - while (lastTime < RealTime::fromMilliseconds(90) && - paintBlockWidth < 1500) { - paintBlockWidth *= 2; - lastTime = lastTime * 2; - } - } - - if (paintBlockWidth < 20) paintBlockWidth = 20; - } - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "[" << this << "]: last paint width: " << m_lastPaintBlockWidth << ", last paint time: " << m_lastPaintTime << ", new paint width: " << paintBlockWidth << endl; -#endif - + // We always paint the full height when refreshing the cache. // Smaller heights can be used when painting direct from cache // (further up in this function), but we want to ensure the cache // is coherent without having to worry about vertical matching of // required and valid areas as well as horizontal. - - int h = v->height(); - - if (cache.validArea.width() > 0) { - - // If part of the cache is known to be valid, select a strip - // immediately to left or right of the valid part - - //!!! this really needs to be coordinated with the selection - //!!! of m_drawBuffer boundaries in the bufferBinResolution - //!!! case below - - int vx0 = 0, vx1 = 0; - vx0 = cache.validArea.x(); - vx1 = cache.validArea.x() + cache.validArea.width(); - + int h = v->getPaintHeight(); + + int repaintWidth = x1 - x0; + #ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "x0 " << x0 << ", x1 " << x1 << ", vx0 " << vx0 << ", vx1 " << vx1 << ", paintBlockWidth " << paintBlockWidth << endl; -#endif - if (x0 < vx0) { - if (x0 + paintBlockWidth < vx0) { - x0 = vx0 - paintBlockWidth; - } - x1 = vx0; - } else if (x0 >= vx1) { - x0 = vx1; - if (x1 > x0 + paintBlockWidth) { - x1 = x0 + paintBlockWidth; - } - } else { - // x0 is within the valid area - if (x1 > vx1) { - x0 = vx1; - if (x0 + paintBlockWidth < x1) { - x1 = x0 + paintBlockWidth; - } - } else { - x1 = x0; // it's all valid, paint nothing - } - } - - cache.validArea = QRect - (std::min(vx0, x0), cache.validArea.y(), - std::max(vx1 - std::min(vx0, x0), - x1 - std::min(vx0, x0)), - cache.validArea.height()); - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Valid area becomes " << cache.validArea.x() - << ", " << cache.validArea.y() << ", " - << cache.validArea.width() << "x" - << cache.validArea.height() << endl; -#endif - - } else { - if (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; - } - } -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Valid area becomes " << x0 << ", 0, " << (x1-x0) - << "x" << h << endl; -#endif - cache.validArea = QRect(x0, 0, x1 - x0, h); - } - -/* - if (xPixelRatio != 1.f) { - x0 = int((int(x0 / xPixelRatio) - 4) * xPixelRatio + 0.0001); - x1 = int((int(x1 / xPixelRatio) + 4) * xPixelRatio + 0.0001); - } -*/ - int w = x1 - x0; - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "x0 " << x0 << ", x1 " << x1 << ", w " << w << ", h " << h << endl; + cerr << "SpectrogramLayer: x0 " << x0 << ", x1 " << x1 + << ", repaintWidth " << repaintWidth << ", h " << h + << ", rightToLeft " << rightToLeft << endl; #endif sv_samplerate_t sr = m_model->getSampleRate(); @@ -2148,30 +1839,17 @@ int increment = getWindowIncrement(); bool logarithmic = (m_frequencyScale == LogFrequencyScale); -/* - double yforbin[maxbin - minbin + 1]; - - for (int q = minbin; q <= maxbin; ++q) { - double f0 = (double(q) * sr) / fftSize; - yforbin[q - minbin] = - v->getYForFrequency(f0, displayMinFreq, displayMaxFreq, - logarithmic); + + MagnitudeRange overallMag = m_viewMags[v->getId()]; + bool overallMagChanged = false; + +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer: " << ((double(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << endl; +#endif + + if (repaintWidth == 0) { + SVDEBUG << "*** NOTE: repaintWidth == 0" << endl; } -*/ - MagnitudeRange overallMag = m_viewMags[v]; - bool overallMagChanged = false; - -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << ((double(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << endl; -#endif - - if (w == 0) { - SVDEBUG << "*** NOTE: w == 0" << endl; - } - -#ifdef DEBUG_SPECTROGRAM_REPAINT - int pixels = 0; -#endif Profiler outerprof("SpectrogramLayer::paint: all cols"); @@ -2188,28 +1866,34 @@ // such boundaries at either side of the draw buffer -- one which // we draw up to, and one which we subsequently crop at. - bool bufferBinResolution = false; - if (increment > zoomLevel) bufferBinResolution = true; + bool bufferIsBinResolution = false; + if (increment > zoomLevel) bufferIsBinResolution = true; sv_frame_t leftBoundaryFrame = -1, leftCropFrame = -1; sv_frame_t rightBoundaryFrame = -1, rightCropFrame = -1; int bufwid; - if (bufferBinResolution) { + if (bufferIsBinResolution) { for (int x = x0; ; --x) { sv_frame_t f = v->getFrameForX(x); if ((f / increment) * increment == f) { if (leftCropFrame == -1) leftCropFrame = f; - else if (x < x0 - 2) { leftBoundaryFrame = f; break; } + else if (x < x0 - 2) { + leftBoundaryFrame = f; + break; + } } } - for (int x = x0 + w; ; ++x) { + for (int x = x0 + repaintWidth; ; ++x) { sv_frame_t f = v->getFrameForX(x); if ((f / increment) * increment == f) { if (rightCropFrame == -1) rightCropFrame = f; - else if (x > x0 + w + 2) { rightBoundaryFrame = f; break; } + else if (x > x0 + repaintWidth + 2) { + rightBoundaryFrame = f; + break; + } } } #ifdef DEBUG_SPECTROGRAM_REPAINT @@ -2221,7 +1905,7 @@ } else { - bufwid = w; + bufwid = repaintWidth; } vector<int> binforx(bufwid); @@ -2229,10 +1913,9 @@ bool usePeaksCache = false; - if (bufferBinResolution) { + if (bufferIsBinResolution) { for (int x = 0; x < bufwid; ++x) { binforx[x] = int(leftBoundaryFrame / increment) + x; -// cerr << "binforx[" << x << "] = " << binforx[x] << endl; } m_drawBuffer = QImage(bufwid, h, QImage::Format_Indexed8); } else { @@ -2244,21 +1927,47 @@ binforx[x] = -1; //??? } } - if (m_drawBuffer.width() < bufwid || m_drawBuffer.height() < h) { + if (m_drawBuffer.width() < bufwid || m_drawBuffer.height() != h) { m_drawBuffer = QImage(bufwid, h, QImage::Format_Indexed8); } usePeaksCache = (increment * 8) < zoomLevel; if (m_colourScale == PhaseColourScale) usePeaksCache = false; } -// No longer exists in Qt5: m_drawBuffer.setNumColors(256); for (int pixel = 0; pixel < 256; ++pixel) { m_drawBuffer.setColor((unsigned char)pixel, m_palette.getColour((unsigned char)pixel).rgb()); } m_drawBuffer.fill(0); - + int attainedBufwid = bufwid; + + double softTimeLimit; + + if (m_synchronous) { + + // must paint the whole thing for synchronous mode, so give + // "no timeout" + softTimeLimit = 0.0; + + } else if (bufferIsBinResolution) { + + // calculating boundaries later will be too fiddly for partial + // paints, and painting should be fast anyway when this is the + // case because it means we're well zoomed in + softTimeLimit = 0.0; + + } else { + + // neither limitation applies, so use a short soft limit + + if (m_binDisplay == PeakFrequencies) { + softTimeLimit = 0.15; + } else { + softTimeLimit = 0.1; + } + } + if (m_binDisplay != PeakFrequencies) { for (int y = 0; y < h; ++y) { @@ -2267,53 +1976,60 @@ binfory[y] = -1; } else { binfory[y] = q0; -// cerr << "binfory[" << y << "] = " << binfory[y] << endl; } } - paintDrawBuffer(v, bufwid, h, binforx, binfory, usePeaksCache, - overallMag, overallMagChanged); + attainedBufwid = + paintDrawBuffer(v, bufwid, h, binforx, binfory, + usePeaksCache, + overallMag, overallMagChanged, + rightToLeft, + softTimeLimit); } else { - paintDrawBufferPeakFrequencies(v, bufwid, h, binforx, - minbin, maxbin, - displayMinFreq, displayMaxFreq, - logarithmic, - overallMag, overallMagChanged); + attainedBufwid = + paintDrawBufferPeakFrequencies(v, bufwid, h, binforx, + minbin, maxbin, + displayMinFreq, displayMaxFreq, + logarithmic, + overallMag, overallMagChanged, + rightToLeft, + softTimeLimit); } -/* - for (int x = 0; x < w / xPixelRatio; ++x) { - - Profiler innerprof("SpectrogramLayer::paint: 1 pixel column"); - - runOutOfData = !paintColumnValues(v, fft, x0, x, - minbin, maxbin, - displayMinFreq, displayMaxFreq, - xPixelRatio, - h, yforbin); - - if (runOutOfData) { + int failedToRepaint = bufwid - attainedBufwid; + + int paintedLeft = x0; + int paintedWidth = x1 - x0; + + if (failedToRepaint > 0) { + #ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Run out of data -- dropping out of loop" << endl; + cerr << "SpectrogramLayer::paint(): Failed to repaint " << failedToRepaint << " of " << bufwid + << " columns in time (so managed to repaint " << bufwid - failedToRepaint << ")" << endl; #endif - break; + + if (rightToLeft) { + paintedLeft += failedToRepaint; } + + paintedWidth -= failedToRepaint; + + if (paintedWidth < 0) { + paintedWidth = 0; + } + + } else if (failedToRepaint < 0) { + cerr << "WARNING: failedToRepaint < 0 (= " << failedToRepaint << ")" + << endl; + failedToRepaint = 0; } -*/ + + if (overallMagChanged) { + m_viewMags[v->getId()] = overallMag; #ifdef DEBUG_SPECTROGRAM_REPAINT -// cerr << pixels << " pixels drawn" << endl; -#endif - - if (overallMagChanged) { - m_viewMags[v] = overallMag; -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Overall mag is now [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "] - will be updating" << endl; -#endif - } else { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Overall mag unchanged at [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << endl; + cerr << "SpectrogramLayer: Overall mag is now [" << m_viewMags[v->getId()].getMin() << "->" << m_viewMags[v->getId()].getMax() << "] - will be updating" << endl; #endif } @@ -2321,129 +2037,153 @@ Profiler profiler2("SpectrogramLayer::paint: draw image"); - if (recreateWholeImageCache) { + if (paintedWidth > 0) { + #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "Recreating image cache: width = " << v->width() - << ", height = " << h << endl; -#endif - cache.image = QImage(v->width(), h, QImage::Format_ARGB32_Premultiplied); - } - - if (w > 0) { -#ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "Painting " << w << "x" << h - << " from draw buffer at " << 0 << "," << 0 - << " to " << w << "x" << h << " on cache at " + cerr << "SpectrogramLayer: Copying " << paintedWidth << "x" << h + << " from draw buffer at " << paintedLeft - x0 << "," << 0 + << " to " << paintedWidth << "x" << h << " on cache at " << x0 << "," << 0 << endl; #endif - QPainter cachePainter(&cache.image); - - if (bufferBinResolution) { + if (bufferIsBinResolution) { + int scaledLeft = v->getXForFrame(leftBoundaryFrame); int scaledRight = v->getXForFrame(rightBoundaryFrame); + #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "Rescaling image from " << bufwid + cerr << "SpectrogramLayer: Rescaling image from " << bufwid << "x" << h << " to " << scaledRight-scaledLeft << "x" << h << endl; #endif + Preferences::SpectrogramXSmoothing xsmoothing = Preferences::getInstance()->getSpectrogramXSmoothing(); -// SVDEBUG << "xsmoothing == " << xsmoothing << endl; + QImage scaled = m_drawBuffer.scaled (scaledRight - scaledLeft, h, Qt::IgnoreAspectRatio, ((xsmoothing == Preferences::SpectrogramXInterpolated) ? Qt::SmoothTransformation : Qt::FastTransformation)); + int scaledLeftCrop = v->getXForFrame(leftCropFrame); int scaledRightCrop = v->getXForFrame(rightCropFrame); + #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "Drawing image region of width " << scaledRightCrop - scaledLeftCrop << " to " + cerr << "SpectrogramLayer: Drawing image region of width " << scaledRightCrop - scaledLeftCrop << " to " << scaledLeftCrop << " from " << scaledLeftCrop - scaledLeft << endl; #endif - cachePainter.drawImage - (QRect(scaledLeftCrop, 0, - scaledRightCrop - scaledLeftCrop, h), - scaled, - QRect(scaledLeftCrop - scaledLeft, 0, - scaledRightCrop - scaledLeftCrop, h)); + + int targetLeft = scaledLeftCrop; + if (targetLeft < 0) { + targetLeft = 0; + } + + int targetWidth = scaledRightCrop - targetLeft; + if (targetLeft + targetWidth > cache.getSize().width()) { + targetWidth = cache.getSize().width() - targetLeft; + } + + int sourceLeft = targetLeft - scaledLeft; + if (sourceLeft < 0) { + sourceLeft = 0; + } + + int sourceWidth = targetWidth; + + if (targetWidth > 0) { + cache.drawImage + (targetLeft, + targetWidth, + scaled, + sourceLeft, + sourceWidth); + } + } else { - cachePainter.drawImage(QRect(x0, 0, w, h), - m_drawBuffer, - QRect(0, 0, w, h)); + + cache.drawImage(paintedLeft, paintedWidth, + m_drawBuffer, + paintedLeft - x0, paintedWidth); } - - cachePainter.end(); } - QRect pr = rect & cache.validArea; - #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "Painting " << pr.width() << "x" << pr.height() + cerr << "SpectrogramLayer: Cache valid area now from " << cache.getValidLeft() + << " width " << cache.getValidWidth() << ", height " + << cache.getSize().height() << endl; +#endif + + QRect pr = rect & cache.getValidArea(); + +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer: Copying " << pr.width() << "x" << pr.height() << " from cache at " << pr.x() << "," << pr.y() << " to window" << endl; #endif - paint.drawImage(pr.x(), pr.y(), cache.image, + paint.drawImage(pr.x(), pr.y(), cache.getImage(), pr.x(), pr.y(), pr.width(), pr.height()); - //!!! -// paint.drawImage(v->rect(), cache.image, -// QRect(QPoint(0, 0), cache.image.size())); - - cache.startFrame = startFrame; - cache.zoomLevel = zoomLevel; if (!m_synchronous) { - if (!m_normalizeVisibleArea || !overallMagChanged) { - - if (cache.validArea.x() > 0) { -#ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::paint() updating left (0, " - << cache.validArea.x() << ")" << endl; -#endif - v->update(0, 0, cache.validArea.x(), h); + if ((m_normalization != NormalizeVisibleArea) || !overallMagChanged) { + + QRect areaLeft(0, 0, cache.getValidLeft(), h); + QRect areaRight(cache.getValidRight(), 0, + cache.getSize().width() - cache.getValidRight(), h); + + bool haveSpaceLeft = (areaLeft.width() > 0); + bool haveSpaceRight = (areaRight.width() > 0); + + bool updateLeft = haveSpaceLeft; + bool updateRight = haveSpaceRight; + + if (updateLeft && updateRight) { + if (rightToLeft) { + // we just did something adjoining the cache on + // its left side, so now do something on its right + updateLeft = false; + } else { + updateRight = false; + } } - if (cache.validArea.x() + cache.validArea.width() < - cache.image.width()) { + if (updateLeft) { #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::paint() updating right (" - << cache.validArea.x() + cache.validArea.width() - << ", " - << cache.image.width() - (cache.validArea.x() + - cache.validArea.width()) - << ")" << endl; + cerr << "SpectrogramLayer::paint() updating left (" + << areaLeft.x() << ", " + << areaLeft.width() << ")" << endl; #endif - v->update(cache.validArea.x() + cache.validArea.width(), - 0, - cache.image.width() - (cache.validArea.x() + - cache.validArea.width()), - h); + v->updatePaintRect(areaLeft); } + + if (updateRight) { +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer::paint() updating right (" + << areaRight.x() << ", " + << areaRight.width() << ")" << endl; +#endif + v->updatePaintRect(areaRight); + } + } else { // overallMagChanged cerr << "\noverallMagChanged - updating all\n" << endl; - cache.validArea = QRect(); - v->update(); + cache.invalidate(); + v->updatePaintRect(v->getPaintRect()); } } illuminateLocalFeatures(v, paint); #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::paint() returning" << endl; + cerr << "SpectrogramLayer::paint() returning" << endl; #endif - - if (!m_synchronous) { - m_lastPaintBlockWidth = paintBlockWidth; - (void)gettimeofday(&tv, 0); - m_lastPaintTime = RealTime::fromTimeval(tv) - mainPaintStart; - } } -bool -SpectrogramLayer::paintDrawBufferPeakFrequencies(View *v, +int +SpectrogramLayer::paintDrawBufferPeakFrequencies(LayerGeometryProvider *v, int w, int h, const vector<int> &binforx, @@ -2453,18 +2193,20 @@ double displayMaxFreq, bool logarithmic, MagnitudeRange &overallMag, - bool &overallMagChanged) const + bool &overallMagChanged, + bool rightToLeft, + double softTimeLimit) const { Profiler profiler("SpectrogramLayer::paintDrawBufferPeakFrequencies"); #ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; + cerr << "SpectrogramLayer::paintDrawBufferPeakFrequencies: minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; #endif if (minbin < 0) minbin = 0; if (maxbin < 0) maxbin = minbin+1; FFTModel *fft = getFFTModel(v); - if (!fft) return false; + if (!fft) return 0; FFTModel::PeakSet peakfreqs; @@ -2476,7 +2218,27 @@ float *values = (float *)alloca((maxbin - minbin + 1) * sizeof(float)); #endif - for (int x = 0; x < w; ++x) { + int minColumns = 4; + bool haveTimeLimits = (softTimeLimit > 0.0); + double hardTimeLimit = softTimeLimit * 2.0; + bool overridingSoftLimit = false; + auto startTime = chrono::steady_clock::now(); + + int start = 0; + int finish = w; + int step = 1; + + if (rightToLeft) { + start = w-1; + finish = -1; + step = -1; + } + + int columnCount = 0; + + for (int x = start; x != finish; x += step) { + + ++columnCount; if (binforx[x] < 0) continue; @@ -2491,15 +2253,6 @@ if (sx < 0 || sx >= int(fft->getWidth())) continue; - if (!m_synchronous) { - if (!fft->isColumnAvailable(sx)) { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Met unavailable column at col " << sx << endl; -#endif - return false; - } - } - MagnitudeRange mag; if (sx != psx) { @@ -2507,14 +2260,14 @@ minbin, maxbin - 1); if (m_colourScale == PhaseColourScale) { fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); - } else if (m_normalizeColumns) { + } else if (m_normalization == NormalizeColumns) { fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); - } else if (m_normalizeHybrid) { - fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); - double max = fft->getMaximumMagnitudeAt(sx); + } else if (m_normalization == NormalizeHybrid) { + float max = fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); if (max > 0.f) { for (int i = minbin; i <= maxbin; ++i) { - values[i - minbin] = float(values[i - minbin] * log10(max)); + values[i - minbin] = float(values[i - minbin] * + log10f(max)); } } } else { @@ -2535,7 +2288,7 @@ double value = values[bin - minbin]; if (m_colourScale != PhaseColourScale) { - if (!m_normalizeColumns && !m_normalizeHybrid) { + if (m_normalization != NormalizeColumns) { value /= (m_fftSize/2.0); } mag.sample(float(value)); @@ -2565,20 +2318,50 @@ } } } + + if (haveTimeLimits) { + if (columnCount >= minColumns) { + auto t = chrono::steady_clock::now(); + double diff = chrono::duration<double>(t - startTime).count(); + if (diff > hardTimeLimit) { +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer::paintDrawBufferPeakFrequencies: hard limit " << hardTimeLimit << " sec exceeded after " + << columnCount << " columns with time " << diff << endl; +#endif + return columnCount; + } else if (diff > softTimeLimit && !overridingSoftLimit) { + // If we're more than half way through by the time + // we reach the soft limit, ignore it (though + // still respect the hard limit, above). Otherwise + // respect the soft limit and return now. + if (columnCount > w/2) { + overridingSoftLimit = true; + } else { +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer::paintDrawBufferPeakFrequencies: soft limit " << softTimeLimit << " sec exceeded after " + << columnCount << " columns with time " << diff << endl; +#endif + return columnCount; + } + } + } + } } - return true; + return columnCount; } -bool -SpectrogramLayer::paintDrawBuffer(View *v, +int +SpectrogramLayer::paintDrawBuffer(LayerGeometryProvider *v, int w, int h, const vector<int> &binforx, const vector<double> &binfory, bool usePeaksCache, MagnitudeRange &overallMag, - bool &overallMagChanged) const + bool &overallMagChanged, + bool rightToLeft, + double softTimeLimit) const { Profiler profiler("SpectrogramLayer::paintDrawBuffer"); @@ -2586,7 +2369,7 @@ int maxbin = int(binfory[h-1]); #ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; + cerr << "SpectrogramLayer::paintDrawBuffer: minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; #endif if (minbin < 0) minbin = 0; if (maxbin < 0) maxbin = minbin+1; @@ -2595,7 +2378,7 @@ FFTModel *fft = 0; int divisor = 1; #ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Note: bin display = " << m_binDisplay << ", w = " << w << ", binforx[" << w-1 << "] = " << binforx[w-1] << ", binforx[0] = " << binforx[0] << endl; + cerr << "SpectrogramLayer::paintDrawBuffer: Note: bin display = " << m_binDisplay << ", w = " << w << ", binforx[" << w-1 << "] = " << binforx[w-1] << ", binforx[0] = " << binforx[0] << endl; #endif if (usePeaksCache) { //!!! sourceModel = getPeakCache(v); @@ -2606,7 +2389,7 @@ sourceModel = fft = getFFTModel(v); } - if (!sourceModel) return false; + if (!sourceModel) return 0; bool interpolate = false; Preferences::SpectrogramSmoothing smoothing = @@ -2632,7 +2415,27 @@ const float *values = autoarray; DenseThreeDimensionalModel::Column c; - for (int x = 0; x < w; ++x) { + int minColumns = 4; + bool haveTimeLimits = (softTimeLimit > 0.0); + double hardTimeLimit = softTimeLimit * 2.0; + bool overridingSoftLimit = false; + auto startTime = chrono::steady_clock::now(); + + int start = 0; + int finish = w; + int step = 1; + + if (rightToLeft) { + start = w-1; + finish = -1; + step = -1; + } + + int columnCount = 0; + + for (int x = start; x != finish; x += step) { + + ++columnCount; if (binforx[x] < 0) continue; @@ -2656,48 +2459,39 @@ if (sx < 0 || sx >= int(sourceModel->getWidth())) continue; - if (!m_synchronous) { - if (!sourceModel->isColumnAvailable(sx)) { -#ifdef DEBUG_SPECTROGRAM_REPAINT - cerr << "Met unavailable column at col " << sx << endl; -#endif - return false; - } - } - MagnitudeRange mag; if (sx != psx) { if (fft) { #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "Retrieving column " << sx << " from fft directly" << endl; +// cerr << "Retrieving column " << sx << " from fft directly" << endl; #endif if (m_colourScale == PhaseColourScale) { fft->getPhasesAt(sx, autoarray, minbin, maxbin - minbin + 1); - } else if (m_normalizeColumns) { + } else if (m_normalization == NormalizeColumns) { fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); - } else if (m_normalizeHybrid) { - fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); - double max = fft->getMaximumMagnitudeAt(sx); + } else if (m_normalization == NormalizeHybrid) { + float max = fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); + float scale = log10f(max + 1.f); +// cout << "sx = " << sx << ", max = " << max << ", log10(max) = " << log10(max) << ", scale = " << scale << endl; for (int i = minbin; i <= maxbin; ++i) { - if (max > 0.0) { - autoarray[i - minbin] = float(autoarray[i - minbin] * log10(max)); - } + autoarray[i - minbin] *= scale; } } else { fft->getMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); } } else { #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "Retrieving column " << sx << " from peaks cache" << endl; +// cerr << "Retrieving column " << sx << " from peaks cache" << endl; #endif c = sourceModel->getColumn(sx); - if (m_normalizeColumns || m_normalizeHybrid) { + if (m_normalization == NormalizeColumns || + m_normalization == NormalizeHybrid) { for (int y = 0; y < h; ++y) { if (c[y] > columnMax) columnMax = c[y]; } } - values = c.constData() + minbin; + values = c.data() + minbin; } psx = sx; } @@ -2735,7 +2529,8 @@ value = prop * v0 + (1.0 - prop) * v1; if (m_colourScale != PhaseColourScale) { - if (!m_normalizeColumns) { + if (m_normalization != NormalizeColumns && + m_normalization != NormalizeHybrid) { value /= (m_fftSize/2.0); } mag.sample(float(value)); @@ -2760,7 +2555,8 @@ } if (m_colourScale != PhaseColourScale) { - if (!m_normalizeColumns) { + if (m_normalization != NormalizeColumns && + m_normalization != NormalizeHybrid) { value /= (m_fftSize/2.0); } mag.sample(float(value)); @@ -2794,11 +2590,12 @@ double peak = peaks[y]; if (m_colourScale != PhaseColourScale && - (m_normalizeColumns || m_normalizeHybrid) && + (m_normalization == NormalizeColumns || + m_normalization == NormalizeHybrid) && columnMax > 0.f) { peak /= columnMax; - if (m_normalizeHybrid) { - peak *= log10(columnMax); + if (m_normalization == NormalizeHybrid) { + peak *= log10(columnMax + 1.f); } } @@ -2806,13 +2603,41 @@ m_drawBuffer.setPixel(x, h-y-1, peakpix); } + + if (haveTimeLimits) { + if (columnCount >= minColumns) { + auto t = chrono::steady_clock::now(); + double diff = chrono::duration<double>(t - startTime).count(); + if (diff > hardTimeLimit) { +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer::paintDrawBuffer: hard limit " << hardTimeLimit << " sec exceeded after " + << columnCount << " columns with time " << diff << endl; +#endif + return columnCount; + } else if (diff > softTimeLimit && !overridingSoftLimit) { + // If we're more than half way through by the time + // we reach the soft limit, ignore it (though + // still respect the hard limit, above). Otherwise + // respect the soft limit and return now. + if (columnCount > w/2) { + overridingSoftLimit = true; + } else { +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "SpectrogramLayer::paintDrawBuffer: soft limit " << softTimeLimit << " sec exceeded after " + << columnCount << " columns with time " << diff << endl; +#endif + return columnCount; + } + } + } + } } - return true; + return columnCount; } void -SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const +SpectrogramLayer::illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &paint) const { Profiler profiler("SpectrogramLayer::illuminateLocalFeatures"); @@ -2851,7 +2676,7 @@ } double -SpectrogramLayer::getYForFrequency(const View *v, double frequency) const +SpectrogramLayer::getYForFrequency(const LayerGeometryProvider *v, double frequency) const { return v->getYForFrequency(frequency, getEffectiveMinFrequency(), @@ -2860,7 +2685,7 @@ } double -SpectrogramLayer::getFrequencyForY(const View *v, int y) const +SpectrogramLayer::getFrequencyForY(const LayerGeometryProvider *v, int y) const { return v->getFrequencyForY(y, getEffectiveMinFrequency(), @@ -2869,23 +2694,25 @@ } int -SpectrogramLayer::getCompletion(View *v) const +SpectrogramLayer::getCompletion(LayerGeometryProvider *v) const { - if (m_updateTimer == 0) return 100; - if (m_fftModels.find(v) == m_fftModels.end()) return 100; - - int completion = m_fftModels[v].first->getCompletion(); + const View *view = v->getView(); + + if (m_fftModels.find(view->getId()) == m_fftModels.end()) return 100; + + int completion = m_fftModels[view->getId()]->getCompletion(); #ifdef DEBUG_SPECTROGRAM_REPAINT - SVDEBUG << "SpectrogramLayer::getCompletion: completion = " << completion << endl; + cerr << "SpectrogramLayer::getCompletion: completion = " << completion << endl; #endif return completion; } QString -SpectrogramLayer::getError(View *v) const +SpectrogramLayer::getError(LayerGeometryProvider *v) const { - if (m_fftModels.find(v) == m_fftModels.end()) return ""; - return m_fftModels[v].first->getError(); + const View *view = v->getView(); + if (m_fftModels.find(view->getId()) == m_fftModels.end()) return ""; + return m_fftModels[view->getId()]->getError(); } bool @@ -2946,7 +2773,7 @@ } bool -SpectrogramLayer::getYScaleValue(const View *v, int y, +SpectrogramLayer::getYScaleValue(const LayerGeometryProvider *v, int y, double &value, QString &unit) const { value = getFrequencyForY(v, y); @@ -2955,7 +2782,7 @@ } bool -SpectrogramLayer::snapToFeatureFrame(View *, +SpectrogramLayer::snapToFeatureFrame(LayerGeometryProvider *, sv_frame_t &frame, int &resolution, SnapType snap) const @@ -2978,14 +2805,15 @@ } void -SpectrogramLayer::measureDoubleClick(View *v, QMouseEvent *e) +SpectrogramLayer::measureDoubleClick(LayerGeometryProvider *v, QMouseEvent *e) { - ImageCache &cache = m_imageCaches[v]; - - cerr << "cache width: " << cache.image.width() << ", height: " - << cache.image.height() << endl; - - QImage image = cache.image; + const View *view = v->getView(); + ScrollableImageCache &cache = getImageCacheReference(view); + + cerr << "cache width: " << cache.getSize().width() << ", height: " + << cache.getSize().height() << endl; + + QImage image = cache.getImage(); ImageRegionFinder finder; QRect rect = finder.findRegionExtents(&image, e->pos()); @@ -2998,11 +2826,11 @@ } bool -SpectrogramLayer::getCrosshairExtents(View *v, QPainter &paint, +SpectrogramLayer::getCrosshairExtents(LayerGeometryProvider *v, QPainter &paint, QPoint cursorPos, - std::vector<QRect> &extents) const + vector<QRect> &extents) const { - QRect vertical(cursorPos.x() - 12, 0, 12, v->height()); + QRect vertical(cursorPos.x() - 12, 0, 12, v->getPaintHeight()); extents.push_back(vertical); QRect horizontal(0, cursorPos.y(), cursorPos.x(), 1); @@ -3021,14 +2849,14 @@ extents.push_back(pitch); QRect rt(cursorPos.x(), - v->height() - paint.fontMetrics().height() - 2, + v->getPaintHeight() - paint.fontMetrics().height() - 2, paint.fontMetrics().width("1234.567 s"), paint.fontMetrics().height()); extents.push_back(rt); int w(paint.fontMetrics().width("1234567890") + 2); QRect frame(cursorPos.x() - w - 2, - v->height() - paint.fontMetrics().height() - 2, + v->getPaintHeight() - paint.fontMetrics().height() - 2, w, paint.fontMetrics().height()); extents.push_back(frame); @@ -3037,7 +2865,7 @@ } void -SpectrogramLayer::paintCrosshairs(View *v, QPainter &paint, +SpectrogramLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint, QPoint cursorPos) const { paint.save(); @@ -3052,7 +2880,7 @@ paint.setPen(m_crosshairColour); paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y()); - paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->height()); + paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->getPaintHeight()); double fundamental = getFrequencyForY(v, cursorPos.y()); @@ -3077,12 +2905,12 @@ QString frameLabel = QString("%1").arg(frame); v->drawVisibleText(paint, cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2, - v->height() - 2, + v->getPaintHeight() - 2, frameLabel, View::OutlinedText); v->drawVisibleText(paint, cursorPos.x() + 2, - v->height() - 2, + v->getPaintHeight() - 2, rtLabel, View::OutlinedText); @@ -3091,7 +2919,7 @@ while (harmonic < 100) { int hy = int(lrint(getYForFrequency(v, fundamental * harmonic))); - if (hy < 0 || hy > v->height()) break; + if (hy < 0 || hy > v->getPaintHeight()) break; int len = 7; @@ -3115,7 +2943,7 @@ } QString -SpectrogramLayer::getFeatureDescription(View *v, QPoint &pos) const +SpectrogramLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { int x = pos.x(); int y = pos.y(); @@ -3237,7 +3065,7 @@ } int -SpectrogramLayer::getVerticalScaleWidth(View *, bool detailed, QPainter &paint) const +SpectrogramLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool detailed, QPainter &paint) const { if (!m_model || !m_model->isOK()) return 0; @@ -3258,7 +3086,7 @@ } void -SpectrogramLayer::paintVerticalScale(View *v, bool detailed, QPainter &paint, QRect rect) const +SpectrogramLayer::paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const { if (!m_model || !m_model->isOK()) { return; @@ -3300,12 +3128,18 @@ paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1); QString top, bottom; - double min = m_viewMags[v].getMin(); - double max = m_viewMags[v].getMax(); + double min = m_viewMags[v->getId()].getMin(); + double max = m_viewMags[v->getId()].getMax(); double dBmin = AudioLevel::multiplier_to_dB(min); double dBmax = AudioLevel::multiplier_to_dB(max); +#ifdef DEBUG_SPECTROGRAM_REPAINT + cerr << "paintVerticalScale: for view id " << v->getId() + << ": min = " << min << ", max = " << max + << ", dBmin = " << dBmin << ", dBmax = " << dBmax << endl; +#endif + if (dBmax < -60.f) dBmax = -60.f; else top = QString("%1").arg(lrint(dBmax)); @@ -3372,10 +3206,10 @@ int bin = -1; - for (int y = 0; y < v->height(); ++y) { + for (int y = 0; y < v->getPaintHeight(); ++y) { double q0, q1; - if (!getYBinRange(v, v->height() - y, q0, q1)) continue; + if (!getYBinRange(v, v->getPaintHeight() - y, q0, q1)) continue; int vy; @@ -3400,7 +3234,7 @@ paint.drawLine(cw + 7, h - vy, w - pkw - 1, h - vy); if (h - vy - textHeight >= -2) { - int tx = w - 3 - paint.fontMetrics().width(text) - std::max(tickw, pkw); + int tx = w - 3 - paint.fontMetrics().width(text) - max(tickw, pkw); paint.drawText(tx, h - vy + toff, text); } @@ -3589,7 +3423,7 @@ } void -SpectrogramLayer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const +SpectrogramLayer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const { int y0 = 0; if (r.startY > 0.0) y0 = int(getYForFrequency(v, r.startY)); @@ -3603,7 +3437,7 @@ } void -SpectrogramLayer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const +SpectrogramLayer::setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const { if (start) { r.startY = getFrequencyForY(v, y); @@ -3647,13 +3481,29 @@ .arg(m_frequencyScale) .arg(m_binDisplay); - s += QString("normalizeColumns=\"%1\" " - "normalizeVisibleArea=\"%2\" " - "normalizeHybrid=\"%3\" ") - .arg(m_normalizeColumns ? "true" : "false") - .arg(m_normalizeVisibleArea ? "true" : "false") - .arg(m_normalizeHybrid ? "true" : "false"); - + // New-style normalization attributes, allowing for more types of + // normalization in future: write out the column normalization + // type separately, and then whether we are normalizing visible + // area as well afterwards + + s += QString("columnNormalization=\"%1\" ") + .arg(m_normalization == NormalizeColumns ? "peak" : + m_normalization == NormalizeHybrid ? "hybrid" : "none"); + + // Old-style normalization attribute. We *don't* write out + // normalizeHybrid here because the only release that would accept + // it (Tony v1.0) has a totally different scale factor for + // it. We'll just have to accept that session files from Tony + // v2.0+ will look odd in Tony v1.0 + + s += QString("normalizeColumns=\"%1\" ") + .arg(m_normalization == NormalizeColumns ? "true" : "false"); + + // And this applies to both old- and new-style attributes + + s += QString("normalizeVisibleArea=\"%1\" ") + .arg(m_normalization == NormalizeVisibleArea ? "true" : "false"); + Layer::toXml(stream, indent, extraAttributes + " " + s); } @@ -3718,16 +3568,54 @@ attributes.value("binDisplay").toInt(&ok); if (ok) setBinDisplay(binDisplay); - bool normalizeColumns = - (attributes.value("normalizeColumns").trimmed() == "true"); - setNormalizeColumns(normalizeColumns); + bool haveNewStyleNormalization = false; + + QString columnNormalization = attributes.value("columnNormalization"); + + if (columnNormalization != "") { + + haveNewStyleNormalization = true; + + if (columnNormalization == "peak") { + setNormalization(NormalizeColumns); + } else if (columnNormalization == "hybrid") { + setNormalization(NormalizeHybrid); + } else if (columnNormalization == "none") { + // do nothing + } else { + cerr << "NOTE: Unknown or unsupported columnNormalization attribute \"" + << columnNormalization << "\"" << endl; + } + } + + if (!haveNewStyleNormalization) { + + bool normalizeColumns = + (attributes.value("normalizeColumns").trimmed() == "true"); + if (normalizeColumns) { + setNormalization(NormalizeColumns); + } + + bool normalizeHybrid = + (attributes.value("normalizeHybrid").trimmed() == "true"); + if (normalizeHybrid) { + setNormalization(NormalizeHybrid); + } + } bool normalizeVisibleArea = (attributes.value("normalizeVisibleArea").trimmed() == "true"); - setNormalizeVisibleArea(normalizeVisibleArea); - - bool normalizeHybrid = - (attributes.value("normalizeHybrid").trimmed() == "true"); - setNormalizeHybrid(normalizeHybrid); + if (normalizeVisibleArea) { + setNormalization(NormalizeVisibleArea); + } + + if (!haveNewStyleNormalization && m_normalization == NormalizeHybrid) { + // Tony v1.0 is (and hopefully will remain!) the only released + // SV-a-like to use old-style attributes when saving sessions + // that ask for hybrid normalization. It saves them with the + // wrong gain factor, so hack in a fix for that here -- this + // gives us backward but not forward compatibility. + setGain(m_gain / float(m_fftSize / 2)); + } }
--- a/layer/SpectrogramLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/SpectrogramLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -13,8 +13,8 @@ COPYING included with this distribution for more information. */ -#ifndef _SPECTROGRAM_LAYER_H_ -#define _SPECTROGRAM_LAYER_H_ +#ifndef SPECTROGRAM_LAYER_H +#define SPECTROGRAM_LAYER_H #include "SliceableLayer.h" #include "base/Window.h" @@ -25,6 +25,8 @@ #include "data/model/DenseTimeValueModel.h" #include "data/model/FFTModel.h" +#include "ScrollableImageCache.h" + #include <QMutex> #include <QWaitCondition> #include <QImage> @@ -57,23 +59,23 @@ virtual const ZoomConstraint *getZoomConstraint() const { return this; } virtual const Model *getModel() const { return m_model; } - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; virtual void setSynchronousPainting(bool synchronous); - virtual int getVerticalScaleWidth(View *v, bool detailed, QPainter &) const; - virtual void paintVerticalScale(View *v, bool detailed, QPainter &paint, QRect rect) const; + virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool detailed, QPainter &) const; + virtual void paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const; - virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos, + virtual bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint cursorPos, std::vector<QRect> &extents) const; - virtual void paintCrosshairs(View *, QPainter &, QPoint) const; + virtual void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; - virtual bool snapToFeatureFrame(View *v, sv_frame_t &frame, + virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual void measureDoubleClick(View *, QMouseEvent *); + virtual void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *); virtual bool hasLightBackground() const; @@ -88,6 +90,8 @@ int *min, int *max, int *deflt) const; virtual QString getPropertyValueLabel(const PropertyName &, int value) const; + virtual QString getPropertyValueIconName(const PropertyName &, + int value) const; virtual RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const; virtual void setProperty(const PropertyName &, int value); @@ -170,27 +174,24 @@ */ void setBinDisplay(BinDisplay); BinDisplay getBinDisplay() const; - - /** - * Normalize each column to its maximum value, independent of its - * neighbours. - */ - void setNormalizeColumns(bool n); - bool getNormalizeColumns() const; + + enum Normalization { + NoNormalization, + NormalizeColumns, + NormalizeVisibleArea, + NormalizeHybrid + }; /** - * Normalize each value against the maximum in the visible region. + * Specify the normalization mode for bin values. */ - void setNormalizeVisibleArea(bool n); - bool getNormalizeVisibleArea() const; + void setNormalization(Normalization); + Normalization getNormalization() const; /** - * Normalize each column to its maximum value, and then scale by - * the log of the (absolute) maximum value. + * Specify the colour map. See ColourMapper for the colour map + * values. */ - void setNormalizeHybrid(bool n); - bool getNormalizeHybrid() const; - void setColourMap(int map); int getColourMap() const; @@ -210,11 +211,11 @@ return ColourHasMeaningfulValue; } - double getYForFrequency(const View *v, double frequency) const; - double getFrequencyForY(const View *v, int y) const; + double getYForFrequency(const LayerGeometryProvider *v, double frequency) const; + double getFrequencyForY(const LayerGeometryProvider *v, int y) const; - virtual int getCompletion(View *v) const; - virtual QString getError(View *v) const; + virtual int getCompletion(LayerGeometryProvider *v) const; + virtual QString getError(LayerGeometryProvider *v) const; virtual bool getValueExtents(double &min, double &max, bool &logarithmic, QString &unit) const; @@ -223,16 +224,16 @@ virtual bool setDisplayExtents(double min, double max); - virtual bool getYScaleValue(const View *, int, double &, QString &) const; + virtual bool getYScaleValue(const LayerGeometryProvider *, int, double &, QString &) const; virtual void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const; void setProperties(const QXmlAttributes &attributes); - virtual void setLayerDormant(const View *v, bool dormant); + virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant); - virtual bool isLayerScrollable(const View *) const { return false; } + virtual bool isLayerScrollable(const LayerGeometryProvider *) const { return false; } virtual int getVerticalZoomSteps(int &defaultStep) const; virtual int getCurrentVerticalZoomStep() const; @@ -247,40 +248,34 @@ void preferenceChanged(PropertyContainer::PropertyName name); - void fillTimerTimedOut(); - protected: const DenseTimeValueModel *m_model; // I do not own this int m_channel; - int m_windowSize; + int m_windowSize; WindowType m_windowType; - int m_windowHopLevel; - int m_zeroPadLevel; - int m_fftSize; + int m_windowHopLevel; + int m_zeroPadLevel; + int m_fftSize; float m_gain; float m_initialGain; float m_threshold; float m_initialThreshold; int m_colourRotation; int m_initialRotation; - int m_minFrequency; - int m_maxFrequency; - int m_initialMaxFrequency; + int m_minFrequency; + int m_maxFrequency; + int m_initialMaxFrequency; ColourScale m_colourScale; int m_colourMap; QColor m_crosshairColour; FrequencyScale m_frequencyScale; BinDisplay m_binDisplay; - bool m_normalizeColumns; - bool m_normalizeVisibleArea; - bool m_normalizeHybrid; + Normalization m_normalization; int m_lastEmittedZoomStep; bool m_synchronous; mutable bool m_haveDetailedScale; - mutable int m_lastPaintBlockWidth; - mutable RealTime m_lastPaintTime; enum { NO_VALUE = 0 }; // colour index for unused pixels @@ -301,22 +296,10 @@ Palette m_palette; - /** - * ImageCache covers the area of the view, at view resolution. - * Not all of it is necessarily valid at once (it is refreshed - * in parts when scrolling, for example). - */ - struct ImageCache - { - QImage image; - QRect validArea; - sv_frame_t startFrame; - int zoomLevel; - }; - typedef std::map<const View *, ImageCache> ViewImageCache; + typedef std::map<int, ScrollableImageCache> ViewImageCache; // key is view id void invalidateImageCaches(); - void invalidateImageCaches(sv_frame_t startFrame, sv_frame_t endFrame); mutable ViewImageCache m_imageCaches; + ScrollableImageCache &getImageCacheReference(const LayerGeometryProvider *) const; /** * When painting, we draw directly onto the draw buffer and then @@ -326,19 +309,16 @@ */ mutable QImage m_drawBuffer; - mutable QTimer *m_updateTimer; - - mutable sv_frame_t m_candidateFillStartFrame; bool m_exiting; void initialisePalette(); void rotatePalette(int distance); - unsigned char getDisplayValue(View *v, double input) const; + unsigned char getDisplayValue(LayerGeometryProvider *v, double input) const; int getColourScaleWidth(QPainter &) const; - void illuminateLocalFeatures(View *v, QPainter &painter) const; + void illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &painter) const; double getEffectiveMinFrequency() const; double getEffectiveMaxFrequency() const; @@ -349,16 +329,16 @@ // position, if the spectrogram has oversampling smoothing. Use // getSmoothedYBinRange to obtain that. - bool getXBinRange(View *v, int x, double &windowMin, double &windowMax) const; - bool getYBinRange(View *v, int y, double &freqBinMin, double &freqBinMax) const; - bool getSmoothedYBinRange(View *v, int y, double &freqBinMin, double &freqBinMax) const; + bool getXBinRange(LayerGeometryProvider *v, int x, double &windowMin, double &windowMax) const; + bool getYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const; + bool getSmoothedYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const; - bool getYBinSourceRange(View *v, int y, double &freqMin, double &freqMax) const; - bool getAdjustedYBinSourceRange(View *v, int x, int y, + bool getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) const; + bool getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &freqMin, double &freqMax, double &adjFreqMin, double &adjFreqMax) const; - bool getXBinSourceRange(View *v, int x, RealTime &timeMin, RealTime &timeMax) const; - bool getXYBinSourceRange(View *v, int x, int y, double &min, double &max, + bool getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &timeMin, RealTime &timeMax) const; + bool getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &min, double &max, double &phaseMin, double &phaseMax) const; int getWindowIncrement() const { @@ -367,15 +347,14 @@ else return m_windowSize / (1 << (m_windowHopLevel - 1)); } - int getZeroPadLevel(const View *v) const; - int getFFTSize(const View *v) const; - FFTModel *getFFTModel(const View *v) const; - Dense3DModelPeakCache *getPeakCache(const View *v) const; + int getZeroPadLevel(const LayerGeometryProvider *v) const; + int getFFTSize(const LayerGeometryProvider *v) const; + FFTModel *getFFTModel(const LayerGeometryProvider *v) const; + Dense3DModelPeakCache *getPeakCache(const LayerGeometryProvider *v) const; void invalidateFFTModels(); - typedef std::pair<FFTModel *, sv_frame_t> FFTFillPair; // model, last fill - typedef std::map<const View *, FFTFillPair> ViewFFTMap; - typedef std::map<const View *, Dense3DModelPeakCache *> PeakCacheMap; + typedef std::map<int, FFTModel *> ViewFFTMap; // key is view id + typedef std::map<int, Dense3DModelPeakCache *> PeakCacheMap; // key is view id mutable ViewFFTMap m_fftModels; mutable PeakCacheMap m_peakCaches; mutable Model *m_sliceableModel; @@ -422,29 +401,33 @@ float m_max; }; - typedef std::map<const View *, MagnitudeRange> ViewMagMap; + typedef std::map<int, MagnitudeRange> ViewMagMap; // key is view id mutable ViewMagMap m_viewMags; mutable std::vector<MagnitudeRange> m_columnMags; void invalidateMagnitudes(); - bool updateViewMagnitudes(View *v) const; - bool paintDrawBuffer(View *v, int w, int h, - const std::vector<int> &binforx, - const std::vector<double> &binfory, - bool usePeaksCache, - MagnitudeRange &overallMag, - bool &overallMagChanged) const; - bool paintDrawBufferPeakFrequencies(View *v, int w, int h, - const std::vector<int> &binforx, - int minbin, - int maxbin, - double displayMinFreq, - double displayMaxFreq, - bool logarithmic, - MagnitudeRange &overallMag, - bool &overallMagChanged) const; + bool updateViewMagnitudes(LayerGeometryProvider *v) const; + int paintDrawBuffer(LayerGeometryProvider *v, int w, int h, + const std::vector<int> &binforx, + const std::vector<double> &binfory, + bool usePeaksCache, + MagnitudeRange &overallMag, + bool &overallMagChanged, + bool rightToLeft, + double softTimeLimit) const; + int paintDrawBufferPeakFrequencies(LayerGeometryProvider *v, int w, int h, + const std::vector<int> &binforx, + int minbin, + int maxbin, + double displayMinFreq, + double displayMaxFreq, + bool logarithmic, + MagnitudeRange &overallMag, + bool &overallMagChanged, + bool rightToLeft, + double softTimeLimit) const; - virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const; - virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const; + virtual void updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const; + virtual void setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const; }; #endif
--- a/layer/SpectrumLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/SpectrumLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -380,18 +380,18 @@ } bool -SpectrumLayer::getXScaleValue(const View *v, int x, +SpectrumLayer::getXScaleValue(const LayerGeometryProvider *v, int x, double &value, QString &unit) const { if (m_xorigins.find(v) == m_xorigins.end()) return false; int xorigin = m_xorigins.find(v)->second; - value = getFrequencyForX(x - xorigin, v->width() - xorigin - 1); + value = getFrequencyForX(x - xorigin, v->getPaintWidth() - xorigin - 1); unit = "Hz"; return true; } bool -SpectrumLayer::getYScaleValue(const View *v, int y, +SpectrumLayer::getYScaleValue(const LayerGeometryProvider *v, int y, double &value, QString &unit) const { value = getValueForY(y, v); @@ -413,7 +413,7 @@ } bool -SpectrumLayer::getYScaleDifference(const View *v, int y0, int y1, +SpectrumLayer::getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1, double &diff, QString &unit) const { bool rv = SliceLayer::getYScaleDifference(v, y0, y1, diff, unit); @@ -423,14 +423,14 @@ bool -SpectrumLayer::getCrosshairExtents(View *v, QPainter &paint, +SpectrumLayer::getCrosshairExtents(LayerGeometryProvider *v, QPainter &paint, QPoint cursorPos, std::vector<QRect> &extents) const { - QRect vertical(cursorPos.x(), cursorPos.y(), 1, v->height() - cursorPos.y()); + QRect vertical(cursorPos.x(), cursorPos.y(), 1, v->getPaintHeight() - cursorPos.y()); extents.push_back(vertical); - QRect horizontal(0, cursorPos.y(), v->width(), 12); + QRect horizontal(0, cursorPos.y(), v->getPaintWidth(), 12); extents.push_back(horizontal); int hoffset = 2; @@ -449,14 +449,14 @@ extents.push_back(log); QRect freq(cursorPos.x(), - v->height() - paint.fontMetrics().height() - hoffset, + v->getPaintHeight() - paint.fontMetrics().height() - hoffset, paint.fontMetrics().width("123456 Hz") + 2, paint.fontMetrics().height()); extents.push_back(freq); int w(paint.fontMetrics().width("C#10+50c") + 2); QRect pitch(cursorPos.x() - w, - v->height() - paint.fontMetrics().height() - hoffset, + v->getPaintHeight() - paint.fontMetrics().height() - hoffset, w, paint.fontMetrics().height()); extents.push_back(pitch); @@ -465,7 +465,7 @@ } void -SpectrumLayer::paintCrosshairs(View *v, QPainter &paint, +SpectrumLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint, QPoint cursorPos) const { if (!m_sliceableModel) return; @@ -481,10 +481,10 @@ paint.setPen(mapper.getContrastingColour()); int xorigin = m_xorigins[v]; - int w = v->width() - xorigin - 1; + int w = v->getPaintWidth() - xorigin - 1; - paint.drawLine(xorigin, cursorPos.y(), v->width(), cursorPos.y()); - paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->height()); + paint.drawLine(xorigin, cursorPos.y(), v->getPaintWidth(), cursorPos.y()); + paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->getPaintHeight()); double fundamental = getFrequencyForX(cursorPos.x() - xorigin, w); @@ -493,7 +493,7 @@ v->drawVisibleText(paint, cursorPos.x() + 2, - v->height() - 2 - hoffset, + v->getPaintHeight() - 2 - hoffset, QString("%1 Hz").arg(fundamental), View::OutlinedText); @@ -501,7 +501,7 @@ QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental); v->drawVisibleText(paint, cursorPos.x() - paint.fontMetrics().width(pitchLabel) - 2, - v->height() - 2 - hoffset, + v->getPaintHeight() - 2 - hoffset, pitchLabel, View::OutlinedText); } @@ -531,7 +531,7 @@ int hx = int(lrint(getXForFrequency(fundamental * harmonic, w))); hx += xorigin; - if (hx < xorigin || hx > v->width()) break; + if (hx < xorigin || hx > v->getPaintWidth()) break; int len = 7; @@ -555,7 +555,7 @@ } QString -SpectrumLayer::getFeatureDescription(View *v, QPoint &p) const +SpectrumLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &p) const { if (!m_sliceableModel) return ""; @@ -644,7 +644,7 @@ } void -SpectrumLayer::paint(View *v, QPainter &paint, QRect rect) const +SpectrumLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { if (!m_originModel || !m_originModel->isOK() || !m_originModel->isReady()) { @@ -663,7 +663,7 @@ double thresh = (pow(10, -6) / m_gain) * (m_windowSize / 2.0); // -60dB adj int xorigin = getVerticalScaleWidth(v, false, paint) + 1; - int w = v->width() - xorigin - 1; + int w = v->getPaintWidth() - xorigin - 1; int pkh = 0; //!!! if (m_binScale == LogBins) { @@ -723,7 +723,7 @@ (void)getYForValue(values[bin], v, norm); // don't need return value, need norm paint.setPen(mapper.map(norm)); - paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1); + paint.drawLine(xorigin + x, 0, xorigin + x, v->getPaintHeight() - pkh - 1); } paint.restore(); @@ -743,7 +743,7 @@ // if (m_binScale == LogBins) { // int pkh = 10; - int h = v->height(); + int h = v->getPaintHeight(); // piano keyboard //!!! should be in a new paintHorizontalScale()?
--- a/layer/SpectrumLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/SpectrumLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -39,13 +39,13 @@ void setModel(DenseTimeValueModel *model); virtual const Model *getModel() const { return m_originModel; } - virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos, + virtual bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint cursorPos, std::vector<QRect> &extents) const; - virtual void paintCrosshairs(View *, QPainter &, QPoint) const; + virtual void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; virtual VerticalPosition getPreferredFrameCountPosition() const { return PositionTop; @@ -67,16 +67,16 @@ virtual bool getValueExtents(double &min, double &max, bool &logarithmic, QString &unit) const; - virtual bool getXScaleValue(const View *v, int x, + virtual bool getXScaleValue(const LayerGeometryProvider *v, int x, double &value, QString &unit) const; - virtual bool getYScaleValue(const View *, int y, + virtual bool getYScaleValue(const LayerGeometryProvider *, int y, double &value, QString &unit) const; - virtual bool getYScaleDifference(const View *, int y0, int y1, + virtual bool getYScaleDifference(const LayerGeometryProvider *, int y0, int y1, double &diff, QString &unit) const; - virtual bool isLayerScrollable(const View *) const { return false; } + virtual bool isLayerScrollable(const LayerGeometryProvider *) const { return false; } void setChannel(int); int getChannel() const { return m_channel; } @@ -93,7 +93,7 @@ void setShowPeaks(bool); bool getShowPeaks() const { return m_showPeaks; } - virtual int getVerticalScaleWidth(View *, bool, QPainter &) const { return 0; } + virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &) const { return 0; } virtual void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const;
--- a/layer/TextLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/TextLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -102,7 +102,7 @@ } bool -TextLayer::isLayerScrollable(const View *v) const +TextLayer::isLayerScrollable(const LayerGeometryProvider *v) const { QPoint discard; return !v->shouldIlluminateLocalFeatures(this, discard); @@ -110,12 +110,12 @@ TextModel::PointList -TextLayer::getLocalPoints(View *v, int x, int y) const +TextLayer::getLocalPoints(LayerGeometryProvider *v, int x, int y) const { if (!m_model) return TextModel::PointList(); sv_frame_t frame0 = v->getFrameForX(-150); - sv_frame_t frame1 = v->getFrameForX(v->width() + 150); + sv_frame_t frame1 = v->getFrameForX(v->getPaintWidth() + 150); TextModel::PointList points(m_model->getPoints(frame0, frame1)); @@ -139,9 +139,9 @@ (QRect(0, 0, 150, 200), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label); - if (py + rect.height() > v->height()) { - if (rect.height() > v->height()) py = 0; - else py = v->height() - rect.height() - 1; + if (py + rect.height() > v->getPaintHeight()) { + if (rect.height() > v->getPaintHeight()) py = 0; + else py = v->getPaintHeight() - rect.height() - 1; } if (x >= px && x < px + rect.width() && @@ -154,7 +154,7 @@ } bool -TextLayer::getPointToDrag(View *v, int x, int y, TextModel::Point &p) const +TextLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, TextModel::Point &p) const { if (!m_model) return false; @@ -182,7 +182,7 @@ } QString -TextLayer::getFeatureDescription(View *v, QPoint &pos) const +TextLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { int x = pos.x(); @@ -220,7 +220,7 @@ //!!! too much overlap with TimeValueLayer/TimeInstantLayer bool -TextLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, +TextLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { @@ -292,21 +292,21 @@ } int -TextLayer::getYForHeight(View *v, double height) const +TextLayer::getYForHeight(LayerGeometryProvider *v, double height) const { - int h = v->height(); + int h = v->getPaintHeight(); return h - int(height * h); } double -TextLayer::getHeightForY(View *v, int y) const +TextLayer::getHeightForY(LayerGeometryProvider *v, int y) const { - int h = v->height(); + int h = v->getPaintHeight(); return double(h - y) / h; } void -TextLayer::paint(View *v, QPainter &paint, QRect rect) const +TextLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { if (!m_model || !m_model->isOK()) return; @@ -347,7 +347,7 @@ int boxMaxHeight = 200; paint.save(); - paint.setClipRect(rect.x(), 0, rect.width() + boxMaxWidth, v->height()); + paint.setClipRect(rect.x(), 0, rect.width() + boxMaxWidth, v->getPaintHeight()); for (TextModel::PointList::const_iterator i = points.begin(); i != points.end(); ++i) { @@ -380,9 +380,9 @@ QRect textRect = QRect(3, 2, boxRect.width(), boxRect.height()); boxRect = QRect(0, 0, boxRect.width() + 6, boxRect.height() + 2); - if (y + boxRect.height() > v->height()) { - if (boxRect.height() > v->height()) y = 0; - else y = v->height() - boxRect.height() - 1; + if (y + boxRect.height() > v->getPaintHeight()) { + if (boxRect.height() > v->getPaintHeight()) y = 0; + else y = v->getPaintHeight() - boxRect.height() - 1; } boxRect = QRect(x, y, boxRect.width(), boxRect.height()); @@ -411,7 +411,7 @@ } void -TextLayer::drawStart(View *v, QMouseEvent *e) +TextLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "TextLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; @@ -437,7 +437,7 @@ } void -TextLayer::drawDrag(View *v, QMouseEvent *e) +TextLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "TextLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; @@ -456,13 +456,13 @@ } void -TextLayer::drawEnd(View *v, QMouseEvent *) +TextLayer::drawEnd(LayerGeometryProvider *v, QMouseEvent *) { // SVDEBUG << "TextLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl; if (!m_model || !m_editing) return; bool ok = false; - QString label = QInputDialog::getText(v, tr("Enter label"), + QString label = QInputDialog::getText(v->getView(), tr("Enter label"), tr("Please enter a new label:"), QLineEdit::Normal, "", &ok); @@ -480,7 +480,7 @@ } void -TextLayer::eraseStart(View *v, QMouseEvent *e) +TextLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return; @@ -495,12 +495,12 @@ } void -TextLayer::eraseDrag(View *, QMouseEvent *) +TextLayer::eraseDrag(LayerGeometryProvider *, QMouseEvent *) { } void -TextLayer::eraseEnd(View *v, QMouseEvent *e) +TextLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -521,7 +521,7 @@ } void -TextLayer::editStart(View *v, QMouseEvent *e) +TextLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) { // SVDEBUG << "TextLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; @@ -543,7 +543,7 @@ } void -TextLayer::editDrag(View *v, QMouseEvent *e) +TextLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -570,7 +570,7 @@ } void -TextLayer::editEnd(View *, QMouseEvent *) +TextLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) { // SVDEBUG << "TextLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl; if (!m_model || !m_editing) return; @@ -598,7 +598,7 @@ } bool -TextLayer::editOpen(View *v, QMouseEvent *e) +TextLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return false; @@ -608,7 +608,7 @@ QString label = text.label; bool ok = false; - label = QInputDialog::getText(v, tr("Enter label"), + label = QInputDialog::getText(v->getView(), tr("Enter label"), tr("Please enter a new label:"), QLineEdit::Normal, label, &ok); if (ok && label != text.label) { @@ -699,7 +699,7 @@ } void -TextLayer::copy(View *v, Selection s, Clipboard &to) +TextLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -717,7 +717,7 @@ } bool -TextLayer::paste(View *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) +TextLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) { if (!m_model) return false; @@ -728,7 +728,7 @@ if (clipboardHasDifferentAlignment(v, from)) { QMessageBox::StandardButton button = - QMessageBox::question(v, tr("Re-align pasted items?"), + QMessageBox::question(v->getView(), tr("Re-align pasted items?"), tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
--- a/layer/TextLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/TextLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -32,35 +32,35 @@ public: TextLayer(); - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; - virtual bool snapToFeatureFrame(View *v, sv_frame_t &frame, + virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual void drawStart(View *v, QMouseEvent *); - virtual void drawDrag(View *v, QMouseEvent *); - virtual void drawEnd(View *v, QMouseEvent *); + virtual void drawStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void eraseStart(View *v, QMouseEvent *); - virtual void eraseDrag(View *v, QMouseEvent *); - virtual void eraseEnd(View *v, QMouseEvent *); + virtual void eraseStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void editStart(View *v, QMouseEvent *); - virtual void editDrag(View *v, QMouseEvent *); - virtual void editEnd(View *v, QMouseEvent *); + virtual void editStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void editDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void editEnd(LayerGeometryProvider *v, QMouseEvent *); virtual void moveSelection(Selection s, sv_frame_t newStartFrame); virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(View *v, Selection s, Clipboard &to); - virtual bool paste(View *v, const Clipboard &from, sv_frame_t frameOffset, + virtual void copy(LayerGeometryProvider *v, Selection s, Clipboard &to); + virtual bool paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool interactive); - virtual bool editOpen(View *, QMouseEvent *); // on double-click + virtual bool editOpen(LayerGeometryProvider *, QMouseEvent *); // on double-click virtual const Model *getModel() const { return m_model; } void setModel(TextModel *model); @@ -74,16 +74,16 @@ int value) const; virtual void setProperty(const PropertyName &, int value); - virtual bool isLayerScrollable(const View *v) const; + virtual bool isLayerScrollable(const LayerGeometryProvider *v) const; virtual bool isLayerEditable() const { return true; } - virtual int getCompletion(View *) const { return m_model->getCompletion(); } + virtual int getCompletion(LayerGeometryProvider *) const { return m_model->getCompletion(); } virtual bool getValueExtents(double &min, double &max, bool &logarithmic, QString &unit) const; - virtual int getVerticalScaleWidth(View *, bool, QPainter &) const { return 0; } + virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &) const { return 0; } virtual void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const; @@ -91,14 +91,14 @@ void setProperties(const QXmlAttributes &attributes); protected: - int getYForHeight(View *v, double height) const; - double getHeightForY(View *v, int y) const; + int getYForHeight(LayerGeometryProvider *v, double height) const; + double getHeightForY(LayerGeometryProvider *v, int y) const; virtual int getDefaultColourHint(bool dark, bool &impose); - TextModel::PointList getLocalPoints(View *v, int x, int y) const; + TextModel::PointList getLocalPoints(LayerGeometryProvider *v, int x, int y) const; - bool getPointToDrag(View *v, int x, int y, TextModel::Point &) const; + bool getPointToDrag(LayerGeometryProvider *v, int x, int y, TextModel::Point &) const; TextModel *m_model; bool m_editing;
--- a/layer/TimeInstantLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/TimeInstantLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -147,14 +147,14 @@ } bool -TimeInstantLayer::isLayerScrollable(const View *v) const +TimeInstantLayer::isLayerScrollable(const LayerGeometryProvider *v) const { QPoint discard; return !v->shouldIlluminateLocalFeatures(this, discard); } SparseOneDimensionalModel::PointList -TimeInstantLayer::getLocalPoints(View *v, int x) const +TimeInstantLayer::getLocalPoints(LayerGeometryProvider *v, int x) const { // Return a set of points that all have the same frame number, the // nearest to the given x coordinate, and that are within a @@ -162,7 +162,7 @@ if (!m_model) return SparseOneDimensionalModel::PointList(); - long frame = v->getFrameForX(x); + sv_frame_t frame = v->getFrameForX(x); SparseOneDimensionalModel::PointList onPoints = m_model->getPoints(frame); @@ -213,7 +213,7 @@ } QString -TimeInstantLayer::getFeatureDescription(View *v, QPoint &pos) const +TimeInstantLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { int x = pos.x(); @@ -229,7 +229,7 @@ } } - long useFrame = points.begin()->frame; + sv_frame_t useFrame = points.begin()->frame; RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); @@ -249,7 +249,7 @@ } bool -TimeInstantLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, +TimeInstantLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { @@ -321,7 +321,7 @@ } void -TimeInstantLayer::paint(View *v, QPainter &paint, QRect rect) const +TimeInstantLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { if (!m_model || !m_model->isOK()) return; @@ -329,8 +329,8 @@ int x0 = rect.left(), x1 = rect.right(); - long frame0 = v->getFrameForX(x0); - long frame1 = v->getFrameForX(x1); + sv_frame_t frame0 = v->getFrameForX(x0); + sv_frame_t frame1 = v->getFrameForX(x1); SparseOneDimensionalModel::PointList points(m_model->getPoints (frame0, frame1)); @@ -367,7 +367,7 @@ // << m_model->getResolution() << " frames" << endl; QPoint localPos; - long illuminateFrame = -1; + sv_frame_t illuminateFrame = -1; if (v->shouldIlluminateLocalFeatures(this, localPos)) { SparseOneDimensionalModel::PointList localPoints = @@ -403,16 +403,16 @@ } if (p.frame == illuminateFrame) { - paint.setPen(getForegroundQColor(v)); + paint.setPen(getForegroundQColor(v->getView())); } else { paint.setPen(brushColour); } if (m_plotStyle == PlotInstants) { if (iw > 1) { - paint.drawRect(x, 0, iw - 1, v->height() - 1); + paint.drawRect(x, 0, iw - 1, v->getPaintHeight() - 1); } else { - paint.drawLine(x, 0, x, v->height() - 1); + paint.drawLine(x, 0, x, v->getPaintHeight() - 1); } } else { @@ -431,11 +431,11 @@ if (nx >= x) { if (illuminateFrame != p.frame && - (nx < x + 5 || x >= v->width() - 1)) { + (nx < x + 5 || x >= v->getPaintWidth() - 1)) { paint.setPen(Qt::NoPen); } - paint.drawRect(x, -1, nx - x, v->height() + 1); + paint.drawRect(x, -1, nx - x, v->getPaintHeight() + 1); } odd = !odd; @@ -466,7 +466,7 @@ } void -TimeInstantLayer::drawStart(View *v, QMouseEvent *e) +TimeInstantLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) { #ifdef DEBUG_TIME_INSTANT_LAYER cerr << "TimeInstantLayer::drawStart(" << e->x() << ")" << endl; @@ -474,7 +474,7 @@ if (!m_model) return; - long frame = v->getFrameForX(e->x()); + sv_frame_t frame = v->getFrameForX(e->x()); if (frame < 0) frame = 0; frame = frame / m_model->getResolution() * m_model->getResolution(); @@ -489,7 +489,7 @@ } void -TimeInstantLayer::drawDrag(View *v, QMouseEvent *e) +TimeInstantLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) { #ifdef DEBUG_TIME_INSTANT_LAYER cerr << "TimeInstantLayer::drawDrag(" << e->x() << ")" << endl; @@ -497,7 +497,7 @@ if (!m_model || !m_editing) return; - long frame = v->getFrameForX(e->x()); + sv_frame_t frame = v->getFrameForX(e->x()); if (frame < 0) frame = 0; frame = frame / m_model->getResolution() * m_model->getResolution(); m_editingCommand->deletePoint(m_editingPoint); @@ -506,7 +506,7 @@ } void -TimeInstantLayer::drawEnd(View *, QMouseEvent *) +TimeInstantLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) { #ifdef DEBUG_TIME_INSTANT_LAYER cerr << "TimeInstantLayer::drawEnd(" << e->x() << ")" << endl; @@ -523,7 +523,7 @@ } void -TimeInstantLayer::eraseStart(View *v, QMouseEvent *e) +TimeInstantLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return; @@ -541,12 +541,12 @@ } void -TimeInstantLayer::eraseDrag(View *, QMouseEvent *) +TimeInstantLayer::eraseDrag(LayerGeometryProvider *, QMouseEvent *) { } void -TimeInstantLayer::eraseEnd(View *v, QMouseEvent *e) +TimeInstantLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -567,7 +567,7 @@ } void -TimeInstantLayer::editStart(View *v, QMouseEvent *e) +TimeInstantLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) { #ifdef DEBUG_TIME_INSTANT_LAYER cerr << "TimeInstantLayer::editStart(" << e->x() << ")" << endl; @@ -589,7 +589,7 @@ } void -TimeInstantLayer::editDrag(View *v, QMouseEvent *e) +TimeInstantLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) { #ifdef DEBUG_TIME_INSTANT_LAYER cerr << "TimeInstantLayer::editDrag(" << e->x() << ")" << endl; @@ -597,7 +597,7 @@ if (!m_model || !m_editing) return; - long frame = v->getFrameForX(e->x()); + sv_frame_t frame = v->getFrameForX(e->x()); if (frame < 0) frame = 0; frame = frame / m_model->getResolution() * m_model->getResolution(); @@ -612,7 +612,7 @@ } void -TimeInstantLayer::editEnd(View *, QMouseEvent *) +TimeInstantLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) { #ifdef DEBUG_TIME_INSTANT_LAYER cerr << "TimeInstantLayer::editEnd(" << e->x() << ")" << endl; @@ -631,7 +631,7 @@ } bool -TimeInstantLayer::editOpen(View *v, QMouseEvent *e) +TimeInstantLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return false; @@ -747,7 +747,7 @@ } void -TimeInstantLayer::copy(View *v, Selection s, Clipboard &to) +TimeInstantLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -765,7 +765,7 @@ } bool -TimeInstantLayer::paste(View *v, const Clipboard &from, sv_frame_t frameOffset, bool) +TimeInstantLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool) { if (!m_model) return false; @@ -776,7 +776,7 @@ if (clipboardHasDifferentAlignment(v, from)) { QMessageBox::StandardButton button = - QMessageBox::question(v, tr("Re-align pasted instants?"), + QMessageBox::question(v->getView(), tr("Re-align pasted instants?"), tr("The instants you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
--- a/layer/TimeInstantLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/TimeInstantLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -33,35 +33,35 @@ TimeInstantLayer(); virtual ~TimeInstantLayer(); - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; virtual QString getLabelPreceding(sv_frame_t) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; - virtual bool snapToFeatureFrame(View *v, sv_frame_t &frame, + virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual void drawStart(View *v, QMouseEvent *); - virtual void drawDrag(View *v, QMouseEvent *); - virtual void drawEnd(View *v, QMouseEvent *); + virtual void drawStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void eraseStart(View *v, QMouseEvent *); - virtual void eraseDrag(View *v, QMouseEvent *); - virtual void eraseEnd(View *v, QMouseEvent *); + virtual void eraseStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void editStart(View *v, QMouseEvent *); - virtual void editDrag(View *v, QMouseEvent *); - virtual void editEnd(View *v, QMouseEvent *); + virtual void editStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void editDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void editEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual bool editOpen(View *, QMouseEvent *); + virtual bool editOpen(LayerGeometryProvider *, QMouseEvent *); virtual void moveSelection(Selection s, sv_frame_t newStartFrame); virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(View *v, Selection s, Clipboard &to); - virtual bool paste(View *v, const Clipboard &from, sv_frame_t frameOffset, + virtual void copy(LayerGeometryProvider *v, Selection s, Clipboard &to); + virtual bool paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool interactive); virtual const Model *getModel() const { return m_model; } @@ -84,11 +84,11 @@ void setPlotStyle(PlotStyle style); PlotStyle getPlotStyle() const { return m_plotStyle; } - virtual bool isLayerScrollable(const View *v) const; + virtual bool isLayerScrollable(const LayerGeometryProvider *v) const; virtual bool isLayerEditable() const { return true; } - virtual int getCompletion(View *) const { return m_model->getCompletion(); } + virtual int getCompletion(LayerGeometryProvider *) const { return m_model->getCompletion(); } virtual bool needsTextLabelHeight() const { return m_model->hasTextLabels(); } @@ -109,14 +109,14 @@ } } - virtual int getVerticalScaleWidth(View *, bool, QPainter &) const { return 0; } + virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &) const { return 0; } protected: - SparseOneDimensionalModel::PointList getLocalPoints(View *v, int) const; + SparseOneDimensionalModel::PointList getLocalPoints(LayerGeometryProvider *v, int) const; virtual int getDefaultColourHint(bool dark, bool &impose); - bool clipboardAlignmentDiffers(View *v, const Clipboard &) const; + bool clipboardAlignmentDiffers(LayerGeometryProvider *v, const Clipboard &) const; SparseOneDimensionalModel *m_model; bool m_editing;
--- a/layer/TimeRulerLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/TimeRulerLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -26,12 +26,11 @@ #include <iostream> #include <cmath> +#include <stdexcept> //#define DEBUG_TIME_RULER_LAYER 1 - - TimeRulerLayer::TimeRulerLayer() : SingleColourLayer(), m_model(0), @@ -49,7 +48,7 @@ } bool -TimeRulerLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, +TimeRulerLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { if (!m_model) { @@ -88,7 +87,7 @@ case SnapNearest: { - if (labs(frame - left) > labs(right - frame)) { + if (llabs(frame - left) > llabs(right - frame)) { frame = right; } else { frame = left; @@ -141,7 +140,7 @@ } int -TimeRulerLayer::getMajorTickSpacing(View *v, bool &quarterTicks) const +TimeRulerLayer::getMajorTickSpacing(LayerGeometryProvider *v, bool &quarterTicks) const { // return value is in milliseconds @@ -158,7 +157,7 @@ RealTime rtStart = RealTime::frame2RealTime(startFrame, sampleRate); RealTime rtEnd = RealTime::frame2RealTime(endFrame, sampleRate); - int count = v->width() / minPixelSpacing; + int count = v->getPaintWidth() / minPixelSpacing; if (count < 1) count = 1; RealTime rtGap = (rtEnd - rtStart) / count; @@ -182,6 +181,8 @@ } else { incms = 1; int ms = rtGap.msec(); +// cerr << "rtGap.msec = " << ms << ", rtGap = " << rtGap << ", count = " << count << endl; +// cerr << "startFrame = " << startFrame << ", endFrame = " << endFrame << " rtStart = " << rtStart << ", rtEnd = " << rtEnd << endl; if (ms > 0) { incms *= 10; ms /= 10; } if (ms > 0) { incms *= 10; ms /= 10; } if (ms > 0) { incms *= 5; ms /= 5; } @@ -192,7 +193,7 @@ } void -TimeRulerLayer::paint(View *v, QPainter &paint, QRect rect) const +TimeRulerLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { #ifdef DEBUG_TIME_RULER_LAYER SVDEBUG << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y() @@ -241,6 +242,9 @@ // time < 0 which would cut it in half int minlabel = 1; // ms + // used for a sanity check + sv_frame_t prevframe = 0; + while (1) { // frame is used to determine where to draw the lines, so it @@ -253,10 +257,17 @@ frame /= v->getZoomLevel(); frame *= v->getZoomLevel(); // so frame corresponds to an exact pixel + if (frame == prevframe && prevframe != 0) { + cerr << "ERROR: frame == prevframe (== " << frame + << ") in TimeRulerLayer::paint" << endl; + throw std::logic_error("frame == prevframe in TimeRulerLayer::paint"); + } + prevframe = frame; + int x = v->getXForFrame(frame); #ifdef DEBUG_TIME_RULER_LAYER - SVDEBUG << "Considering frame = " << frame << ", x = " << x << endl; + cerr << "Considering frame = " << frame << ", x = " << x << endl; #endif if (x >= rect.x() + rect.width() + 50) { @@ -287,11 +298,11 @@ } paint.setPen(greyColour); - paint.drawLine(x, 0, x, v->height()); + paint.drawLine(x, 0, x, v->getPaintHeight()); paint.setPen(getBaseQColor()); paint.drawLine(x, 0, x, 5); - paint.drawLine(x, v->height() - 6, x, v->height() - 1); + paint.drawLine(x, v->getPaintHeight() - 6, x, v->getPaintHeight() - 1); int y; switch (m_labelHeight) { @@ -300,16 +311,16 @@ y = 6 + metrics.ascent(); break; case LabelMiddle: - y = v->height() / 2 - metrics.height() / 2 + metrics.ascent(); + y = v->getPaintHeight() / 2 - metrics.height() / 2 + metrics.ascent(); break; case LabelBottom: - y = v->height() - metrics.height() + metrics.ascent() - 6; + y = v->getPaintHeight() - metrics.height() + metrics.ascent() - 6; } if (v->getViewManager() && v->getViewManager()->getOverlayMode() != ViewManager::NoOverlays) { - if (v->getLayer(0) == this) { + if (v->getView()->getLayer(0) == this) { // backmost layer, don't worry about outlining the text paint.drawText(x+2 - tw/2, y, text); } else { @@ -344,14 +355,14 @@ if (ticks == 10) { if ((i % 2) == 1) { if (i == 5) { - paint.drawLine(x, 0, x, v->height()); + paint.drawLine(x, 0, x, v->getPaintHeight()); } else sz = 3; } else { sz = 7; } } paint.drawLine(x, 0, x, sz); - paint.drawLine(x, v->height() - sz - 1, x, v->height() - 1); + paint.drawLine(x, v->getPaintHeight() - sz - 1, x, v->getPaintHeight() - 1); } ms += incms;
--- a/layer/TimeRulerLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/TimeRulerLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -32,7 +32,7 @@ public: TimeRulerLayer(); - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; void setModel(Model *); virtual const Model *getModel() const { return m_model; } @@ -41,7 +41,7 @@ void setLabelHeight(LabelHeight h) { m_labelHeight = h; } LabelHeight getLabelHeight() const { return m_labelHeight; } - virtual bool snapToFeatureFrame(View *, sv_frame_t &, int &, SnapType) const; + virtual bool snapToFeatureFrame(LayerGeometryProvider *, sv_frame_t &, int &, SnapType) const; virtual ColourSignificance getLayerColourSignificance() const { return ColourIrrelevant; @@ -53,7 +53,7 @@ virtual QString getLayerPresentationName() const; - virtual int getVerticalScaleWidth(View *, bool, QPainter &) const { return 0; } + virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &) const { return 0; } virtual void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const; @@ -68,7 +68,7 @@ virtual int getDefaultColourHint(bool dark, bool &impose); - int getMajorTickSpacing(View *, bool &quarterTicks) const; + int getMajorTickSpacing(LayerGeometryProvider *, bool &quarterTicks) const; }; #endif
--- a/layer/TimeValueLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/TimeValueLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -316,7 +316,7 @@ } bool -TimeValueLayer::isLayerScrollable(const View *v) const +TimeValueLayer::isLayerScrollable(const LayerGeometryProvider *v) const { // We don't illuminate sections in the line or curve modes, so // they're always scrollable @@ -530,7 +530,7 @@ } SparseTimeValueModel::PointList -TimeValueLayer::getLocalPoints(View *v, int x) const +TimeValueLayer::getLocalPoints(LayerGeometryProvider *v, int x) const { if (!m_model) return SparseTimeValueModel::PointList(); @@ -587,7 +587,7 @@ } QString -TimeValueLayer::getFeatureDescription(View *v, QPoint &pos) const +TimeValueLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { int x = pos.x(); @@ -641,7 +641,7 @@ } bool -TimeValueLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, +TimeValueLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { @@ -713,7 +713,7 @@ } bool -TimeValueLayer::snapToSimilarFeature(View *v, sv_frame_t &frame, +TimeValueLayer::snapToSimilarFeature(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const { @@ -794,7 +794,7 @@ } void -TimeValueLayer::getScaleExtents(View *v, double &min, double &max, bool &log) const +TimeValueLayer::getScaleExtents(LayerGeometryProvider *v, double &min, double &max, bool &log) const { min = 0.0; max = 0.0; @@ -830,11 +830,11 @@ } int -TimeValueLayer::getYForValue(View *v, double val) const +TimeValueLayer::getYForValue(LayerGeometryProvider *v, double val) const { double min = 0.0, max = 0.0; bool logarithmic = false; - int h = v->height(); + int h = v->getPaintHeight(); getScaleExtents(v, min, max, logarithmic); @@ -851,11 +851,11 @@ } double -TimeValueLayer::getValueForY(View *v, int y) const +TimeValueLayer::getValueForY(LayerGeometryProvider *v, int y) const { double min = 0.0, max = 0.0; bool logarithmic = false; - int h = v->height(); + int h = v->getPaintHeight(); getScaleExtents(v, min, max, logarithmic); @@ -877,7 +877,7 @@ } QColor -TimeValueLayer::getColourForValue(View *v, double val) const +TimeValueLayer::getColourForValue(LayerGeometryProvider *v, double val) const { double min, max; bool log; @@ -908,7 +908,7 @@ } void -TimeValueLayer::paint(View *v, QPainter &paint, QRect rect) const +TimeValueLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const { if (!m_model || !m_model->isOK()) return; @@ -943,8 +943,8 @@ double max = m_model->getValueMaximum(); if (max == min) max = min + 1.0; - int origin = int(nearbyint(v->height() - - (-min * v->height()) / (max - min))); + int origin = int(nearbyint(v->getPaintHeight() - + (-min * v->getPaintHeight()) / (max - min))); QPoint localPos; sv_frame_t illuminateFrame = -1; @@ -978,7 +978,7 @@ textY = v->getTextLabelHeight(this, paint); } else { int originY = getYForValue(v, 0.f); - if (originY > 0 && originY < v->height()) { + if (originY > 0 && originY < v->getPaintHeight()) { paint.save(); paint.setPen(getPartialShades(v)[1]); paint.drawLine(x0, originY, x1, originY); @@ -1183,12 +1183,12 @@ if (!illuminate) { if (!m_drawSegmentDivisions || nx < x + 5 || - x >= v->width() - 1) { + x >= v->getPaintWidth() - 1) { paint.setPen(Qt::NoPen); } } - paint.drawRect(x, -1, nx - x, v->height() + 1); + paint.drawRect(x, -1, nx - x, v->getPaintHeight() + 1); } if (v->shouldShowFeatureLabels()) { @@ -1231,7 +1231,7 @@ paint.drawPath(path); } else if ((m_plotStyle == PlotCurve || m_plotStyle == PlotLines) && !path.isEmpty()) { - paint.setRenderHint(QPainter::Antialiasing, pointCount <= v->width()); + paint.setRenderHint(QPainter::Antialiasing, pointCount <= v->getPaintWidth()); paint.drawPath(path); } @@ -1242,7 +1242,7 @@ } int -TimeValueLayer::getVerticalScaleWidth(View *v, bool, QPainter &paint) const +TimeValueLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const { if (!m_model || shouldAutoAlign()) { return 0; @@ -1262,7 +1262,7 @@ } void -TimeValueLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect) const +TimeValueLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const { if (!m_model || m_model->getPoints().empty()) return; @@ -1271,7 +1271,7 @@ bool logarithmic; int w = getVerticalScaleWidth(v, false, paint); - int h = v->height(); + int h = v->getPaintHeight(); if (m_plotStyle == PlotSegmentation) { @@ -1314,7 +1314,7 @@ } void -TimeValueLayer::drawStart(View *v, QMouseEvent *e) +TimeValueLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) { #ifdef DEBUG_TIME_VALUE_LAYER cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; @@ -1364,7 +1364,7 @@ } void -TimeValueLayer::drawDrag(View *v, QMouseEvent *e) +TimeValueLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) { #ifdef DEBUG_TIME_VALUE_LAYER cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; @@ -1426,7 +1426,7 @@ } void -TimeValueLayer::drawEnd(View *, QMouseEvent *) +TimeValueLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) { #ifdef DEBUG_TIME_VALUE_LAYER cerr << "TimeValueLayer::drawEnd" << endl; @@ -1438,7 +1438,7 @@ } void -TimeValueLayer::eraseStart(View *v, QMouseEvent *e) +TimeValueLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return; @@ -1456,12 +1456,12 @@ } void -TimeValueLayer::eraseDrag(View *, QMouseEvent *) +TimeValueLayer::eraseDrag(LayerGeometryProvider *, QMouseEvent *) { } void -TimeValueLayer::eraseEnd(View *v, QMouseEvent *e) +TimeValueLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model || !m_editing) return; @@ -1483,7 +1483,7 @@ } void -TimeValueLayer::editStart(View *v, QMouseEvent *e) +TimeValueLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) { #ifdef DEBUG_TIME_VALUE_LAYER cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; @@ -1506,7 +1506,7 @@ } void -TimeValueLayer::editDrag(View *v, QMouseEvent *e) +TimeValueLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) { #ifdef DEBUG_TIME_VALUE_LAYER cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl; @@ -1532,7 +1532,7 @@ } void -TimeValueLayer::editEnd(View *, QMouseEvent *) +TimeValueLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) { #ifdef DEBUG_TIME_VALUE_LAYER cerr << "TimeValueLayer::editEnd" << endl; @@ -1562,7 +1562,7 @@ } bool -TimeValueLayer::editOpen(View *v, QMouseEvent *e) +TimeValueLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) { if (!m_model) return false; @@ -1685,7 +1685,7 @@ } void -TimeValueLayer::copy(View *v, Selection s, Clipboard &to) +TimeValueLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -1703,7 +1703,7 @@ } bool -TimeValueLayer::paste(View *v, const Clipboard &from, sv_frame_t /* frameOffset */, +TimeValueLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool interactive) { if (!m_model) return false; @@ -1715,7 +1715,7 @@ if (clipboardHasDifferentAlignment(v, from)) { QMessageBox::StandardButton button = - QMessageBox::question(v, tr("Re-align pasted items?"), + QMessageBox::question(v->getView(), tr("Re-align pasted items?"), tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
--- a/layer/TimeValueLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/TimeValueLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -37,41 +37,41 @@ public: TimeValueLayer(); - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; - virtual int getVerticalScaleWidth(View *v, bool, QPainter &) const; - virtual void paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const; + virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &) const; + virtual void paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; virtual QString getLabelPreceding(sv_frame_t) const; - virtual bool snapToFeatureFrame(View *v, sv_frame_t &frame, + virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual bool snapToSimilarFeature(View *v, sv_frame_t &frame, + virtual bool snapToSimilarFeature(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap) const; - virtual void drawStart(View *v, QMouseEvent *); - virtual void drawDrag(View *v, QMouseEvent *); - virtual void drawEnd(View *v, QMouseEvent *); + virtual void drawStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void drawEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void eraseStart(View *v, QMouseEvent *); - virtual void eraseDrag(View *v, QMouseEvent *); - virtual void eraseEnd(View *v, QMouseEvent *); + virtual void eraseStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void eraseEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual void editStart(View *v, QMouseEvent *); - virtual void editDrag(View *v, QMouseEvent *); - virtual void editEnd(View *v, QMouseEvent *); + virtual void editStart(LayerGeometryProvider *v, QMouseEvent *); + virtual void editDrag(LayerGeometryProvider *v, QMouseEvent *); + virtual void editEnd(LayerGeometryProvider *v, QMouseEvent *); - virtual bool editOpen(View *v, QMouseEvent *); + virtual bool editOpen(LayerGeometryProvider *v, QMouseEvent *); virtual void moveSelection(Selection s, sv_frame_t newStartFrame); virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(View *v, Selection s, Clipboard &to); - virtual bool paste(View *v, const Clipboard &from, sv_frame_t frameOffset, + virtual void copy(LayerGeometryProvider *v, Selection s, Clipboard &to); + virtual bool paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool interactive); virtual const Model *getModel() const { return m_model; } @@ -120,11 +120,11 @@ void setShowDerivative(bool); bool getShowDerivative() const { return m_derivative; } - virtual bool isLayerScrollable(const View *v) const; + virtual bool isLayerScrollable(const LayerGeometryProvider *v) const; virtual bool isLayerEditable() const { return true; } - virtual int getCompletion(View *) const { return m_model->getCompletion(); } + virtual int getCompletion(LayerGeometryProvider *) const { return m_model->getCompletion(); } virtual bool needsTextLabelHeight() const { return m_plotStyle == PlotSegmentation && m_model->hasTextLabels(); @@ -155,16 +155,16 @@ } /// VerticalScaleLayer and ColourScaleLayer methods - virtual int getYForValue(View *, double value) const; - virtual double getValueForY(View *, int y) const; + virtual int getYForValue(LayerGeometryProvider *, double value) const; + virtual double getValueForY(LayerGeometryProvider *, int y) const; virtual QString getScaleUnits() const; - virtual QColor getColourForValue(View *v, double value) const; + virtual QColor getColourForValue(LayerGeometryProvider *v, double value) const; protected: - void getScaleExtents(View *, double &min, double &max, bool &log) const; + void getScaleExtents(LayerGeometryProvider *, double &min, double &max, bool &log) const; bool shouldAutoAlign() const; - SparseTimeValueModel::PointList getLocalPoints(View *v, int) const; + SparseTimeValueModel::PointList getLocalPoints(LayerGeometryProvider *v, int) const; virtual int getDefaultColourHint(bool dark, bool &impose);
--- a/layer/VerticalScaleLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/VerticalScaleLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -19,8 +19,8 @@ class VerticalScaleLayer { public: - virtual int getYForValue(View *, double value) const = 0; - virtual double getValueForY(View *, int y) const = 0; + virtual int getYForValue(LayerGeometryProvider *, double value) const = 0; + virtual double getValueForY(LayerGeometryProvider *, int y) const = 0; virtual QString getScaleUnits() const = 0; };
--- a/layer/WaveformLayer.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/WaveformLayer.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -326,7 +326,7 @@ } int -WaveformLayer::getCompletion(View *) const +WaveformLayer::getCompletion(LayerGeometryProvider *) const { int completion = 100; if (!m_model || !m_model->isOK()) return completion; @@ -399,7 +399,7 @@ } bool -WaveformLayer::isLayerScrollable(const View *) const +WaveformLayer::isLayerScrollable(const LayerGeometryProvider *) const { return !m_autoNormalize; } @@ -408,7 +408,7 @@ -5, -3, -2, -1, -0.5, 0 }; bool -WaveformLayer::getSourceFramesForX(View *v, int x, int modelZoomLevel, +WaveformLayer::getSourceFramesForX(LayerGeometryProvider *v, int x, int modelZoomLevel, sv_frame_t &f0, sv_frame_t &f1) const { sv_frame_t viewFrame = v->getFrameForX(x); @@ -433,7 +433,7 @@ } float -WaveformLayer::getNormalizeGain(View *v, int channel) const +WaveformLayer::getNormalizeGain(LayerGeometryProvider *v, int channel) const { sv_frame_t startFrame = v->getStartFrame(); sv_frame_t endFrame = v->getEndFrame(); @@ -473,7 +473,7 @@ } void -WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const +WaveformLayer::paint(LayerGeometryProvider *v, QPainter &viewPainter, QRect rect) const { if (!m_model || !m_model->isOK()) { return; @@ -494,8 +494,8 @@ mergingChannels, mixingChannels); if (channels == 0) return; - int w = v->width(); - int h = v->height(); + int w = v->getPaintWidth(); + int h = v->getPaintHeight(); bool ready = m_model->isReady(); QPainter *paint; @@ -559,7 +559,7 @@ y1 = rect.bottom(); if (x0 > 0) --x0; - if (x1 < v->width()) ++x1; + if (x1 < w) ++x1; // Our zoom level may differ from that at which the underlying // model has its blocks. @@ -730,14 +730,17 @@ cerr << "WaveformLayer::paint: ERROR: i1 " << i1 << " > i0 " << i0 << " plus one (zoom = " << zoomLevel << ", model zoom = " << modelZoomLevel << ")" << endl; } - if (ranges && i0 < (int)ranges->size()) { + if (ranges && i0 < (sv_frame_t)ranges->size()) { - range = (*ranges)[i0]; + range = (*ranges)[size_t(i0)]; if (i1 > i0 && i1 < (int)ranges->size()) { - range.setMax(std::max(range.max(), (*ranges)[i1].max())); - range.setMin(std::min(range.min(), (*ranges)[i1].min())); - range.setAbsmean((range.absmean() + (*ranges)[i1].absmean()) / 2); + range.setMax(std::max(range.max(), + (*ranges)[size_t(i1)].max())); + range.setMin(std::min(range.min(), + (*ranges)[size_t(i1)].min())); + range.setAbsmean((range.absmean() + + (*ranges)[size_t(i1)].absmean()) / 2); } } else { @@ -751,30 +754,33 @@ if (mergingChannels) { - if (otherChannelRanges && i0 < (int)otherChannelRanges->size()) { + if (otherChannelRanges && i0 < (sv_frame_t)otherChannelRanges->size()) { range.setMax(fabsf(range.max())); - range.setMin(-fabsf((*otherChannelRanges)[i0].max())); + range.setMin(-fabsf((*otherChannelRanges)[size_t(i0)].max())); range.setAbsmean ((range.absmean() + - (*otherChannelRanges)[i0].absmean()) / 2); + (*otherChannelRanges)[size_t(i0)].absmean()) / 2); - if (i1 > i0 && i1 < (int)otherChannelRanges->size()) { + if (i1 > i0 && i1 < (sv_frame_t)otherChannelRanges->size()) { // let's not concern ourselves about the mean range.setMin (std::min (range.min(), - -fabsf((*otherChannelRanges)[i1].max()))); + -fabsf((*otherChannelRanges)[size_t(i1)].max()))); } } } else if (mixingChannels) { - if (otherChannelRanges && i0 < (int)otherChannelRanges->size()) { + if (otherChannelRanges && i0 < (sv_frame_t)otherChannelRanges->size()) { - range.setMax((range.max() + (*otherChannelRanges)[i0].max()) / 2); - range.setMin((range.min() + (*otherChannelRanges)[i0].min()) / 2); - range.setAbsmean((range.absmean() + (*otherChannelRanges)[i0].absmean()) / 2); + range.setMax((range.max() + + (*otherChannelRanges)[size_t(i0)].max()) / 2); + range.setMin((range.min() + + (*otherChannelRanges)[size_t(i0)].min()) / 2); + range.setAbsmean((range.absmean() + + (*otherChannelRanges)[size_t(i0)].absmean()) / 2); } } @@ -939,7 +945,7 @@ if (m_aggressive) { - if (ready && rect == v->rect()) { + if (ready && rect == v->getPaintRect()) { m_cacheValid = true; m_cacheZoomLevel = zoomLevel; } @@ -953,7 +959,7 @@ } QString -WaveformLayer::getFeatureDescription(View *v, QPoint &pos) const +WaveformLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const { int x = pos.x(); @@ -1036,7 +1042,7 @@ } int -WaveformLayer::getYForValue(const View *v, double value, int channel) const +WaveformLayer::getYForValue(const LayerGeometryProvider *v, double value, int channel) const { int channels = 0, minChannel = 0, maxChannel = 0; bool mergingChannels = false, mixingChannels = false; @@ -1046,7 +1052,7 @@ if (channels == 0) return 0; if (maxChannel < minChannel || channel < minChannel) return 0; - int h = v->height(); + int h = v->getPaintHeight(); int m = (h / channels) / 2; if ((m_scale == dBScale || m_scale == MeterScale) && @@ -1079,7 +1085,7 @@ } double -WaveformLayer::getValueForY(const View *v, int y, int &channel) const +WaveformLayer::getValueForY(const LayerGeometryProvider *v, int y, int &channel) const { int channels = 0, minChannel = 0, maxChannel = 0; bool mergingChannels = false, mixingChannels = false; @@ -1089,7 +1095,7 @@ if (channels == 0) return 0; if (maxChannel < minChannel) return 0; - int h = v->height(); + int h = v->getPaintHeight(); int m = (h / channels) / 2; if ((m_scale == dBScale || m_scale == MeterScale) && @@ -1125,7 +1131,7 @@ } bool -WaveformLayer::getYScaleValue(const View *v, int y, +WaveformLayer::getYScaleValue(const LayerGeometryProvider *v, int y, double &value, QString &unit) const { int channel; @@ -1151,7 +1157,7 @@ } bool -WaveformLayer::getYScaleDifference(const View *v, int y0, int y1, +WaveformLayer::getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1, double &diff, QString &unit) const { int c0, c1; @@ -1189,7 +1195,7 @@ } int -WaveformLayer::getVerticalScaleWidth(View *, bool, QPainter &paint) const +WaveformLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const { if (m_scale == LinearScale) { return paint.fontMetrics().width("0.0") + 13; @@ -1200,7 +1206,7 @@ } void -WaveformLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const +WaveformLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const { if (!m_model || !m_model->isOK()) { return;
--- a/layer/WaveformLayer.h Mon Jun 15 09:15:55 2015 +0100 +++ b/layer/WaveformLayer.h Wed Mar 02 17:25:27 2016 +0000 @@ -38,16 +38,16 @@ return m_model ? m_model->getZoomConstraint() : 0; } virtual const Model *getModel() const { return m_model; } - virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; - virtual QString getFeatureDescription(View *v, QPoint &) const; + virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const; virtual ColourSignificance getLayerColourSignificance() const { return ColourAndBackgroundSignificant; } - virtual int getVerticalScaleWidth(View *v, bool detailed, QPainter &) const; - virtual void paintVerticalScale(View *v, bool detailed, QPainter &paint, QRect rect) const; + virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool detailed, QPainter &) const; + virtual void paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const; void setModel(const RangeSummarisableTimeValueModel *model); @@ -180,17 +180,17 @@ void setAggressiveCacheing(bool); bool getAggressiveCacheing() const { return m_aggressive; } - virtual bool isLayerScrollable(const View *) const; + virtual bool isLayerScrollable(const LayerGeometryProvider *) const; - virtual int getCompletion(View *) const; + virtual int getCompletion(LayerGeometryProvider *) const; virtual bool getValueExtents(double &min, double &max, bool &log, QString &unit) const; - virtual bool getYScaleValue(const View *v, int y, + virtual bool getYScaleValue(const LayerGeometryProvider *v, int y, double &value, QString &unit) const; - virtual bool getYScaleDifference(const View *v, int y0, int y1, + virtual bool getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1, double &diff, QString &unit) const; virtual void toXml(QTextStream &stream, QString indent = "", @@ -213,14 +213,14 @@ int getChannelArrangement(int &min, int &max, bool &merging, bool &mixing) const; - int getYForValue(const View *v, double value, int channel) const; + int getYForValue(const LayerGeometryProvider *v, double value, int channel) const; - double getValueForY(const View *v, int y, int &channel) const; + double getValueForY(const LayerGeometryProvider *v, int y, int &channel) const; - bool getSourceFramesForX(View *v, int x, int modelZoomLevel, + bool getSourceFramesForX(LayerGeometryProvider *v, int x, int modelZoomLevel, sv_frame_t &f0, sv_frame_t &f1) const; - float getNormalizeGain(View *v, int channel) const; + float getNormalizeGain(LayerGeometryProvider *v, int channel) const; virtual void flagBaseColourChanged() { m_cacheValid = false; }
--- a/svgui.pro Mon Jun 15 09:15:55 2015 +0100 +++ b/svgui.pro Wed Mar 02 17:25:27 2016 +0000 @@ -26,7 +26,7 @@ } CONFIG += staticlib qt thread warn_on stl rtti exceptions c++11 -QT += network xml gui widgets +QT += network xml gui widgets svg TARGET = svgui @@ -52,6 +52,7 @@ layer/PaintAssistant.h \ layer/PianoScale.h \ layer/RegionLayer.h \ + layer/ScrollableImageCache.h \ layer/SingleColourLayer.h \ layer/SliceableLayer.h \ layer/SliceLayer.h \ @@ -79,6 +80,7 @@ layer/PaintAssistant.cpp \ layer/PianoScale.cpp \ layer/RegionLayer.cpp \ + layer/ScrollableImageCache.cpp \ layer/SingleColourLayer.cpp \ layer/SliceLayer.cpp \ layer/SpectrogramLayer.cpp \ @@ -94,7 +96,9 @@ view/Pane.h \ view/PaneStack.h \ view/View.h \ - view/ViewManager.h + view/ViewManager.h \ + view/ViewProxy.h + SOURCES += view/AlignmentView.cpp \ view/Overview.cpp \ view/Pane.cpp \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/view/LayerGeometryProvider.h Wed Mar 02 17:25:27 2016 +0000 @@ -0,0 +1,174 @@ +/* -*- 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 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 LAYER_GEOMETRY_PROVIDER_H +#define LAYER_GEOMETRY_PROVIDER_H + +#include "base/BaseTypes.h" + +#include <QMutex> +#include <QMutexLocker> +#include <QPainter> + +class ViewManager; +class View; +class Layer; + +class LayerGeometryProvider +{ +protected: + static int getNextId() { + static QMutex idMutex; + static int nextId = 1; + static int maxId = INT_MAX; + QMutexLocker locker(&idMutex); + int id = nextId; + if (nextId == maxId) { + // we don't expect this to happen in the lifetime of a + // process, but it would be undefined behaviour if it did + // since we're using a signed int, so we should really + // guard for it... + nextId = 1; + } else { + nextId++; + } + return id; + } + +public: + LayerGeometryProvider() { } + + /** + * Retrieve the id of this object. + */ + virtual int getId() const = 0; + + /** + * Retrieve the first visible sample frame on the widget. + * This is a calculated value based on the centre-frame, widget + * width and zoom level. The result may be negative. + */ + virtual sv_frame_t getStartFrame() const = 0; + + /** + * Return the centre frame of the visible widget. This is an + * exact value that does not depend on the zoom block size. Other + * frame values (start, end) are calculated from this based on the + * zoom and other factors. + */ + virtual sv_frame_t getCentreFrame() const = 0; + + /** + * Retrieve the last visible sample frame on the widget. + * This is a calculated value based on the centre-frame, widget + * width and zoom level. + */ + virtual sv_frame_t getEndFrame() const = 0; + + /** + * Return the pixel x-coordinate corresponding to a given sample + * frame (which may be negative). + */ + virtual int getXForFrame(sv_frame_t frame) const = 0; + + /** + * Return the closest frame to the given pixel x-coordinate. + */ + virtual sv_frame_t getFrameForX(int x) const = 0; + + virtual sv_frame_t getModelsStartFrame() const = 0; + virtual sv_frame_t getModelsEndFrame() const = 0; + + /** + * Return the closest pixel x-coordinate corresponding to a given + * view x-coordinate. + */ + virtual int getXForViewX(int viewx) const = 0; + + /** + * Return the closest view x-coordinate corresponding to a given + * pixel x-coordinate. + */ + virtual int getViewXForX(int x) const = 0; + + /** + * Return the pixel y-coordinate corresponding to a given + * frequency, if the frequency range is as specified. This does + * not imply any policy about layer frequency ranges, but it might + * be useful for layers to match theirs up if desired. + * + * Not thread-safe in logarithmic mode. Call only from GUI thread. + */ + virtual double getYForFrequency(double frequency, double minFreq, double maxFreq, + bool logarithmic) const = 0; + + /** + * Return the closest frequency to the given pixel y-coordinate, + * if the frequency range is as specified. + * + * Not thread-safe in logarithmic mode. Call only from GUI thread. + */ + virtual double getFrequencyForY(int y, double minFreq, double maxFreq, + bool logarithmic) const = 0; + + virtual int getTextLabelHeight(const Layer *layer, QPainter &) const = 0; + + virtual bool getValueExtents(QString unit, double &min, double &max, + bool &log) const = 0; + + /** + * Return the zoom level, i.e. the number of frames per pixel + */ + virtual int getZoomLevel() const = 0; + + /** + * To be called from a layer, to obtain the extent of the surface + * that the layer is currently painting to. This may be the extent + * of the view (if 1x display scaling is in effect) or of a larger + * cached pixmap (if greater display scaling is in effect). + */ + virtual QRect getPaintRect() const = 0; + + virtual QSize getPaintSize() const { return getPaintRect().size(); } + virtual int getPaintWidth() const { return getPaintRect().width(); } + virtual int getPaintHeight() const { return getPaintRect().height(); } + + virtual bool hasLightBackground() const = 0; + virtual QColor getForeground() const = 0; + virtual QColor getBackground() const = 0; + + virtual ViewManager *getViewManager() const = 0; + + virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const = 0; + virtual bool shouldShowFeatureLabels() const = 0; + + enum TextStyle { + BoxedText, + OutlinedText, + OutlinedItalicText + }; + + virtual void drawVisibleText(QPainter &p, int x, int y, + QString text, TextStyle style) const = 0; + + virtual void drawMeasurementRect(QPainter &p, const Layer *, + QRect rect, bool focus) const = 0; + + virtual void updatePaintRect(QRect r) = 0; + + virtual View *getView() = 0; + virtual const View *getView() const = 0; +}; + +#endif
--- a/view/View.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/view/View.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -20,6 +20,7 @@ #include "base/Profiler.h" #include "base/Pitch.h" #include "base/Preferences.h" +#include "ViewProxy.h" #include "layer/TimeRulerLayer.h" #include "layer/SingleColourLayer.h" @@ -37,6 +38,7 @@ #include <QFont> #include <QMessageBox> #include <QPushButton> +#include <QSettings> #include <iostream> #include <cassert> @@ -47,9 +49,9 @@ //#define DEBUG_VIEW 1 //#define DEBUG_VIEW_WIDGET_PAINT 1 - View::View(QWidget *w, bool showProgress) : QFrame(w), + m_id(getNextId()), m_centreFrame(0), m_zoomLevel(1024), m_followPan(true), @@ -59,6 +61,7 @@ m_playPointerFrame(0), m_showProgress(showProgress), m_cache(0), + m_buffer(0), m_cacheCentreFrame(0), m_cacheZoomLevel(1024), m_selectionCached(false), @@ -362,15 +365,17 @@ sv_frame_t View::getFrameForX(int x) const { - int z = m_zoomLevel; + sv_frame_t z = m_zoomLevel; // nb not just int, or multiplication may overflow sv_frame_t frame = m_centreFrame - (width()/2) * z; + frame = (frame / z) * z; // this is start frame + frame = frame + x * z; + #ifdef DEBUG_VIEW_WIDGET_PAINT - SVDEBUG << "View::getFrameForX(" << x << "): z = " << z << ", m_centreFrame = " << m_centreFrame << ", width() = " << width() << ", frame = " << frame << endl; + cerr << "View::getFrameForX(" << x << "): z = " << z << ", m_centreFrame = " << m_centreFrame << ", width() = " << width() << ", frame = " << frame << endl; #endif - frame = (frame / z) * z; // this is start frame - return frame + x * z; + return frame; } double @@ -448,9 +453,30 @@ return m_zoomLevel; } +int +View::effectiveDevicePixelRatio() const +{ +#ifdef Q_OS_MAC + int dpratio = devicePixelRatio(); + if (dpratio > 1) { + QSettings settings; + settings.beginGroup("Preferences"); + if (!settings.value("scaledHiDpi", true).toBool()) { + dpratio = 1; + } + settings.endGroup(); + } + return dpratio; +#else + return 1; +#endif +} + void View::setZoomLevel(int z) { + int dpratio = effectiveDevicePixelRatio(); + if (z < dpratio) return; if (z < 1) z = 1; if (m_zoomLevel != int(z)) { m_zoomLevel = z; @@ -1027,7 +1053,7 @@ f = getAlignedPlaybackFrame(); #ifdef DEBUG_VIEW - cerr << " -> aligned frame = " << af << endl; + cerr << " -> aligned frame = " << f << endl; #endif movePlayPointer(f); @@ -1653,11 +1679,27 @@ void View::setPaintFont(QPainter &paint) { + int scaleFactor = 1; + int dpratio = effectiveDevicePixelRatio(); + if (dpratio > 1) { + QPaintDevice *dev = paint.device(); + if (dynamic_cast<QPixmap *>(dev) || dynamic_cast<QImage *>(dev)) { + scaleFactor = dpratio; + } + } + QFont font(paint.font()); - font.setPointSize(Preferences::getInstance()->getViewFontSize()); + font.setPointSize(Preferences::getInstance()->getViewFontSize() + * scaleFactor); paint.setFont(font); } +QRect +View::getPaintRect() const +{ + return rect(); +} + void View::paintEvent(QPaintEvent *e) { @@ -1694,6 +1736,8 @@ QRect nonCacheRect(cacheRect); + int dpratio = effectiveDevicePixelRatio(); + // If not all layers are scrollable, but some of the back layers // are, we should store only those in the cache. @@ -1705,25 +1749,34 @@ // If all the non-scrollable layers are non-opaque, then we draw // the selection rectangle behind them and cache it. If any are - // opaque, however, we can't cache. + // opaque, however, or if our device-pixel ratio is not 1 (so we + // need to paint direct to the widget), then we can't cache. // - if (!selectionCacheable) { - selectionCacheable = true; - for (LayerList::const_iterator i = nonScrollables.begin(); - i != nonScrollables.end(); ++i) { - if ((*i)->isLayerOpaque()) { - selectionCacheable = false; - break; - } - } - } - - if (selectionCacheable) { - QPoint localPos; - bool closeToLeft, closeToRight; - if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) { - selectionCacheable = false; - } + if (dpratio == 1) { + + if (!selectionCacheable) { + selectionCacheable = true; + for (LayerList::const_iterator i = nonScrollables.begin(); + i != nonScrollables.end(); ++i) { + if ((*i)->isLayerOpaque()) { + selectionCacheable = false; + break; + } + } + } + + if (selectionCacheable) { + QPoint localPos; + bool closeToLeft, closeToRight; + if (shouldIlluminateLocalSelection + (localPos, closeToLeft, closeToRight)) { + selectionCacheable = false; + } + } + + } else { + + selectionCacheable = false; } #ifdef DEBUG_VIEW_WIDGET_PAINT @@ -1741,6 +1794,14 @@ m_selectionCached = false; } + QSize scaledCacheSize(scaledSize(size(), dpratio)); + QRect scaledCacheRect(scaledRect(cacheRect, dpratio)); + + if (!m_buffer || scaledCacheSize != m_buffer->size()) { + delete m_buffer; + m_buffer = new QPixmap(scaledCacheSize); + } + if (!scrollables.empty()) { #ifdef DEBUG_VIEW_WIDGET_PAINT @@ -1750,8 +1811,7 @@ if (!m_cache || m_cacheZoomLevel != m_zoomLevel || - width() != m_cache->width() || - height() != m_cache->height()) { + scaledCacheSize != m_cache->size()) { // cache is not valid @@ -1763,7 +1823,7 @@ #endif } else { delete m_cache; - m_cache = new QPixmap(width(), height()); + m_cache = new QPixmap(scaledCacheSize); #ifdef DEBUG_VIEW_WIDGET_PAINT cerr << "View(" << this << ")::paintEvent: recreated cache" << endl; #endif @@ -1778,24 +1838,10 @@ getXForFrame(m_centreFrame); if (dx > -width() && dx < width()) { -#ifdef PIXMAP_COPY_TO_SELF - // This is not normally defined. Copying a pixmap to - // itself doesn't work properly on Windows, Mac, or - // X11 with the raster backend (it only works when - // moving in one direction and then presumably only by - // accident). It does actually seem to be fine on X11 - // with the native backend, but we prefer not to use - // that anyway - paint.begin(m_cache); - paint.drawPixmap(dx, 0, *m_cache); - paint.end(); -#else static QPixmap *tmpPixmap = 0; - if (!tmpPixmap || - tmpPixmap->width() != width() || - tmpPixmap->height() != height()) { + if (!tmpPixmap || tmpPixmap->size() != scaledCacheSize) { delete tmpPixmap; - tmpPixmap = new QPixmap(width(), height()); + tmpPixmap = new QPixmap(scaledCacheSize); } paint.begin(tmpPixmap); paint.drawPixmap(0, 0, *m_cache); @@ -1803,7 +1849,6 @@ paint.begin(m_cache); paint.drawPixmap(dx, 0, *tmpPixmap); paint.end(); -#endif if (dx < 0) { cacheRect = QRect(width() + dx, 0, -dx, height()); } else { @@ -1824,8 +1869,8 @@ #ifdef DEBUG_VIEW_WIDGET_PAINT cerr << "View(" << this << ")::paintEvent: cache is good" << endl; #endif - paint.begin(this); - paint.drawPixmap(cacheRect, *m_cache, cacheRect); + paint.begin(m_buffer); + paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect); paint.end(); QFrame::paintEvent(e); paintedCacheRect = true; @@ -1841,16 +1886,26 @@ // Scrollable (cacheable) items first + ViewProxy proxy(this, dpratio); + if (!paintedCacheRect) { - if (repaintCache) paint.begin(m_cache); - else paint.begin(this); + QRect rectToPaint; + + if (repaintCache) { + paint.begin(m_cache); + rectToPaint = scaledCacheRect; + } else { + paint.begin(m_buffer); + rectToPaint = scaledCacheRect; + } + setPaintFont(paint); - paint.setClipRect(cacheRect); + paint.setClipRect(rectToPaint); paint.setPen(getBackground()); paint.setBrush(getBackground()); - paint.drawRect(cacheRect); + paint.drawRect(rectToPaint); paint.setPen(getForeground()); paint.setBrush(Qt::NoBrush); @@ -1858,7 +1913,10 @@ for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) { paint.setRenderHint(QPainter::Antialiasing, false); paint.save(); - (*i)->paint(this, paint, cacheRect); +#ifdef DEBUG_VIEW_WIDGET_PAINT + cerr << "Painting scrollable layer " << *i << " using proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << rectToPaint.x() << "," << rectToPaint.y() << " " << rectToPaint.width() << "x" << rectToPaint.height() << endl; +#endif + (*i)->paint(&proxy, paint, rectToPaint); paint.restore(); } @@ -1871,8 +1929,9 @@ if (repaintCache) { cacheRect |= (e ? e->rect() : rect()); - paint.begin(this); - paint.drawPixmap(cacheRect, *m_cache, cacheRect); + scaledCacheRect = scaledRect(cacheRect, dpratio); + paint.begin(m_buffer); + paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect); paint.end(); } } @@ -1883,13 +1942,15 @@ nonCacheRect |= cacheRect; - paint.begin(this); - paint.setClipRect(nonCacheRect); + QRect scaledNonCacheRect = scaledRect(nonCacheRect, dpratio); + + paint.begin(m_buffer); + paint.setClipRect(scaledNonCacheRect); setPaintFont(paint); if (scrollables.empty()) { paint.setPen(getBackground()); paint.setBrush(getBackground()); - paint.drawRect(nonCacheRect); + paint.drawRect(scaledNonCacheRect); } paint.setPen(getForeground()); @@ -1897,10 +1958,18 @@ for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) { // Profiler profiler2("View::paintEvent non-cacheable"); - (*i)->paint(this, paint, nonCacheRect); +#ifdef DEBUG_VIEW_WIDGET_PAINT + cerr << "Painting non-scrollable layer " << *i << " without proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << nonCacheRect.x() << "," << nonCacheRect.y() << " " << nonCacheRect.width() << "x" << nonCacheRect.height() << endl; +#endif + (*i)->paint(&proxy, paint, scaledNonCacheRect); } paint.end(); + + paint.begin(this); + QRect finalPaintRect = e ? e->rect() : rect(); + paint.drawPixmap(finalPaintRect, *m_buffer, scaledRect(finalPaintRect, dpratio)); + paint.end(); paint.begin(this); setPaintFont(paint); @@ -1925,7 +1994,7 @@ showPlayPointer = false; } } - + if (showPlayPointer) { paint.begin(this); @@ -2412,23 +2481,23 @@ for (LayerList::iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) { - if(!((*i)->isLayerDormant(this))){ - - paint.setRenderHint(QPainter::Antialiasing, false); - - paint.save(); - paint.translate(xorigin + x, 0); - - cerr << "Centre frame now: " << m_centreFrame << " drawing to " << chunk.x() + x + xorigin << ", " << chunk.width() << endl; - - (*i)->setSynchronousPainting(true); - - (*i)->paint(this, paint, chunk); - - (*i)->setSynchronousPainting(false); - - paint.restore(); - } + if (!((*i)->isLayerDormant(this))){ + + paint.setRenderHint(QPainter::Antialiasing, false); + + paint.save(); + paint.translate(xorigin + x, 0); + + cerr << "Centre frame now: " << m_centreFrame << " drawing to " << chunk.x() + x + xorigin << ", " << chunk.width() << endl; + + (*i)->setSynchronousPainting(true); + + (*i)->paint(this, paint, chunk); + + (*i)->setSynchronousPainting(false); + + paint.restore(); + } } }
--- a/view/View.h Mon Jun 15 09:15:55 2015 +0100 +++ b/view/View.h Wed Mar 02 17:25:27 2016 +0000 @@ -19,6 +19,8 @@ #include <QFrame> #include <QProgressBar> +#include "LayerGeometryProvider.h" + #include "base/ZoomConstraint.h" #include "base/PropertyContainer.h" #include "ViewManager.h" @@ -49,7 +51,8 @@ */ class View : public QFrame, - public XmlExportable + public XmlExportable, + public LayerGeometryProvider { Q_OBJECT @@ -61,6 +64,12 @@ virtual ~View(); /** + * Retrieve the id of this object. Views have their own unique + * ids, but ViewProxy objects share the id of their View. + */ + int getId() const { return m_id; } + + /** * Retrieve the first visible sample frame on the widget. * This is a calculated value based on the centre-frame, widget * width and zoom level. The result may be negative. @@ -105,6 +114,20 @@ sv_frame_t getFrameForX(int x) const; /** + * Return the closest pixel x-coordinate corresponding to a given + * view x-coordinate. Default is no scaling, ViewProxy handles + * scaling case. + */ + int getXForViewX(int viewx) const { return viewx; } + + /** + * Return the closest view x-coordinate corresponding to a given + * pixel x-coordinate. Default is no scaling, ViewProxy handles + * scaling case. + */ + int getViewXForX(int x) const { return x; } + + /** * Return the pixel y-coordinate corresponding to a given * frequency, if the frequency range is as specified. This does * not imply any policy about layer frequency ranges, but it might @@ -243,12 +266,6 @@ virtual QColor getForeground() const; virtual QColor getBackground() const; - enum TextStyle { - BoxedText, - OutlinedText, - OutlinedItalicText - }; - virtual void drawVisibleText(QPainter &p, int x, int y, QString text, TextStyle style) const; @@ -315,6 +332,18 @@ sv_frame_t getModelsStartFrame() const; sv_frame_t getModelsEndFrame() const; + /** + * To be called from a layer, to obtain the extent of the surface + * that the layer is currently painting to. This may be the extent + * of the view (if 1x display scaling is in effect) or of a larger + * cached pixmap (if greater display scaling is in effect). + */ + QRect getPaintRect() const; + + QSize getPaintSize() const { return getPaintRect().size(); } + int getPaintWidth() const { return getPaintRect().width(); } + int getPaintHeight() const { return getPaintRect().height(); } + typedef std::set<Model *> ModelSet; ModelSet getModels(); @@ -324,6 +353,11 @@ sv_frame_t alignToReference(sv_frame_t) const; sv_frame_t getAlignedPlaybackFrame() const; + void updatePaintRect(QRect r) { update(r); } + + View *getView() { return this; } + const View *getView() const { return this; } + signals: void propertyContainerAdded(PropertyContainer *pc); void propertyContainerRemoved(PropertyContainer *pc); @@ -372,11 +406,22 @@ protected: View(QWidget *, bool showProgress); + + int m_id; + virtual void paintEvent(QPaintEvent *e); virtual void drawSelections(QPainter &); virtual bool shouldLabelSelections() const { return true; } virtual bool render(QPainter &paint, int x0, sv_frame_t f0, sv_frame_t f1); virtual void setPaintFont(QPainter &paint); + + QSize scaledSize(const QSize &s, int factor) { + return QSize(s.width() * factor, s.height() * factor); + } + QRect scaledRect(const QRect &r, int factor) { + return QRect(r.x() * factor, r.y() * factor, + r.width() * factor, r.height() * factor); + } typedef std::vector<Layer *> LayerList; @@ -406,6 +451,8 @@ void checkProgress(void *object); int getProgressBarWidth() const; // if visible + int effectiveDevicePixelRatio() const; + sv_frame_t m_centreFrame; int m_zoomLevel; bool m_followPan; @@ -417,6 +464,7 @@ bool m_showProgress; QPixmap *m_cache; + QPixmap *m_buffer; sv_frame_t m_cacheCentreFrame; int m_cacheZoomLevel; bool m_selectionCached;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/view/ViewProxy.h Wed Mar 02 17:25:27 2016 +0000 @@ -0,0 +1,156 @@ +/* -*- 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 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 VIEW_PROXY_H +#define VIEW_PROXY_H + +#include "LayerGeometryProvider.h" + +class ViewProxy : public LayerGeometryProvider +{ +public: + ViewProxy(View *view, int scaleFactor) : + m_view(view), m_scaleFactor(scaleFactor) { } + + virtual int getId() const { + return m_view->getId(); + } + virtual sv_frame_t getStartFrame() const { + return m_view->getStartFrame(); + } + virtual sv_frame_t getCentreFrame() const { + return m_view->getCentreFrame(); + } + virtual sv_frame_t getEndFrame() const { + return m_view->getEndFrame(); + } + virtual int getXForFrame(sv_frame_t frame) const { + //!!! not actually correct, if frame lies between view's pixels + return m_scaleFactor * m_view->getXForFrame(frame); + } + virtual sv_frame_t getFrameForX(int x) const { + sv_frame_t f0 = m_view->getFrameForX(x / m_scaleFactor); + if (m_scaleFactor == 1) return f0; + sv_frame_t f1 = m_view->getFrameForX((x / m_scaleFactor) + 1); + return f0 + ((f1 - f0) * (x % m_scaleFactor)) / m_scaleFactor; + } + virtual int getXForViewX(int viewx) const { + return viewx * m_scaleFactor; + } + virtual int getViewXForX(int x) const { + return x / m_scaleFactor; + } + virtual sv_frame_t getModelsStartFrame() const { + return m_view->getModelsStartFrame(); + } + virtual sv_frame_t getModelsEndFrame() const { + return m_view->getModelsEndFrame(); + } + virtual double getYForFrequency(double frequency, + double minFreq, double maxFreq, + bool logarithmic) const { + return m_scaleFactor * + m_view->getYForFrequency(frequency, minFreq, maxFreq, logarithmic); + } + virtual double getFrequencyForY(int y, double minFreq, double maxFreq, + bool logarithmic) const { + double f0 = m_view->getFrequencyForY + (y / m_scaleFactor, minFreq, maxFreq, logarithmic); + if (m_scaleFactor == 1) return f0; + double f1 = m_view->getFrequencyForY + ((y / m_scaleFactor) + 1, minFreq, maxFreq, logarithmic); + return f0 + ((f1 - f0) * (y % m_scaleFactor)) / m_scaleFactor; + } + virtual int getTextLabelHeight(const Layer *layer, QPainter &paint) const { + return m_scaleFactor * m_view->getTextLabelHeight(layer, paint); + } + virtual bool getValueExtents(QString unit, double &min, double &max, + bool &log) const { + return m_view->getValueExtents(unit, min, max, log); + } + virtual int getZoomLevel() const { + int z = m_view->getZoomLevel(); +// cerr << "getZoomLevel: from " << z << " to "; + z = z / m_scaleFactor; +// cerr << z << endl; + if (z < 1) z = 1; + return z; + } + virtual QRect getPaintRect() const { + QRect r = m_view->getPaintRect(); + return QRect(r.x() * m_scaleFactor, + r.y() * m_scaleFactor, + r.width() * m_scaleFactor, + r.height() * m_scaleFactor); + } + virtual QSize getPaintSize() const { + return getPaintRect().size(); + } + virtual int getPaintWidth() const { + return getPaintRect().width(); + } + virtual int getPaintHeight() const { + return getPaintRect().height(); + } + virtual bool hasLightBackground() const { + return m_view->hasLightBackground(); + } + virtual QColor getForeground() const { + return m_view->getForeground(); + } + virtual QColor getBackground() const { + return m_view->getBackground(); + } + virtual ViewManager *getViewManager() const { + return m_view->getViewManager(); + } + + virtual bool shouldIlluminateLocalFeatures(const Layer *layer, + QPoint &point) const { + QPoint p; + bool should = m_view->shouldIlluminateLocalFeatures(layer, p); + point = QPoint(p.x() * m_scaleFactor, p.y() * m_scaleFactor); + return should; + } + + virtual bool shouldShowFeatureLabels() const { + return m_view->shouldShowFeatureLabels(); + } + + virtual void drawVisibleText(QPainter &p, int x, int y, + QString text, TextStyle style) const { + m_view->drawVisibleText(p, x, y, text, style); + } + + virtual void drawMeasurementRect(QPainter &p, const Layer *layer, + QRect rect, bool focus) const { + m_view->drawMeasurementRect(p, layer, rect, focus); + } + + virtual void updatePaintRect(QRect r) { + m_view->update(r.x() / m_scaleFactor, + r.y() / m_scaleFactor, + r.width() / m_scaleFactor, + r.height() / m_scaleFactor); + } + + virtual View *getView() { return m_view; } + virtual const View *getView() const { return m_view; } + +private: + View *m_view; + int m_scaleFactor; +}; + +#endif
--- a/widgets/CSVFormatDialog.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/widgets/CSVFormatDialog.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -254,8 +254,12 @@ { // First check if we already have any. NB there may be fewer than // m_format.getColumnCount() elements in m_columnPurposeCombos - // (because of the fuzzy column behaviour) + // (because of the fuzzy column behaviour). Note also that the + // fuzzy column (which is the one just showing how many more + // columns there are) has a different combo with only two items + // (ignore or Values) for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { + if (i == m_fuzzyColumn) continue; QComboBox *cb = m_columnPurposeCombos[i]; if (cb->currentIndex() == int(CSVFormat::ColumnStartTime)) { return; @@ -263,6 +267,7 @@ } // and if not, select one for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { + if (i == m_fuzzyColumn) continue; QComboBox *cb = m_columnPurposeCombos[i]; if (cb->currentIndex() == int(CSVFormat::ColumnValue)) { cb->setCurrentIndex(int(CSVFormat::ColumnStartTime)); @@ -278,6 +283,7 @@ // in m_columnPurposeCombos (because of the fuzzy column // behaviour) for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { + if (i == m_fuzzyColumn) continue; QComboBox *cb = m_columnPurposeCombos[i]; if (cb->currentIndex() == int(CSVFormat::ColumnStartTime)) { cb->setCurrentIndex(int(CSVFormat::ColumnValue)); @@ -345,6 +351,11 @@ for (int i = 0; i < m_columnPurposeCombos.size(); ++i) { + // The fuzzy column combo only has the entries <ignore> or + // Values, so it can't affect the timing type and none of this + // logic affects it + if (i == m_fuzzyColumn) continue; + QComboBox *thisCombo = m_columnPurposeCombos[i]; CSVFormat::ColumnPurpose cp = (CSVFormat::ColumnPurpose) @@ -353,8 +364,6 @@ if (!thisChanged) { - if (i == m_fuzzyColumn) continue; - // We can only have one ColumnStartTime column, and only // one of either ColumnDuration or ColumnEndTime @@ -442,24 +451,8 @@ CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose) (thisCombo->currentIndex()); - if (purpose == CSVFormat::ColumnStartTime) { - haveStartTime = true; - } - if (purpose == CSVFormat::ColumnEndTime || - purpose == CSVFormat::ColumnDuration) { - haveDuration = true; - } - if (purpose == CSVFormat::ColumnPitch) { - havePitch = true; - } - if (purpose == CSVFormat::ColumnValue) { - ++valueCount; - } - - m_format.setColumnPurpose(i, purpose); - if (i == m_fuzzyColumn) { - for (int j = i + 1; j < m_format.getColumnCount(); ++j) { + for (int j = i; j < m_format.getColumnCount(); ++j) { if (purpose == CSVFormat::ColumnUnknown) { m_format.setColumnPurpose(j, CSVFormat::ColumnUnknown); } else { // Value @@ -467,6 +460,23 @@ ++valueCount; } } + } else { + + if (purpose == CSVFormat::ColumnStartTime) { + haveStartTime = true; + } + if (purpose == CSVFormat::ColumnEndTime || + purpose == CSVFormat::ColumnDuration) { + haveDuration = true; + } + if (purpose == CSVFormat::ColumnPitch) { + havePitch = true; + } + if (purpose == CSVFormat::ColumnValue) { + ++valueCount; + } + + m_format.setColumnPurpose(i, purpose); } }
--- a/widgets/CommandHistory.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/widgets/CommandHistory.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -26,6 +26,8 @@ #include "base/Command.h" +#include "IconLoader.h" + #include <QRegExp> #include <QMenu> #include <QToolBar> @@ -53,12 +55,16 @@ m_bundleTimer(0), m_bundleTimeout(3000) { - m_undoAction = new QAction(QIcon(":/icons/undo.png"), tr("&Undo"), this); + IconLoader loader; + QIcon undoIcon(loader.load("undo")); + QIcon redoIcon(loader.load("redo")); + + m_undoAction = new QAction(undoIcon, ("&Undo"), this); m_undoAction->setShortcut(tr("Ctrl+Z")); m_undoAction->setStatusTip(tr("Undo the last editing operation")); connect(m_undoAction, SIGNAL(triggered()), this, SLOT(undo())); - m_undoMenuAction = new QAction(QIcon(":/icons/undo.png"), tr("&Undo"), this); + m_undoMenuAction = new QAction(undoIcon, tr("&Undo"), this); connect(m_undoMenuAction, SIGNAL(triggered()), this, SLOT(undo())); m_undoMenu = new QMenu(tr("&Undo")); @@ -66,12 +72,12 @@ connect(m_undoMenu, SIGNAL(triggered(QAction *)), this, SLOT(undoActivated(QAction*))); - m_redoAction = new QAction(QIcon(":/icons/redo.png"), tr("Re&do"), this); + m_redoAction = new QAction(redoIcon, tr("Re&do"), this); m_redoAction->setShortcut(tr("Ctrl+Shift+Z")); m_redoAction->setStatusTip(tr("Redo the last operation that was undone")); connect(m_redoAction, SIGNAL(triggered()), this, SLOT(redo())); - m_redoMenuAction = new QAction(QIcon(":/icons/redo.png"), tr("Re&do"), this); + m_redoMenuAction = new QAction(redoIcon, tr("Re&do"), this); connect(m_redoMenuAction, SIGNAL(triggered()), this, SLOT(redo())); m_redoMenu = new QMenu(tr("Re&do"));
--- a/widgets/IconLoader.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/widgets/IconLoader.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -19,8 +19,17 @@ #include <QApplication> #include <QPainter> #include <QPalette> +#include <QFile> +#include <QSvgRenderer> -static const char *autoInvertExceptions[] = { +#include <vector> +#include <set> + +#include "base/Debug.h" + +using namespace std; + +static set<QString> autoInvertExceptions { // These are the icons that look OK in their default colours, even // in a colour scheme with a black background. (They may also be // icons that would look worse if we tried to auto-invert them.) @@ -29,16 +38,13 @@ // supply inverted versions -- the loader will load xx_inverse.png // in preference to xx.png if a dark background is found.) "fileclose", - "filenew-22", "filenew", - "fileopen-22", "fileopen", "fileopenaudio", "fileopensession", - "filesave-22", "filesave", - "filesaveas-22", "filesaveas", + "filesaveas-sv", "help", "editcut", "editcopy", @@ -51,42 +57,121 @@ "zoom" }; +static vector<int> sizes { 0, 16, 22, 24, 32, 48, 64, 128 }; + QIcon IconLoader::load(QString name) { - QPixmap pmap(loadPixmap(name)); - if (pmap.isNull()) return QIcon(); - else return QIcon(pmap); + QIcon icon; + for (int sz: sizes) { + QPixmap pmap(loadPixmap(name, sz)); + if (!pmap.isNull()) icon.addPixmap(pmap); + } + return icon; +} + +bool +IconLoader::shouldInvert() const +{ + QColor bg = QApplication::palette().window().color(); + bool darkBackground = (bg.red() + bg.green() + bg.blue() <= 384); + return darkBackground; +} + +bool +IconLoader::shouldAutoInvert(QString name) const +{ + if (shouldInvert()) { + return (autoInvertExceptions.find(name) == autoInvertExceptions.end()); + } else { + return false; + } } QPixmap -IconLoader::loadPixmap(QString name) +IconLoader::loadPixmap(QString name, int size) { - QColor bg = QApplication::palette().window().color(); - if (bg.red() + bg.green() + bg.blue() > 384) { // light background - QPixmap pmap(QString(":icons/%1").arg(name)); - if (pmap.isNull()) { - pmap = QPixmap(QString(":icons/%1.png").arg(name)); - } - return pmap; + bool invert = shouldInvert(); + + QString scalableName, nonScalableName; + QPixmap pmap; + + nonScalableName = makeNonScalableFilename(name, size, invert); + pmap = QPixmap(nonScalableName); + if (!pmap.isNull()) return pmap; + + if (size > 0) { + scalableName = makeScalableFilename(name, invert); + pmap = loadScalable(scalableName, size); + if (!pmap.isNull()) return pmap; } - QPixmap pmap(QString(":icons/%1").arg(name)); - if (pmap.isNull()) { - pmap = QPixmap(QString(":icons/%1_inverse.png").arg(name)); - if (pmap.isNull()) { - pmap = QPixmap(QString(":icons/%1.png").arg(name)); - } - } - if (pmap.isNull()) return pmap; + if (invert && shouldAutoInvert(name)) { - for (int i = 0; i < int(sizeof(autoInvertExceptions)/ - sizeof(autoInvertExceptions[0])); ++i) { - if (autoInvertExceptions[i] == name) { - return pmap; + nonScalableName = makeNonScalableFilename(name, size, false); + pmap = QPixmap(nonScalableName); + if (!pmap.isNull()) return invertPixmap(pmap); + + if (size > 0) { + scalableName = makeScalableFilename(name, false); + pmap = loadScalable(scalableName, size); + if (!pmap.isNull()) return invertPixmap(pmap); } } + return QPixmap(); +} + +QPixmap +IconLoader::loadScalable(QString name, int size) +{ + if (!QFile(name).exists()) { +// cerr << "loadScalable: no such file as: \"" << name << "\"" << endl; + return QPixmap(); + } + QPixmap pmap(size, size); + pmap.fill(Qt::transparent); + QSvgRenderer renderer(name); + QPainter painter; + painter.begin(&pmap); +// cerr << "calling renderer for " << name << " at size " << size << "..." << endl; + renderer.render(&painter); +// cerr << "renderer completed" << endl; + painter.end(); + return pmap; +} + +QString +IconLoader::makeNonScalableFilename(QString name, int size, bool invert) +{ + if (invert) { + if (size == 0) { + return QString(":icons/%1_inverse.png").arg(name); + } else { + return QString(":icons/%1-%2_inverse.png").arg(name).arg(size); + } + } else { + if (size == 0) { + return QString(":icons/%1.png").arg(name); + } else { + return QString(":icons/%1-%2.png").arg(name).arg(size); + } + } +} + +QString +IconLoader::makeScalableFilename(QString name, bool invert) +{ + if (invert) { + return QString(":icons/scalable/%1_inverse.svg").arg(name); + } else { + return QString(":icons/scalable/%1.svg").arg(name); + } +} + +QPixmap +IconLoader::invertPixmap(QPixmap pmap) +{ // No suitable inverted icon found for black background; try to // auto-invert the default one
--- a/widgets/IconLoader.h Mon Jun 15 09:15:55 2015 +0100 +++ b/widgets/IconLoader.h Wed Mar 02 17:25:27 2016 +0000 @@ -25,7 +25,15 @@ virtual ~IconLoader() { } QIcon load(QString name); - QPixmap loadPixmap(QString name); + +private: + bool shouldInvert() const; + bool shouldAutoInvert(QString) const; + QPixmap loadPixmap(QString, int); + QPixmap loadScalable(QString, int); + QPixmap invertPixmap(QPixmap); + QString makeScalableFilename(QString, bool); + QString makeNonScalableFilename(QString, int, bool); }; #endif
--- a/widgets/LEDButton.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/widgets/LEDButton.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -38,8 +38,6 @@ int dark_factor; QColor offcolor; - QPixmap *off_map; - QPixmap *on_map; }; @@ -51,8 +49,6 @@ d = new LEDButton::LEDButtonPrivate; d->dark_factor = 300; d->offcolor = col.dark(300); - d->off_map = 0; - d->on_map = 0; setColor(col); } @@ -65,8 +61,6 @@ d = new LEDButton::LEDButtonPrivate; d->dark_factor = 300; d->offcolor = col.dark(300); - d->off_map = 0; - d->on_map = 0; setColor(col); } @@ -78,16 +72,12 @@ d = new LEDButton::LEDButtonPrivate; d->dark_factor = 300; d->offcolor = col.dark(300); - d->off_map = 0; - d->on_map = 0; setColor(col); } LEDButton::~LEDButton() { - delete d->off_map; - delete d->on_map; delete d; } @@ -135,40 +125,7 @@ if (width < 0) width = 0; - QPixmap *tmpMap = 0; - - if (led_state) { - if (d->on_map) { - if (d->on_map->size() == size()) { - paint.begin(this); - paint.drawPixmap(0, 0, *d->on_map); - paint.end(); - return; - } else { - delete d->on_map; - d->on_map = 0; - } - } - } else { - if (d->off_map) { - if (d->off_map->size() == size()) { - paint.begin(this); - paint.drawPixmap(0, 0, *d->off_map); - paint.end(); - return; - } else { - delete d->off_map; - d->off_map = 0; - } - } - } - - int scale = 1; - width *= scale; - - tmpMap = new QPixmap(width, width); - tmpMap->fill(palette().background().color()); - paint.begin(tmpMap); + paint.begin(this); paint.setRenderHint(QPainter::Antialiasing, true); @@ -182,14 +139,14 @@ paint.setBrush(brush); // Draws a "flat" LED with the given color: - paint.drawEllipse( scale, scale, width - scale*2, width - scale*2 ); + paint.drawEllipse( 1, 1, width - 2, width - 2 ); // Draw the bright light spot of the LED now, using modified "old" // painter routine taken from KDEUI´s LEDButton widget: // Setting the new width of the pen is essential to avoid "pixelized" // shadow like it can be observed with the old LED code - pen.setWidth( 2 * scale ); + pen.setWidth( 2 ); // shrink the light on the LED to a size about 2/3 of the complete LED int pos = width/5 + 1; @@ -217,12 +174,13 @@ pos++; light_width--; } + paint.drawPoint(pos, pos); + // Drawing of bright spot finished, now draw a thin border // around the LED which resembles a shadow with light coming // from the upper left. -// pen.setWidth( 2 * scale + 1 ); // ### shouldn't this value be smaller for smaller LEDs? - pen.setWidth(2 * scale); + pen.setWidth(2); brush.setStyle(Qt::NoBrush); paint.setBrush(brush); // This avoids filling of the ellipse @@ -235,36 +193,13 @@ for (int arc = 120; arc < 2880; arc += 240) { pen.setColor(color); paint.setPen(pen); - int w = width - pen.width()/2 - scale + 1; + int w = width - pen.width()/2; paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle + arc, 240); paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle - arc, 240); color = color.dark(110); //FIXME: this should somehow use the contrast value } // end for ( angle = 720; angle < 6480; angle += 160 ) paint.end(); - // - // painting done - - QPixmap *&dest = led_state ? d->on_map : d->off_map; - - if (scale > 1) { - - QImage i = tmpMap->toImage(); - width /= scale; - delete tmpMap; - dest = new QPixmap(QPixmap::fromImage - (i.scaled(width, width, - Qt::KeepAspectRatio, - Qt::SmoothTransformation))); - - } else { - - dest = tmpMap; - } - - paint.begin(this); - paint.drawPixmap(0, 0, *dest); - paint.end(); } bool @@ -303,10 +238,6 @@ if(led_color!=col) { led_color = col; d->offcolor = col.dark(d->dark_factor); - delete d->on_map; - d->on_map = 0; - delete d->off_map; - d->off_map = 0; update(); } }
--- a/widgets/PropertyBox.cpp Mon Jun 15 09:15:55 2015 +0100 +++ b/widgets/PropertyBox.cpp Wed Mar 02 17:25:27 2016 +0000 @@ -63,6 +63,12 @@ m_mainBox = new QVBoxLayout; setLayout(m_mainBox); +#ifdef Q_OS_MAC + QMargins mm = m_mainBox->contentsMargins(); + QMargins mmhalf(mm.left()/2, mm.top()/3, mm.right()/2, mm.bottom()/3); + m_mainBox->setContentsMargins(mmhalf); +#endif + // m_nameWidget = new QLabel; // m_mainBox->addWidget(m_nameWidget); // m_nameWidget->setText(container->objectName()); @@ -443,7 +449,16 @@ if (type == PropertyContainer::ValueProperty) { for (int i = min; i <= max; ++i) { - cb->addItem(m_container->getPropertyValueLabel(name, i)); + + QString label = m_container->getPropertyValueLabel(name, i); + QString iname = m_container->getPropertyValueIconName(name, i); + + if (iname != "") { + QIcon icon(IconLoader().load(iname)); + cb->addItem(icon, label); + } else { + cb->addItem(label); + } } } else if (type == PropertyContainer::UnitsProperty) { @@ -512,8 +527,10 @@ cb->blockSignals(false); #ifdef Q_OS_MAC - // Crashes on startup without this, for some reason - cb->setMinimumSize(QSize(10, 10)); + // Crashes on startup without this, for some reason; also + // prevents combo boxes from getting weirdly squished + // vertically + cb->setMinimumSize(QSize(10, cb->font().pixelSize() * 2)); #endif break;