1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Sonic Visualiser
5     An audio file viewer and annotation editor.
6     Centre for Digital Music, Queen Mary, University of London.
7     This file copyright 2006 Chris Cannam and QMUL.
8 
9     This program is free software; you can redistribute it and/or
10     modify it under the terms of the GNU General Public License as
11     published by the Free Software Foundation; either version 2 of the
12     License, or (at your option) any later version.  See the file
13     COPYING included with this distribution for more information.
14 */
15 
16 #ifndef SV_LAYER_H
17 #define SV_LAYER_H
18 
19 #include "base/PropertyContainer.h"
20 #include "base/XmlExportable.h"
21 #include "base/Selection.h"
22 
23 #include "data/model/Model.h"
24 
25 #include "widgets/CommandHistory.h"
26 
27 #include "system/System.h"
28 
29 #include <QObject>
30 #include <QRect>
31 #include <QXmlAttributes>
32 #include <QMutex>
33 #include <QPixmap>
34 
35 #include <map>
36 #include <set>
37 
38 #include <iostream>
39 
40 class ZoomConstraint;
41 class QPainter;
42 class View;
43 class LayerGeometryProvider;
44 class QMouseEvent;
45 class Clipboard;
46 class RangeMapper;
47 
48 /**
49  * The base class for visual representations of the data found in a
50  * Model.  Layers are expected to be able to draw themselves onto a
51  * View, and may also be editable.
52  */
53 
54 class Layer : public PropertyContainer,
55               public XmlExportable
56 {
57     Q_OBJECT
58 
59 public:
60     Layer();
61     virtual ~Layer();
62 
63     /**
64      * Return the ID of the model represented in this layer.
65      */
66     virtual ModelId getModel() const = 0;
67 
68     /**
69      * Return the ID of the source model for the model represented in
70      * this layer. If the model has no other source, or there is no
71      * model here, return None.
72      */
73     ModelId getSourceModel() const;
74 
75     /**
76      * Return a zoom constraint object defining the supported zoom
77      * levels for this layer.  If this returns zero, the layer will
78      * support any integer zoom level.
79      */
getZoomConstraint()80     virtual const ZoomConstraint *getZoomConstraint() const { return 0; }
81 
82     /**
83      * Return true if this layer can handle zoom levels other than
84      * those supported by its zoom constraint (presumably less
85      * efficiently or accurately than the officially supported zoom
86      * levels).  If true, the layer will unenthusistically accept any
87      * integer zoom level from 1 to the maximum returned by its zoom
88      * constraint.
89      */
supportsOtherZoomLevels()90     virtual bool supportsOtherZoomLevels() const { return true; }
91 
92     /**
93      * Paint the given rectangle of this layer onto the given view
94      * using the given painter, superimposing it on top of any
95      * existing material in that view.  The LayerGeometryProvider (an
96      * interface implemented by View) is provided here because it is
97      * possible for one layer to exist in more than one view, so the
98      * dimensions of the view may vary from one paint call to another
99      * (without any view having been resized).
100      */
101     virtual void paint(LayerGeometryProvider *, QPainter &, QRect) const = 0;
102 
103     /**
104      * Enable or disable synchronous painting.  If synchronous
105      * painting is enabled, a call to paint() must complete painting
106      * the entire rectangle before it returns.  If synchronous
107      * painting is disabled (which should be the default), the paint()
108      * call may defer painting some regions if data is not yet
109      * available, by calling back on its view to schedule another
110      * update.  Synchronous painting is necessary when rendering to an
111      * image.  Simple layer types will always paint synchronously, and
112      * so may ignore this.
113      */
setSynchronousPainting(bool)114     virtual void setSynchronousPainting(bool /* synchronous */) { }
115 
116     enum VerticalPosition {
117         PositionTop, PositionMiddle, PositionBottom
118     };
getPreferredTimeRulerPosition()119     virtual VerticalPosition getPreferredTimeRulerPosition() const {
120         return PositionMiddle;
121     }
getPreferredFrameCountPosition()122     virtual VerticalPosition getPreferredFrameCountPosition() const {
123         return PositionBottom;
124     }
hasLightBackground()125     virtual bool hasLightBackground() const {
126         return true;
127     }
128 
129     QString getPropertyContainerIconName() const override;
130 
getPropertyContainerName()131     QString getPropertyContainerName() const override {
132         if (m_presentationName != "") return m_presentationName;
133         else return objectName();
134     }
135 
136     virtual void setPresentationName(QString name);
137 
138     virtual QString getLayerPresentationName() const;
getLayerPresentationPixmap(QSize)139     virtual QPixmap getLayerPresentationPixmap(QSize) const { return QPixmap(); }
140 
141     virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool detailed,
142                                       QPainter &) const = 0;
143 
paintVerticalScale(LayerGeometryProvider *,bool,QPainter &,QRect)144     virtual void paintVerticalScale(LayerGeometryProvider *, bool /* detailed */,
145                                     QPainter &, QRect) const { }
146 
getHorizontalScaleHeight(LayerGeometryProvider *,QPainter &)147     virtual int getHorizontalScaleHeight(LayerGeometryProvider *, QPainter &) const { return 0; }
148 
getCrosshairExtents(LayerGeometryProvider *,QPainter &,QPoint,std::vector<QRect> &)149     virtual bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint /* cursorPos */,
150                                      std::vector<QRect> &) const {
151         return false;
152     }
paintCrosshairs(LayerGeometryProvider *,QPainter &,QPoint)153     virtual void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const { }
154 
155     virtual void paintMeasurementRects(LayerGeometryProvider *, QPainter &,
156                                        bool showFocus, QPoint focusPoint) const;
157 
158     virtual bool nearestMeasurementRectChanged(LayerGeometryProvider *, QPoint prev,
159                                                QPoint now) const;
160 
getFeatureDescription(LayerGeometryProvider *,QPoint &)161     virtual QString getFeatureDescription(LayerGeometryProvider *, QPoint &) const {
162         return "";
163     }
164 
getLabelPreceding(sv_frame_t)165     virtual QString getLabelPreceding(sv_frame_t /* frame */) const {
166         return "";
167     }
168 
169     enum SnapType {
170         SnapLeft,
171         SnapRight,
172         SnapNeighbouring
173     };
174 
175     /**
176      * Adjust the given frame to snap to the nearest feature, if
177      * possible.
178      *
179      * If snap is SnapLeft or SnapRight, adjust the frame to match
180      * that of the nearest feature in the given direction regardless
181      * of how far away it is. If snap is SnapNeighbouring, adjust the
182      * frame to that of the nearest feature in either direction if it
183      * is close, and leave it alone (returning false) otherwise.
184      * SnapNeighbouring should always choose the same feature that
185      * would be used in an editing operation through calls to
186      * editStart etc.
187      *
188      * If ycoord is non-negative, it contains the y coordinate at
189      * which the interaction that prompts this snap is taking place
190      * (e.g. of the mouse press used for a selection action). Layers
191      * that have objects at multiple different heights may choose to
192      * use this information. If the current action has no particular y
193      * coordinate associated with it, ycoord will be passed as -1.
194      *
195      * Return true if a suitable feature was found and frame adjusted
196      * accordingly.  Return false if no suitable feature was available
197      * (and leave frame unmodified).  If returning true, also return
198      * the resolution of the model in this layer in sample frames.
199      */
snapToFeatureFrame(LayerGeometryProvider *,sv_frame_t &,int & resolution,SnapType,int)200     virtual bool snapToFeatureFrame(LayerGeometryProvider * /* v */,
201                                     sv_frame_t & /* frame */,
202                                     int &resolution,
203                                     SnapType /* snap */,
204                                     int /* ycoord */) const {
205         resolution = 1;
206         return false;
207     }
208 
209     /**
210      * Adjust the given frame to snap to the next feature that has
211      * "effectively" the same value as the feature prior to the given
212      * frame, if possible.
213      *
214      * The snap type must be SnapLeft (snap to the time of the next
215      * feature prior to the one preceding the given frame that has a
216      * similar value to it) or SnapRight (snap to the time of the next
217      * feature following the given frame that has a similar value to
218      * the feature preceding it).  Other values are not permitted.
219      *
220      * Return true if a suitable feature was found and frame adjusted
221      * accordingly.  Return false if no suitable feature was available
222      * (and leave frame unmodified).  If returning true, also return
223      * the resolution of the model in this layer in sample frames.
224      */
snapToSimilarFeature(LayerGeometryProvider *,sv_frame_t &,int & resolution,SnapType)225     virtual bool snapToSimilarFeature(LayerGeometryProvider * /* v */,
226                                       sv_frame_t & /* source frame */,
227                                       int &resolution,
228                                       SnapType /* snap */) const {
229         resolution = 1;
230         return false;
231     }
232 
233     // Draw, erase, and edit modes:
234     //
235     // Layer needs to get actual mouse events, I guess.  Draw mode is
236     // probably the easier.
237 
drawStart(LayerGeometryProvider *,QMouseEvent *)238     virtual void drawStart(LayerGeometryProvider *, QMouseEvent *) { }
drawDrag(LayerGeometryProvider *,QMouseEvent *)239     virtual void drawDrag(LayerGeometryProvider *, QMouseEvent *) { }
drawEnd(LayerGeometryProvider *,QMouseEvent *)240     virtual void drawEnd(LayerGeometryProvider *, QMouseEvent *) { }
241 
eraseStart(LayerGeometryProvider *,QMouseEvent *)242     virtual void eraseStart(LayerGeometryProvider *, QMouseEvent *) { }
eraseDrag(LayerGeometryProvider *,QMouseEvent *)243     virtual void eraseDrag(LayerGeometryProvider *, QMouseEvent *) { }
eraseEnd(LayerGeometryProvider *,QMouseEvent *)244     virtual void eraseEnd(LayerGeometryProvider *, QMouseEvent *) { }
245 
editStart(LayerGeometryProvider *,QMouseEvent *)246     virtual void editStart(LayerGeometryProvider *, QMouseEvent *) { }
editDrag(LayerGeometryProvider *,QMouseEvent *)247     virtual void editDrag(LayerGeometryProvider *, QMouseEvent *) { }
editEnd(LayerGeometryProvider *,QMouseEvent *)248     virtual void editEnd(LayerGeometryProvider *, QMouseEvent *) { }
249 
splitStart(LayerGeometryProvider *,QMouseEvent *)250     virtual void splitStart(LayerGeometryProvider *, QMouseEvent *) { }
splitEnd(LayerGeometryProvider *,QMouseEvent *)251     virtual void splitEnd(LayerGeometryProvider *, QMouseEvent *) { }
addNote(LayerGeometryProvider *,QMouseEvent *)252     virtual void addNote(LayerGeometryProvider *, QMouseEvent *) { };
253 
254     // Measurement rectangle (or equivalent).  Unlike draw and edit,
255     // the base Layer class can provide working implementations of
256     // these for most situations.
257     //
258     virtual void measureStart(LayerGeometryProvider *, QMouseEvent *);
259     virtual void measureDrag(LayerGeometryProvider *, QMouseEvent *);
260     virtual void measureEnd(LayerGeometryProvider *, QMouseEvent *);
261     virtual void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *);
262 
haveCurrentMeasureRect()263     virtual bool haveCurrentMeasureRect() const {
264         return m_haveCurrentMeasureRect;
265     }
266     virtual void deleteCurrentMeasureRect(); // using a command
267 
268     /**
269      * Open an editor on the item under the mouse (e.g. on
270      * double-click).  If there is no item or editing is not
271      * supported, return false.
272      */
editOpen(LayerGeometryProvider *,QMouseEvent *)273     virtual bool editOpen(LayerGeometryProvider *, QMouseEvent *) { return false; }
274 
moveSelection(Selection,sv_frame_t)275     virtual void moveSelection(Selection, sv_frame_t /* newStartFrame */) { }
resizeSelection(Selection,Selection)276     virtual void resizeSelection(Selection, Selection /* newSize */) { }
deleteSelection(Selection)277     virtual void deleteSelection(Selection) { }
278 
copy(LayerGeometryProvider *,Selection,Clipboard &)279     virtual void copy(LayerGeometryProvider *, Selection, Clipboard & /* to */) { }
280 
281     /**
282      * Paste from the given clipboard onto the layer at the given
283      * frame offset.  If interactive is true, the layer may ask the
284      * user about paste options through a dialog if desired, and may
285      * return false if the user cancelled the paste operation.  This
286      * function should return true if a paste actually occurred.
287      */
paste(LayerGeometryProvider *,const Clipboard &,sv_frame_t,bool)288     virtual bool paste(LayerGeometryProvider *,
289                        const Clipboard & /* from */,
290                        sv_frame_t /* frameOffset */,
291                        bool /* interactive */) { return false; }
292 
293     // Text mode:
294     //
295     // Label nearest feature.  We need to get the feature coordinates
296     // and current label from the layer, and then the pane can pop up
297     // a little text entry dialog at the right location.  Or we edit
298     // in place?  Probably the dialog is easier.
299 
300     /**
301      * This should return true if the layer can safely be scrolled
302      * automatically by a given view (simply copying the existing data
303      * and then refreshing the exposed area) without altering its
304      * meaning.  For the view widget as a whole this is usually not
305      * possible because of invariant (non-scrolling) material
306      * displayed over the top, but the widget may be able to optimise
307      * scrolling better if it is known that individual views can be
308      * scrolled safely in this way.
309      */
isLayerScrollable(const LayerGeometryProvider *)310     virtual bool isLayerScrollable(const LayerGeometryProvider *) const { return true; }
311 
312     /**
313      * This should return true if the layer completely obscures any
314      * underlying layers.  It's used to determine whether the view can
315      * safely draw any selection rectangles under the layer instead of
316      * over it, in the case where the layer is not scrollable and
317      * therefore needs to be redrawn each time (so that the selection
318      * rectangle can be cached).
319      */
isLayerOpaque()320     virtual bool isLayerOpaque() const { return false; }
321 
322     enum ColourSignificance {
323         ColourAbsent,
324         ColourIrrelevant,
325         ColourDistinguishes,
326         ColourAndBackgroundSignificant,
327         ColourHasMeaningfulValue
328     };
329 
330     /**
331      * This should return the degree of meaning associated with colour
332      * in this layer.
333      *
334      * If ColourAbsent, the layer does not use colour.  If
335      * ColourIrrelevant, the layer is coloured and the colour may be
336      * set by the user, but it doesn't really matter what the colour
337      * is (for example, in a time ruler layer).  If
338      * ColourDistinguishes, then the colour is used to distinguish
339      * this layer from other similar layers (e.g. for data layers).
340      * If ColourAndBackgroundSignificant, then the layer should be
341      * given greater weight than ColourDistinguishes layers when
342      * choosing a background colour (e.g. for waveforms).  If
343      * ColourHasMeaningfulValue, colours are actually meaningful --
344      * the view will then show selections using unfilled rectangles
345      * instead of translucent filled rectangles, so as not to disturb
346      * the colours underneath.
347      */
348     virtual ColourSignificance getLayerColourSignificance() const = 0;
349 
350     /**
351      * This should return true if the layer can be edited by the user.
352      * If this is the case, the appropriate edit tools may be made
353      * available by the application and the layer's drawStart/Drag/End
354      * and editStart/Drag/End methods should be implemented.
355      */
isLayerEditable()356     virtual bool isLayerEditable() const { return false; }
357 
358     /**
359      * Return the proportion of background work complete in drawing
360      * this view, as a percentage -- in most cases this will be the
361      * value returned by pointer from a call to the underlying model's
362      * isReady(int *) call.  The view may choose to show a progress
363      * meter if it finds that this returns < 100 at any given moment.
364      */
getCompletion(LayerGeometryProvider *)365     virtual int getCompletion(LayerGeometryProvider *) const { return 100; }
366 
367     /**
368      * Return an error string if any errors have occurred while
369      * loading or processing data for the given view.  Return the
370      * empty string if no error has occurred.
371      */
getError(LayerGeometryProvider *)372     virtual QString getError(LayerGeometryProvider *) const { return ""; }
373 
374     virtual void setObjectName(const QString &name);
375 
376     /**
377      * Convert the layer's data (though not those of the model it
378      * refers to) into XML for file output.  This class implements the
379      * basic name/type/model-id output; subclasses will typically call
380      * this superclass implementation with extra attributes describing
381      * their particular properties.
382      */
383     void toXml(QTextStream &stream, QString indent = "",
384                        QString extraAttributes = "") const override;
385 
386     /**
387      * Set the particular properties of a layer (those specific to the
388      * subclass) from a set of XML attributes.  This is the effective
389      * inverse of the toXml method.
390      */
391     virtual void setProperties(const QXmlAttributes &) = 0;
392 
393     /**
394      * Produce XML containing the layer's ID and type.  This is used
395      * to refer to the layer in the display section of the SV session
396      * file, for a layer that has already been described in the data
397      * section.
398      */
399     virtual void toBriefXml(QTextStream &stream,
400                             QString indent = "",
401                             QString extraAttributes = "") const;
402 
403     /**
404      * Add a measurement rectangle from the given XML attributes
405      * (presumably taken from a measurement element).
406      * Does not use a command.
407      */
408     virtual void addMeasurementRect(const QXmlAttributes &);
409 
410     /**
411      * Indicate that a layer is not currently visible in the given
412      * view and is not expected to become visible in the near future
413      * (for example because the user has explicitly removed or hidden
414      * it).  The layer may respond by (for example) freeing any cache
415      * memory it is using, until next time its paint method is called,
416      * when it should set itself un-dormant again.
417      *
418      * A layer class that overrides this function must also call this
419      * class's implementation.
420      */
421     virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant);
422 
423     /**
424      * Return whether the layer is dormant (i.e. hidden) in the given
425      * view.
426      */
427     virtual bool isLayerDormant(const LayerGeometryProvider *v) const;
428 
429     /**
430      * Return the play parameters for this layer, if any. The return
431      * value is a shared_ptr that can be passed to (e.g.)
432      * PlayParameterRepository::EditCommand to change the parameters.
433      */
434     std::shared_ptr<PlayParameters> getPlayParameters() override;
435 
436     /**
437      * True if this layer will need to place text labels when it is
438      * painted. The view will take into account how many layers are
439      * requesting this, and will provide a distinct y-coord to each
440      * layer on request via View::getTextLabelHeight().
441      */
needsTextLabelHeight()442     virtual bool needsTextLabelHeight() const { return false; }
443 
444     /**
445      * Return true if the X axis on the layer is time proportional to
446      * audio frames, false otherwise. Almost all layer types return
447      * true here: the exceptions are spectrum and slice layers.
448      */
hasTimeXAxis()449     virtual bool hasTimeXAxis() const { return true; }
450 
451     /**
452      * Update the X and Y axis scales, where appropriate, to focus on
453      * the given rectangular region. This should *only* be overridden
454      * by layers whose hasTimeXAxis() returns false - the pane handles
455      * zooming appropriately in every "normal" case.
456      */
zoomToRegion(const LayerGeometryProvider *,QRect)457     virtual void zoomToRegion(const LayerGeometryProvider *, QRect) {
458         return;
459     }
460 
461     /**
462      * Return the minimum and maximum values for the y axis of the
463      * model in this layer, as well as whether the layer is configured
464      * to use a logarithmic y axis display.  Also return the unit for
465      * these values if known.
466      *
467      * This function returns the "normal" extents for the layer, not
468      * necessarily the extents actually in use in the display (see
469      * getDisplayExtents).
470      */
471     virtual bool getValueExtents(double &min, double &max,
472                                  bool &logarithmic, QString &unit) const = 0;
473 
474     /**
475      * Return the minimum and maximum values within the visible area
476      * for the y axis of this layer.
477      *
478      * Return false if the layer has no display extents of its
479      * own. This could be because the layer is "auto-aligning" against
480      * another layer with the same units elsewhere in the view, or
481      * because the layer has no concept of a vertical scale at all.
482      */
getDisplayExtents(double &,double &)483     virtual bool getDisplayExtents(double & /* min */,
484                                    double & /* max */) const {
485         return false;
486     }
487 
488     /**
489      * Set the displayed minimum and maximum values for the y axis to
490      * the given range, if supported.  Return false if not supported
491      * on this layer (and set nothing).  In most cases, layers that
492      * return false for getDisplayExtents should also return false for
493      * this function.
494      */
setDisplayExtents(double,double)495     virtual bool setDisplayExtents(double /* min */,
496                                    double /* max */) {
497         return false;
498     }
499 
500     /**
501      * Consider using the given value extents and units for this
502      * layer. This may be called on a new layer when added, to prepare
503      * it for editing, and the extents are those of the layer
504      * underneath it. May not be appropriate for most layer types.
505      */
adoptExtents(double,double,QString)506     virtual bool adoptExtents(double /* min */, double /* max */,
507                               QString /* unit */) {
508         return false;
509     }
510 
511     /**
512      * Return the value and unit at the given x coordinate in the
513      * given view.  This is for descriptive purposes using the
514      * measurement tool.  The default implementation works correctly
515      * if the layer hasTimeXAxis().
516      */
517     virtual bool getXScaleValue(const LayerGeometryProvider *v, int x,
518                                 double &value, QString &unit) const;
519 
520     /**
521      * Return the value and unit at the given y coordinate in the
522      * given view.
523      */
getYScaleValue(const LayerGeometryProvider *,int,double &,QString &)524     virtual bool getYScaleValue(const LayerGeometryProvider *, int /* y */,
525                                 double &/* value */, QString &/* unit */) const {
526         return false;
527     }
528 
529     /**
530      * Return the difference between the values at the given y
531      * coordinates in the given view, and the unit of the difference.
532      * The default implementation just calls getYScaleValue twice and
533      * returns the difference, with the same unit.
534      */
535     virtual bool getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1,
536                                      double &diff, QString &unit) const;
537 
538     /**
539      * Get the number of vertical zoom steps available for this layer.
540      * If vertical zooming is not available, return 0.  The meaning of
541      * "zooming" is entirely up to the layer -- changing the zoom
542      * level may cause the layer to reset its display extents or
543      * change another property such as display gain.  However, layers
544      * are advised for consistency to treat smaller zoom steps as
545      * "more distant" or "zoomed out" and larger ones as "closer" or
546      * "zoomed in".
547      *
548      * Layers that provide this facility should also emit the
549      * verticalZoomChanged signal if their vertical zoom changes
550      * due to factors other than setVerticalZoomStep being called.
551      */
getVerticalZoomSteps(int &)552     virtual int getVerticalZoomSteps(int & /* defaultStep */) const { return 0; }
553 
554     /**
555      * Get the current vertical zoom step.  A layer may support finer
556      * control over ranges etc than is available through the integer
557      * zoom step mechanism; if this one does, it should just return
558      * the nearest of the available zoom steps to the current settings.
559      */
getCurrentVerticalZoomStep()560     virtual int getCurrentVerticalZoomStep() const { return 0; }
561 
562     /**
563      * Set the vertical zoom step.  The meaning of "zooming" is
564      * entirely up to the layer -- changing the zoom level may cause
565      * the layer to reset its display extents or change another
566      * property such as display gain.
567      */
setVerticalZoomStep(int)568     virtual void setVerticalZoomStep(int) { }
569 
570     /**
571      * Create and return a range mapper for vertical zoom step values.
572      * See the RangeMapper documentation for more details.  The
573      * returned value is allocated on the heap and will be deleted by
574      * the caller.
575      */
getNewVerticalZoomRangeMapper()576     virtual RangeMapper *getNewVerticalZoomRangeMapper() const { return 0; }
577 
578     /**
579      * Return true if this layer type can function without a model
580      * being set. If false (the default), the layer will not be loaded
581      * from a session if its model cannot be found.
582      */
canExistWithoutModel()583     virtual bool canExistWithoutModel() const { return false; }
584 
585 public slots:
586     /**
587      * Change the visibility status (dormancy) of the layer in the
588      * given view.
589      */
590     void showLayer(LayerGeometryProvider *, bool show);
591 
592 signals:
593     void modelChanged(ModelId);
594     void modelCompletionChanged(ModelId);
595     void modelAlignmentCompletionChanged(ModelId);
596     void modelChangedWithin(ModelId, sv_frame_t startFrame, sv_frame_t endFrame);
597     void modelReplaced();
598 
599     void layerParametersChanged();
600     void layerParameterRangesChanged();
601     void layerMeasurementRectsChanged();
602     void layerNameChanged();
603 
604     void verticalZoomChanged();
605 
606 protected:
607     void connectSignals(ModelId);
608 
609     virtual sv_frame_t alignToReference(LayerGeometryProvider *v, sv_frame_t frame) const;
610     virtual sv_frame_t alignFromReference(LayerGeometryProvider *v, sv_frame_t frame) const;
611     bool clipboardHasDifferentAlignment(LayerGeometryProvider *v, const Clipboard &clip) const;
612 
613     struct MeasureRect {
614 
615         mutable QRect pixrect;
616         bool haveFrames;
617         sv_frame_t startFrame; // only valid if haveFrames
618         sv_frame_t endFrame;   // ditto
619         double startY;
620         double endY;
621 
622         bool operator<(const MeasureRect &mr) const;
623         void toXml(QTextStream &stream, QString indent) const;
624     };
625 
626     class AddMeasurementRectCommand : public Command
627     {
628     public:
AddMeasurementRectCommand(Layer * layer,MeasureRect rect)629         AddMeasurementRectCommand(Layer *layer, MeasureRect rect) :
630             m_layer(layer), m_rect(rect) { }
631 
632         QString getName() const override;
633         void execute() override;
634         void unexecute() override;
635 
636     private:
637         Layer *m_layer;
638         MeasureRect m_rect;
639     };
640 
641     class DeleteMeasurementRectCommand : public Command
642     {
643     public:
DeleteMeasurementRectCommand(Layer * layer,MeasureRect rect)644         DeleteMeasurementRectCommand(Layer *layer, MeasureRect rect) :
645             m_layer(layer), m_rect(rect) { }
646 
647         QString getName() const override;
648         void execute() override;
649         void unexecute() override;
650 
651     private:
652         Layer *m_layer;
653         MeasureRect m_rect;
654     };
655 
addMeasureRectToSet(const MeasureRect & r)656     void addMeasureRectToSet(const MeasureRect &r) {
657         m_measureRects.insert(r);
658         emit layerMeasurementRectsChanged();
659     }
660 
deleteMeasureRectFromSet(const MeasureRect & r)661     void deleteMeasureRectFromSet(const MeasureRect &r) {
662         m_measureRects.erase(r);
663         emit layerMeasurementRectsChanged();
664     }
665 
666     typedef std::set<MeasureRect> MeasureRectSet;
667     MeasureRectSet m_measureRects;
668     MeasureRect m_draggingRect;
669     bool m_haveDraggingRect;
670     mutable bool m_haveCurrentMeasureRect;
671     mutable QPoint m_currentMeasureRectPoint;
672 
673     // Note that pixrects are only correct for a single view.
674     // So we should update them at the start of the paint procedure
675     // (painting is single threaded) and only use them after that.
676     void updateMeasurePixrects(LayerGeometryProvider *v) const;
677 
678     virtual void updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const;
679     virtual void setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const;
680     virtual void setMeasureRectFromPixrect(LayerGeometryProvider *v, MeasureRect &r, QRect pixrect) const;
681 
682     // This assumes updateMeasurementPixrects has been called
683     MeasureRectSet::const_iterator findFocusedMeasureRect(QPoint) const;
684 
685     void paintMeasurementRect(LayerGeometryProvider *v, QPainter &paint,
686                               const MeasureRect &r, bool focus) const;
687 
688     bool valueExtentsMatchMine(LayerGeometryProvider *v) const;
689 
690     QString m_presentationName;
691 
692 private:
693     mutable QMutex m_dormancyMutex;
694     mutable std::map<const void *, bool> m_dormancy;
695 };
696 
697 #endif
698 
699