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