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.
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_VIEW_H
17 #define SV_VIEW_H
18 
19 #include <QFrame>
20 #include <QProgressBar>
21 
22 #include "layer/LayerGeometryProvider.h"
23 
24 #include "base/ZoomConstraint.h"
25 #include "base/PropertyContainer.h"
26 #include "ViewManager.h"
27 #include "base/XmlExportable.h"
28 #include "base/BaseTypes.h"
29 
30 #include "data/model/Model.h"
31 
32 // #define DEBUG_VIEW_WIDGET_PAINT 1
33 
34 class Layer;
35 class ViewPropertyContainer;
36 
37 class QPushButton;
38 
39 #include <map>
40 #include <set>
41 
42 /**
43  * View is the base class of widgets that display one or more
44  * overlaid views of data against a horizontal time scale.
45  *
46  * A View may have any number of attached Layers, each of which
47  * is expected to have one data Model (although multiple views may
48  * share the same model).
49  *
50  * A View may be panned in time and zoomed, although the
51  * mechanisms for doing so (as well as any other operations and
52  * properties available) depend on the subclass.
53  */
54 
55 class View : public QFrame,
56              public XmlExportable,
57              public LayerGeometryProvider
58 {
59     Q_OBJECT
60 
61 public:
62     /**
63      * Deleting a View does not delete any of its layers.  They should
64      * be managed elsewhere (e.g. by the Document).
65      */
66     virtual ~View();
67 
68     /**
69      * Retrieve the id of this object. Views have their own unique
70      * ids, but ViewProxy objects share the id of their View.
71      */
getId()72     int getId() const override { return m_id; }
73 
74     /**
75      * Retrieve the first visible sample frame on the widget.
76      * This is a calculated value based on the centre-frame, widget
77      * width and zoom level.  The result may be negative.
78      */
79     sv_frame_t getStartFrame() const override;
80 
81     /**
82      * Set the widget pan based on the given first visible frame.  The
83      * frame value may be negative.
84      */
85     void setStartFrame(sv_frame_t);
86 
87     /**
88      * Return the centre frame of the visible widget.  This is an
89      * exact value that does not depend on the zoom block size.  Other
90      * frame values (start, end) are calculated from this based on the
91      * zoom and other factors.
92      */
getCentreFrame()93     sv_frame_t getCentreFrame() const override { return m_centreFrame; }
94 
95     /**
96      * Set the centre frame of the visible widget.
97      */
setCentreFrame(sv_frame_t f)98     void setCentreFrame(sv_frame_t f) { setCentreFrame(f, true); }
99 
100     /**
101      * Retrieve the last visible sample frame on the widget.
102      * This is a calculated value based on the centre-frame, widget
103      * width and zoom level.
104      */
105     sv_frame_t getEndFrame() const override;
106 
107     /**
108      * Return the pixel x-coordinate corresponding to a given sample
109      * frame. The frame is permitted to be negative, and the result
110      * may be outside the currently visible area. But this should not
111      * be called with frame values very far away from the currently
112      * visible area, as that could lead to overflow. In that situation
113      * an error will be logged and 0 returned.
114      */
115     int getXForFrame(sv_frame_t frame) const override;
116 
117     /**
118      * Return the closest frame to the given pixel x-coordinate.
119      */
120     sv_frame_t getFrameForX(int x) const override;
121 
122     /**
123      * Return the closest pixel x-coordinate corresponding to a given
124      * view x-coordinate. Default is no scaling, ViewProxy handles
125      * scaling case.
126      */
getXForViewX(int viewx)127     int getXForViewX(int viewx) const override { return viewx; }
128 
129     /**
130      * Return the closest view x-coordinate corresponding to a given
131      * pixel x-coordinate. Default is no scaling, ViewProxy handles
132      * scaling case.
133      */
getViewXForX(int x)134     int getViewXForX(int x) const override { return x; }
135 
136     /**
137      * Return the pixel y-coordinate corresponding to a given
138      * frequency, if the frequency range is as specified.  This does
139      * not imply any policy about layer frequency ranges, but it might
140      * be useful for layers to match theirs up if desired.
141      *
142      * Not thread-safe in logarithmic mode.  Call only from GUI thread.
143      */
144     double getYForFrequency(double frequency, double minFreq, double maxFreq,
145                            bool logarithmic) const override;
146 
147     /**
148      * Return the closest frequency to the given pixel y-coordinate,
149      * if the frequency range is as specified.
150      *
151      * Not thread-safe in logarithmic mode.  Call only from GUI thread.
152      */
153     double getFrequencyForY(double y, double minFreq, double maxFreq,
154                             bool logarithmic) const override;
155 
156     /**
157      * Return the zoom level, i.e. the number of frames per pixel or
158      * pixels per frame
159      */
160     ZoomLevel getZoomLevel() const override;
161 
162     /**
163      * Set the zoom level, i.e. the number of frames per pixel or
164      * pixels per frame.  The centre frame will be unchanged; the
165      * start and end frames will change.
166      */
167     virtual void setZoomLevel(ZoomLevel z);
168 
169     /**
170      * Zoom in or out.
171      */
172     virtual void zoom(bool in);
173 
174     /**
175      * Scroll left or right by a smallish or largish amount.
176      */
177     virtual void scroll(bool right, bool lots, bool doEmit = true);
178 
179     /**
180      * Add a layer to the view. (Normally this should be handled
181      * through some command abstraction instead of using this function
182      * directly.)
183      */
184     virtual void addLayer(Layer *v);
185 
186     /**
187      * Remove a layer from the view. Does not delete the
188      * layer. (Normally this should be handled through some command
189      * abstraction instead of using this function directly.)
190      */
191     virtual void removeLayer(Layer *v);
192 
193     /**
194      * Return the number of layers, regardless of whether visible or
195      * dormant, i.e. invisible, in this view.
196      */
getLayerCount()197     virtual int getLayerCount() const { return int(m_layerStack.size()); }
198 
199     /**
200      * Return the nth layer, counted in stacking order.  That is,
201      * layer 0 is the bottom layer and layer "getLayerCount()-1" is
202      * the top one. The returned layer may be visible or it may be
203      * dormant, i.e. invisible.
204      */
getLayer(int n)205     virtual Layer *getLayer(int n) {
206         if (in_range_for(m_layerStack, n)) return m_layerStack[n];
207         else return 0;
208     }
209 
210     /**
211      * Return the nth layer, counted in the order they were
212      * added. Unlike the stacking order used in getLayer(), which
213      * changes each time a layer is selected, this ordering remains
214      * fixed. The returned layer may be visible or it may be dormant,
215      * i.e. invisible.
216      */
getFixedOrderLayer(int n)217     virtual Layer *getFixedOrderLayer(int n) {
218         if (n < int(m_fixedOrderLayers.size())) return m_fixedOrderLayers[n];
219         else return 0;
220     }
221 
222     /**
223      * Return the layer currently active for tool interaction. This is
224      * the topmost non-dormant (i.e. visible) layer in the view. If
225      * there are no visible layers in the view, return 0.
226      */
227     virtual Layer *getInteractionLayer();
228 
229     virtual const Layer *getInteractionLayer() const;
230 
231     /**
232      * Return the layer most recently selected by the user. This is
233      * the layer that any non-tool-driven commands should operate on,
234      * in the case where this view is the "current" one.
235      *
236      * If the user has selected the view itself more recently than any
237      * of the layers on it, this function will return 0, and any
238      * non-tool-driven layer commands should be deactivated while this
239      * view is current. It will also return 0 if there are no layers
240      * in the view.
241      *
242      * Note that, unlike getInteractionLayer(), this could return an
243      * invisible (dormant) layer.
244      */
245     virtual Layer *getSelectedLayer();
246 
247     virtual const Layer *getSelectedLayer() const;
248 
249     /**
250      * Return the "top" layer in the view, whether visible or dormant.
251      * This is the same as getLayer(getLayerCount()-1) if there is at
252      * least one layer, and 0 otherwise.
253      *
254      * For most purposes involving interaction or commands, you
255      * probably want either getInteractionLayer() or
256      * getSelectedLayer() instead.
257      */
getTopLayer()258     virtual Layer *getTopLayer() {
259         return m_layerStack.empty() ? 0 : m_layerStack[m_layerStack.size()-1];
260     }
261 
262     virtual void setViewManager(ViewManager *m);
263     virtual void setViewManager(ViewManager *m, sv_frame_t initialFrame);
getViewManager()264     ViewManager *getViewManager() const override { return m_manager; }
265 
266     virtual void setFollowGlobalPan(bool f);
getFollowGlobalPan()267     virtual bool getFollowGlobalPan() const { return m_followPan; }
268 
269     virtual void setFollowGlobalZoom(bool f);
getFollowGlobalZoom()270     virtual bool getFollowGlobalZoom() const { return m_followZoom; }
271 
272     bool hasLightBackground() const override;
273     QColor getForeground() const override;
274     QColor getBackground() const override;
275 
276     void drawMeasurementRect(QPainter &p, const Layer *,
277                                      QRect rect, bool focus) const override;
278 
shouldShowFeatureLabels()279     bool shouldShowFeatureLabels() const override {
280         return m_manager && m_manager->shouldShowFeatureLabels();
281     }
shouldIlluminateLocalFeatures(const Layer *,QPoint &)282     bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const override {
283         return false;
284     }
shouldIlluminateLocalSelection(QPoint &,bool &,bool &)285     virtual bool shouldIlluminateLocalSelection(QPoint &, bool &, bool &) const {
286         return false;
287     }
288 
289     virtual void setPlaybackFollow(PlaybackFollowMode m);
getPlaybackFollow()290     virtual PlaybackFollowMode getPlaybackFollow() const { return m_followPlay; }
291 
292     typedef PropertyContainer::PropertyName PropertyName;
293 
294     // We implement the PropertyContainer API, although we don't
295     // actually subclass PropertyContainer.  We have our own
296     // PropertyContainer that we can return on request that just
297     // delegates back to us.
298     virtual PropertyContainer::PropertyList getProperties() const;
299     virtual QString getPropertyLabel(const PropertyName &) const;
300     virtual PropertyContainer::PropertyType getPropertyType(const PropertyName &) const;
301     virtual int getPropertyRangeAndValue(const PropertyName &,
302                                          int *min, int *max, int *deflt) const;
303     virtual QString getPropertyValueLabel(const PropertyName &,
304                                           int value) const;
305     virtual void setProperty(const PropertyName &, int value);
getPropertyContainerName()306     virtual QString getPropertyContainerName() const {
307         return objectName();
308     }
309     virtual QString getPropertyContainerIconName() const = 0;
310 
311     virtual int getPropertyContainerCount() const;
312 
313     // The 0th property container is the view's own; the rest are the
314     // layers in fixed-order series
315     virtual const PropertyContainer *getPropertyContainer(int i) const;
316     virtual PropertyContainer *getPropertyContainer(int i);
317 
318     /**
319      * Render the view contents to a new QImage (which may be wider
320      * than the visible View).
321      */
322     virtual QImage *renderToNewImage();
323 
324     /**
325      * Render the view contents between the given frame extents to a
326      * new QImage (which may be wider than the visible View).
327      */
328     virtual QImage *renderPartToNewImage(sv_frame_t f0, sv_frame_t f1);
329 
330     /**
331      * Calculate and return the size of image that will be generated
332      * by renderToNewImage().
333      */
334     virtual QSize getRenderedImageSize();
335 
336     /**
337      * Calculate and return the size of image that will be generated
338      * by renderPartToNewImage(f0, f1).
339      */
340     virtual QSize getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1);
341 
342     /**
343      * Render the view contents to a new SVG file.
344      */
345     virtual bool renderToSvgFile(QString filename);
346 
347     /**
348      * Render the view contents between the given frame extents to a
349      * new SVG file.
350      */
351     virtual bool renderPartToSvgFile(QString filename,
352                                      sv_frame_t f0, sv_frame_t f1);
353 
354     /**
355      * Return the visible vertical extents for the given unit, if any.
356      * Overridden from LayerGeometryProvider (see docs there).
357      */
358     bool getVisibleExtentsForUnit(QString unit, double &min, double &max,
359                                   bool &log) const override;
360 
361     /**
362      * Return some visible vertical extents and unit. That is, if at
363      * least one non-dormant layer has a non-empty unit and returns
364      * some values from its getDisplayExtents() method, return the
365      * extents and unit from the topmost of those. Otherwise return
366      * false.
367      */
368     bool getVisibleExtentsForAnyUnit(double &min, double &max,
369                                      bool &logarithmic, QString &unit) const;
370 
371     int getTextLabelYCoord(const Layer *layer, QPainter &) const override;
372 
373     void toXml(QTextStream &stream, QString indent = "",
374                        QString extraAttributes = "") const override;
375 
376     // First frame actually in model, to right of scale, if present
377     virtual sv_frame_t getFirstVisibleFrame() const;
378     virtual sv_frame_t getLastVisibleFrame() const;
379 
380     sv_frame_t getModelsStartFrame() const override;
381     sv_frame_t getModelsEndFrame() const override;
382 
383     /**
384      * To be called from a layer, to obtain the extent of the surface
385      * that the layer is currently painting to. This may be the extent
386      * of the view (if 1x display scaling is in effect) or of a larger
387      * cached pixmap (if greater display scaling is in effect).
388      */
389     QRect getPaintRect() const override;
390 
getPaintSize()391     QSize getPaintSize() const override { return getPaintRect().size(); }
getPaintWidth()392     int getPaintWidth() const override { return getPaintRect().width(); }
getPaintHeight()393     int getPaintHeight() const override { return getPaintRect().height(); }
394 
395     double scaleSize(double size) const override;
396     int scalePixelSize(int size) const override;
397     double scalePenWidth(double width) const override;
398     QPen scalePen(QPen pen) const override;
399 
400     typedef std::set<ModelId> ModelSet;
401     ModelSet getModels();
402 
403     //!!!??? poor name, probably poor api, consider this
setUseAligningProxy(bool uap)404     void setUseAligningProxy(bool uap) {
405         m_useAligningProxy = uap;
406     }
407 
408     //!!!
409     ModelId getAligningModel() const;
410     void getAligningAndReferenceModels(ModelId &aligning, ModelId &reference) const;
411     sv_frame_t alignFromReference(sv_frame_t) const;
412     sv_frame_t alignToReference(sv_frame_t) const;
413     sv_frame_t getAlignedPlaybackFrame() const;
414 
updatePaintRect(QRect r)415     void updatePaintRect(QRect r) override { update(r); }
416 
getView()417     View *getView() override { return this; }
getView()418     const View *getView() const override { return this; }
419 
420 signals:
421     void propertyContainerAdded(PropertyContainer *pc);
422     void propertyContainerRemoved(PropertyContainer *pc);
423     void propertyContainerPropertyChanged(PropertyContainer *pc);
424     void propertyContainerPropertyRangeChanged(PropertyContainer *pc);
425     void propertyContainerNameChanged(PropertyContainer *pc);
426     void propertyContainerSelected(PropertyContainer *pc);
427     void propertyChanged(PropertyContainer::PropertyName);
428 
429     void layerModelChanged();
430 
431     void cancelButtonPressed(Layer *);
432 
433     void centreFrameChanged(sv_frame_t frame,
434                             bool globalScroll,
435                             PlaybackFollowMode followMode);
436 
437     void zoomLevelChanged(ZoomLevel level, bool locked);
438 
439     void contextHelpChanged(const QString &);
440 
441 public slots:
442     virtual void modelChanged(ModelId);
443     virtual void modelChangedWithin(ModelId, sv_frame_t startFrame, sv_frame_t endFrame);
444     virtual void modelCompletionChanged(ModelId);
445     virtual void modelAlignmentCompletionChanged(ModelId);
446     virtual void modelReplaced();
447     virtual void layerParametersChanged();
448     virtual void layerParameterRangesChanged();
449     virtual void layerMeasurementRectsChanged();
450     virtual void layerNameChanged();
451 
452     virtual void globalCentreFrameChanged(sv_frame_t);
453     virtual void viewCentreFrameChanged(View *, sv_frame_t);
454     virtual void viewManagerPlaybackFrameChanged(sv_frame_t);
455     virtual void viewZoomLevelChanged(View *, ZoomLevel, bool);
456 
457     /**
458      * A property container has been selected, for example in the
459      * associated property stack. The property container may be a
460      * layer, in which case the effect should be to raise that layer
461      * to the front of the view and select it; or it may be the view's
462      * own property container, in which case the effect is to switch
463      * to a mode in which no layer is selected.
464      *
465      * (This is the main slot for raising a layer.)
466      */
467     virtual void propertyContainerSelected(View *, PropertyContainer *pc);
468 
469     virtual void selectionChanged();
470     virtual void toolModeChanged();
471     virtual void overlayModeChanged();
472     virtual void zoomWheelsEnabledChanged();
473 
474     virtual void cancelClicked();
475 
476     virtual void progressCheckStalledTimerElapsed();
477 
478 protected:
479     View(QWidget *, bool showProgress);
480 
481     int m_id;
482 
483     void paintEvent(QPaintEvent *e) override;
484     virtual void drawSelections(QPainter &);
shouldLabelSelections()485     virtual bool shouldLabelSelections() const { return true; }
486     virtual void drawPlayPointer(QPainter &);
487     virtual bool render(QPainter &paint, int x0, sv_frame_t f0, sv_frame_t f1);
488     virtual void setPaintFont(QPainter &paint);
489 
scaledSize(const QSize & s,int factor)490     QSize scaledSize(const QSize &s, int factor) {
491         return QSize(s.width() * factor, s.height() * factor);
492     }
scaledRect(const QRect & r,int factor)493     QRect scaledRect(const QRect &r, int factor) {
494         return QRect(r.x() * factor, r.y() * factor,
495                      r.width() * factor, r.height() * factor);
496     }
497 
498     typedef std::vector<Layer *> LayerList;
499 
500     sv_samplerate_t getModelsSampleRate() const;
501     bool areLayersScrollable() const;
502     LayerList getScrollableBackLayers(bool testChanged, bool &changed) const;
503     LayerList getNonScrollableFrontLayers(bool testChanged, bool &changed) const;
504 
505     Layer *getScaleProvidingLayerForUnit(QString unit) const;
506 
507     ZoomLevel getZoomConstraintLevel(ZoomLevel level,
508                                      ZoomConstraint::RoundingDirection dir =
509                                      ZoomConstraint::RoundNearest) const;
510 
511     // These three are slow, intended for indexing GUI thumbwheel stuff
512     int countZoomLevels() const;
513     int getZoomLevelIndex(ZoomLevel level) const;
514     ZoomLevel getZoomLevelByIndex(int ix) const;
515 
516     // True if the top layer(s) use colours for meaningful things.  If
517     // this is the case, selections will be shown using unfilled boxes
518     // rather than with a translucent fill.
519     bool areLayerColoursSignificant() const;
520 
521     // True if the top layer has a time axis on the x coordinate (this
522     // is generally the case except for spectrum/slice layers).  It
523     // will not be possible to make or display selections if this is
524     // false.
525     bool hasTopLayerTimeXAxis() const;
526 
527     bool setCentreFrame(sv_frame_t f, bool doEmit);
528 
529     void movePlayPointer(sv_frame_t f);
530 
531     void checkProgress(ModelId);
532     void checkAlignmentProgress(ModelId);
533 
534     int getProgressBarWidth() const; // if visible
535 
536     int effectiveDevicePixelRatio() const;
537 
538     sv_frame_t          m_centreFrame;
539     ZoomLevel           m_zoomLevel;
540     bool                m_followPan;
541     bool                m_followZoom;
542     PlaybackFollowMode  m_followPlay;
543     bool                m_followPlayIsDetached;
544     sv_frame_t          m_playPointerFrame;
545     bool                m_lightBackground;
546     bool                m_showProgress;
547 
548     QPixmap            *m_cache;  // I own this
549     QPixmap            *m_buffer; // I own this
550     bool                m_cacheValid;
551     sv_frame_t          m_cacheCentreFrame;
552     ZoomLevel           m_cacheZoomLevel;
553     bool                m_selectionCached;
554 
555     bool                m_deleting;
556 
557     LayerList           m_layerStack; // I don't own these, but see dtor note above
558     LayerList           m_fixedOrderLayers;
559     bool                m_haveSelectedLayer;
560 
561     bool                m_useAligningProxy;
562 
563     QString             m_lastError;
564 
565     // caches for use in getScrollableBackLayers, getNonScrollableFrontLayers
566     mutable LayerList m_lastScrollableBackLayers;
567     mutable LayerList m_lastNonScrollableBackLayers;
568 
569     struct ProgressBarRec {
570         QPushButton *cancel;
571         QProgressBar *bar;
572         int lastStallCheckValue;
573         QTimer *stallCheckTimer;
574     };
575     typedef std::map<Layer *, ProgressBarRec> ProgressMap;
576     ProgressMap m_progressBars; // I own the ProgressBarRecs and their contents
577 
578     struct AlignmentProgressBarRec {
579         ModelId alignedModel;
580         QProgressBar *bar;
581     };
582     AlignmentProgressBarRec m_alignmentProgressBar;
583 
584     ViewManager *m_manager; // I don't own this
585     ViewPropertyContainer *m_propertyContainer; // I own this
586 };
587 
588 
589 // Use this for delegation, because we can't subclass from
590 // PropertyContainer (which is a QObject) ourselves because of
591 // ambiguity with QFrame parent
592 
593 class ViewPropertyContainer : public PropertyContainer
594 {
595     Q_OBJECT
596 
597 public:
598     ViewPropertyContainer(View *v);
599     virtual ~ViewPropertyContainer();
600 
getProperties()601     PropertyList getProperties() const override { return m_v->getProperties(); }
getPropertyLabel(const PropertyName & n)602     QString getPropertyLabel(const PropertyName &n) const override {
603         return m_v->getPropertyLabel(n);
604     }
getPropertyType(const PropertyName & n)605     PropertyType getPropertyType(const PropertyName &n) const override {
606         return m_v->getPropertyType(n);
607     }
getPropertyRangeAndValue(const PropertyName & n,int * min,int * max,int * deflt)608     int getPropertyRangeAndValue(const PropertyName &n, int *min, int *max,
609                                  int *deflt) const override {
610         return m_v->getPropertyRangeAndValue(n, min, max, deflt);
611     }
getPropertyValueLabel(const PropertyName & n,int value)612     QString getPropertyValueLabel(const PropertyName &n, int value) const override {
613         return m_v->getPropertyValueLabel(n, value);
614     }
getPropertyContainerName()615     QString getPropertyContainerName() const override {
616         return m_v->getPropertyContainerName();
617     }
getPropertyContainerIconName()618     QString getPropertyContainerIconName() const override {
619         return m_v->getPropertyContainerIconName();
620     }
621 
622 public slots:
setProperty(const PropertyName & n,int value)623     void setProperty(const PropertyName &n, int value) override {
624         m_v->setProperty(n, value);
625     }
626 
627 protected:
628     View *m_v;
629 };
630 
631 #endif
632 
633