Chris@0: Chris@0: /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@0: A waveform viewer and audio annotation editor. Chris@2: Chris Cannam, Queen Mary University of London, 2005-2006 Chris@0: Chris@0: This is experimental software. Not for distribution. Chris@0: */ Chris@0: Chris@26: #ifndef _LAYER_H_ Chris@26: #define _LAYER_H_ Chris@0: Chris@0: #include "PropertyContainer.h" Chris@3: #include "XmlExportable.h" Chris@35: #include "Selection.h" Chris@0: Chris@0: #include Chris@0: #include Chris@6: #include Chris@0: Chris@39: #include Chris@39: Chris@0: class ZoomConstraint; Chris@0: class Model; Chris@0: class QPainter; Chris@0: class View; Chris@12: class QMouseEvent; Chris@0: Chris@0: /** Chris@0: * The base class for visual representations of the data found in a Chris@0: * Model. Layers are expected to be able to draw themselves onto a Chris@0: * View, and may also be editable. Chris@0: */ Chris@0: Chris@29: class Layer : public PropertyContainer, Chris@3: public XmlExportable Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@0: public: Chris@36: Layer(); Chris@0: virtual ~Layer(); Chris@0: Chris@0: virtual const Model *getModel() const = 0; Chris@0: virtual const ZoomConstraint *getZoomConstraint() const { return 0; } Chris@36: virtual void paint(View *, QPainter &, QRect) const = 0; Chris@0: Chris@0: enum VerticalPosition { Chris@0: PositionTop, PositionMiddle, PositionBottom Chris@0: }; Chris@0: virtual VerticalPosition getPreferredTimeRulerPosition() const { Chris@0: return PositionMiddle; Chris@0: } Chris@0: virtual VerticalPosition getPreferredFrameCountPosition() const { Chris@0: return PositionBottom; Chris@0: } Chris@0: Chris@12: virtual QString getPropertyContainerIconName() const; Chris@12: Chris@0: virtual QString getPropertyContainerName() const { Chris@0: return objectName(); Chris@0: } Chris@0: Chris@36: virtual int getVerticalScaleWidth(View *, QPainter &) const { return 0; } Chris@36: virtual void paintVerticalScale(View *, QPainter &, QRect) const { } Chris@0: Chris@36: virtual QString getFeatureDescription(View *, QPoint &) const { Chris@20: return ""; Chris@0: } Chris@0: Chris@8: //!!! We also need a method (like the vertical scale method) for Chris@8: //drawing additional scales like a colour scale. That is, unless Chris@8: //all applicable layers can actually do this from Chris@8: //paintVerticalScale as well? Chris@8: Chris@23: enum SnapType { Chris@23: SnapLeft, Chris@23: SnapRight, Chris@23: SnapNearest, Chris@23: SnapNeighbouring Chris@23: }; Chris@8: Chris@23: /** Chris@23: * Adjust the given frame to snap to the nearest feature, if Chris@23: * possible. Chris@23: * Chris@23: * If snap is SnapLeft or SnapRight, adjust the frame to match Chris@23: * that of the nearest feature in the given direction regardless Chris@23: * of how far away it is. If snap is SnapNearest, adjust the Chris@23: * frame to that of the nearest feature in either direction. If Chris@23: * snap is SnapNeighbouring, adjust the frame to that of the Chris@23: * nearest feature if it is close, and leave it alone (returning Chris@23: * false) otherwise. SnapNeighbouring should always choose the Chris@23: * same feature that would be used in an editing operation through Chris@23: * calls to editStart etc. Chris@23: * Chris@23: * Return true if a suitable feature was found and frame adjusted Chris@23: * accordingly. Return false if no suitable feature was Chris@23: * available. Also return the resolution of the model in this Chris@23: * layer in sample frames. Chris@23: */ Chris@36: virtual bool snapToFeatureFrame(View *v, Chris@36: int &frame, Chris@23: size_t &resolution, Chris@23: SnapType snap) const { Chris@8: resolution = 1; Chris@23: return false; Chris@8: } Chris@8: Chris@12: // Draw and edit modes: Chris@8: // Chris@12: // Layer needs to get actual mouse events, I guess. Draw mode is Chris@8: // probably the easier. Chris@8: Chris@36: virtual void drawStart(View *, QMouseEvent *) { } Chris@36: virtual void drawDrag(View *, QMouseEvent *) { } Chris@36: virtual void drawEnd(View *, QMouseEvent *) { } Chris@13: Chris@36: virtual void editStart(View *, QMouseEvent *) { } Chris@36: virtual void editDrag(View *, QMouseEvent *) { } Chris@36: virtual void editEnd(View *, QMouseEvent *) { } Chris@12: Chris@36: virtual void editOpen(View *, QMouseEvent *) { } // on double-click Chris@32: Chris@35: virtual void moveSelection(Selection s, size_t newStartFrame) { } Chris@35: virtual void resizeSelection(Selection s, Selection newSize) { } Chris@35: virtual void deleteSelection(Selection s) { } Chris@35: Chris@35: Chris@8: // Text mode: Chris@8: // Chris@8: // Label nearest feature. We need to get the feature coordinates Chris@8: // and current label from the layer, and then the pane can pop up Chris@8: // a little text entry dialog at the right location. Or we edit Chris@8: // in place? Probably the dialog is easier. Chris@8: Chris@0: /** Chris@36: * This should return true if the layer can safely be scrolled Chris@36: * automatically by a given view (simply copying the existing data Chris@0: * and then refreshing the exposed area) without altering its Chris@36: * meaning. For the view widget as a whole this is usually not Chris@0: * possible because of invariant (non-scrolling) material Chris@0: * displayed over the top, but the widget may be able to optimise Chris@0: * scrolling better if it is known that individual views can be Chris@0: * scrolled safely in this way. Chris@0: */ Chris@36: virtual bool isLayerScrollable(const View *) const { return true; } Chris@0: Chris@0: /** Chris@10: * This should return true if the layer completely obscures any Chris@10: * underlying layers. It's used to determine whether the view can Chris@10: * safely draw any selection rectangles under the layer instead of Chris@10: * over it, in the case where the layer is not scrollable and Chris@10: * therefore needs to be redrawn each time (so that the selection Chris@10: * rectangle can be cached). Chris@10: */ Chris@10: virtual bool isLayerOpaque() const { return false; } Chris@10: Chris@10: /** Chris@18: * This should return true if the layer can be edited by the user. Chris@18: * If this is the case, the appropriate edit tools may be made Chris@18: * available by the application and the layer's drawStart/Drag/End Chris@18: * and editStart/Drag/End methods should be implemented. Chris@18: */ Chris@18: virtual bool isLayerEditable() const { return false; } Chris@18: Chris@18: /** Chris@0: * Return the proportion of background work complete in drawing Chris@0: * this view, as a percentage -- in most cases this will be the Chris@0: * value returned by pointer from a call to the underlying model's Chris@0: * isReady(int *) call. The widget may choose to show a progress Chris@0: * meter if it finds that this returns < 100 at any given moment. Chris@0: */ Chris@0: virtual int getCompletion() const { return 100; } Chris@0: Chris@0: virtual void setObjectName(const QString &name); Chris@0: Chris@7: /** Chris@7: * Convert the layer's data (though not those of the model it Chris@7: * refers to) into an XML string for file output. This class Chris@7: * implements the basic name/type/model-id output; subclasses will Chris@7: * typically call this superclass implementation with extra Chris@7: * attributes describing their particular properties. Chris@7: */ Chris@3: virtual QString toXmlString(QString indent = "", Chris@3: QString extraAttributes = "") const; Chris@3: Chris@7: /** Chris@7: * Set the particular properties of a layer (those specific to the Chris@7: * subclass) from a set of XML attributes. This is the effective Chris@7: * inverse of the toXmlString method. Chris@7: */ Chris@6: virtual void setProperties(const QXmlAttributes &) = 0; Chris@6: Chris@24: /** Chris@39: * Indicate that a layer is not currently visible in the given Chris@39: * view and is not expected to become visible in the near future Chris@39: * (for example because the user has explicitly removed or hidden Chris@39: * it). The layer may respond by (for example) freeing any cache Chris@40: * memory it is using, until next time its paint method is called, Chris@40: * when it should set itself un-dormant again. Chris@24: */ Chris@39: virtual void setLayerDormant(const View *v, bool dormant) { Chris@39: m_dormancy[v] = dormant; Chris@39: } Chris@24: Chris@29: /** Chris@39: * Return whether the layer is dormant (i.e. hidden) in the given Chris@39: * view. Chris@29: */ Chris@39: virtual bool isLayerDormant(const View *v) const { Chris@39: if (m_dormancy.find(v) == m_dormancy.end()) return false; Chris@39: return m_dormancy.find(v)->second; Chris@39: } Chris@29: Chris@29: virtual PlayParameters *getPlayParameters(); Chris@29: Chris@29: public slots: Chris@36: void showLayer(View *, bool show); Chris@28: Chris@0: signals: Chris@0: void modelChanged(); Chris@0: void modelCompletionChanged(); Chris@0: void modelChanged(size_t startFrame, size_t endFrame); Chris@0: void modelReplaced(); Chris@0: Chris@0: void layerParametersChanged(); Chris@0: void layerNameChanged(); Chris@0: Chris@0: protected: Chris@40: mutable std::map m_dormancy; Chris@0: }; Chris@0: Chris@0: #endif Chris@0: