lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 Chris Cannam. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #ifndef _VIEW_H_ lbajardsilogic@0: #define _VIEW_H_ lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: #include "base/ZoomConstraint.h" lbajardsilogic@0: #include "base/PropertyContainer.h" lbajardsilogic@0: #include "ViewManager.h" lbajardsilogic@0: #include "base/XmlExportable.h" lbajardsilogic@0: lbajardsilogic@0: // #define DEBUG_VIEW_WIDGET_PAINT 1 lbajardsilogic@0: lbajardsilogic@0: class Layer; lbajardsilogic@0: class ViewPropertyContainer; lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * View is the base class of widgets that display one or more lbajardsilogic@0: * overlaid views of data against a horizontal time scale. lbajardsilogic@0: * lbajardsilogic@0: * A View may have any number of attached Layers, each of which lbajardsilogic@0: * is expected to have one data Model (although multiple views may lbajardsilogic@0: * share the same model). lbajardsilogic@0: * lbajardsilogic@0: * A View may be panned in time and zoomed, although the lbajardsilogic@0: * mechanisms for doing so (as well as any other operations and lbajardsilogic@0: * properties available) depend on the subclass. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: class View : public QFrame, lbajardsilogic@0: public XmlExportable lbajardsilogic@0: { lbajardsilogic@0: Q_OBJECT lbajardsilogic@0: lbajardsilogic@0: public: lbajardsilogic@0: /** lbajardsilogic@0: * Deleting a View does not delete any of its layers. They should lbajardsilogic@0: * be managed elsewhere (e.g. by the Document). lbajardsilogic@0: */ lbajardsilogic@0: virtual ~View(); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Retrieve the first visible sample frame on the widget. lbajardsilogic@0: * This is a calculated value based on the centre-frame, widget lbajardsilogic@0: * width and zoom level. The result may be negative. lbajardsilogic@0: */ lbajardsilogic@0: virtual long getStartFrame() const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Set the widget pan based on the given first visible frame. The lbajardsilogic@0: * frame value may be negative. lbajardsilogic@0: */ lbajardsilogic@0: virtual void setStartFrame(long); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the centre frame of the visible widget. This is an lbajardsilogic@0: * exact value that does not depend on the zoom block size. Other lbajardsilogic@0: * frame values (start, end) are calculated from this based on the lbajardsilogic@0: * zoom and other factors. lbajardsilogic@0: */ lbajardsilogic@0: virtual size_t getCentreFrame() const { return m_centreFrame; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Set the centre frame of the visible widget. lbajardsilogic@0: */ lbajardsilogic@0: virtual void setCentreFrame(size_t f) { setCentreFrame(f, true); } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Retrieve the last visible sample frame on the widget. lbajardsilogic@0: * This is a calculated value based on the centre-frame, widget lbajardsilogic@0: * width and zoom level. lbajardsilogic@0: */ lbajardsilogic@0: virtual size_t getEndFrame() const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the pixel x-coordinate corresponding to a given sample lbajardsilogic@0: * frame (which may be negative). lbajardsilogic@0: */ lbajardsilogic@0: int getXForFrame(long frame) const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the closest frame to the given pixel x-coordinate. lbajardsilogic@0: */ lbajardsilogic@0: long getFrameForX(int x) const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the pixel y-coordinate corresponding to a given lbajardsilogic@0: * frequency, if the frequency range is as specified. This does lbajardsilogic@0: * not imply any policy about layer frequency ranges, but it might lbajardsilogic@0: * be useful for layers to match theirs up if desired. lbajardsilogic@0: * lbajardsilogic@0: * Not thread-safe in logarithmic mode. Call only from GUI thread. lbajardsilogic@0: */ lbajardsilogic@0: float getYForFrequency(float frequency, float minFreq, float maxFreq, lbajardsilogic@0: bool logarithmic) const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the closest frequency to the given pixel y-coordinate, lbajardsilogic@0: * if the frequency range is as specified. lbajardsilogic@0: * lbajardsilogic@0: * Not thread-safe in logarithmic mode. Call only from GUI thread. lbajardsilogic@0: */ lbajardsilogic@0: float getFrequencyForY(int y, float minFreq, float maxFreq, lbajardsilogic@0: bool logarithmic) const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the zoom level, i.e. the number of frames per pixel lbajardsilogic@0: */ lbajardsilogic@0: int getZoomLevel() const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Set the zoom level, i.e. the number of frames per pixel. The lbajardsilogic@0: * centre frame will be unchanged; the start and end frames will lbajardsilogic@0: * change. lbajardsilogic@0: */ lbajardsilogic@0: virtual void setZoomLevel(size_t z); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Zoom in or out. lbajardsilogic@0: */ lbajardsilogic@0: virtual void zoom(bool in); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Scroll left or right by a smallish or largish amount. lbajardsilogic@0: */ lbajardsilogic@0: virtual void scroll(bool right, bool lots); lbajardsilogic@0: lbajardsilogic@0: virtual void addLayer(Layer *v); lbajardsilogic@0: virtual void removeLayer(Layer *v); // does not delete the layer lbajardsilogic@0: virtual int getLayerCount() const { return m_layers.size(); } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return a layer, counted in stacking order. That is, layer 0 is lbajardsilogic@0: * the bottom layer and layer "getLayerCount()-1" is the top one. lbajardsilogic@0: */ lbajardsilogic@0: virtual Layer *getLayer(int n) { return m_layers[n]; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the layer last selected by the user. This is normally lbajardsilogic@0: * the top layer, the same as getLayer(getLayerCount()-1). lbajardsilogic@0: * However, if the user has selected the pane itself more recently lbajardsilogic@0: * than any of the layers on it, this function will return 0. It lbajardsilogic@0: * will also return 0 if there are no layers. lbajardsilogic@0: */ lbajardsilogic@0: virtual Layer *getSelectedLayer(); lbajardsilogic@0: virtual const Layer *getSelectedLayer() const; lbajardsilogic@0: lbajardsilogic@0: virtual void setViewManager(ViewManager *m); lbajardsilogic@0: virtual ViewManager *getViewManager() const { return m_manager; } lbajardsilogic@0: lbajardsilogic@0: virtual void setFollowGlobalPan(bool f); lbajardsilogic@0: virtual bool getFollowGlobalPan() const { return m_followPan; } lbajardsilogic@0: lbajardsilogic@0: virtual void setFollowGlobalZoom(bool f); lbajardsilogic@0: virtual bool getFollowGlobalZoom() const { return m_followZoom; } lbajardsilogic@0: lbajardsilogic@0: virtual bool hasLightBackground() const; lbajardsilogic@0: lbajardsilogic@0: enum TextStyle { lbajardsilogic@0: BoxedText, lbajardsilogic@0: OutlinedText lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: virtual void drawVisibleText(QPainter &p, int x, int y, lbajardsilogic@0: QString text, TextStyle style); lbajardsilogic@0: lbajardsilogic@0: virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const { lbajardsilogic@0: return false; lbajardsilogic@0: } lbajardsilogic@0: virtual bool shouldIlluminateLocalSelection(QPoint &, bool &, bool &) const { lbajardsilogic@0: return false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: virtual void setPlaybackFollow(PlaybackFollowMode m); lbajardsilogic@0: virtual PlaybackFollowMode getPlaybackFollow() const { return m_followPlay; } lbajardsilogic@0: lbajardsilogic@0: typedef PropertyContainer::PropertyName PropertyName; lbajardsilogic@0: lbajardsilogic@0: // We implement the PropertyContainer API, although we don't lbajardsilogic@0: // actually subclass PropertyContainer. We have our own lbajardsilogic@0: // PropertyContainer that we can return on request that just lbajardsilogic@0: // delegates back to us. lbajardsilogic@0: virtual PropertyContainer::PropertyList getProperties() const; lbajardsilogic@0: virtual QString getPropertyLabel(const PropertyName &) const; lbajardsilogic@0: virtual PropertyContainer::PropertyType getPropertyType(const PropertyName &) const; lbajardsilogic@0: virtual int getPropertyRangeAndValue(const PropertyName &, lbajardsilogic@0: int *min, int *max, int *deflt) const; lbajardsilogic@0: virtual QString getPropertyValueLabel(const PropertyName &, lbajardsilogic@0: int value) const; lbajardsilogic@0: virtual void setProperty(const PropertyName &, int value); lbajardsilogic@0: virtual QString getPropertyContainerName() const { lbajardsilogic@0: return objectName(); lbajardsilogic@0: } lbajardsilogic@0: virtual QString getPropertyContainerIconName() const = 0; lbajardsilogic@0: lbajardsilogic@0: virtual size_t getPropertyContainerCount() const; lbajardsilogic@0: lbajardsilogic@0: virtual const PropertyContainer *getPropertyContainer(size_t i) const; lbajardsilogic@0: virtual PropertyContainer *getPropertyContainer(size_t i); lbajardsilogic@0: lbajardsilogic@0: // Render the contents on a wide canvas lbajardsilogic@0: virtual QImage *toNewImage(size_t f0, size_t f1); lbajardsilogic@0: virtual QImage *toNewImage(); lbajardsilogic@0: virtual QSize getImageSize(size_t f0, size_t f1); lbajardsilogic@0: virtual QSize getImageSize(); lbajardsilogic@0: lbajardsilogic@0: virtual int getTextLabelHeight(const Layer *layer, QPainter &) const; lbajardsilogic@0: lbajardsilogic@0: virtual bool getValueExtents(QString unit, float &min, float &max, lbajardsilogic@0: bool &log) const; lbajardsilogic@0: lbajardsilogic@0: virtual QString toXmlString(QString indent = "", lbajardsilogic@0: QString extraAttributes = "") const; lbajardsilogic@0: lbajardsilogic@23: virtual QString toEasaierXmlString(QString indent = "", lbajardsilogic@23: QString extraAttributes = "") const; lbajardsilogic@23: lbajardsilogic@0: // First frame actually in model, to right of scale, if present lbajardsilogic@0: virtual size_t getFirstVisibleFrame() const; lbajardsilogic@0: virtual size_t getLastVisibleFrame() const; lbajardsilogic@0: lbajardsilogic@0: size_t getModelsStartFrame() const; lbajardsilogic@0: size_t getModelsEndFrame() const; lbajardsilogic@0: lbajardsilogic@0: signals: lbajardsilogic@0: void propertyContainerAdded(PropertyContainer *pc); lbajardsilogic@0: void propertyContainerRemoved(PropertyContainer *pc); lbajardsilogic@0: void propertyContainerPropertyChanged(PropertyContainer *pc); lbajardsilogic@0: void propertyContainerPropertyRangeChanged(PropertyContainer *pc); lbajardsilogic@0: void propertyContainerNameChanged(PropertyContainer *pc); lbajardsilogic@0: void propertyChanged(PropertyContainer::PropertyName); lbajardsilogic@0: lbajardsilogic@0: void centreFrameChanged(unsigned long frame, lbajardsilogic@0: bool globalScroll, lbajardsilogic@0: PlaybackFollowMode followMode); lbajardsilogic@0: lbajardsilogic@0: void zoomLevelChanged(unsigned long, bool); lbajardsilogic@0: lbajardsilogic@0: void contextHelpChanged(const QString &); lbajardsilogic@0: lbajardsilogic@0: public slots: lbajardsilogic@0: virtual void modelChanged(); lbajardsilogic@0: virtual void modelChanged(size_t startFrame, size_t endFrame); lbajardsilogic@0: virtual void modelCompletionChanged(); lbajardsilogic@0: virtual void modelReplaced(); lbajardsilogic@0: virtual void layerParametersChanged(); lbajardsilogic@0: virtual void layerParameterRangesChanged(); lbajardsilogic@0: virtual void layerNameChanged(); lbajardsilogic@0: lbajardsilogic@0: virtual void globalCentreFrameChanged(unsigned long); lbajardsilogic@0: virtual void viewCentreFrameChanged(View *, unsigned long); lbajardsilogic@0: virtual void viewManagerPlaybackFrameChanged(unsigned long); lbajardsilogic@0: virtual void viewZoomLevelChanged(View *, unsigned long, bool); lbajardsilogic@0: lbajardsilogic@0: virtual void propertyContainerSelected(View *, PropertyContainer *pc); lbajardsilogic@0: lbajardsilogic@0: virtual void selectionChanged(); lbajardsilogic@0: virtual void toolModeChanged(); lbajardsilogic@0: virtual void overlayModeChanged(); lbajardsilogic@0: virtual void zoomWheelsEnabledChanged(); lbajardsilogic@0: lbajardsilogic@0: protected: lbajardsilogic@0: View(QWidget *, bool showProgress); lbajardsilogic@0: virtual void paintEvent(QPaintEvent *e); lbajardsilogic@0: virtual void drawSelections(QPainter &); lbajardsilogic@0: virtual bool shouldLabelSelections() const { return true; } lbajardsilogic@0: virtual bool render(QPainter &paint, int x0, size_t f0, size_t f1); lbajardsilogic@0: lbajardsilogic@0: typedef std::vector LayerList; lbajardsilogic@0: lbajardsilogic@0: int getModelsSampleRate() const; lbajardsilogic@0: bool areLayersScrollable() const; lbajardsilogic@0: LayerList getScrollableBackLayers(bool testChanged, bool &changed) const; lbajardsilogic@0: LayerList getNonScrollableFrontLayers(bool testChanged, bool &changed) const; lbajardsilogic@0: size_t getZoomConstraintBlockSize(size_t blockSize, lbajardsilogic@0: ZoomConstraint::RoundingDirection dir = lbajardsilogic@0: ZoomConstraint::RoundNearest) const; lbajardsilogic@0: lbajardsilogic@0: // True if the top layer(s) use colours for meaningful things. If lbajardsilogic@0: // this is the case, selections will be shown using unfilled boxes lbajardsilogic@0: // rather than with a translucent fill. lbajardsilogic@0: bool areLayerColoursSignificant() const; lbajardsilogic@0: lbajardsilogic@0: // True if the top layer has a time axis on the x coordinate (this lbajardsilogic@0: // is generally the case except for spectrum/slice layers). It lbajardsilogic@0: // will not be possible to make or display selections if this is lbajardsilogic@0: // false. lbajardsilogic@0: bool hasTopLayerTimeXAxis() const; lbajardsilogic@0: lbajardsilogic@0: bool setCentreFrame(size_t f, bool doEmit); lbajardsilogic@0: lbajardsilogic@0: void checkProgress(void *object); lbajardsilogic@0: lbajardsilogic@0: size_t m_centreFrame; lbajardsilogic@0: int m_zoomLevel; lbajardsilogic@0: bool m_followPan; lbajardsilogic@0: bool m_followZoom; lbajardsilogic@0: PlaybackFollowMode m_followPlay; lbajardsilogic@0: size_t m_playPointerFrame; lbajardsilogic@0: bool m_lightBackground; lbajardsilogic@0: bool m_showProgress; lbajardsilogic@0: lbajardsilogic@0: QPixmap *m_cache; lbajardsilogic@0: size_t m_cacheCentreFrame; lbajardsilogic@0: int m_cacheZoomLevel; lbajardsilogic@0: bool m_selectionCached; lbajardsilogic@0: lbajardsilogic@0: bool m_deleting; lbajardsilogic@0: lbajardsilogic@0: LayerList m_layers; // I don't own these, but see dtor note above lbajardsilogic@0: bool m_haveSelectedLayer; lbajardsilogic@0: lbajardsilogic@0: // caches for use in getScrollableBackLayers, getNonScrollableFrontLayers lbajardsilogic@0: mutable LayerList m_lastScrollableBackLayers; lbajardsilogic@0: mutable LayerList m_lastNonScrollableBackLayers; lbajardsilogic@0: lbajardsilogic@0: class LayerProgressBar : public QProgressBar { lbajardsilogic@0: public: lbajardsilogic@0: LayerProgressBar(QWidget *parent); lbajardsilogic@0: virtual QString text() const { return m_text; } lbajardsilogic@0: virtual void setText(QString text) { m_text = text; } lbajardsilogic@0: protected: lbajardsilogic@0: QString m_text; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: typedef std::map ProgressMap; lbajardsilogic@0: ProgressMap m_progressBars; // I own the ProgressBars lbajardsilogic@0: lbajardsilogic@0: ViewManager *m_manager; // I don't own this lbajardsilogic@0: ViewPropertyContainer *m_propertyContainer; // I own this lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: // Use this for delegation, because we can't subclass from lbajardsilogic@0: // PropertyContainer (which is a QObject) ourselves because of lbajardsilogic@0: // ambiguity with QFrame parent lbajardsilogic@0: lbajardsilogic@0: class ViewPropertyContainer : public PropertyContainer lbajardsilogic@0: { lbajardsilogic@0: Q_OBJECT lbajardsilogic@0: lbajardsilogic@0: public: lbajardsilogic@0: ViewPropertyContainer(View *v); lbajardsilogic@0: PropertyList getProperties() const { return m_v->getProperties(); } lbajardsilogic@0: QString getPropertyLabel(const PropertyName &n) const { lbajardsilogic@0: return m_v->getPropertyLabel(n); lbajardsilogic@0: } lbajardsilogic@0: PropertyType getPropertyType(const PropertyName &n) const { lbajardsilogic@0: return m_v->getPropertyType(n); lbajardsilogic@0: } lbajardsilogic@0: int getPropertyRangeAndValue(const PropertyName &n, int *min, int *max, lbajardsilogic@0: int *deflt) const { lbajardsilogic@0: return m_v->getPropertyRangeAndValue(n, min, max, deflt); lbajardsilogic@0: } lbajardsilogic@0: QString getPropertyValueLabel(const PropertyName &n, int value) const { lbajardsilogic@0: return m_v->getPropertyValueLabel(n, value); lbajardsilogic@0: } lbajardsilogic@0: QString getPropertyContainerName() const { lbajardsilogic@0: return m_v->getPropertyContainerName(); lbajardsilogic@0: } lbajardsilogic@0: QString getPropertyContainerIconName() const { lbajardsilogic@0: return m_v->getPropertyContainerIconName(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: public slots: lbajardsilogic@0: virtual void setProperty(const PropertyName &n, int value) { lbajardsilogic@0: m_v->setProperty(n, value); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: protected: lbajardsilogic@0: View *m_v; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: #endif lbajardsilogic@0: