| Chris@127 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@127 | 2 | 
| Chris@127 | 3 /* | 
| Chris@127 | 4     Sonic Visualiser | 
| Chris@127 | 5     An audio file viewer and annotation editor. | 
| Chris@127 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@182 | 7     This file copyright 2006 Chris Cannam and QMUL. | 
| Chris@127 | 8 | 
| Chris@127 | 9     This program is free software; you can redistribute it and/or | 
| Chris@127 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@127 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@127 | 12     License, or (at your option) any later version.  See the file | 
| Chris@127 | 13     COPYING included with this distribution for more information. | 
| Chris@127 | 14 */ | 
| Chris@127 | 15 | 
| Chris@127 | 16 #ifndef _LAYER_H_ | 
| Chris@127 | 17 #define _LAYER_H_ | 
| Chris@127 | 18 | 
| Chris@128 | 19 #include "base/PropertyContainer.h" | 
| Chris@128 | 20 #include "base/XmlExportable.h" | 
| Chris@128 | 21 #include "base/Selection.h" | 
| Chris@127 | 22 | 
| Chris@127 | 23 #include <QObject> | 
| Chris@127 | 24 #include <QRect> | 
| Chris@127 | 25 #include <QXmlAttributes> | 
| Chris@131 | 26 #include <QMutex> | 
| Chris@127 | 27 | 
| Chris@127 | 28 #include <map> | 
| Chris@268 | 29 #include <set> | 
| Chris@127 | 30 | 
| Chris@127 | 31 class ZoomConstraint; | 
| Chris@127 | 32 class Model; | 
| Chris@127 | 33 class QPainter; | 
| Chris@127 | 34 class View; | 
| Chris@127 | 35 class QMouseEvent; | 
| Chris@127 | 36 class Clipboard; | 
| Chris@187 | 37 class RangeMapper; | 
| Chris@127 | 38 | 
| Chris@127 | 39 /** | 
| Chris@127 | 40  * The base class for visual representations of the data found in a | 
| Chris@127 | 41  * Model.  Layers are expected to be able to draw themselves onto a | 
| Chris@127 | 42  * View, and may also be editable. | 
| Chris@127 | 43  */ | 
| Chris@127 | 44 | 
| Chris@127 | 45 class Layer : public PropertyContainer, | 
| Chris@127 | 46 	      public XmlExportable | 
| Chris@127 | 47 { | 
| Chris@127 | 48     Q_OBJECT | 
| Chris@127 | 49 | 
| Chris@127 | 50 public: | 
| Chris@127 | 51     Layer(); | 
| Chris@127 | 52     virtual ~Layer(); | 
| Chris@127 | 53 | 
| Chris@127 | 54     virtual const Model *getModel() const = 0; | 
| Chris@127 | 55     virtual Model *getModel() { | 
| Chris@127 | 56 	return const_cast<Model *>(const_cast<const Layer *>(this)->getModel()); | 
| Chris@127 | 57     } | 
| Chris@127 | 58 | 
| Chris@137 | 59     /** | 
| Chris@137 | 60      * Return a zoom constraint object defining the supported zoom | 
| Chris@137 | 61      * levels for this layer.  If this returns zero, the layer will | 
| Chris@137 | 62      * support any integer zoom level. | 
| Chris@137 | 63      */ | 
| Chris@127 | 64     virtual const ZoomConstraint *getZoomConstraint() const { return 0; } | 
| Chris@137 | 65 | 
| Chris@137 | 66     /** | 
| Chris@137 | 67      * Return true if this layer can handle zoom levels other than | 
| Chris@137 | 68      * those supported by its zoom constraint (presumably less | 
| Chris@137 | 69      * efficiently or accurately than the officially supported zoom | 
| Chris@137 | 70      * levels).  If true, the layer will unenthusistically accept any | 
| Chris@137 | 71      * integer zoom level from 1 to the maximum returned by its zoom | 
| Chris@137 | 72      * constraint. | 
| Chris@137 | 73      */ | 
| Chris@137 | 74     virtual bool supportsOtherZoomLevels() const { return true; } | 
| Chris@137 | 75 | 
| Chris@127 | 76     virtual void paint(View *, QPainter &, QRect) const = 0; | 
| Chris@127 | 77 | 
| Chris@127 | 78     enum VerticalPosition { | 
| Chris@127 | 79 	PositionTop, PositionMiddle, PositionBottom | 
| Chris@127 | 80     }; | 
| Chris@127 | 81     virtual VerticalPosition getPreferredTimeRulerPosition() const { | 
| Chris@127 | 82 	return PositionMiddle; | 
| Chris@127 | 83     } | 
| Chris@127 | 84     virtual VerticalPosition getPreferredFrameCountPosition() const { | 
| Chris@127 | 85 	return PositionBottom; | 
| Chris@127 | 86     } | 
| Chris@224 | 87     virtual bool hasLightBackground() const { | 
| Chris@224 | 88         return true; | 
| Chris@224 | 89     } | 
| Chris@127 | 90 | 
| Chris@127 | 91     virtual QString getPropertyContainerIconName() const; | 
| Chris@127 | 92 | 
| Chris@127 | 93     virtual QString getPropertyContainerName() const { | 
| Chris@127 | 94 	return objectName(); | 
| Chris@127 | 95     } | 
| Chris@127 | 96 | 
| Chris@127 | 97     virtual QString getLayerPresentationName() const; | 
| Chris@127 | 98 | 
| Chris@127 | 99     virtual int getVerticalScaleWidth(View *, QPainter &) const { return 0; } | 
| Chris@127 | 100     virtual void paintVerticalScale(View *, QPainter &, QRect) const { } | 
| Chris@127 | 101 | 
| Chris@127 | 102     virtual bool getCrosshairExtents(View *, QPainter &, QPoint /* cursorPos */, | 
| Chris@127 | 103                                      std::vector<QRect> &) const { | 
| Chris@127 | 104         return false; | 
| Chris@127 | 105     } | 
| Chris@127 | 106     virtual void paintCrosshairs(View *, QPainter &, QPoint) const { } | 
| Chris@127 | 107 | 
| Chris@272 | 108     virtual void paintMeasurementRects(View *, QPainter &, | 
| Chris@272 | 109                                        bool showFocus, QPoint focusPoint) const; | 
| Chris@272 | 110 | 
| Chris@272 | 111     virtual bool nearestMeasurementRectChanged(View *, QPoint prev, | 
| Chris@272 | 112                                                QPoint now) const; | 
| Chris@267 | 113 | 
| Chris@127 | 114     virtual QString getFeatureDescription(View *, QPoint &) const { | 
| Chris@127 | 115 	return ""; | 
| Chris@127 | 116     } | 
| Chris@127 | 117 | 
| Chris@127 | 118     enum SnapType { | 
| Chris@127 | 119 	SnapLeft, | 
| Chris@127 | 120 	SnapRight, | 
| Chris@127 | 121 	SnapNearest, | 
| Chris@127 | 122 	SnapNeighbouring | 
| Chris@127 | 123     }; | 
| Chris@127 | 124 | 
| Chris@127 | 125     /** | 
| Chris@127 | 126      * Adjust the given frame to snap to the nearest feature, if | 
| Chris@127 | 127      * possible. | 
| Chris@127 | 128      * | 
| Chris@127 | 129      * If snap is SnapLeft or SnapRight, adjust the frame to match | 
| Chris@127 | 130      * that of the nearest feature in the given direction regardless | 
| Chris@127 | 131      * of how far away it is.  If snap is SnapNearest, adjust the | 
| Chris@127 | 132      * frame to that of the nearest feature in either direction.  If | 
| Chris@127 | 133      * snap is SnapNeighbouring, adjust the frame to that of the | 
| Chris@127 | 134      * nearest feature if it is close, and leave it alone (returning | 
| Chris@127 | 135      * false) otherwise.  SnapNeighbouring should always choose the | 
| Chris@127 | 136      * same feature that would be used in an editing operation through | 
| Chris@127 | 137      * calls to editStart etc. | 
| Chris@127 | 138      * | 
| Chris@127 | 139      * Return true if a suitable feature was found and frame adjusted | 
| Chris@180 | 140      * accordingly.  Return false if no suitable feature was available | 
| Chris@180 | 141      * (and leave frame unmodified).  Also return the resolution of | 
| Chris@180 | 142      * the model in this layer in sample frames. | 
| Chris@127 | 143      */ | 
| Chris@127 | 144     virtual bool snapToFeatureFrame(View *   /* v */, | 
| Chris@127 | 145 				    int &    /* frame */, | 
| Chris@127 | 146 				    size_t &resolution, | 
| Chris@127 | 147 				    SnapType /* snap */) const { | 
| Chris@127 | 148 	resolution = 1; | 
| Chris@127 | 149 	return false; | 
| Chris@127 | 150     } | 
| Chris@127 | 151 | 
| Chris@127 | 152     // Draw and edit modes: | 
| Chris@127 | 153     // | 
| Chris@127 | 154     // Layer needs to get actual mouse events, I guess.  Draw mode is | 
| Chris@127 | 155     // probably the easier. | 
| Chris@127 | 156 | 
| Chris@127 | 157     virtual void drawStart(View *, QMouseEvent *) { } | 
| Chris@127 | 158     virtual void drawDrag(View *, QMouseEvent *) { } | 
| Chris@127 | 159     virtual void drawEnd(View *, QMouseEvent *) { } | 
| Chris@127 | 160 | 
| Chris@127 | 161     virtual void editStart(View *, QMouseEvent *) { } | 
| Chris@127 | 162     virtual void editDrag(View *, QMouseEvent *) { } | 
| Chris@127 | 163     virtual void editEnd(View *, QMouseEvent *) { } | 
| Chris@127 | 164 | 
| Chris@267 | 165     // Measurement rectangle (or equivalent).  Unlike draw and edit, | 
| Chris@267 | 166     // the base Layer class can provide working implementations of | 
| Chris@267 | 167     // these for most situations. | 
| Chris@267 | 168     // | 
| Chris@267 | 169     virtual void measureStart(View *, QMouseEvent *); | 
| Chris@267 | 170     virtual void measureDrag(View *, QMouseEvent *); | 
| Chris@267 | 171     virtual void measureEnd(View *, QMouseEvent *); | 
| Chris@280 | 172     virtual void measureDoubleClick(View *, QMouseEvent *); | 
| Chris@267 | 173 | 
| Chris@283 | 174     virtual bool haveCurrentMeasureRect() const { | 
| Chris@283 | 175         return m_haveCurrentMeasureRect; | 
| Chris@283 | 176     } | 
| Chris@283 | 177     virtual void deleteCurrentMeasureRect(); // using a command | 
| Chris@283 | 178 | 
| Chris@255 | 179     /** | 
| Chris@255 | 180      * Open an editor on the item under the mouse (e.g. on | 
| Chris@255 | 181      * double-click).  If there is no item or editing is not | 
| Chris@255 | 182      * supported, return false. | 
| Chris@255 | 183      */ | 
| Chris@255 | 184     virtual bool editOpen(View *, QMouseEvent *) { return false; } | 
| Chris@127 | 185 | 
| Chris@127 | 186     virtual void moveSelection(Selection, size_t /* newStartFrame */) { } | 
| Chris@127 | 187     virtual void resizeSelection(Selection, Selection /* newSize */) { } | 
| Chris@127 | 188     virtual void deleteSelection(Selection) { } | 
| Chris@127 | 189 | 
| Chris@127 | 190     virtual void copy(Selection, Clipboard & /* to */) { } | 
| Chris@127 | 191 | 
| Chris@127 | 192     /** | 
| Chris@127 | 193      * Paste from the given clipboard onto the layer at the given | 
| Chris@127 | 194      * frame offset.  If interactive is true, the layer may ask the | 
| Chris@127 | 195      * user about paste options through a dialog if desired, and may | 
| Chris@127 | 196      * return false if the user cancelled the paste operation.  This | 
| Chris@127 | 197      * function should return true if a paste actually occurred. | 
| Chris@127 | 198      */ | 
| Chris@127 | 199     virtual bool paste(const Clipboard & /* from */, | 
| Chris@127 | 200                        int /* frameOffset */, | 
| Chris@127 | 201                        bool /* interactive */) { return false; } | 
| Chris@127 | 202 | 
| Chris@127 | 203     // Text mode: | 
| Chris@127 | 204     // | 
| Chris@127 | 205     // Label nearest feature.  We need to get the feature coordinates | 
| Chris@127 | 206     // and current label from the layer, and then the pane can pop up | 
| Chris@127 | 207     // a little text entry dialog at the right location.  Or we edit | 
| Chris@127 | 208     // in place?  Probably the dialog is easier. | 
| Chris@127 | 209 | 
| Chris@127 | 210     /** | 
| Chris@127 | 211      * This should return true if the layer can safely be scrolled | 
| Chris@127 | 212      * automatically by a given view (simply copying the existing data | 
| Chris@127 | 213      * and then refreshing the exposed area) without altering its | 
| Chris@127 | 214      * meaning.  For the view widget as a whole this is usually not | 
| Chris@127 | 215      * possible because of invariant (non-scrolling) material | 
| Chris@127 | 216      * displayed over the top, but the widget may be able to optimise | 
| Chris@127 | 217      * scrolling better if it is known that individual views can be | 
| Chris@127 | 218      * scrolled safely in this way. | 
| Chris@127 | 219      */ | 
| Chris@127 | 220     virtual bool isLayerScrollable(const View *) const { return true; } | 
| Chris@127 | 221 | 
| Chris@127 | 222     /** | 
| Chris@127 | 223      * This should return true if the layer completely obscures any | 
| Chris@127 | 224      * underlying layers.  It's used to determine whether the view can | 
| Chris@127 | 225      * safely draw any selection rectangles under the layer instead of | 
| Chris@127 | 226      * over it, in the case where the layer is not scrollable and | 
| Chris@127 | 227      * therefore needs to be redrawn each time (so that the selection | 
| Chris@127 | 228      * rectangle can be cached). | 
| Chris@127 | 229      */ | 
| Chris@127 | 230     virtual bool isLayerOpaque() const { return false; } | 
| Chris@127 | 231 | 
| Chris@287 | 232     enum ColourSignificance { | 
| Chris@287 | 233         ColourAbsent, | 
| Chris@287 | 234         ColourIrrelevant, | 
| Chris@287 | 235         ColourDistinguishes, | 
| Chris@287 | 236         ColourAndBackgroundSignificant, | 
| Chris@287 | 237         ColourHasMeaningfulValue | 
| Chris@287 | 238     }; | 
| Chris@287 | 239 | 
| Chris@127 | 240     /** | 
| Chris@287 | 241      * This should return the degree of meaning associated with colour | 
| Chris@287 | 242      * in this layer. | 
| Chris@287 | 243      * | 
| Chris@287 | 244      * If ColourAbsent, the layer does not use colour.  If | 
| Chris@287 | 245      * ColourIrrelevant, the layer is coloured and the colour may be | 
| Chris@287 | 246      * set by the user, but it doesn't really matter what the colour | 
| Chris@287 | 247      * is (for example, in a time ruler layer).  If | 
| Chris@287 | 248      * ColourDistinguishes, then the colour is used to distinguish | 
| Chris@287 | 249      * this layer from other similar layers (e.g. for data layers). | 
| Chris@287 | 250      * If ColourAndBackgroundSignificant, then the layer should be | 
| Chris@287 | 251      * given greater weight than ColourDistinguishes layers when | 
| Chris@287 | 252      * choosing a background colour (e.g. for waveforms).  If | 
| Chris@287 | 253      * ColourHasMeaningfulValue, colours are actually meaningful -- | 
| Chris@287 | 254      * the view will then show selections using unfilled rectangles | 
| Chris@287 | 255      * instead of translucent filled rectangles, so as not to disturb | 
| Chris@287 | 256      * the colours underneath. | 
| Chris@183 | 257      */ | 
| Chris@287 | 258     virtual ColourSignificance getLayerColourSignificance() const = 0; | 
| Chris@183 | 259 | 
| Chris@183 | 260     /** | 
| Chris@127 | 261      * This should return true if the layer can be edited by the user. | 
| Chris@127 | 262      * If this is the case, the appropriate edit tools may be made | 
| Chris@127 | 263      * available by the application and the layer's drawStart/Drag/End | 
| Chris@127 | 264      * and editStart/Drag/End methods should be implemented. | 
| Chris@127 | 265      */ | 
| Chris@127 | 266     virtual bool isLayerEditable() const { return false; } | 
| Chris@127 | 267 | 
| Chris@127 | 268     /** | 
| Chris@127 | 269      * Return the proportion of background work complete in drawing | 
| Chris@127 | 270      * this view, as a percentage -- in most cases this will be the | 
| Chris@127 | 271      * value returned by pointer from a call to the underlying model's | 
| Chris@226 | 272      * isReady(int *) call.  The view may choose to show a progress | 
| Chris@127 | 273      * meter if it finds that this returns < 100 at any given moment. | 
| Chris@127 | 274      */ | 
| Chris@127 | 275     virtual int getCompletion(View *) const { return 100; } | 
| Chris@127 | 276 | 
| Chris@127 | 277     virtual void setObjectName(const QString &name); | 
| Chris@127 | 278 | 
| Chris@127 | 279     /** | 
| Chris@127 | 280      * Convert the layer's data (though not those of the model it | 
| Chris@127 | 281      * refers to) into an XML string for file output.  This class | 
| Chris@127 | 282      * implements the basic name/type/model-id output; subclasses will | 
| Chris@127 | 283      * typically call this superclass implementation with extra | 
| Chris@127 | 284      * attributes describing their particular properties. | 
| Chris@127 | 285      */ | 
| Chris@127 | 286     virtual QString toXmlString(QString indent = "", | 
| Chris@127 | 287 				QString extraAttributes = "") const; | 
| Chris@127 | 288 | 
| Chris@127 | 289     /** | 
| Chris@127 | 290      * Set the particular properties of a layer (those specific to the | 
| Chris@127 | 291      * subclass) from a set of XML attributes.  This is the effective | 
| Chris@127 | 292      * inverse of the toXmlString method. | 
| Chris@127 | 293      */ | 
| Chris@127 | 294     virtual void setProperties(const QXmlAttributes &) = 0; | 
| Chris@127 | 295 | 
| Chris@127 | 296     /** | 
| Chris@269 | 297      * Produce an XML string containing the layer's ID and type.  This | 
| Chris@269 | 298      * is used to refer to the layer in the display section of the SV | 
| Chris@269 | 299      * session file, for a layer that has already been described in | 
| Chris@269 | 300      * the data section. | 
| Chris@269 | 301      */ | 
| Chris@269 | 302     virtual QString toBriefXmlString(QString indent = "", | 
| Chris@269 | 303                                      QString extraAttributes = "") const; | 
| Chris@269 | 304 | 
| Chris@269 | 305     /** | 
| Chris@269 | 306      * Add a measurement rectangle from the given XML attributes | 
| Chris@269 | 307      * (presumably taken from a measurement element). | 
| Chris@269 | 308      * Does not use a command. | 
| Chris@269 | 309      */ | 
| Chris@269 | 310     virtual void addMeasurementRect(const QXmlAttributes &); | 
| Chris@269 | 311 | 
| Chris@269 | 312     /** | 
| Chris@127 | 313      * Indicate that a layer is not currently visible in the given | 
| Chris@127 | 314      * view and is not expected to become visible in the near future | 
| Chris@127 | 315      * (for example because the user has explicitly removed or hidden | 
| Chris@127 | 316      * it).  The layer may respond by (for example) freeing any cache | 
| Chris@127 | 317      * memory it is using, until next time its paint method is called, | 
| Chris@127 | 318      * when it should set itself un-dormant again. | 
| Chris@131 | 319      * | 
| Chris@131 | 320      * A layer class that overrides this function must also call this | 
| Chris@131 | 321      * class's implementation. | 
| Chris@127 | 322      */ | 
| Chris@131 | 323     virtual void setLayerDormant(const View *v, bool dormant); | 
| Chris@127 | 324 | 
| Chris@127 | 325     /** | 
| Chris@127 | 326      * Return whether the layer is dormant (i.e. hidden) in the given | 
| Chris@127 | 327      * view. | 
| Chris@127 | 328      */ | 
| Chris@131 | 329     virtual bool isLayerDormant(const View *v) const; | 
| Chris@127 | 330 | 
| Chris@127 | 331     virtual PlayParameters *getPlayParameters(); | 
| Chris@127 | 332 | 
| Chris@127 | 333     virtual bool needsTextLabelHeight() const { return false; } | 
| Chris@127 | 334 | 
| Chris@217 | 335     virtual bool hasTimeXAxis() const { return true; } | 
| Chris@217 | 336 | 
| Chris@127 | 337     /** | 
| Chris@127 | 338      * Return the minimum and maximum values for the y axis of the | 
| Chris@127 | 339      * model in this layer, as well as whether the layer is configured | 
| Chris@127 | 340      * to use a logarithmic y axis display.  Also return the unit for | 
| Chris@127 | 341      * these values if known. | 
| Chris@127 | 342      * | 
| Chris@127 | 343      * This function returns the "normal" extents for the layer, not | 
| Chris@127 | 344      * necessarily the extents actually in use in the display. | 
| Chris@127 | 345      */ | 
| Chris@127 | 346     virtual bool getValueExtents(float &min, float &max, | 
| Chris@127 | 347                                  bool &logarithmic, QString &unit) const = 0; | 
| Chris@127 | 348 | 
| Chris@127 | 349     /** | 
| Chris@127 | 350      * Return the minimum and maximum values within the displayed | 
| Chris@127 | 351      * range for the y axis, if only a subset of the whole range of | 
| Chris@127 | 352      * the model (returned by getValueExtents) is being displayed. | 
| Chris@127 | 353      * Return false if the layer is not imposing a particular display | 
| Chris@127 | 354      * extent (using the normal layer extents or deferring to whatever | 
| Chris@127 | 355      * is in use for the same units elsewhere in the view). | 
| Chris@127 | 356      */ | 
| Chris@127 | 357     virtual bool getDisplayExtents(float & /* min */, | 
| Chris@127 | 358                                    float & /* max */) const { | 
| Chris@127 | 359         return false; | 
| Chris@127 | 360     } | 
| Chris@127 | 361 | 
| Chris@127 | 362     /** | 
| Chris@127 | 363      * Set the displayed minimum and maximum values for the y axis to | 
| Chris@127 | 364      * the given range, if supported.  Return false if not supported | 
| Chris@127 | 365      * on this layer (and set nothing).  In most cases, layers that | 
| Chris@127 | 366      * return false for getDisplayExtents should also return false for | 
| Chris@127 | 367      * this function. | 
| Chris@127 | 368      */ | 
| Chris@127 | 369     virtual bool setDisplayExtents(float /* min */, | 
| Chris@127 | 370                                    float /* max */) { | 
| Chris@127 | 371         return false; | 
| Chris@127 | 372     } | 
| Chris@127 | 373 | 
| Chris@133 | 374     /** | 
| Chris@260 | 375      * Return the value and unit at the given x coordinate in the | 
| Chris@260 | 376      * given view.  This is for descriptive purposes using the | 
| Chris@260 | 377      * measurement tool.  The default implementation works correctly | 
| Chris@260 | 378      * if the layer hasTimeXAxis(). | 
| Chris@260 | 379      */ | 
| Chris@267 | 380     virtual bool getXScaleValue(const View *v, int x, | 
| Chris@260 | 381                                 float &value, QString &unit) const; | 
| Chris@260 | 382 | 
| Chris@260 | 383     /** | 
| Chris@260 | 384      * Return the value and unit at the given y coordinate in the | 
| Chris@260 | 385      * given view. | 
| Chris@260 | 386      */ | 
| Chris@267 | 387     virtual bool getYScaleValue(const View *, int /* y */, | 
| Chris@260 | 388                                 float &/* value */, QString &/* unit */) const { | 
| Chris@260 | 389         return false; | 
| Chris@260 | 390     } | 
| Chris@260 | 391 | 
| Chris@260 | 392     /** | 
| Chris@274 | 393      * Return the difference between the values at the given y | 
| Chris@274 | 394      * coordinates in the given view, and the unit of the difference. | 
| Chris@274 | 395      * The default implementation just calls getYScaleValue twice and | 
| Chris@274 | 396      * returns the difference, with the same unit. | 
| Chris@274 | 397      */ | 
| Chris@274 | 398     virtual bool getYScaleDifference(const View *v, int y0, int y1, | 
| Chris@274 | 399                                      float &diff, QString &unit) const; | 
| Chris@274 | 400 | 
| Chris@274 | 401     /** | 
| Chris@133 | 402      * Get the number of vertical zoom steps available for this layer. | 
| Chris@133 | 403      * If vertical zooming is not available, return 0.  The meaning of | 
| Chris@133 | 404      * "zooming" is entirely up to the layer -- changing the zoom | 
| Chris@133 | 405      * level may cause the layer to reset its display extents or | 
| Chris@180 | 406      * change another property such as display gain.  However, layers | 
| Chris@180 | 407      * are advised for consistency to treat smaller zoom steps as | 
| Chris@180 | 408      * "more distant" or "zoomed out" and larger ones as "closer" or | 
| Chris@180 | 409      * "zoomed in". | 
| Chris@180 | 410      * | 
| Chris@133 | 411      * Layers that provide this facility should also emit the | 
| Chris@133 | 412      * verticalZoomChanged signal if their vertical zoom changes | 
| Chris@133 | 413      * due to factors other than setVerticalZoomStep being called. | 
| Chris@133 | 414      */ | 
| Chris@248 | 415     virtual int getVerticalZoomSteps(int & /* defaultStep */) const { return 0; } | 
| Chris@133 | 416 | 
| Chris@133 | 417     /** | 
| Chris@133 | 418      * Get the current vertical zoom step.  A layer may support finer | 
| Chris@133 | 419      * control over ranges etc than is available through the integer | 
| Chris@133 | 420      * zoom step mechanism; if this one does, it should just return | 
| Chris@133 | 421      * the nearest of the available zoom steps to the current settings. | 
| Chris@133 | 422      */ | 
| Chris@133 | 423     virtual int getCurrentVerticalZoomStep() const { return 0; } | 
| Chris@133 | 424 | 
| Chris@133 | 425     /** | 
| Chris@133 | 426      * Set the vertical zoom step.  The meaning of "zooming" is | 
| Chris@133 | 427      * entirely up to the layer -- changing the zoom level may cause | 
| Chris@133 | 428      * the layer to reset its display extents or change another | 
| Chris@133 | 429      * property such as display gain. | 
| Chris@133 | 430      */ | 
| Chris@133 | 431     virtual void setVerticalZoomStep(int) { } | 
| Chris@133 | 432 | 
| Chris@187 | 433     /** | 
| Chris@187 | 434      * Create and return a range mapper for vertical zoom step values. | 
| Chris@187 | 435      * See the RangeMapper documentation for more details.  The | 
| Chris@187 | 436      * returned value is allocated on the heap and will be deleted by | 
| Chris@187 | 437      * the caller. | 
| Chris@187 | 438      */ | 
| Chris@187 | 439     virtual RangeMapper *getNewVerticalZoomRangeMapper() const { return 0; } | 
| Chris@187 | 440 | 
| Chris@127 | 441 public slots: | 
| Chris@127 | 442     void showLayer(View *, bool show); | 
| Chris@127 | 443 | 
| Chris@127 | 444 signals: | 
| Chris@127 | 445     void modelChanged(); | 
| Chris@127 | 446     void modelCompletionChanged(); | 
| Chris@127 | 447     void modelChanged(size_t startFrame, size_t endFrame); | 
| Chris@127 | 448     void modelReplaced(); | 
| Chris@127 | 449 | 
| Chris@127 | 450     void layerParametersChanged(); | 
| Chris@197 | 451     void layerParameterRangesChanged(); | 
| Chris@268 | 452     void layerMeasurementRectsChanged(); | 
| Chris@127 | 453     void layerNameChanged(); | 
| Chris@127 | 454 | 
| Chris@133 | 455     void verticalZoomChanged(); | 
| Chris@133 | 456 | 
| Chris@267 | 457 protected: | 
| Chris@267 | 458     struct MeasureRect { | 
| Chris@268 | 459 | 
| Chris@267 | 460         mutable QRect pixrect; | 
| Chris@268 | 461         bool haveFrames; | 
| Chris@268 | 462         long startFrame; // only valid if haveFrames | 
| Chris@267 | 463         long endFrame;   // ditto | 
| Chris@273 | 464         double startY; | 
| Chris@273 | 465         double endY; | 
| Chris@268 | 466 | 
| Chris@268 | 467         bool operator<(const MeasureRect &mr) const; | 
| Chris@269 | 468         QString toXmlString(QString indent) const; | 
| Chris@267 | 469     }; | 
| Chris@267 | 470 | 
| Chris@268 | 471     class AddMeasurementRectCommand : public Command | 
| Chris@268 | 472     { | 
| Chris@268 | 473     public: | 
| Chris@268 | 474         AddMeasurementRectCommand(Layer *layer, MeasureRect rect) : | 
| Chris@268 | 475             m_layer(layer), m_rect(rect) { } | 
| Chris@268 | 476 | 
| Chris@268 | 477         virtual QString getName() const; | 
| Chris@268 | 478         virtual void execute(); | 
| Chris@268 | 479         virtual void unexecute(); | 
| Chris@268 | 480 | 
| Chris@268 | 481     private: | 
| Chris@268 | 482         Layer *m_layer; | 
| Chris@268 | 483         MeasureRect m_rect; | 
| Chris@268 | 484     }; | 
| Chris@268 | 485 | 
| Chris@283 | 486     class DeleteMeasurementRectCommand : public Command | 
| Chris@283 | 487     { | 
| Chris@283 | 488     public: | 
| Chris@283 | 489         DeleteMeasurementRectCommand(Layer *layer, MeasureRect rect) : | 
| Chris@283 | 490             m_layer(layer), m_rect(rect) { } | 
| Chris@283 | 491 | 
| Chris@283 | 492         virtual QString getName() const; | 
| Chris@283 | 493         virtual void execute(); | 
| Chris@283 | 494         virtual void unexecute(); | 
| Chris@283 | 495 | 
| Chris@283 | 496     private: | 
| Chris@283 | 497         Layer *m_layer; | 
| Chris@283 | 498         MeasureRect m_rect; | 
| Chris@283 | 499     }; | 
| Chris@283 | 500 | 
| Chris@269 | 501     void addMeasureRectToSet(const MeasureRect &r) { | 
| Chris@268 | 502         m_measureRects.insert(r); | 
| Chris@268 | 503         emit layerMeasurementRectsChanged(); | 
| Chris@268 | 504     } | 
| Chris@268 | 505 | 
| Chris@269 | 506     void deleteMeasureRectFromSet(const MeasureRect &r) { | 
| Chris@268 | 507         m_measureRects.erase(r); | 
| Chris@268 | 508         emit layerMeasurementRectsChanged(); | 
| Chris@268 | 509     } | 
| Chris@268 | 510 | 
| Chris@268 | 511     typedef std::set<MeasureRect> MeasureRectSet; | 
| Chris@268 | 512     MeasureRectSet m_measureRects; | 
| Chris@267 | 513     MeasureRect m_draggingRect; | 
| Chris@267 | 514     bool m_haveDraggingRect; | 
| Chris@283 | 515     mutable bool m_haveCurrentMeasureRect; | 
| Chris@283 | 516     mutable QPoint m_currentMeasureRectPoint; | 
| Chris@272 | 517 | 
| Chris@272 | 518     // Note that pixrects are only correct for a single view. | 
| Chris@272 | 519     // So we should update them at the start of the paint procedure | 
| Chris@272 | 520     // (painting is single threaded) and only use them after that. | 
| Chris@273 | 521     void updateMeasurePixrects(View *v) const; | 
| Chris@273 | 522 | 
| Chris@273 | 523     virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const; | 
| Chris@273 | 524     virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const; | 
| Chris@283 | 525     virtual void setMeasureRectFromPixrect(View *v, MeasureRect &r, QRect pixrect) const; | 
| Chris@272 | 526 | 
| Chris@272 | 527     // This assumes updateMeasurementPixrects has been called | 
| Chris@272 | 528     MeasureRectSet::const_iterator findFocusedMeasureRect(QPoint) const; | 
| Chris@267 | 529 | 
| Chris@269 | 530     void paintMeasurementRect(View *v, QPainter &paint, | 
| Chris@270 | 531                               const MeasureRect &r, bool focus) const; | 
| Chris@268 | 532 | 
| Chris@131 | 533 private: | 
| Chris@131 | 534     mutable QMutex m_dormancyMutex; | 
| Chris@127 | 535     mutable std::map<const void *, bool> m_dormancy; | 
| Chris@127 | 536 }; | 
| Chris@127 | 537 | 
| Chris@127 | 538 #endif | 
| Chris@127 | 539 |