annotate layer/Layer.h @ 183:5f86ae638b04

* Omit translucent blue fill for selection rectangles that are superimposed over layers that use colours for meaningful purposes such as the spectrogram (CHARM change request)
author Chris Cannam
date Fri, 24 Nov 2006 16:56:15 +0000
parents 42118892f428
children e7cf6044c2a0
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@182 8 This file copyright 2006 Chris Cannam and QMUL.
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@180 130 * accordingly. Return false if no suitable feature was available
Chris@180 131 * (and leave frame unmodified). Also return the resolution of
Chris@180 132 * the model in this 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@183 204 * This should return true if the layer uses colours to indicate
Chris@183 205 * meaningful information (as opposed to just using a single
Chris@183 206 * colour of the user's choice). If this is the case, the view
Chris@183 207 * will show selections using unfilled rectangles instead of
Chris@183 208 * translucent filled rectangles, so as not to disturb the colours
Chris@183 209 * underneath.
Chris@183 210 */
Chris@183 211 virtual bool isLayerColourSignificant() const { return false; }
Chris@183 212
Chris@183 213 /**
Chris@127 214 * This should return true if the layer can be edited by the user.
Chris@127 215 * If this is the case, the appropriate edit tools may be made
Chris@127 216 * available by the application and the layer's drawStart/Drag/End
Chris@127 217 * and editStart/Drag/End methods should be implemented.
Chris@127 218 */
Chris@127 219 virtual bool isLayerEditable() const { return false; }
Chris@127 220
Chris@127 221 /**
Chris@127 222 * Return the proportion of background work complete in drawing
Chris@127 223 * this view, as a percentage -- in most cases this will be the
Chris@127 224 * value returned by pointer from a call to the underlying model's
Chris@127 225 * isReady(int *) call. The widget may choose to show a progress
Chris@127 226 * meter if it finds that this returns < 100 at any given moment.
Chris@127 227 */
Chris@127 228 virtual int getCompletion(View *) const { return 100; }
Chris@127 229
Chris@127 230 virtual void setObjectName(const QString &name);
Chris@127 231
Chris@127 232 /**
Chris@127 233 * Convert the layer's data (though not those of the model it
Chris@127 234 * refers to) into an XML string for file output. This class
Chris@127 235 * implements the basic name/type/model-id output; subclasses will
Chris@127 236 * typically call this superclass implementation with extra
Chris@127 237 * attributes describing their particular properties.
Chris@127 238 */
Chris@127 239 virtual QString toXmlString(QString indent = "",
Chris@127 240 QString extraAttributes = "") const;
Chris@127 241
Chris@127 242 /**
Chris@127 243 * Set the particular properties of a layer (those specific to the
Chris@127 244 * subclass) from a set of XML attributes. This is the effective
Chris@127 245 * inverse of the toXmlString method.
Chris@127 246 */
Chris@127 247 virtual void setProperties(const QXmlAttributes &) = 0;
Chris@127 248
Chris@127 249 /**
Chris@127 250 * Indicate that a layer is not currently visible in the given
Chris@127 251 * view and is not expected to become visible in the near future
Chris@127 252 * (for example because the user has explicitly removed or hidden
Chris@127 253 * it). The layer may respond by (for example) freeing any cache
Chris@127 254 * memory it is using, until next time its paint method is called,
Chris@127 255 * when it should set itself un-dormant again.
Chris@131 256 *
Chris@131 257 * A layer class that overrides this function must also call this
Chris@131 258 * class's implementation.
Chris@127 259 */
Chris@131 260 virtual void setLayerDormant(const View *v, bool dormant);
Chris@127 261
Chris@127 262 /**
Chris@127 263 * Return whether the layer is dormant (i.e. hidden) in the given
Chris@127 264 * view.
Chris@127 265 */
Chris@131 266 virtual bool isLayerDormant(const View *v) const;
Chris@127 267
Chris@127 268 virtual PlayParameters *getPlayParameters();
Chris@127 269
Chris@127 270 virtual bool needsTextLabelHeight() const { return false; }
Chris@127 271
Chris@127 272 /**
Chris@127 273 * Return the minimum and maximum values for the y axis of the
Chris@127 274 * model in this layer, as well as whether the layer is configured
Chris@127 275 * to use a logarithmic y axis display. Also return the unit for
Chris@127 276 * these values if known.
Chris@127 277 *
Chris@127 278 * This function returns the "normal" extents for the layer, not
Chris@127 279 * necessarily the extents actually in use in the display.
Chris@127 280 */
Chris@127 281 virtual bool getValueExtents(float &min, float &max,
Chris@127 282 bool &logarithmic, QString &unit) const = 0;
Chris@127 283
Chris@127 284 /**
Chris@127 285 * Return the minimum and maximum values within the displayed
Chris@127 286 * range for the y axis, if only a subset of the whole range of
Chris@127 287 * the model (returned by getValueExtents) is being displayed.
Chris@127 288 * Return false if the layer is not imposing a particular display
Chris@127 289 * extent (using the normal layer extents or deferring to whatever
Chris@127 290 * is in use for the same units elsewhere in the view).
Chris@127 291 */
Chris@127 292 virtual bool getDisplayExtents(float & /* min */,
Chris@127 293 float & /* max */) const {
Chris@127 294 return false;
Chris@127 295 }
Chris@127 296
Chris@127 297 /**
Chris@127 298 * Set the displayed minimum and maximum values for the y axis to
Chris@127 299 * the given range, if supported. Return false if not supported
Chris@127 300 * on this layer (and set nothing). In most cases, layers that
Chris@127 301 * return false for getDisplayExtents should also return false for
Chris@127 302 * this function.
Chris@127 303 */
Chris@127 304 virtual bool setDisplayExtents(float /* min */,
Chris@127 305 float /* max */) {
Chris@127 306 return false;
Chris@127 307 }
Chris@127 308
Chris@133 309 /**
Chris@133 310 * Get the number of vertical zoom steps available for this layer.
Chris@133 311 * If vertical zooming is not available, return 0. The meaning of
Chris@133 312 * "zooming" is entirely up to the layer -- changing the zoom
Chris@133 313 * level may cause the layer to reset its display extents or
Chris@180 314 * change another property such as display gain. However, layers
Chris@180 315 * are advised for consistency to treat smaller zoom steps as
Chris@180 316 * "more distant" or "zoomed out" and larger ones as "closer" or
Chris@180 317 * "zoomed in".
Chris@180 318 *
Chris@133 319 * Layers that provide this facility should also emit the
Chris@133 320 * verticalZoomChanged signal if their vertical zoom changes
Chris@133 321 * due to factors other than setVerticalZoomStep being called.
Chris@133 322 */
Chris@133 323 virtual int getVerticalZoomSteps(int &defaultStep) const { return 0; }
Chris@133 324
Chris@133 325 /**
Chris@133 326 * Get the current vertical zoom step. A layer may support finer
Chris@133 327 * control over ranges etc than is available through the integer
Chris@133 328 * zoom step mechanism; if this one does, it should just return
Chris@133 329 * the nearest of the available zoom steps to the current settings.
Chris@133 330 */
Chris@133 331 virtual int getCurrentVerticalZoomStep() const { return 0; }
Chris@133 332
Chris@133 333 /**
Chris@133 334 * Set the vertical zoom step. The meaning of "zooming" is
Chris@133 335 * entirely up to the layer -- changing the zoom level may cause
Chris@133 336 * the layer to reset its display extents or change another
Chris@133 337 * property such as display gain.
Chris@133 338 */
Chris@133 339 virtual void setVerticalZoomStep(int) { }
Chris@133 340
Chris@127 341 public slots:
Chris@127 342 void showLayer(View *, bool show);
Chris@127 343
Chris@127 344 signals:
Chris@127 345 void modelChanged();
Chris@127 346 void modelCompletionChanged();
Chris@127 347 void modelChanged(size_t startFrame, size_t endFrame);
Chris@127 348 void modelReplaced();
Chris@127 349
Chris@127 350 void layerParametersChanged();
Chris@127 351 void layerNameChanged();
Chris@127 352
Chris@133 353 void verticalZoomChanged();
Chris@133 354
Chris@131 355 private:
Chris@131 356 mutable QMutex m_dormancyMutex;
Chris@127 357 mutable std::map<const void *, bool> m_dormancy;
Chris@127 358 };
Chris@127 359
Chris@127 360 #endif
Chris@127 361