lbajardsilogic@0: 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 and QMUL. 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 _LAYER_H_ lbajardsilogic@0: #define _LAYER_H_ lbajardsilogic@0: lbajardsilogic@0: #include "base/PropertyContainer.h" lbajardsilogic@0: #include "base/XmlExportable.h" lbajardsilogic@0: #include "base/Selection.h" lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: benoitrigolleau@61: lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: class ZoomConstraint; lbajardsilogic@0: class Model; lbajardsilogic@0: class QPainter; lbajardsilogic@0: class View; lbajardsilogic@0: class QMouseEvent; lbajardsilogic@0: class Clipboard; lbajardsilogic@0: class RangeMapper; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * The base class for visual representations of the data found in a lbajardsilogic@0: * Model. Layers are expected to be able to draw themselves onto a lbajardsilogic@0: * View, and may also be editable. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: class Layer : public PropertyContainer, lbajardsilogic@0: public XmlExportable lbajardsilogic@0: { lbajardsilogic@0: Q_OBJECT lbajardsilogic@0: lbajardsilogic@0: public: lbajardsilogic@0: Layer(); lbajardsilogic@0: virtual ~Layer(); lbajardsilogic@0: lbajardsilogic@18: inline QString getModelName() const {return m_modelName;} lbajardsilogic@18: inline int getModelId() const {return m_modelId;} lbajardsilogic@18: lbajardsilogic@18: inline void setModelName(QString& name) {m_modelName = name;} lbajardsilogic@18: inline void setModelId(int& id){m_modelId = id;} lbajardsilogic@18: lbajardsilogic@0: virtual const Model *getModel() const = 0; lbajardsilogic@0: virtual Model *getModel() { lbajardsilogic@0: return const_cast(const_cast(this)->getModel()); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return a zoom constraint object defining the supported zoom lbajardsilogic@0: * levels for this layer. If this returns zero, the layer will lbajardsilogic@0: * support any integer zoom level. lbajardsilogic@0: */ lbajardsilogic@0: virtual const ZoomConstraint *getZoomConstraint() const { return 0; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return true if this layer can handle zoom levels other than lbajardsilogic@0: * those supported by its zoom constraint (presumably less lbajardsilogic@0: * efficiently or accurately than the officially supported zoom lbajardsilogic@0: * levels). If true, the layer will unenthusistically accept any lbajardsilogic@0: * integer zoom level from 1 to the maximum returned by its zoom lbajardsilogic@0: * constraint. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool supportsOtherZoomLevels() const { return true; } lbajardsilogic@0: lbajardsilogic@0: virtual void paint(View *, QPainter &, QRect) const = 0; lbajardsilogic@0: lbajardsilogic@0: enum VerticalPosition { lbajardsilogic@0: PositionTop, PositionMiddle, PositionBottom lbajardsilogic@0: }; lbajardsilogic@0: virtual VerticalPosition getPreferredTimeRulerPosition() const { lbajardsilogic@0: return PositionMiddle; lbajardsilogic@0: } lbajardsilogic@0: virtual VerticalPosition getPreferredFrameCountPosition() const { lbajardsilogic@0: return PositionBottom; lbajardsilogic@0: } lbajardsilogic@0: virtual bool hasLightBackground() const { lbajardsilogic@0: return true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: virtual QString getPropertyContainerIconName() const; lbajardsilogic@0: lbajardsilogic@0: virtual QString getPropertyContainerName() const { lbajardsilogic@0: return objectName(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: virtual QString getLayerPresentationName() const; lbajardsilogic@0: lbajardsilogic@0: virtual int getVerticalScaleWidth(View *, QPainter &) const { return 0; } lbajardsilogic@0: virtual void paintVerticalScale(View *, QPainter &, QRect) const { } lbajardsilogic@0: lbajardsilogic@0: virtual bool getCrosshairExtents(View *, QPainter &, QPoint /* cursorPos */, lbajardsilogic@0: std::vector &) const { lbajardsilogic@0: return false; lbajardsilogic@0: } lbajardsilogic@0: virtual void paintCrosshairs(View *, QPainter &, QPoint) const { } lbajardsilogic@0: lbajardsilogic@0: virtual QString getFeatureDescription(View *, QPoint &) const { lbajardsilogic@0: return ""; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: enum SnapType { lbajardsilogic@0: SnapLeft, lbajardsilogic@0: SnapRight, lbajardsilogic@0: SnapNearest, lbajardsilogic@0: SnapNeighbouring lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Adjust the given frame to snap to the nearest feature, if lbajardsilogic@0: * possible. lbajardsilogic@0: * lbajardsilogic@0: * If snap is SnapLeft or SnapRight, adjust the frame to match lbajardsilogic@0: * that of the nearest feature in the given direction regardless lbajardsilogic@0: * of how far away it is. If snap is SnapNearest, adjust the lbajardsilogic@0: * frame to that of the nearest feature in either direction. If lbajardsilogic@0: * snap is SnapNeighbouring, adjust the frame to that of the lbajardsilogic@0: * nearest feature if it is close, and leave it alone (returning lbajardsilogic@0: * false) otherwise. SnapNeighbouring should always choose the lbajardsilogic@0: * same feature that would be used in an editing operation through lbajardsilogic@0: * calls to editStart etc. lbajardsilogic@0: * lbajardsilogic@0: * Return true if a suitable feature was found and frame adjusted lbajardsilogic@0: * accordingly. Return false if no suitable feature was available lbajardsilogic@0: * (and leave frame unmodified). Also return the resolution of lbajardsilogic@0: * the model in this layer in sample frames. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool snapToFeatureFrame(View * /* v */, lbajardsilogic@0: int & /* frame */, lbajardsilogic@0: size_t &resolution, lbajardsilogic@0: SnapType /* snap */) const { lbajardsilogic@0: resolution = 1; lbajardsilogic@0: return false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // Draw and edit modes: lbajardsilogic@0: // lbajardsilogic@0: // Layer needs to get actual mouse events, I guess. Draw mode is lbajardsilogic@0: // probably the easier. lbajardsilogic@0: lbajardsilogic@0: virtual void drawStart(View *, QMouseEvent *) { } lbajardsilogic@0: virtual void drawDrag(View *, QMouseEvent *) { } lbajardsilogic@0: virtual void drawEnd(View *, QMouseEvent *) { } lbajardsilogic@0: lbajardsilogic@0: virtual void editStart(View *, QMouseEvent *) { } lbajardsilogic@0: virtual void editDrag(View *, QMouseEvent *) { } lbajardsilogic@0: virtual void editEnd(View *, QMouseEvent *) { } lbajardsilogic@0: lbajardsilogic@0: virtual void editOpen(View *, QMouseEvent *) { } // on double-click lbajardsilogic@0: lbajardsilogic@0: virtual void moveSelection(Selection, size_t /* newStartFrame */) { } lbajardsilogic@0: virtual void resizeSelection(Selection, Selection /* newSize */) { } lbajardsilogic@0: virtual void deleteSelection(Selection) { } lbajardsilogic@0: lbajardsilogic@0: virtual void copy(Selection, Clipboard & /* to */) { } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Paste from the given clipboard onto the layer at the given lbajardsilogic@0: * frame offset. If interactive is true, the layer may ask the lbajardsilogic@0: * user about paste options through a dialog if desired, and may lbajardsilogic@0: * return false if the user cancelled the paste operation. This lbajardsilogic@0: * function should return true if a paste actually occurred. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool paste(const Clipboard & /* from */, lbajardsilogic@0: int /* frameOffset */, lbajardsilogic@0: bool /* interactive */) { return false; } lbajardsilogic@0: lbajardsilogic@0: // Text mode: lbajardsilogic@0: // lbajardsilogic@0: // Label nearest feature. We need to get the feature coordinates lbajardsilogic@0: // and current label from the layer, and then the pane can pop up lbajardsilogic@0: // a little text entry dialog at the right location. Or we edit lbajardsilogic@0: // in place? Probably the dialog is easier. lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * This should return true if the layer can safely be scrolled lbajardsilogic@0: * automatically by a given view (simply copying the existing data lbajardsilogic@0: * and then refreshing the exposed area) without altering its lbajardsilogic@0: * meaning. For the view widget as a whole this is usually not lbajardsilogic@0: * possible because of invariant (non-scrolling) material lbajardsilogic@0: * displayed over the top, but the widget may be able to optimise lbajardsilogic@0: * scrolling better if it is known that individual views can be lbajardsilogic@0: * scrolled safely in this way. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool isLayerScrollable(const View *) const { return true; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * This should return true if the layer completely obscures any lbajardsilogic@0: * underlying layers. It's used to determine whether the view can lbajardsilogic@0: * safely draw any selection rectangles under the layer instead of lbajardsilogic@0: * over it, in the case where the layer is not scrollable and lbajardsilogic@0: * therefore needs to be redrawn each time (so that the selection lbajardsilogic@0: * rectangle can be cached). lbajardsilogic@0: */ lbajardsilogic@0: virtual bool isLayerOpaque() const { return false; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * This should return true if the layer uses colours to indicate lbajardsilogic@0: * meaningful information (as opposed to just using a single lbajardsilogic@0: * colour of the user's choice). If this is the case, the view lbajardsilogic@0: * will show selections using unfilled rectangles instead of lbajardsilogic@0: * translucent filled rectangles, so as not to disturb the colours lbajardsilogic@0: * underneath. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool isLayerColourSignificant() const { return false; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * This should return true if the layer can be edited by the user. lbajardsilogic@0: * If this is the case, the appropriate edit tools may be made lbajardsilogic@0: * available by the application and the layer's drawStart/Drag/End lbajardsilogic@0: * and editStart/Drag/End methods should be implemented. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool isLayerEditable() const { return false; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the proportion of background work complete in drawing lbajardsilogic@0: * this view, as a percentage -- in most cases this will be the lbajardsilogic@0: * value returned by pointer from a call to the underlying model's lbajardsilogic@0: * isReady(int *) call. The view may choose to show a progress lbajardsilogic@0: * meter if it finds that this returns < 100 at any given moment. lbajardsilogic@0: */ lbajardsilogic@0: virtual int getCompletion(View *) const { return 100; } lbajardsilogic@0: lbajardsilogic@0: virtual void setObjectName(const QString &name); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Convert the layer's data (though not those of the model it lbajardsilogic@0: * refers to) into an XML string for file output. This class lbajardsilogic@0: * implements the basic name/type/model-id output; subclasses will lbajardsilogic@0: * typically call this superclass implementation with extra lbajardsilogic@0: * attributes describing their particular properties. lbajardsilogic@0: */ lbajardsilogic@0: virtual QString toXmlString(QString indent = "", lbajardsilogic@0: QString extraAttributes = "") const; lbajardsilogic@0: lbajardsilogic@18: virtual QString toEasaierXmlString(QString indent = "", lbajardsilogic@18: QString extraAttributes = "") const; lbajardsilogic@18: lbajardsilogic@0: /** lbajardsilogic@0: * Set the particular properties of a layer (those specific to the lbajardsilogic@0: * subclass) from a set of XML attributes. This is the effective lbajardsilogic@0: * inverse of the toXmlString method. lbajardsilogic@0: */ lbajardsilogic@0: virtual void setProperties(const QXmlAttributes &) = 0; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Indicate that a layer is not currently visible in the given lbajardsilogic@0: * view and is not expected to become visible in the near future lbajardsilogic@0: * (for example because the user has explicitly removed or hidden lbajardsilogic@0: * it). The layer may respond by (for example) freeing any cache lbajardsilogic@0: * memory it is using, until next time its paint method is called, lbajardsilogic@0: * when it should set itself un-dormant again. lbajardsilogic@0: * lbajardsilogic@0: * A layer class that overrides this function must also call this lbajardsilogic@0: * class's implementation. lbajardsilogic@0: */ lbajardsilogic@0: virtual void setLayerDormant(const View *v, bool dormant); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return whether the layer is dormant (i.e. hidden) in the given lbajardsilogic@0: * view. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool isLayerDormant(const View *v) const; lbajardsilogic@0: lbajardsilogic@0: virtual PlayParameters *getPlayParameters(); lbajardsilogic@0: lbajardsilogic@0: virtual bool needsTextLabelHeight() const { return false; } lbajardsilogic@0: lbajardsilogic@0: virtual bool hasTimeXAxis() const { return true; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the minimum and maximum values for the y axis of the lbajardsilogic@0: * model in this layer, as well as whether the layer is configured lbajardsilogic@0: * to use a logarithmic y axis display. Also return the unit for lbajardsilogic@0: * these values if known. lbajardsilogic@0: * lbajardsilogic@0: * This function returns the "normal" extents for the layer, not lbajardsilogic@0: * necessarily the extents actually in use in the display. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool getValueExtents(float &min, float &max, lbajardsilogic@0: bool &logarithmic, QString &unit) const = 0; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return the minimum and maximum values within the displayed lbajardsilogic@0: * range for the y axis, if only a subset of the whole range of lbajardsilogic@0: * the model (returned by getValueExtents) is being displayed. lbajardsilogic@0: * Return false if the layer is not imposing a particular display lbajardsilogic@0: * extent (using the normal layer extents or deferring to whatever lbajardsilogic@0: * is in use for the same units elsewhere in the view). lbajardsilogic@0: */ lbajardsilogic@0: virtual bool getDisplayExtents(float & /* min */, lbajardsilogic@0: float & /* max */) const { lbajardsilogic@0: return false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Set the displayed minimum and maximum values for the y axis to lbajardsilogic@0: * the given range, if supported. Return false if not supported lbajardsilogic@0: * on this layer (and set nothing). In most cases, layers that lbajardsilogic@0: * return false for getDisplayExtents should also return false for lbajardsilogic@0: * this function. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool setDisplayExtents(float /* min */, lbajardsilogic@0: float /* max */) { lbajardsilogic@0: return false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Get the number of vertical zoom steps available for this layer. lbajardsilogic@0: * If vertical zooming is not available, return 0. The meaning of lbajardsilogic@0: * "zooming" is entirely up to the layer -- changing the zoom lbajardsilogic@0: * level may cause the layer to reset its display extents or lbajardsilogic@0: * change another property such as display gain. However, layers lbajardsilogic@0: * are advised for consistency to treat smaller zoom steps as lbajardsilogic@0: * "more distant" or "zoomed out" and larger ones as "closer" or lbajardsilogic@0: * "zoomed in". lbajardsilogic@0: * lbajardsilogic@0: * Layers that provide this facility should also emit the lbajardsilogic@0: * verticalZoomChanged signal if their vertical zoom changes lbajardsilogic@0: * due to factors other than setVerticalZoomStep being called. lbajardsilogic@0: */ lbajardsilogic@0: virtual int getVerticalZoomSteps(int & /* defaultStep */) const { return 0; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Get the current vertical zoom step. A layer may support finer lbajardsilogic@0: * control over ranges etc than is available through the integer lbajardsilogic@0: * zoom step mechanism; if this one does, it should just return lbajardsilogic@0: * the nearest of the available zoom steps to the current settings. lbajardsilogic@0: */ lbajardsilogic@0: virtual int getCurrentVerticalZoomStep() const { return 0; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Set the vertical zoom step. The meaning of "zooming" is lbajardsilogic@0: * entirely up to the layer -- changing the zoom level may cause lbajardsilogic@0: * the layer to reset its display extents or change another lbajardsilogic@0: * property such as display gain. lbajardsilogic@0: */ lbajardsilogic@0: virtual void setVerticalZoomStep(int) { } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Create and return a range mapper for vertical zoom step values. lbajardsilogic@0: * See the RangeMapper documentation for more details. The lbajardsilogic@0: * returned value is allocated on the heap and will be deleted by lbajardsilogic@0: * the caller. lbajardsilogic@0: */ lbajardsilogic@0: virtual RangeMapper *getNewVerticalZoomRangeMapper() const { return 0; } lbajardsilogic@0: benoitrigolleau@61: /** benoitrigolleau@61: * Set the basic display colour for waveforms. benoitrigolleau@61: * benoitrigolleau@61: */ benoitrigolleau@61: virtual void setBaseColour(QColor){}; benoitrigolleau@61: virtual QColor getBaseColour() const {return -1;}; benoitrigolleau@61: lbajardsilogic@0: public slots: lbajardsilogic@0: void showLayer(View *, bool show); lbajardsilogic@0: lbajardsilogic@0: signals: lbajardsilogic@0: void modelChanged(); lbajardsilogic@0: void modelCompletionChanged(); lbajardsilogic@0: void modelChanged(size_t startFrame, size_t endFrame); lbajardsilogic@0: void modelReplaced(); lbajardsilogic@0: lbajardsilogic@0: void layerParametersChanged(); lbajardsilogic@0: void layerParameterRangesChanged(); lbajardsilogic@0: void layerNameChanged(); lbajardsilogic@0: lbajardsilogic@0: void verticalZoomChanged(); lbajardsilogic@0: lbajardsilogic@0: private: lbajardsilogic@0: mutable QMutex m_dormancyMutex; lbajardsilogic@0: mutable std::map m_dormancy; lbajardsilogic@18: lbajardsilogic@18: QString m_modelName; lbajardsilogic@18: int m_modelId; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: #endif lbajardsilogic@0: