| Chris@58 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@0 | 2 | 
| Chris@0 | 3 /* | 
| Chris@59 | 4     Sonic Visualiser | 
| Chris@59 | 5     An audio file viewer and annotation editor. | 
| Chris@59 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@182 | 7     This file copyright 2006 Chris Cannam and QMUL. | 
| Chris@0 | 8 | 
| Chris@59 | 9     This program is free software; you can redistribute it and/or | 
| Chris@59 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@59 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@59 | 12     License, or (at your option) any later version.  See the file | 
| Chris@59 | 13     COPYING included with this distribution for more information. | 
| Chris@0 | 14 */ | 
| Chris@0 | 15 | 
| Chris@30 | 16 #ifndef _SPECTROGRAM_LAYER_H_ | 
| Chris@30 | 17 #define _SPECTROGRAM_LAYER_H_ | 
| Chris@0 | 18 | 
| Chris@193 | 19 #include "SliceableLayer.h" | 
| Chris@0 | 20 #include "base/Window.h" | 
| Chris@71 | 21 #include "base/RealTime.h" | 
| Chris@92 | 22 #include "base/Thread.h" | 
| Chris@122 | 23 #include "base/PropertyContainer.h" | 
| Chris@128 | 24 #include "data/model/PowerOfSqrtTwoZoomConstraint.h" | 
| Chris@128 | 25 #include "data/model/DenseTimeValueModel.h" | 
| Chris@130 | 26 #include "data/model/FFTModel.h" | 
| Chris@0 | 27 | 
| Chris@0 | 28 #include <QMutex> | 
| Chris@0 | 29 #include <QWaitCondition> | 
| Chris@95 | 30 #include <QImage> | 
| Chris@95 | 31 #include <QPixmap> | 
| Chris@0 | 32 | 
| Chris@0 | 33 class View; | 
| Chris@0 | 34 class QPainter; | 
| Chris@0 | 35 class QImage; | 
| Chris@0 | 36 class QPixmap; | 
| Chris@0 | 37 class QTimer; | 
| Chris@130 | 38 class FFTModel; | 
| Chris@114 | 39 | 
| Chris@0 | 40 | 
| Chris@0 | 41 /** | 
| Chris@0 | 42  * SpectrogramLayer represents waveform data (obtained from a | 
| Chris@0 | 43  * DenseTimeValueModel) in spectrogram form. | 
| Chris@0 | 44  */ | 
| Chris@0 | 45 | 
| Chris@193 | 46 class SpectrogramLayer : public SliceableLayer, | 
| Chris@31 | 47 			 public PowerOfSqrtTwoZoomConstraint | 
| Chris@0 | 48 { | 
| Chris@0 | 49     Q_OBJECT | 
| Chris@0 | 50 | 
| Chris@0 | 51 public: | 
| Chris@37 | 52     enum Configuration { FullRangeDb, MelodicRange, MelodicPeaks }; | 
| Chris@0 | 53 | 
| Chris@44 | 54     SpectrogramLayer(Configuration = FullRangeDb); | 
| Chris@0 | 55     ~SpectrogramLayer(); | 
| Chris@0 | 56 | 
| Chris@0 | 57     virtual const ZoomConstraint *getZoomConstraint() const { return this; } | 
| Chris@0 | 58     virtual const Model *getModel() const { return m_model; } | 
| Chris@44 | 59     virtual void paint(View *v, QPainter &paint, QRect rect) const; | 
| Chris@389 | 60     virtual void setSynchronousPainting(bool synchronous); | 
| Chris@0 | 61 | 
| Chris@44 | 62     virtual int getVerticalScaleWidth(View *v, QPainter &) const; | 
| Chris@44 | 63     virtual void paintVerticalScale(View *v, QPainter &paint, QRect rect) const; | 
| Chris@0 | 64 | 
| Chris@77 | 65     virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos, | 
| Chris@77 | 66                                      std::vector<QRect> &extents) const; | 
| Chris@77 | 67     virtual void paintCrosshairs(View *, QPainter &, QPoint) const; | 
| Chris@77 | 68 | 
| Chris@44 | 69     virtual QString getFeatureDescription(View *v, QPoint &) const; | 
| Chris@0 | 70 | 
| Chris@44 | 71     virtual bool snapToFeatureFrame(View *v, int &frame, | 
| Chris@28 | 72 				    size_t &resolution, | 
| Chris@28 | 73 				    SnapType snap) const; | 
| Chris@13 | 74 | 
| Chris@283 | 75     virtual void measureDoubleClick(View *, QMouseEvent *); | 
| Chris@283 | 76 | 
| Chris@224 | 77     virtual bool hasLightBackground() const; | 
| Chris@224 | 78 | 
| Chris@0 | 79     void setModel(const DenseTimeValueModel *model); | 
| Chris@0 | 80 | 
| Chris@0 | 81     virtual PropertyList getProperties() const; | 
| Chris@87 | 82     virtual QString getPropertyLabel(const PropertyName &) const; | 
| Chris@335 | 83     virtual QString getPropertyIconName(const PropertyName &) const; | 
| Chris@0 | 84     virtual PropertyType getPropertyType(const PropertyName &) const; | 
| Chris@0 | 85     virtual QString getPropertyGroupName(const PropertyName &) const; | 
| Chris@0 | 86     virtual int getPropertyRangeAndValue(const PropertyName &, | 
| Chris@216 | 87                                          int *min, int *max, int *deflt) const; | 
| Chris@0 | 88     virtual QString getPropertyValueLabel(const PropertyName &, | 
| Chris@0 | 89 					  int value) const; | 
| Chris@167 | 90     virtual RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const; | 
| Chris@0 | 91     virtual void setProperty(const PropertyName &, int value); | 
| Chris@0 | 92 | 
| Chris@0 | 93     /** | 
| Chris@0 | 94      * Specify the channel to use from the source model. | 
| Chris@0 | 95      * A value of -1 means to mix all available channels. | 
| Chris@0 | 96      * The default is channel 0. | 
| Chris@0 | 97      */ | 
| Chris@0 | 98     void setChannel(int); | 
| Chris@0 | 99     int getChannel() const; | 
| Chris@0 | 100 | 
| Chris@0 | 101     void setWindowSize(size_t); | 
| Chris@0 | 102     size_t getWindowSize() const; | 
| Chris@0 | 103 | 
| Chris@109 | 104     void setWindowHopLevel(size_t level); | 
| Chris@97 | 105     size_t getWindowHopLevel() const; | 
| Chris@0 | 106 | 
| Chris@0 | 107     void setWindowType(WindowType type); | 
| Chris@0 | 108     WindowType getWindowType() const; | 
| Chris@0 | 109 | 
| Chris@109 | 110     void setZeroPadLevel(size_t level); | 
| Chris@109 | 111     size_t getZeroPadLevel() const; | 
| Chris@109 | 112 | 
| Chris@0 | 113     /** | 
| Chris@110 | 114      * Set the gain multiplier for sample values in this view. | 
| Chris@0 | 115      * The default is 1.0. | 
| Chris@0 | 116      */ | 
| Chris@0 | 117     void setGain(float gain); | 
| Chris@0 | 118     float getGain() const; | 
| Chris@0 | 119 | 
| Chris@37 | 120     /** | 
| Chris@110 | 121      * Set the threshold for sample values to qualify for being shown | 
| Chris@110 | 122      * in the FFT, in voltage units. | 
| Chris@37 | 123      * | 
| Chris@37 | 124      * The default is 0.0. | 
| Chris@37 | 125      */ | 
| Chris@37 | 126     void setThreshold(float threshold); | 
| Chris@37 | 127     float getThreshold() const; | 
| Chris@37 | 128 | 
| Chris@37 | 129     void setMinFrequency(size_t); | 
| Chris@37 | 130     size_t getMinFrequency() const; | 
| Chris@37 | 131 | 
| Chris@0 | 132     void setMaxFrequency(size_t); // 0 -> no maximum | 
| Chris@0 | 133     size_t getMaxFrequency() const; | 
| Chris@0 | 134 | 
| Chris@37 | 135     enum ColourScale { | 
| Chris@37 | 136 	LinearColourScale, | 
| Chris@37 | 137 	MeterColourScale, | 
| Chris@215 | 138         dBSquaredColourScale, | 
| Chris@37 | 139 	dBColourScale, | 
| Chris@37 | 140 	PhaseColourScale | 
| Chris@37 | 141     }; | 
| Chris@0 | 142 | 
| Chris@0 | 143     /** | 
| Chris@0 | 144      * Specify the scale for sample levels.  See WaveformLayer for | 
| Chris@0 | 145      * details of meter and dB scaling.  The default is dBColourScale. | 
| Chris@0 | 146      */ | 
| Chris@0 | 147     void setColourScale(ColourScale); | 
| Chris@0 | 148     ColourScale getColourScale() const; | 
| Chris@0 | 149 | 
| Chris@35 | 150     enum FrequencyScale { | 
| Chris@35 | 151 	LinearFrequencyScale, | 
| Chris@35 | 152 	LogFrequencyScale | 
| Chris@35 | 153     }; | 
| Chris@0 | 154 | 
| Chris@0 | 155     /** | 
| Chris@0 | 156      * Specify the scale for the y axis. | 
| Chris@0 | 157      */ | 
| Chris@0 | 158     void setFrequencyScale(FrequencyScale); | 
| Chris@0 | 159     FrequencyScale getFrequencyScale() const; | 
| Chris@0 | 160 | 
| Chris@37 | 161     enum BinDisplay { | 
| Chris@37 | 162 	AllBins, | 
| Chris@37 | 163 	PeakBins, | 
| Chris@37 | 164 	PeakFrequencies | 
| Chris@35 | 165     }; | 
| Chris@35 | 166 | 
| Chris@35 | 167     /** | 
| Chris@35 | 168      * Specify the processing of frequency bins for the y axis. | 
| Chris@35 | 169      */ | 
| Chris@37 | 170     void setBinDisplay(BinDisplay); | 
| Chris@37 | 171     BinDisplay getBinDisplay() const; | 
| Chris@35 | 172 | 
| Chris@36 | 173     void setNormalizeColumns(bool n); | 
| Chris@36 | 174     bool getNormalizeColumns() const; | 
| Chris@36 | 175 | 
| Chris@120 | 176     void setNormalizeVisibleArea(bool n); | 
| Chris@120 | 177     bool getNormalizeVisibleArea() const; | 
| Chris@120 | 178 | 
| Chris@197 | 179     void setColourMap(int map); | 
| Chris@197 | 180     int getColourMap() const; | 
| Chris@0 | 181 | 
| Chris@9 | 182     /** | 
| Chris@9 | 183      * Specify the colourmap rotation for the colour scale. | 
| Chris@9 | 184      */ | 
| Chris@9 | 185     void setColourRotation(int); | 
| Chris@9 | 186     int getColourRotation() const; | 
| Chris@9 | 187 | 
| Chris@0 | 188     virtual VerticalPosition getPreferredFrameCountPosition() const { | 
| Chris@0 | 189 	return PositionTop; | 
| Chris@0 | 190     } | 
| Chris@0 | 191 | 
| Chris@15 | 192     virtual bool isLayerOpaque() const { return true; } | 
| Chris@287 | 193 | 
| Chris@287 | 194     virtual ColourSignificance getLayerColourSignificance() const { | 
| Chris@287 | 195         return ColourHasMeaningfulValue; | 
| Chris@287 | 196     } | 
| Chris@15 | 197 | 
| Chris@267 | 198     float getYForFrequency(const View *v, float frequency) const; | 
| Chris@267 | 199     float getFrequencyForY(const View *v, int y) const; | 
| Chris@42 | 200 | 
| Chris@115 | 201     virtual int getCompletion(View *v) const; | 
| Chris@0 | 202 | 
| Chris@101 | 203     virtual bool getValueExtents(float &min, float &max, | 
| Chris@101 | 204                                  bool &logarithmic, QString &unit) const; | 
| Chris@101 | 205 | 
| Chris@101 | 206     virtual bool getDisplayExtents(float &min, float &max) const; | 
| Chris@79 | 207 | 
| Chris@120 | 208     virtual bool setDisplayExtents(float min, float max); | 
| Chris@120 | 209 | 
| Chris@267 | 210     virtual bool getYScaleValue(const View *, int, float &, QString &) const; | 
| Chris@261 | 211 | 
| Chris@316 | 212     virtual void toXml(QTextStream &stream, QString indent = "", | 
| Chris@316 | 213                        QString extraAttributes = "") const; | 
| Chris@6 | 214 | 
| Chris@11 | 215     void setProperties(const QXmlAttributes &attributes); | 
| Chris@11 | 216 | 
| Chris@47 | 217     virtual void setLayerDormant(const View *v, bool dormant); | 
| Chris@29 | 218 | 
| Chris@248 | 219     virtual bool isLayerScrollable(const View *) const { return false; } | 
| Chris@94 | 220 | 
| Chris@133 | 221     virtual int getVerticalZoomSteps(int &defaultStep) const; | 
| Chris@133 | 222     virtual int getCurrentVerticalZoomStep() const; | 
| Chris@133 | 223     virtual void setVerticalZoomStep(int); | 
| Chris@187 | 224     virtual RangeMapper *getNewVerticalZoomRangeMapper() const; | 
| Chris@133 | 225 | 
| Chris@193 | 226     virtual const Model *getSliceableModel() const; | 
| Chris@193 | 227 | 
| Chris@0 | 228 protected slots: | 
| Chris@0 | 229     void cacheInvalid(); | 
| Chris@0 | 230     void cacheInvalid(size_t startFrame, size_t endFrame); | 
| Chris@122 | 231 | 
| Chris@122 | 232     void preferenceChanged(PropertyContainer::PropertyName name); | 
| Chris@0 | 233 | 
| Chris@0 | 234     void fillTimerTimedOut(); | 
| Chris@0 | 235 | 
| Chris@0 | 236 protected: | 
| Chris@0 | 237     const DenseTimeValueModel *m_model; // I do not own this | 
| Chris@0 | 238 | 
| Chris@35 | 239     int                 m_channel; | 
| Chris@35 | 240     size_t              m_windowSize; | 
| Chris@35 | 241     WindowType          m_windowType; | 
| Chris@97 | 242     size_t              m_windowHopLevel; | 
| Chris@109 | 243     size_t              m_zeroPadLevel; | 
| Chris@107 | 244     size_t              m_fftSize; | 
| Chris@35 | 245     float               m_gain; | 
| Chris@215 | 246     float               m_initialGain; | 
| Chris@37 | 247     float               m_threshold; | 
| Chris@215 | 248     float               m_initialThreshold; | 
| Chris@35 | 249     int                 m_colourRotation; | 
| Chris@215 | 250     int                 m_initialRotation; | 
| Chris@37 | 251     size_t              m_minFrequency; | 
| Chris@35 | 252     size_t              m_maxFrequency; | 
| Chris@135 | 253     size_t              m_initialMaxFrequency; | 
| Chris@35 | 254     ColourScale         m_colourScale; | 
| Chris@197 | 255     int                 m_colourMap; | 
| Chris@77 | 256     QColor              m_crosshairColour; | 
| Chris@35 | 257     FrequencyScale      m_frequencyScale; | 
| Chris@37 | 258     BinDisplay          m_binDisplay; | 
| Chris@36 | 259     bool                m_normalizeColumns; | 
| Chris@120 | 260     bool                m_normalizeVisibleArea; | 
| Chris@133 | 261     int                 m_lastEmittedZoomStep; | 
| Chris@389 | 262     bool                m_synchronous; | 
| Chris@0 | 263 | 
| Chris@215 | 264     mutable int         m_lastPaintBlockWidth; | 
| Chris@215 | 265     mutable RealTime    m_lastPaintTime; | 
| Chris@215 | 266 | 
| Chris@38 | 267     enum { NO_VALUE = 0 }; // colour index for unused pixels | 
| Chris@38 | 268 | 
| Chris@197 | 269     class Palette | 
| Chris@86 | 270     { | 
| Chris@86 | 271     public: | 
| Chris@86 | 272         QColor getColour(unsigned char index) const { | 
| Chris@86 | 273             return m_colours[index]; | 
| Chris@86 | 274         } | 
| Chris@86 | 275 | 
| Chris@86 | 276         void setColour(unsigned char index, QColor colour) { | 
| Chris@86 | 277             m_colours[index] = colour; | 
| Chris@86 | 278         } | 
| Chris@86 | 279 | 
| Chris@86 | 280     private: | 
| Chris@86 | 281         QColor m_colours[256]; | 
| Chris@86 | 282     }; | 
| Chris@86 | 283 | 
| Chris@197 | 284     Palette m_palette; | 
| Chris@31 | 285 | 
| Chris@95 | 286     struct PixmapCache | 
| Chris@95 | 287     { | 
| Chris@95 | 288         QPixmap pixmap; | 
| Chris@95 | 289         QRect validArea; | 
| Chris@95 | 290         long startFrame; | 
| Chris@95 | 291         size_t zoomLevel; | 
| Chris@95 | 292     }; | 
| Chris@95 | 293     typedef std::map<const View *, PixmapCache> ViewPixmapCache; | 
| Chris@95 | 294     void invalidatePixmapCaches(); | 
| Chris@95 | 295     void invalidatePixmapCaches(size_t startFrame, size_t endFrame); | 
| Chris@95 | 296     mutable ViewPixmapCache m_pixmapCaches; | 
| Chris@95 | 297     mutable QImage m_drawBuffer; | 
| Chris@0 | 298 | 
| Chris@114 | 299     mutable QTimer *m_updateTimer; | 
| Chris@110 | 300 | 
| Chris@44 | 301     mutable size_t m_candidateFillStartFrame; | 
| Chris@0 | 302     bool m_exiting; | 
| Chris@0 | 303 | 
| Chris@197 | 304     void initialisePalette(); | 
| Chris@197 | 305     void rotatePalette(int distance); | 
| Chris@0 | 306 | 
| Chris@119 | 307     unsigned char getDisplayValue(View *v, float input) const; | 
| Chris@40 | 308     float getInputForDisplayValue(unsigned char uc) const; | 
| Chris@40 | 309 | 
| Chris@40 | 310     int getColourScaleWidth(QPainter &) const; | 
| Chris@40 | 311 | 
| Chris@121 | 312     void illuminateLocalFeatures(View *v, QPainter &painter) const; | 
| Chris@121 | 313 | 
| Chris@40 | 314     float getEffectiveMinFrequency() const; | 
| Chris@40 | 315     float getEffectiveMaxFrequency() const; | 
| Chris@38 | 316 | 
| Chris@0 | 317     struct LayerRange { | 
| Chris@0 | 318 	long   startFrame; | 
| Chris@0 | 319 	int    zoomLevel; | 
| Chris@0 | 320 	size_t modelStart; | 
| Chris@0 | 321 	size_t modelEnd; | 
| Chris@0 | 322     }; | 
| Chris@44 | 323     bool getXBinRange(View *v, int x, float &windowMin, float &windowMax) const; | 
| Chris@44 | 324     bool getYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const; | 
| Chris@0 | 325 | 
| Chris@44 | 326     bool getYBinSourceRange(View *v, int y, float &freqMin, float &freqMax) const; | 
| Chris@44 | 327     bool getAdjustedYBinSourceRange(View *v, int x, int y, | 
| Chris@35 | 328 				    float &freqMin, float &freqMax, | 
| Chris@35 | 329 				    float &adjFreqMin, float &adjFreqMax) const; | 
| Chris@44 | 330     bool getXBinSourceRange(View *v, int x, RealTime &timeMin, RealTime &timeMax) const; | 
| Chris@44 | 331     bool getXYBinSourceRange(View *v, int x, int y, float &min, float &max, | 
| Chris@38 | 332 			     float &phaseMin, float &phaseMax) const; | 
| Chris@0 | 333 | 
| Chris@0 | 334     size_t getWindowIncrement() const { | 
| Chris@97 | 335         if (m_windowHopLevel == 0) return m_windowSize; | 
| Chris@97 | 336         else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4; | 
| Chris@97 | 337         else return m_windowSize / (1 << (m_windowHopLevel - 1)); | 
| Chris@0 | 338     } | 
| Chris@113 | 339 | 
| Chris@114 | 340     size_t getZeroPadLevel(const View *v) const; | 
| Chris@114 | 341     size_t getFFTSize(const View *v) const; | 
| Chris@130 | 342     FFTModel *getFFTModel(const View *v) const; | 
| Chris@130 | 343     void invalidateFFTModels(); | 
| Chris@115 | 344 | 
| Chris@130 | 345     typedef std::pair<FFTModel *, int> FFTFillPair; // model, last fill | 
| Chris@115 | 346     typedef std::map<const View *, FFTFillPair> ViewFFTMap; | 
| Chris@119 | 347     typedef std::vector<float> FloatVector; | 
| Chris@130 | 348     mutable ViewFFTMap m_fftModels; | 
| Chris@193 | 349     mutable Model *m_sliceableModel; | 
| Chris@119 | 350 | 
| Chris@119 | 351     class MagnitudeRange { | 
| Chris@119 | 352     public: | 
| Chris@119 | 353         MagnitudeRange() : m_min(0), m_max(0) { } | 
| Chris@119 | 354         bool operator==(const MagnitudeRange &r) { | 
| Chris@119 | 355             return r.m_min == m_min && r.m_max == m_max; | 
| Chris@119 | 356         } | 
| Chris@119 | 357         bool isSet() const { return (m_min != 0 || m_max != 0); } | 
| Chris@119 | 358         void set(float min, float max) { | 
| Chris@119 | 359             m_min = convert(min); | 
| Chris@119 | 360             m_max = convert(max); | 
| Chris@119 | 361             if (m_max < m_min) m_max = m_min; | 
| Chris@119 | 362         } | 
| Chris@119 | 363         bool sample(float f) { | 
| Chris@119 | 364             unsigned int ui = convert(f); | 
| Chris@119 | 365             bool changed = false; | 
| Chris@119 | 366             if (isSet()) { | 
| Chris@119 | 367                 if (ui < m_min) { m_min = ui; changed = true; } | 
| Chris@119 | 368                 if (ui > m_max) { m_max = ui; changed = true; } | 
| Chris@119 | 369             } else { | 
| Chris@119 | 370                 m_max = m_min = ui; | 
| Chris@119 | 371                 changed = true; | 
| Chris@119 | 372             } | 
| Chris@119 | 373             return changed; | 
| Chris@119 | 374         } | 
| Chris@119 | 375         bool sample(const MagnitudeRange &r) { | 
| Chris@119 | 376             bool changed = false; | 
| Chris@119 | 377             if (isSet()) { | 
| Chris@119 | 378                 if (r.m_min < m_min) { m_min = r.m_min; changed = true; } | 
| Chris@119 | 379                 if (r.m_max > m_max) { m_max = r.m_max; changed = true; } | 
| Chris@119 | 380             } else { | 
| Chris@119 | 381                 m_min = r.m_min; | 
| Chris@119 | 382                 m_max = r.m_max; | 
| Chris@119 | 383                 changed = true; | 
| Chris@119 | 384             } | 
| Chris@119 | 385             return changed; | 
| Chris@119 | 386         } | 
| Chris@119 | 387         float getMin() const { return float(m_min) / UINT_MAX; } | 
| Chris@119 | 388         float getMax() const { return float(m_max) / UINT_MAX; } | 
| Chris@119 | 389     private: | 
| Chris@119 | 390         unsigned int m_min; | 
| Chris@119 | 391         unsigned int m_max; | 
| Chris@119 | 392         unsigned int convert(float f) { | 
| Chris@119 | 393             if (f < 0.f) f = 0.f; | 
| Chris@119 | 394             if (f > 1.f) f = 1.f; | 
| Chris@119 | 395             return (unsigned int)(f * UINT_MAX); | 
| Chris@119 | 396         } | 
| Chris@119 | 397     }; | 
| Chris@119 | 398 | 
| Chris@119 | 399     typedef std::map<const View *, MagnitudeRange> ViewMagMap; | 
| Chris@119 | 400     mutable ViewMagMap m_viewMags; | 
| Chris@119 | 401     mutable std::vector<MagnitudeRange> m_columnMags; | 
| Chris@119 | 402     void invalidateMagnitudes(); | 
| Chris@119 | 403     bool updateViewMagnitudes(View *v) const; | 
| Chris@273 | 404 | 
| Chris@273 | 405     virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const; | 
| Chris@273 | 406     virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const; | 
| Chris@0 | 407 }; | 
| Chris@0 | 408 | 
| Chris@0 | 409 #endif |