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