Chris@127: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@127: 
Chris@127: /*
Chris@127:     Sonic Visualiser
Chris@127:     An audio file viewer and annotation editor.
Chris@127:     Centre for Digital Music, Queen Mary, University of London.
Chris@127:     This file copyright 2006 Chris Cannam.
Chris@127:     
Chris@127:     This program is free software; you can redistribute it and/or
Chris@127:     modify it under the terms of the GNU General Public License as
Chris@127:     published by the Free Software Foundation; either version 2 of the
Chris@127:     License, or (at your option) any later version.  See the file
Chris@127:     COPYING included with this distribution for more information.
Chris@127: */
Chris@127: 
Chris@1225: #ifndef SV_VIEW_H
Chris@1225: #define SV_VIEW_H
Chris@127: 
Chris@127: #include <QFrame>
Chris@127: #include <QProgressBar>
Chris@127: 
Chris@1077: #include "layer/LayerGeometryProvider.h"
Chris@916: 
Chris@127: #include "base/ZoomConstraint.h"
Chris@127: #include "base/PropertyContainer.h"
Chris@128: #include "ViewManager.h"
Chris@127: #include "base/XmlExportable.h"
Chris@902: #include "base/BaseTypes.h"
Chris@127: 
Chris@1475: #include "data/model/Model.h"
Chris@1475: 
Chris@127: // #define DEBUG_VIEW_WIDGET_PAINT 1
Chris@127: 
Chris@127: class Layer;
Chris@127: class ViewPropertyContainer;
Chris@127: 
Chris@797: class QPushButton;
Chris@797: 
Chris@127: #include <map>
Chris@315: #include <set>
Chris@127: 
Chris@127: /**
Chris@127:  * View is the base class of widgets that display one or more
Chris@127:  * overlaid views of data against a horizontal time scale. 
Chris@127:  *
Chris@127:  * A View may have any number of attached Layers, each of which
Chris@127:  * is expected to have one data Model (although multiple views may
Chris@127:  * share the same model).
Chris@127:  *
Chris@127:  * A View may be panned in time and zoomed, although the
Chris@127:  * mechanisms for doing so (as well as any other operations and
Chris@127:  * properties available) depend on the subclass.
Chris@127:  */
Chris@127: 
Chris@127: class View : public QFrame,
Chris@1266:              public XmlExportable,
Chris@916:              public LayerGeometryProvider
Chris@127: {
Chris@127:     Q_OBJECT
Chris@127: 
Chris@127: public:
Chris@127:     /**
Chris@127:      * Deleting a View does not delete any of its layers.  They should
Chris@127:      * be managed elsewhere (e.g. by the Document).
Chris@127:      */
Chris@127:     virtual ~View();
Chris@1044: 
Chris@1044:     /**
Chris@1044:      * Retrieve the id of this object. Views have their own unique
Chris@1044:      * ids, but ViewProxy objects share the id of their View.
Chris@1044:      */
Chris@1406:     int getId() const override { return m_id; }
Chris@1030:     
Chris@127:     /**
Chris@127:      * Retrieve the first visible sample frame on the widget.
Chris@127:      * This is a calculated value based on the centre-frame, widget
Chris@127:      * width and zoom level.  The result may be negative.
Chris@127:      */
Chris@1406:     sv_frame_t getStartFrame() const override;
Chris@127: 
Chris@127:     /**
Chris@127:      * Set the widget pan based on the given first visible frame.  The
Chris@127:      * frame value may be negative.
Chris@127:      */
Chris@902:     void setStartFrame(sv_frame_t);
Chris@127: 
Chris@127:     /**
Chris@127:      * Return the centre frame of the visible widget.  This is an
Chris@127:      * exact value that does not depend on the zoom block size.  Other
Chris@127:      * frame values (start, end) are calculated from this based on the
Chris@127:      * zoom and other factors.
Chris@127:      */
Chris@1406:     sv_frame_t getCentreFrame() const override { return m_centreFrame; }
Chris@127: 
Chris@127:     /**
Chris@127:      * Set the centre frame of the visible widget.
Chris@127:      */
Chris@902:     void setCentreFrame(sv_frame_t f) { setCentreFrame(f, true); }
Chris@127: 
Chris@127:     /**
Chris@127:      * Retrieve the last visible sample frame on the widget.
Chris@127:      * This is a calculated value based on the centre-frame, widget
Chris@127:      * width and zoom level.
Chris@127:      */
Chris@1406:     sv_frame_t getEndFrame() const override;
Chris@127: 
Chris@127:     /**
Chris@127:      * Return the pixel x-coordinate corresponding to a given sample
Chris@1375:      * frame. The frame is permitted to be negative, and the result
Chris@1375:      * may be outside the currently visible area. But this should not
Chris@1375:      * be called with frame values very far away from the currently
Chris@1375:      * visible area, as that could lead to overflow. In that situation
Chris@1375:      * an error will be logged and 0 returned.
Chris@127:      */
Chris@1406:     int getXForFrame(sv_frame_t frame) const override;
Chris@127: 
Chris@127:     /**
Chris@127:      * Return the closest frame to the given pixel x-coordinate.
Chris@127:      */
Chris@1406:     sv_frame_t getFrameForX(int x) const override;
Chris@127: 
Chris@127:     /**
Chris@1030:      * Return the closest pixel x-coordinate corresponding to a given
Chris@1030:      * view x-coordinate. Default is no scaling, ViewProxy handles
Chris@1030:      * scaling case.
Chris@1030:      */
Chris@1406:     int getXForViewX(int viewx) const override { return viewx; }
Chris@1030: 
Chris@1030:     /**
Chris@1030:      * Return the closest view x-coordinate corresponding to a given
Chris@1030:      * pixel x-coordinate. Default is no scaling, ViewProxy handles
Chris@1030:      * scaling case.
Chris@1030:      */
Chris@1406:     int getViewXForX(int x) const override { return x; }
Chris@1030: 
Chris@1030:     /**
Chris@127:      * Return the pixel y-coordinate corresponding to a given
Chris@127:      * frequency, if the frequency range is as specified.  This does
Chris@127:      * not imply any policy about layer frequency ranges, but it might
Chris@127:      * be useful for layers to match theirs up if desired.
Chris@127:      *
Chris@127:      * Not thread-safe in logarithmic mode.  Call only from GUI thread.
Chris@127:      */
Chris@904:     double getYForFrequency(double frequency, double minFreq, double maxFreq, 
Chris@1406:                            bool logarithmic) const override;
Chris@127: 
Chris@127:     /**
Chris@127:      * Return the closest frequency to the given pixel y-coordinate,
Chris@127:      * if the frequency range is as specified.
Chris@127:      *
Chris@127:      * Not thread-safe in logarithmic mode.  Call only from GUI thread.
Chris@127:      */
Chris@1085:     double getFrequencyForY(double y, double minFreq, double maxFreq,
Chris@1406:                             bool logarithmic) const override;
Chris@127: 
Chris@127:     /**
Chris@1183:      * Return the zoom level, i.e. the number of frames per pixel or
Chris@1183:      * pixels per frame
Chris@127:      */
Chris@1406:     ZoomLevel getZoomLevel() const override;
Chris@127: 
Chris@127:     /**
Chris@1183:      * Set the zoom level, i.e. the number of frames per pixel or
Chris@1183:      * pixels per frame.  The centre frame will be unchanged; the
Chris@1183:      * start and end frames will change.
Chris@127:      */
Chris@1183:     virtual void setZoomLevel(ZoomLevel z);
Chris@127: 
Chris@127:     /**
Chris@127:      * Zoom in or out.
Chris@127:      */
Chris@127:     virtual void zoom(bool in);
Chris@127: 
Chris@127:     /**
Chris@127:      * Scroll left or right by a smallish or largish amount.
Chris@127:      */
Chris@510:     virtual void scroll(bool right, bool lots, bool doEmit = true);
Chris@127: 
Chris@834:     /**
Chris@834:      * Add a layer to the view. (Normally this should be handled
Chris@834:      * through some command abstraction instead of using this function
Chris@834:      * directly.)
Chris@834:      */
Chris@127:     virtual void addLayer(Layer *v);
Chris@834: 
Chris@834:     /**
Chris@834:      * Remove a layer from the view. Does not delete the
Chris@834:      * layer. (Normally this should be handled through some command
Chris@834:      * abstraction instead of using this function directly.)
Chris@834:      */
Chris@834:     virtual void removeLayer(Layer *v);
Chris@834: 
Chris@834:     /**
Chris@834:      * Return the number of layers, regardless of whether visible or
Chris@834:      * dormant, i.e. invisible, in this view.
Chris@834:      */
Chris@902:     virtual int getLayerCount() const { return int(m_layerStack.size()); }
Chris@127: 
Chris@127:     /**
Chris@834:      * Return the nth layer, counted in stacking order.  That is,
Chris@834:      * layer 0 is the bottom layer and layer "getLayerCount()-1" is
Chris@834:      * the top one. The returned layer may be visible or it may be
Chris@834:      * dormant, i.e. invisible.
Chris@127:      */
Chris@277:     virtual Layer *getLayer(int n) {
Chris@902:         if (in_range_for(m_layerStack, n)) return m_layerStack[n];
Chris@835:         else return 0;
Chris@277:     }
Chris@127: 
Chris@127:     /**
Chris@835:      * Return the nth layer, counted in the order they were
Chris@835:      * added. Unlike the stacking order used in getLayer(), which
Chris@835:      * changes each time a layer is selected, this ordering remains
Chris@835:      * fixed. The returned layer may be visible or it may be dormant,
Chris@835:      * i.e. invisible.
Chris@268:      */
Chris@835:     virtual Layer *getFixedOrderLayer(int n) {
Chris@835:         if (n < int(m_fixedOrderLayers.size())) return m_fixedOrderLayers[n];
Chris@835:         else return 0;
Chris@268:     }
Chris@268: 
Chris@268:     /**
Chris@834:      * Return the layer currently active for tool interaction. This is
Chris@834:      * the topmost non-dormant (i.e. visible) layer in the view. If
Chris@834:      * there are no visible layers in the view, return 0.
Chris@834:      */
Chris@834:     virtual Layer *getInteractionLayer();
Chris@834: 
Chris@841:     virtual const Layer *getInteractionLayer() const;
Chris@841: 
Chris@834:     /**
Chris@835:      * Return the layer most recently selected by the user. This is
Chris@835:      * the layer that any non-tool-driven commands should operate on,
Chris@835:      * in the case where this view is the "current" one.
Chris@835:      *
Chris@835:      * If the user has selected the view itself more recently than any
Chris@835:      * of the layers on it, this function will return 0, and any
Chris@835:      * non-tool-driven layer commands should be deactivated while this
Chris@835:      * view is current. It will also return 0 if there are no layers
Chris@835:      * in the view.
Chris@834:      *
Chris@834:      * Note that, unlike getInteractionLayer(), this could return an
Chris@834:      * invisible (dormant) layer.
Chris@127:      */
Chris@127:     virtual Layer *getSelectedLayer();
Chris@834: 
Chris@127:     virtual const Layer *getSelectedLayer() const;
Chris@127: 
Chris@835:     /**
Chris@835:      * Return the "top" layer in the view, whether visible or dormant.
Chris@835:      * This is the same as getLayer(getLayerCount()-1) if there is at
Chris@835:      * least one layer, and 0 otherwise.
Chris@835:      *
Chris@835:      * For most purposes involving interaction or commands, you
Chris@835:      * probably want either getInteractionLayer() or
Chris@835:      * getSelectedLayer() instead.
Chris@835:      */
Chris@835:     virtual Layer *getTopLayer() {
Chris@835:         return m_layerStack.empty() ? 0 : m_layerStack[m_layerStack.size()-1];
Chris@835:     }
Chris@835: 
Chris@127:     virtual void setViewManager(ViewManager *m);
Chris@908:     virtual void setViewManager(ViewManager *m, sv_frame_t initialFrame);
Chris@1406:     ViewManager *getViewManager() const override { return m_manager; }
Chris@127: 
Chris@127:     virtual void setFollowGlobalPan(bool f);
Chris@127:     virtual bool getFollowGlobalPan() const { return m_followPan; }
Chris@127: 
Chris@127:     virtual void setFollowGlobalZoom(bool f);
Chris@127:     virtual bool getFollowGlobalZoom() const { return m_followZoom; }
Chris@127: 
Chris@1406:     bool hasLightBackground() const override;
Chris@1406:     QColor getForeground() const override;
Chris@1406:     QColor getBackground() const override;
Chris@127: 
Chris@1406:     void drawMeasurementRect(QPainter &p, const Layer *,
Chris@1406:                                      QRect rect, bool focus) const override;
Chris@127: 
Chris@1406:     bool shouldShowFeatureLabels() const override {
Chris@741:         return m_manager && m_manager->shouldShowFeatureLabels();
Chris@741:     }
Chris@1406:     bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const override {
Chris@1266:         return false;
Chris@127:     }
Chris@127:     virtual bool shouldIlluminateLocalSelection(QPoint &, bool &, bool &) const {
Chris@1266:         return false;
Chris@127:     }
Chris@127: 
Chris@127:     virtual void setPlaybackFollow(PlaybackFollowMode m);
Chris@127:     virtual PlaybackFollowMode getPlaybackFollow() const { return m_followPlay; }
Chris@127: 
Chris@127:     typedef PropertyContainer::PropertyName PropertyName;
Chris@127: 
Chris@127:     // We implement the PropertyContainer API, although we don't
Chris@127:     // actually subclass PropertyContainer.  We have our own
Chris@127:     // PropertyContainer that we can return on request that just
Chris@127:     // delegates back to us.
Chris@127:     virtual PropertyContainer::PropertyList getProperties() const;
Chris@127:     virtual QString getPropertyLabel(const PropertyName &) const;
Chris@127:     virtual PropertyContainer::PropertyType getPropertyType(const PropertyName &) const;
Chris@127:     virtual int getPropertyRangeAndValue(const PropertyName &,
Chris@1266:                                          int *min, int *max, int *deflt) const;
Chris@127:     virtual QString getPropertyValueLabel(const PropertyName &,
Chris@1266:                                           int value) const;
Chris@127:     virtual void setProperty(const PropertyName &, int value);
Chris@127:     virtual QString getPropertyContainerName() const {
Chris@1266:         return objectName();
Chris@127:     }
Chris@127:     virtual QString getPropertyContainerIconName() const = 0;
Chris@127: 
Chris@806:     virtual int getPropertyContainerCount() const;
Chris@127: 
Chris@837:     // The 0th property container is the view's own; the rest are the
Chris@837:     // layers in fixed-order series
Chris@806:     virtual const PropertyContainer *getPropertyContainer(int i) const;
Chris@806:     virtual PropertyContainer *getPropertyContainer(int i);
Chris@127: 
Chris@1202:     /** 
Chris@1202:      * Render the view contents to a new QImage (which may be wider
Chris@1202:      * than the visible View).
Chris@1202:      */
Chris@1202:     virtual QImage *renderToNewImage();
Chris@226: 
Chris@1202:     /** 
Chris@1202:      * Render the view contents between the given frame extents to a
Chris@1202:      * new QImage (which may be wider than the visible View).
Chris@1202:      */
Chris@1202:     virtual QImage *renderPartToNewImage(sv_frame_t f0, sv_frame_t f1);
Chris@1202: 
Chris@1202:     /**
Chris@1202:      * Calculate and return the size of image that will be generated
Chris@1202:      * by renderToNewImage().
Chris@1202:      */
Chris@1202:     virtual QSize getRenderedImageSize();
Chris@1202: 
Chris@1202:     /**
Chris@1202:      * Calculate and return the size of image that will be generated
Chris@1202:      * by renderPartToNewImage(f0, f1).
Chris@1202:      */
Chris@1202:     virtual QSize getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1);
Chris@1202: 
Chris@1202:     /**
Chris@1202:      * Render the view contents to a new SVG file.
Chris@1202:      */
Chris@1202:     virtual bool renderToSvgFile(QString filename);
Chris@1202: 
Chris@1202:     /**
Chris@1202:      * Render the view contents between the given frame extents to a
Chris@1202:      * new SVG file.
Chris@1202:      */
Chris@1202:     virtual bool renderPartToSvgFile(QString filename,
Chris@1202:                                      sv_frame_t f0, sv_frame_t f1);
Chris@1537: 
Chris@1537:     /**
Chris@1537:      * Return the visible vertical extents for the given unit, if any.
Chris@1537:      * Overridden from LayerGeometryProvider (see docs there).
Chris@1537:      */
Chris@1537:     bool getVisibleExtentsForUnit(QString unit, double &min, double &max,
Chris@1537:                                   bool &log) const override;
Chris@1537: 
Chris@1537:     /**
Chris@1537:      * Return some visible vertical extents and unit. That is, if at
Chris@1537:      * least one non-dormant layer has a non-empty unit and returns
Chris@1537:      * some values from its getDisplayExtents() method, return the
Chris@1537:      * extents and unit from the topmost of those. Otherwise return
Chris@1537:      * false.
Chris@1537:      */
Chris@1537:     bool getVisibleExtentsForAnyUnit(double &min, double &max,
Chris@1537:                                      bool &logarithmic, QString &unit) const;
Chris@1202:     
Chris@1537:     int getTextLabelYCoord(const Layer *layer, QPainter &) const override;
Chris@127: 
Chris@1406:     void toXml(QTextStream &stream, QString indent = "",
Chris@1406:                        QString extraAttributes = "") const override;
Chris@127: 
Chris@222:     // First frame actually in model, to right of scale, if present
Chris@902:     virtual sv_frame_t getFirstVisibleFrame() const;
Chris@902:     virtual sv_frame_t getLastVisibleFrame() const;
Chris@222: 
Chris@1406:     sv_frame_t getModelsStartFrame() const override;
Chris@1406:     sv_frame_t getModelsEndFrame() const override;
Chris@127: 
Chris@915:     /**
Chris@915:      * To be called from a layer, to obtain the extent of the surface
Chris@915:      * that the layer is currently painting to. This may be the extent
Chris@915:      * of the view (if 1x display scaling is in effect) or of a larger
Chris@915:      * cached pixmap (if greater display scaling is in effect).
Chris@915:      */
Chris@1406:     QRect getPaintRect() const override;
Chris@915: 
Chris@1406:     QSize getPaintSize() const override { return getPaintRect().size(); }
Chris@1406:     int getPaintWidth() const override { return getPaintRect().width(); }
Chris@1406:     int getPaintHeight() const override { return getPaintRect().height(); }
Chris@915: 
Chris@1406:     double scaleSize(double size) const override;
Chris@1406:     int scalePixelSize(int size) const override;
Chris@1406:     double scalePenWidth(double width) const override;
Chris@1406:     QPen scalePen(QPen pen) const override;
Chris@1401: 
Chris@1475:     typedef std::set<ModelId> ModelSet;
Chris@315:     ModelSet getModels();
Chris@315: 
Chris@1490:     //!!!??? poor name, probably poor api, consider this
Chris@1490:     void setUseAligningProxy(bool uap) {
Chris@1490:         m_useAligningProxy = uap;
Chris@1490:     }
Chris@1490:     
Chris@301:     //!!!
Chris@1475:     ModelId getAligningModel() const;
Chris@1490:     void getAligningAndReferenceModels(ModelId &aligning, ModelId &reference) const;
Chris@902:     sv_frame_t alignFromReference(sv_frame_t) const;
Chris@902:     sv_frame_t alignToReference(sv_frame_t) const;
Chris@902:     sv_frame_t getAlignedPlaybackFrame() const;
Chris@301: 
Chris@1406:     void updatePaintRect(QRect r) override { update(r); }
Chris@1030:     
Chris@1406:     View *getView() override { return this; } 
Chris@1406:     const View *getView() const override { return this; } 
Chris@918:     
Chris@127: signals:
Chris@127:     void propertyContainerAdded(PropertyContainer *pc);
Chris@127:     void propertyContainerRemoved(PropertyContainer *pc);
Chris@127:     void propertyContainerPropertyChanged(PropertyContainer *pc);
Chris@197:     void propertyContainerPropertyRangeChanged(PropertyContainer *pc);
Chris@127:     void propertyContainerNameChanged(PropertyContainer *pc);
Chris@298:     void propertyContainerSelected(PropertyContainer *pc);
Chris@127:     void propertyChanged(PropertyContainer::PropertyName);
Chris@127: 
Chris@336:     void layerModelChanged();
Chris@336: 
Chris@1483:     void cancelButtonPressed(Layer *);
Chris@1483:     
Chris@902:     void centreFrameChanged(sv_frame_t frame,
Chris@211:                             bool globalScroll,
Chris@211:                             PlaybackFollowMode followMode);
Chris@211: 
Chris@1183:     void zoomLevelChanged(ZoomLevel level, bool locked);
Chris@127: 
Chris@189:     void contextHelpChanged(const QString &);
Chris@189: 
Chris@127: public slots:
Chris@1481:     virtual void modelChanged(ModelId);
Chris@1481:     virtual void modelChangedWithin(ModelId, sv_frame_t startFrame, sv_frame_t endFrame);
Chris@1481:     virtual void modelCompletionChanged(ModelId);
Chris@1481:     virtual void modelAlignmentCompletionChanged(ModelId);
Chris@127:     virtual void modelReplaced();
Chris@127:     virtual void layerParametersChanged();
Chris@197:     virtual void layerParameterRangesChanged();
Chris@268:     virtual void layerMeasurementRectsChanged();
Chris@127:     virtual void layerNameChanged();
Chris@127: 
Chris@902:     virtual void globalCentreFrameChanged(sv_frame_t);
Chris@902:     virtual void viewCentreFrameChanged(View *, sv_frame_t);
Chris@902:     virtual void viewManagerPlaybackFrameChanged(sv_frame_t);
Chris@1183:     virtual void viewZoomLevelChanged(View *, ZoomLevel, bool);
Chris@127: 
Chris@1441:     /**
Chris@1441:      * A property container has been selected, for example in the
Chris@1441:      * associated property stack. The property container may be a
Chris@1441:      * layer, in which case the effect should be to raise that layer
Chris@1441:      * to the front of the view and select it; or it may be the view's
Chris@1441:      * own property container, in which case the effect is to switch
Chris@1441:      * to a mode in which no layer is selected.
Chris@1441:      *
Chris@1441:      * (This is the main slot for raising a layer.)
Chris@1441:      */
Chris@127:     virtual void propertyContainerSelected(View *, PropertyContainer *pc);
Chris@127: 
Chris@127:     virtual void selectionChanged();
Chris@127:     virtual void toolModeChanged();
Chris@133:     virtual void overlayModeChanged();
Chris@133:     virtual void zoomWheelsEnabledChanged();
Chris@127: 
Chris@797:     virtual void cancelClicked();
Chris@797: 
Chris@555:     virtual void progressCheckStalledTimerElapsed();
Chris@555: 
Chris@127: protected:
Chris@127:     View(QWidget *, bool showProgress);
Chris@1030: 
Chris@1030:     int m_id;
Chris@1030:     
Chris@1406:     void paintEvent(QPaintEvent *e) override;
Chris@127:     virtual void drawSelections(QPainter &);
Chris@127:     virtual bool shouldLabelSelections() const { return true; }
Chris@1357:     virtual void drawPlayPointer(QPainter &);
Chris@908:     virtual bool render(QPainter &paint, int x0, sv_frame_t f0, sv_frame_t f1);
Chris@339:     virtual void setPaintFont(QPainter &paint);
Chris@952: 
Chris@952:     QSize scaledSize(const QSize &s, int factor) {
Chris@952:         return QSize(s.width() * factor, s.height() * factor);
Chris@952:     }
Chris@952:     QRect scaledRect(const QRect &r, int factor) {
Chris@952:         return QRect(r.x() * factor, r.y() * factor,
Chris@952:                      r.width() * factor, r.height() * factor);
Chris@952:     }
Chris@339:     
Chris@127:     typedef std::vector<Layer *> LayerList;
Chris@127: 
Chris@908:     sv_samplerate_t getModelsSampleRate() const;
Chris@127:     bool areLayersScrollable() const;
Chris@127:     LayerList getScrollableBackLayers(bool testChanged, bool &changed) const;
Chris@127:     LayerList getNonScrollableFrontLayers(bool testChanged, bool &changed) const;
Chris@1354: 
Chris@1539:     Layer *getScaleProvidingLayerForUnit(QString unit) const;
Chris@1539:     
Chris@1183:     ZoomLevel getZoomConstraintLevel(ZoomLevel level,
Chris@1183:                                      ZoomConstraint::RoundingDirection dir =
Chris@1183:                                      ZoomConstraint::RoundNearest) const;
Chris@127: 
Chris@1354:     // These three are slow, intended for indexing GUI thumbwheel stuff
Chris@1354:     int countZoomLevels() const;
Chris@1354:     int getZoomLevelIndex(ZoomLevel level) const;
Chris@1354:     ZoomLevel getZoomLevelByIndex(int ix) const;
Chris@1354:     
Chris@183:     // True if the top layer(s) use colours for meaningful things.  If
Chris@183:     // this is the case, selections will be shown using unfilled boxes
Chris@183:     // rather than with a translucent fill.
Chris@183:     bool areLayerColoursSignificant() const;
Chris@183: 
Chris@217:     // True if the top layer has a time axis on the x coordinate (this
Chris@217:     // is generally the case except for spectrum/slice layers).  It
Chris@217:     // will not be possible to make or display selections if this is
Chris@217:     // false.
Chris@217:     bool hasTopLayerTimeXAxis() const;
Chris@217: 
Chris@902:     bool setCentreFrame(sv_frame_t f, bool doEmit);
Chris@127: 
Chris@902:     void movePlayPointer(sv_frame_t f);
Chris@511: 
Chris@1481:     void checkProgress(ModelId);
Chris@1496:     void checkAlignmentProgress(ModelId);
Chris@1605: 
Chris@1605:     bool waitForLayersToBeReady(); // returns false if user cancelled waiting
Chris@1496:     
Chris@384:     int getProgressBarWidth() const; // if visible
Chris@127: 
Chris@956:     int effectiveDevicePixelRatio() const;
Chris@956: 
Chris@902:     sv_frame_t          m_centreFrame;
Chris@1183:     ZoomLevel           m_zoomLevel;
Chris@127:     bool                m_followPan;
Chris@127:     bool                m_followZoom;
Chris@127:     PlaybackFollowMode  m_followPlay;
Chris@789:     bool                m_followPlayIsDetached;
Chris@902:     sv_frame_t          m_playPointerFrame;
Chris@127:     bool                m_lightBackground;
Chris@127:     bool                m_showProgress;
Chris@127: 
Chris@1215:     QPixmap            *m_cache;  // I own this
Chris@1215:     QPixmap            *m_buffer; // I own this
Chris@1357:     bool                m_cacheValid;
Chris@902:     sv_frame_t          m_cacheCentreFrame;
Chris@1183:     ZoomLevel           m_cacheZoomLevel;
Chris@127:     bool                m_selectionCached;
Chris@127: 
Chris@127:     bool                m_deleting;
Chris@127: 
Chris@835:     LayerList           m_layerStack; // I don't own these, but see dtor note above
Chris@835:     LayerList           m_fixedOrderLayers;
Chris@127:     bool                m_haveSelectedLayer;
Chris@127: 
Chris@1490:     bool                m_useAligningProxy;
Chris@1490: 
Chris@583:     QString             m_lastError;
Chris@583: 
Chris@127:     // caches for use in getScrollableBackLayers, getNonScrollableFrontLayers
Chris@127:     mutable LayerList m_lastScrollableBackLayers;
Chris@127:     mutable LayerList m_lastNonScrollableBackLayers;
Chris@127: 
Chris@555:     struct ProgressBarRec {
Chris@797:         QPushButton *cancel;
Chris@555:         QProgressBar *bar;
Chris@1496:         int lastStallCheckValue;
Chris@1496:         QTimer *stallCheckTimer;
Chris@555:     };
Chris@555:     typedef std::map<Layer *, ProgressBarRec> ProgressMap;
Chris@1496:     ProgressMap m_progressBars; // I own the ProgressBarRecs and their contents
Chris@1496: 
Chris@1496:     struct AlignmentProgressBarRec {
Chris@1496:         ModelId alignedModel;
Chris@1496:         QProgressBar *bar;
Chris@1496:     };
Chris@1496:     AlignmentProgressBarRec m_alignmentProgressBar;
Chris@127: 
Chris@127:     ViewManager *m_manager; // I don't own this
Chris@127:     ViewPropertyContainer *m_propertyContainer; // I own this
Chris@127: };
Chris@127: 
Chris@127: 
Chris@127: // Use this for delegation, because we can't subclass from
Chris@127: // PropertyContainer (which is a QObject) ourselves because of
Chris@127: // ambiguity with QFrame parent
Chris@127: 
Chris@127: class ViewPropertyContainer : public PropertyContainer
Chris@127: {
Chris@127:     Q_OBJECT
Chris@127: 
Chris@127: public:
Chris@127:     ViewPropertyContainer(View *v);
Chris@728:     virtual ~ViewPropertyContainer();
Chris@728: 
Chris@1406:     PropertyList getProperties() const override { return m_v->getProperties(); }
Chris@1406:     QString getPropertyLabel(const PropertyName &n) const override {
Chris@127:         return m_v->getPropertyLabel(n);
Chris@127:     }
Chris@1406:     PropertyType getPropertyType(const PropertyName &n) const override {
Chris@1266:         return m_v->getPropertyType(n);
Chris@127:     }
Chris@216:     int getPropertyRangeAndValue(const PropertyName &n, int *min, int *max,
Chris@1406:                                  int *deflt) const override {
Chris@1266:         return m_v->getPropertyRangeAndValue(n, min, max, deflt);
Chris@127:     }
Chris@1406:     QString getPropertyValueLabel(const PropertyName &n, int value) const override {
Chris@1266:         return m_v->getPropertyValueLabel(n, value);
Chris@127:     }
Chris@1406:     QString getPropertyContainerName() const override {
Chris@1266:         return m_v->getPropertyContainerName();
Chris@127:     }
Chris@1406:     QString getPropertyContainerIconName() const override {
Chris@1266:         return m_v->getPropertyContainerIconName();
Chris@127:     }
Chris@127: 
Chris@127: public slots:
Chris@1406:     void setProperty(const PropertyName &n, int value) override {
Chris@1266:         m_v->setProperty(n, value);
Chris@127:     }
Chris@127: 
Chris@127: protected:
Chris@127:     View *m_v;
Chris@127: };
Chris@127: 
Chris@127: #endif
Chris@127: