annotate layer/Layer.h @ 162:f32212631b9c

* Handle generator transforms (plugins whose channel count isn't dependent on number of audio inputs, as they have none) * Be less keen to suspend writing FFT data in spectrogram repaint -- only do it if we find we actually need to query the FFT data (i.e. we aren't repainting an area that hasn't been generated at all yet)
author Chris Cannam
date Tue, 10 Oct 2006 19:04:57 +0000
parents 10a82b2bbb8b
children 29f01de27db4
rev   line source
Chris@127 1
Chris@127 2 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@127 3
Chris@127 4 /*
Chris@127 5 Sonic Visualiser
Chris@127 6 An audio file viewer and annotation editor.
Chris@127 7 Centre for Digital Music, Queen Mary, University of London.
Chris@127 8 This file copyright 2006 Chris Cannam.
Chris@127 9
Chris@127 10 This program is free software; you can redistribute it and/or
Chris@127 11 modify it under the terms of the GNU General Public License as
Chris@127 12 published by the Free Software Foundation; either version 2 of the
Chris@127 13 License, or (at your option) any later version. See the file
Chris@127 14 COPYING included with this distribution for more information.
Chris@127 15 */
Chris@127 16
Chris@127 17 #ifndef _LAYER_H_
Chris@127 18 #define _LAYER_H_
Chris@127 19
Chris@128 20 #include "base/PropertyContainer.h"
Chris@128 21 #include "base/XmlExportable.h"
Chris@128 22 #include "base/Selection.h"
Chris@127 23
Chris@127 24 #include <QObject>
Chris@127 25 #include <QRect>
Chris@127 26 #include <QXmlAttributes>
Chris@131 27 #include <QMutex>
Chris@127 28
Chris@127 29 #include <map>
Chris@127 30
Chris@127 31 class ZoomConstraint;
Chris@127 32 class Model;
Chris@127 33 class QPainter;
Chris@127 34 class View;
Chris@127 35 class QMouseEvent;
Chris@127 36 class Clipboard;
Chris@127 37
Chris@127 38 /**
Chris@127 39 * The base class for visual representations of the data found in a
Chris@127 40 * Model. Layers are expected to be able to draw themselves onto a
Chris@127 41 * View, and may also be editable.
Chris@127 42 */
Chris@127 43
Chris@127 44 class Layer : public PropertyContainer,
Chris@127 45 public XmlExportable
Chris@127 46 {
Chris@127 47 Q_OBJECT
Chris@127 48
Chris@127 49 public:
Chris@127 50 Layer();
Chris@127 51 virtual ~Layer();
Chris@127 52
Chris@127 53 virtual const Model *getModel() const = 0;
Chris@127 54 virtual Model *getModel() {
Chris@127 55 return const_cast<Model *>(const_cast<const Layer *>(this)->getModel());
Chris@127 56 }
Chris@127 57
Chris@137 58 /**
Chris@137 59 * Return a zoom constraint object defining the supported zoom
Chris@137 60 * levels for this layer. If this returns zero, the layer will
Chris@137 61 * support any integer zoom level.
Chris@137 62 */
Chris@127 63 virtual const ZoomConstraint *getZoomConstraint() const { return 0; }
Chris@137 64
Chris@137 65 /**
Chris@137 66 * Return true if this layer can handle zoom levels other than
Chris@137 67 * those supported by its zoom constraint (presumably less
Chris@137 68 * efficiently or accurately than the officially supported zoom
Chris@137 69 * levels). If true, the layer will unenthusistically accept any
Chris@137 70 * integer zoom level from 1 to the maximum returned by its zoom
Chris@137 71 * constraint.
Chris@137 72 */
Chris@137 73 virtual bool supportsOtherZoomLevels() const { return true; }
Chris@137 74
Chris@127 75 virtual void paint(View *, QPainter &, QRect) const = 0;
Chris@127 76
Chris@127 77 enum VerticalPosition {
Chris@127 78 PositionTop, PositionMiddle, PositionBottom
Chris@127 79 };
Chris@127 80 virtual VerticalPosition getPreferredTimeRulerPosition() const {
Chris@127 81 return PositionMiddle;
Chris@127 82 }
Chris@127 83 virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@127 84 return PositionBottom;
Chris@127 85 }
Chris@127 86
Chris@127 87 virtual QString getPropertyContainerIconName() const;
Chris@127 88
Chris@127 89 virtual QString getPropertyContainerName() const {
Chris@127 90 return objectName();
Chris@127 91 }
Chris@127 92
Chris@127 93 virtual QString getLayerPresentationName() const;
Chris@127 94
Chris@127 95 virtual int getVerticalScaleWidth(View *, QPainter &) const { return 0; }
Chris@127 96 virtual void paintVerticalScale(View *, QPainter &, QRect) const { }
Chris@127 97
Chris@127 98 virtual bool getCrosshairExtents(View *, QPainter &, QPoint /* cursorPos */,
Chris@127 99 std::vector<QRect> &) const {
Chris@127 100 return false;
Chris@127 101 }
Chris@127 102 virtual void paintCrosshairs(View *, QPainter &, QPoint) const { }
Chris@127 103
Chris@127 104 virtual QString getFeatureDescription(View *, QPoint &) const {
Chris@127 105 return "";
Chris@127 106 }
Chris@127 107
Chris@127 108 enum SnapType {
Chris@127 109 SnapLeft,
Chris@127 110 SnapRight,
Chris@127 111 SnapNearest,
Chris@127 112 SnapNeighbouring
Chris@127 113 };
Chris@127 114
Chris@127 115 /**
Chris@127 116 * Adjust the given frame to snap to the nearest feature, if
Chris@127 117 * possible.
Chris@127 118 *
Chris@127 119 * If snap is SnapLeft or SnapRight, adjust the frame to match
Chris@127 120 * that of the nearest feature in the given direction regardless
Chris@127 121 * of how far away it is. If snap is SnapNearest, adjust the
Chris@127 122 * frame to that of the nearest feature in either direction. If
Chris@127 123 * snap is SnapNeighbouring, adjust the frame to that of the
Chris@127 124 * nearest feature if it is close, and leave it alone (returning
Chris@127 125 * false) otherwise. SnapNeighbouring should always choose the
Chris@127 126 * same feature that would be used in an editing operation through
Chris@127 127 * calls to editStart etc.
Chris@127 128 *
Chris@127 129 * Return true if a suitable feature was found and frame adjusted
Chris@127 130 * accordingly. Return false if no suitable feature was
Chris@127 131 * available. Also return the resolution of the model in this
Chris@127 132 * layer in sample frames.
Chris@127 133 */
Chris@127 134 virtual bool snapToFeatureFrame(View * /* v */,
Chris@127 135 int & /* frame */,
Chris@127 136 size_t &resolution,
Chris@127 137 SnapType /* snap */) const {
Chris@127 138 resolution = 1;
Chris@127 139 return false;
Chris@127 140 }
Chris@127 141
Chris@127 142 // Draw and edit modes:
Chris@127 143 //
Chris@127 144 // Layer needs to get actual mouse events, I guess. Draw mode is
Chris@127 145 // probably the easier.
Chris@127 146
Chris@127 147 virtual void drawStart(View *, QMouseEvent *) { }
Chris@127 148 virtual void drawDrag(View *, QMouseEvent *) { }
Chris@127 149 virtual void drawEnd(View *, QMouseEvent *) { }
Chris@127 150
Chris@127 151 virtual void editStart(View *, QMouseEvent *) { }
Chris@127 152 virtual void editDrag(View *, QMouseEvent *) { }
Chris@127 153 virtual void editEnd(View *, QMouseEvent *) { }
Chris@127 154
Chris@127 155 virtual void editOpen(View *, QMouseEvent *) { } // on double-click
Chris@127 156
Chris@127 157 virtual void moveSelection(Selection, size_t /* newStartFrame */) { }
Chris@127 158 virtual void resizeSelection(Selection, Selection /* newSize */) { }
Chris@127 159 virtual void deleteSelection(Selection) { }
Chris@127 160
Chris@127 161 virtual void copy(Selection, Clipboard & /* to */) { }
Chris@127 162
Chris@127 163 /**
Chris@127 164 * Paste from the given clipboard onto the layer at the given
Chris@127 165 * frame offset. If interactive is true, the layer may ask the
Chris@127 166 * user about paste options through a dialog if desired, and may
Chris@127 167 * return false if the user cancelled the paste operation. This
Chris@127 168 * function should return true if a paste actually occurred.
Chris@127 169 */
Chris@127 170 virtual bool paste(const Clipboard & /* from */,
Chris@127 171 int /* frameOffset */,
Chris@127 172 bool /* interactive */) { return false; }
Chris@127 173
Chris@127 174 // Text mode:
Chris@127 175 //
Chris@127 176 // Label nearest feature. We need to get the feature coordinates
Chris@127 177 // and current label from the layer, and then the pane can pop up
Chris@127 178 // a little text entry dialog at the right location. Or we edit
Chris@127 179 // in place? Probably the dialog is easier.
Chris@127 180
Chris@127 181 /**
Chris@127 182 * This should return true if the layer can safely be scrolled
Chris@127 183 * automatically by a given view (simply copying the existing data
Chris@127 184 * and then refreshing the exposed area) without altering its
Chris@127 185 * meaning. For the view widget as a whole this is usually not
Chris@127 186 * possible because of invariant (non-scrolling) material
Chris@127 187 * displayed over the top, but the widget may be able to optimise
Chris@127 188 * scrolling better if it is known that individual views can be
Chris@127 189 * scrolled safely in this way.
Chris@127 190 */
Chris@127 191 virtual bool isLayerScrollable(const View *) const { return true; }
Chris@127 192
Chris@127 193 /**
Chris@127 194 * This should return true if the layer completely obscures any
Chris@127 195 * underlying layers. It's used to determine whether the view can
Chris@127 196 * safely draw any selection rectangles under the layer instead of
Chris@127 197 * over it, in the case where the layer is not scrollable and
Chris@127 198 * therefore needs to be redrawn each time (so that the selection
Chris@127 199 * rectangle can be cached).
Chris@127 200 */
Chris@127 201 virtual bool isLayerOpaque() const { return false; }
Chris@127 202
Chris@127 203 /**
Chris@127 204 * This should return true if the layer can be edited by the user.
Chris@127 205 * If this is the case, the appropriate edit tools may be made
Chris@127 206 * available by the application and the layer's drawStart/Drag/End
Chris@127 207 * and editStart/Drag/End methods should be implemented.
Chris@127 208 */
Chris@127 209 virtual bool isLayerEditable() const { return false; }
Chris@127 210
Chris@127 211 /**
Chris@127 212 * Return the proportion of background work complete in drawing
Chris@127 213 * this view, as a percentage -- in most cases this will be the
Chris@127 214 * value returned by pointer from a call to the underlying model's
Chris@127 215 * isReady(int *) call. The widget may choose to show a progress
Chris@127 216 * meter if it finds that this returns < 100 at any given moment.
Chris@127 217 */
Chris@127 218 virtual int getCompletion(View *) const { return 100; }
Chris@127 219
Chris@127 220 virtual void setObjectName(const QString &name);
Chris@127 221
Chris@127 222 /**
Chris@127 223 * Convert the layer's data (though not those of the model it
Chris@127 224 * refers to) into an XML string for file output. This class
Chris@127 225 * implements the basic name/type/model-id output; subclasses will
Chris@127 226 * typically call this superclass implementation with extra
Chris@127 227 * attributes describing their particular properties.
Chris@127 228 */
Chris@127 229 virtual QString toXmlString(QString indent = "",
Chris@127 230 QString extraAttributes = "") const;
Chris@127 231
Chris@127 232 /**
Chris@127 233 * Set the particular properties of a layer (those specific to the
Chris@127 234 * subclass) from a set of XML attributes. This is the effective
Chris@127 235 * inverse of the toXmlString method.
Chris@127 236 */
Chris@127 237 virtual void setProperties(const QXmlAttributes &) = 0;
Chris@127 238
Chris@127 239 /**
Chris@127 240 * Indicate that a layer is not currently visible in the given
Chris@127 241 * view and is not expected to become visible in the near future
Chris@127 242 * (for example because the user has explicitly removed or hidden
Chris@127 243 * it). The layer may respond by (for example) freeing any cache
Chris@127 244 * memory it is using, until next time its paint method is called,
Chris@127 245 * when it should set itself un-dormant again.
Chris@131 246 *
Chris@131 247 * A layer class that overrides this function must also call this
Chris@131 248 * class's implementation.
Chris@127 249 */
Chris@131 250 virtual void setLayerDormant(const View *v, bool dormant);
Chris@127 251
Chris@127 252 /**
Chris@127 253 * Return whether the layer is dormant (i.e. hidden) in the given
Chris@127 254 * view.
Chris@127 255 */
Chris@131 256 virtual bool isLayerDormant(const View *v) const;
Chris@127 257
Chris@127 258 virtual PlayParameters *getPlayParameters();
Chris@127 259
Chris@127 260 virtual bool needsTextLabelHeight() const { return false; }
Chris@127 261
Chris@127 262 /**
Chris@127 263 * Return the minimum and maximum values for the y axis of the
Chris@127 264 * model in this layer, as well as whether the layer is configured
Chris@127 265 * to use a logarithmic y axis display. Also return the unit for
Chris@127 266 * these values if known.
Chris@127 267 *
Chris@127 268 * This function returns the "normal" extents for the layer, not
Chris@127 269 * necessarily the extents actually in use in the display.
Chris@127 270 */
Chris@127 271 virtual bool getValueExtents(float &min, float &max,
Chris@127 272 bool &logarithmic, QString &unit) const = 0;
Chris@127 273
Chris@127 274 /**
Chris@127 275 * Return the minimum and maximum values within the displayed
Chris@127 276 * range for the y axis, if only a subset of the whole range of
Chris@127 277 * the model (returned by getValueExtents) is being displayed.
Chris@127 278 * Return false if the layer is not imposing a particular display
Chris@127 279 * extent (using the normal layer extents or deferring to whatever
Chris@127 280 * is in use for the same units elsewhere in the view).
Chris@127 281 */
Chris@127 282 virtual bool getDisplayExtents(float & /* min */,
Chris@127 283 float & /* max */) const {
Chris@127 284 return false;
Chris@127 285 }
Chris@127 286
Chris@127 287 /**
Chris@127 288 * Set the displayed minimum and maximum values for the y axis to
Chris@127 289 * the given range, if supported. Return false if not supported
Chris@127 290 * on this layer (and set nothing). In most cases, layers that
Chris@127 291 * return false for getDisplayExtents should also return false for
Chris@127 292 * this function.
Chris@127 293 */
Chris@127 294 virtual bool setDisplayExtents(float /* min */,
Chris@127 295 float /* max */) {
Chris@127 296 return false;
Chris@127 297 }
Chris@127 298
Chris@133 299 /**
Chris@133 300 * Get the number of vertical zoom steps available for this layer.
Chris@133 301 * If vertical zooming is not available, return 0. The meaning of
Chris@133 302 * "zooming" is entirely up to the layer -- changing the zoom
Chris@133 303 * level may cause the layer to reset its display extents or
Chris@133 304 * change another property such as display gain.
Chris@133 305 * Layers that provide this facility should also emit the
Chris@133 306 * verticalZoomChanged signal if their vertical zoom changes
Chris@133 307 * due to factors other than setVerticalZoomStep being called.
Chris@133 308 */
Chris@133 309 virtual int getVerticalZoomSteps(int &defaultStep) const { return 0; }
Chris@133 310
Chris@133 311 /**
Chris@133 312 * Get the current vertical zoom step. A layer may support finer
Chris@133 313 * control over ranges etc than is available through the integer
Chris@133 314 * zoom step mechanism; if this one does, it should just return
Chris@133 315 * the nearest of the available zoom steps to the current settings.
Chris@133 316 */
Chris@133 317 virtual int getCurrentVerticalZoomStep() const { return 0; }
Chris@133 318
Chris@133 319 /**
Chris@133 320 * Set the vertical zoom step. The meaning of "zooming" is
Chris@133 321 * entirely up to the layer -- changing the zoom level may cause
Chris@133 322 * the layer to reset its display extents or change another
Chris@133 323 * property such as display gain.
Chris@133 324 */
Chris@133 325 virtual void setVerticalZoomStep(int) { }
Chris@133 326
Chris@127 327 public slots:
Chris@127 328 void showLayer(View *, bool show);
Chris@127 329
Chris@127 330 signals:
Chris@127 331 void modelChanged();
Chris@127 332 void modelCompletionChanged();
Chris@127 333 void modelChanged(size_t startFrame, size_t endFrame);
Chris@127 334 void modelReplaced();
Chris@127 335
Chris@127 336 void layerParametersChanged();
Chris@127 337 void layerNameChanged();
Chris@127 338
Chris@133 339 void verticalZoomChanged();
Chris@133 340
Chris@131 341 private:
Chris@131 342 mutable QMutex m_dormancyMutex;
Chris@127 343 mutable std::map<const void *, bool> m_dormancy;
Chris@127 344 };
Chris@127 345
Chris@127 346 #endif
Chris@127 347