Chris@0: 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@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@74: class Clipboard; 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@41: virtual Model *getModel() { Chris@41: return const_cast(const_cast(this)->getModel()); Chris@41: } Chris@41: 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@47: virtual QString getLayerPresentationName() const; Chris@47: Chris@36: virtual int getVerticalScaleWidth(View *, QPainter &) const { return 0; } Chris@36: virtual void paintVerticalScale(View *, QPainter &, QRect) const { } Chris@0: Chris@76: virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos, Chris@76: std::vector &) const { return false; } Chris@76: virtual void paintCrosshairs(View *, QPainter &, QPoint) const { } Chris@76: Chris@36: virtual QString getFeatureDescription(View *, QPoint &) const { Chris@20: return ""; Chris@0: } Chris@0: 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@74: virtual void copy(Selection s, Clipboard &to) { } Chris@74: virtual void paste(const Clipboard &from, int frameOffset) { } 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@134: virtual int getCompletion(View *) 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@78: virtual bool needsTextLabelHeight() const { return false; } Chris@78: Chris@117: virtual bool getValueExtents(float &min, float &max, Chris@117: bool &logarithmic, QString &unit) const = 0; Chris@117: Chris@117: virtual bool getDisplayExtents(float &min, float &max) const { Chris@117: return false; Chris@117: } Chris@78: 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: