annotate layer/Layer.h @ 1551:e79731086b0f

Fixes to NoteLayer, particularly to calculation of vertical scale when model unit is not Hz. To avoid inconsistency we now behave as if the unit is always Hz from the point of view of the external API and display, converting at the point where we obtain values from the events themselves. Also various fixes to editing.
author Chris Cannam
date Thu, 21 Nov 2019 14:02:57 +0000
parents e6362cf5ff1d
children a0b2f3b4dd2f
rev   line source
Chris@127 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@127 2
Chris@127 3 /*
Chris@127 4 Sonic Visualiser
Chris@127 5 An audio file viewer and annotation editor.
Chris@127 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@127 8
Chris@127 9 This program is free software; you can redistribute it and/or
Chris@127 10 modify it under the terms of the GNU General Public License as
Chris@127 11 published by the Free Software Foundation; either version 2 of the
Chris@127 12 License, or (at your option) any later version. See the file
Chris@127 13 COPYING included with this distribution for more information.
Chris@127 14 */
Chris@127 15
Chris@1407 16 #ifndef SV_LAYER_H
Chris@1407 17 #define SV_LAYER_H
Chris@127 18
Chris@128 19 #include "base/PropertyContainer.h"
Chris@128 20 #include "base/XmlExportable.h"
Chris@128 21 #include "base/Selection.h"
Chris@127 22
Chris@1469 23 #include "data/model/Model.h"
Chris@1469 24
Chris@376 25 #include "widgets/CommandHistory.h"
Chris@376 26
Chris@523 27 #include "system/System.h"
Chris@523 28
Chris@127 29 #include <QObject>
Chris@127 30 #include <QRect>
Chris@127 31 #include <QXmlAttributes>
Chris@131 32 #include <QMutex>
Chris@299 33 #include <QPixmap>
Chris@127 34
Chris@127 35 #include <map>
Chris@268 36 #include <set>
Chris@127 37
Chris@552 38 #include <iostream>
Chris@552 39
Chris@127 40 class ZoomConstraint;
Chris@127 41 class QPainter;
Chris@127 42 class View;
Chris@916 43 class LayerGeometryProvider;
Chris@127 44 class QMouseEvent;
Chris@127 45 class Clipboard;
Chris@187 46 class RangeMapper;
Chris@127 47
Chris@127 48 /**
Chris@127 49 * The base class for visual representations of the data found in a
Chris@127 50 * Model. Layers are expected to be able to draw themselves onto a
Chris@127 51 * View, and may also be editable.
Chris@127 52 */
Chris@127 53
Chris@127 54 class Layer : public PropertyContainer,
Chris@1266 55 public XmlExportable
Chris@127 56 {
Chris@127 57 Q_OBJECT
Chris@127 58
Chris@127 59 public:
Chris@127 60 Layer();
Chris@127 61 virtual ~Layer();
Chris@127 62
Chris@1469 63 /**
Chris@1469 64 * Return the ID of the model represented in this layer.
Chris@1469 65 */
Chris@1469 66 virtual ModelId getModel() const = 0;
Chris@1489 67
Chris@1489 68 /**
Chris@1489 69 * Return the ID of the source model for the model represented in
Chris@1489 70 * this layer. If the model has no other source, or there is no
Chris@1489 71 * model here, return None.
Chris@1489 72 */
Chris@1489 73 ModelId getSourceModel() const;
Chris@947 74
Chris@137 75 /**
Chris@137 76 * Return a zoom constraint object defining the supported zoom
Chris@137 77 * levels for this layer. If this returns zero, the layer will
Chris@137 78 * support any integer zoom level.
Chris@137 79 */
Chris@127 80 virtual const ZoomConstraint *getZoomConstraint() const { return 0; }
Chris@137 81
Chris@137 82 /**
Chris@137 83 * Return true if this layer can handle zoom levels other than
Chris@137 84 * those supported by its zoom constraint (presumably less
Chris@137 85 * efficiently or accurately than the officially supported zoom
Chris@137 86 * levels). If true, the layer will unenthusistically accept any
Chris@137 87 * integer zoom level from 1 to the maximum returned by its zoom
Chris@137 88 * constraint.
Chris@137 89 */
Chris@137 90 virtual bool supportsOtherZoomLevels() const { return true; }
Chris@137 91
Chris@389 92 /**
Chris@389 93 * Paint the given rectangle of this layer onto the given view
Chris@389 94 * using the given painter, superimposing it on top of any
Chris@916 95 * existing material in that view. The LayerGeometryProvider (an
Chris@916 96 * interface implemented by View) is provided here because it is
Chris@916 97 * possible for one layer to exist in more than one view, so the
Chris@916 98 * dimensions of the view may vary from one paint call to another
Chris@916 99 * (without any view having been resized).
Chris@389 100 */
Chris@916 101 virtual void paint(LayerGeometryProvider *, QPainter &, QRect) const = 0;
Chris@127 102
Chris@389 103 /**
Chris@389 104 * Enable or disable synchronous painting. If synchronous
Chris@389 105 * painting is enabled, a call to paint() must complete painting
Chris@389 106 * the entire rectangle before it returns. If synchronous
Chris@389 107 * painting is disabled (which should be the default), the paint()
Chris@389 108 * call may defer painting some regions if data is not yet
Chris@389 109 * available, by calling back on its view to schedule another
Chris@389 110 * update. Synchronous painting is necessary when rendering to an
Chris@389 111 * image. Simple layer types will always paint synchronously, and
Chris@389 112 * so may ignore this.
Chris@389 113 */
Chris@389 114 virtual void setSynchronousPainting(bool /* synchronous */) { }
Chris@389 115
Chris@127 116 enum VerticalPosition {
Chris@1266 117 PositionTop, PositionMiddle, PositionBottom
Chris@127 118 };
Chris@127 119 virtual VerticalPosition getPreferredTimeRulerPosition() const {
Chris@1266 120 return PositionMiddle;
Chris@127 121 }
Chris@127 122 virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@1266 123 return PositionBottom;
Chris@127 124 }
Chris@224 125 virtual bool hasLightBackground() const {
Chris@224 126 return true;
Chris@224 127 }
Chris@127 128
Chris@1406 129 QString getPropertyContainerIconName() const override;
Chris@127 130
Chris@1406 131 QString getPropertyContainerName() const override {
Chris@363 132 if (m_presentationName != "") return m_presentationName;
Chris@1266 133 else return objectName();
Chris@127 134 }
Chris@127 135
Chris@363 136 virtual void setPresentationName(QString name);
Chris@363 137
Chris@127 138 virtual QString getLayerPresentationName() const;
Chris@299 139 virtual QPixmap getLayerPresentationPixmap(QSize) const { return QPixmap(); }
Chris@127 140
Chris@916 141 virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool detailed,
Chris@607 142 QPainter &) const = 0;
Chris@607 143
Chris@916 144 virtual void paintVerticalScale(LayerGeometryProvider *, bool /* detailed */,
Chris@607 145 QPainter &, QRect) const { }
Chris@127 146
Chris@1390 147 virtual int getHorizontalScaleHeight(LayerGeometryProvider *, QPainter &) const { return 0; }
Chris@1390 148
Chris@916 149 virtual bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint /* cursorPos */,
Chris@127 150 std::vector<QRect> &) const {
Chris@127 151 return false;
Chris@127 152 }
Chris@916 153 virtual void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const { }
Chris@127 154
Chris@916 155 virtual void paintMeasurementRects(LayerGeometryProvider *, QPainter &,
Chris@272 156 bool showFocus, QPoint focusPoint) const;
Chris@272 157
Chris@916 158 virtual bool nearestMeasurementRectChanged(LayerGeometryProvider *, QPoint prev,
Chris@272 159 QPoint now) const;
Chris@267 160
Chris@916 161 virtual QString getFeatureDescription(LayerGeometryProvider *, QPoint &) const {
Chris@1266 162 return "";
Chris@127 163 }
Chris@127 164
Chris@909 165 virtual QString getLabelPreceding(sv_frame_t /* frame */) const {
Chris@552 166 return "";
Chris@552 167 }
Chris@552 168
Chris@127 169 enum SnapType {
Chris@1266 170 SnapLeft,
Chris@1266 171 SnapRight,
Chris@1266 172 SnapNeighbouring
Chris@127 173 };
Chris@127 174
Chris@127 175 /**
Chris@127 176 * Adjust the given frame to snap to the nearest feature, if
Chris@127 177 * possible.
Chris@127 178 *
Chris@127 179 * If snap is SnapLeft or SnapRight, adjust the frame to match
Chris@127 180 * that of the nearest feature in the given direction regardless
Chris@1431 181 * of how far away it is. If snap is SnapNeighbouring, adjust the
Chris@1431 182 * frame to that of the nearest feature in either direction if it
Chris@1431 183 * is close, and leave it alone (returning false) otherwise.
Chris@1431 184 * SnapNeighbouring should always choose the same feature that
Chris@1431 185 * would be used in an editing operation through calls to
Chris@1431 186 * editStart etc.
Chris@127 187 *
Chris@1547 188 * If ycoord is non-negative, it contains the y coordinate at
Chris@1547 189 * which the interaction that prompts this snap is taking place
Chris@1547 190 * (e.g. of the mouse press used for a selection action). Layers
Chris@1547 191 * that have objects at multiple different heights may choose to
Chris@1547 192 * use this information. If the current action has no particular y
Chris@1547 193 * coordinate associated with it, ycoord will be passed as -1.
Chris@1547 194 *
Chris@127 195 * Return true if a suitable feature was found and frame adjusted
Chris@180 196 * accordingly. Return false if no suitable feature was available
Chris@517 197 * (and leave frame unmodified). If returning true, also return
Chris@517 198 * the resolution of the model in this layer in sample frames.
Chris@127 199 */
Chris@916 200 virtual bool snapToFeatureFrame(LayerGeometryProvider * /* v */,
Chris@1266 201 sv_frame_t & /* frame */,
Chris@1266 202 int &resolution,
Chris@1547 203 SnapType /* snap */,
Chris@1547 204 int /* ycoord */) const {
Chris@1266 205 resolution = 1;
Chris@1266 206 return false;
Chris@127 207 }
Chris@127 208
Chris@517 209 /**
Chris@517 210 * Adjust the given frame to snap to the next feature that has
Chris@517 211 * "effectively" the same value as the feature prior to the given
Chris@517 212 * frame, if possible.
Chris@517 213 *
Chris@517 214 * The snap type must be SnapLeft (snap to the time of the next
Chris@517 215 * feature prior to the one preceding the given frame that has a
Chris@517 216 * similar value to it) or SnapRight (snap to the time of the next
Chris@517 217 * feature following the given frame that has a similar value to
Chris@517 218 * the feature preceding it). Other values are not permitted.
Chris@517 219 *
Chris@517 220 * Return true if a suitable feature was found and frame adjusted
Chris@517 221 * accordingly. Return false if no suitable feature was available
Chris@517 222 * (and leave frame unmodified). If returning true, also return
Chris@517 223 * the resolution of the model in this layer in sample frames.
Chris@517 224 */
Chris@916 225 virtual bool snapToSimilarFeature(LayerGeometryProvider * /* v */,
Chris@904 226 sv_frame_t & /* source frame */,
Chris@805 227 int &resolution,
Chris@517 228 SnapType /* snap */) const {
Chris@1266 229 resolution = 1;
Chris@1266 230 return false;
Chris@517 231 }
Chris@517 232
Chris@335 233 // Draw, erase, and edit modes:
Chris@127 234 //
Chris@127 235 // Layer needs to get actual mouse events, I guess. Draw mode is
Chris@127 236 // probably the easier.
Chris@127 237
Chris@916 238 virtual void drawStart(LayerGeometryProvider *, QMouseEvent *) { }
Chris@916 239 virtual void drawDrag(LayerGeometryProvider *, QMouseEvent *) { }
Chris@916 240 virtual void drawEnd(LayerGeometryProvider *, QMouseEvent *) { }
Chris@127 241
Chris@916 242 virtual void eraseStart(LayerGeometryProvider *, QMouseEvent *) { }
Chris@916 243 virtual void eraseDrag(LayerGeometryProvider *, QMouseEvent *) { }
Chris@916 244 virtual void eraseEnd(LayerGeometryProvider *, QMouseEvent *) { }
Chris@335 245
Chris@916 246 virtual void editStart(LayerGeometryProvider *, QMouseEvent *) { }
Chris@916 247 virtual void editDrag(LayerGeometryProvider *, QMouseEvent *) { }
Chris@916 248 virtual void editEnd(LayerGeometryProvider *, QMouseEvent *) { }
Chris@127 249
Chris@916 250 virtual void splitStart(LayerGeometryProvider *, QMouseEvent *) { }
Chris@916 251 virtual void splitEnd(LayerGeometryProvider *, QMouseEvent *) { }
Chris@916 252 virtual void addNote(LayerGeometryProvider *, QMouseEvent *) { };
gyorgyf@635 253
Chris@267 254 // Measurement rectangle (or equivalent). Unlike draw and edit,
Chris@267 255 // the base Layer class can provide working implementations of
Chris@267 256 // these for most situations.
Chris@267 257 //
Chris@916 258 virtual void measureStart(LayerGeometryProvider *, QMouseEvent *);
Chris@916 259 virtual void measureDrag(LayerGeometryProvider *, QMouseEvent *);
Chris@916 260 virtual void measureEnd(LayerGeometryProvider *, QMouseEvent *);
Chris@916 261 virtual void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *);
Chris@267 262
Chris@283 263 virtual bool haveCurrentMeasureRect() const {
Chris@283 264 return m_haveCurrentMeasureRect;
Chris@283 265 }
Chris@283 266 virtual void deleteCurrentMeasureRect(); // using a command
Chris@283 267
Chris@255 268 /**
Chris@255 269 * Open an editor on the item under the mouse (e.g. on
Chris@255 270 * double-click). If there is no item or editing is not
Chris@255 271 * supported, return false.
Chris@255 272 */
Chris@916 273 virtual bool editOpen(LayerGeometryProvider *, QMouseEvent *) { return false; }
Chris@127 274
Chris@905 275 virtual void moveSelection(Selection, sv_frame_t /* newStartFrame */) { }
Chris@127 276 virtual void resizeSelection(Selection, Selection /* newSize */) { }
Chris@127 277 virtual void deleteSelection(Selection) { }
Chris@127 278
Chris@916 279 virtual void copy(LayerGeometryProvider *, Selection, Clipboard & /* to */) { }
Chris@127 280
Chris@127 281 /**
Chris@127 282 * Paste from the given clipboard onto the layer at the given
Chris@127 283 * frame offset. If interactive is true, the layer may ask the
Chris@127 284 * user about paste options through a dialog if desired, and may
Chris@127 285 * return false if the user cancelled the paste operation. This
Chris@127 286 * function should return true if a paste actually occurred.
Chris@127 287 */
Chris@916 288 virtual bool paste(LayerGeometryProvider *,
Chris@359 289 const Clipboard & /* from */,
Chris@904 290 sv_frame_t /* frameOffset */,
Chris@127 291 bool /* interactive */) { return false; }
Chris@127 292
Chris@127 293 // Text mode:
Chris@127 294 //
Chris@127 295 // Label nearest feature. We need to get the feature coordinates
Chris@127 296 // and current label from the layer, and then the pane can pop up
Chris@127 297 // a little text entry dialog at the right location. Or we edit
Chris@127 298 // in place? Probably the dialog is easier.
Chris@127 299
Chris@127 300 /**
Chris@127 301 * This should return true if the layer can safely be scrolled
Chris@127 302 * automatically by a given view (simply copying the existing data
Chris@127 303 * and then refreshing the exposed area) without altering its
Chris@127 304 * meaning. For the view widget as a whole this is usually not
Chris@127 305 * possible because of invariant (non-scrolling) material
Chris@127 306 * displayed over the top, but the widget may be able to optimise
Chris@127 307 * scrolling better if it is known that individual views can be
Chris@127 308 * scrolled safely in this way.
Chris@127 309 */
Chris@916 310 virtual bool isLayerScrollable(const LayerGeometryProvider *) const { return true; }
Chris@127 311
Chris@127 312 /**
Chris@127 313 * This should return true if the layer completely obscures any
Chris@127 314 * underlying layers. It's used to determine whether the view can
Chris@127 315 * safely draw any selection rectangles under the layer instead of
Chris@127 316 * over it, in the case where the layer is not scrollable and
Chris@127 317 * therefore needs to be redrawn each time (so that the selection
Chris@127 318 * rectangle can be cached).
Chris@127 319 */
Chris@127 320 virtual bool isLayerOpaque() const { return false; }
Chris@127 321
Chris@287 322 enum ColourSignificance {
Chris@287 323 ColourAbsent,
Chris@287 324 ColourIrrelevant,
Chris@287 325 ColourDistinguishes,
Chris@287 326 ColourAndBackgroundSignificant,
Chris@287 327 ColourHasMeaningfulValue
Chris@287 328 };
Chris@287 329
Chris@127 330 /**
Chris@287 331 * This should return the degree of meaning associated with colour
Chris@287 332 * in this layer.
Chris@287 333 *
Chris@287 334 * If ColourAbsent, the layer does not use colour. If
Chris@287 335 * ColourIrrelevant, the layer is coloured and the colour may be
Chris@287 336 * set by the user, but it doesn't really matter what the colour
Chris@287 337 * is (for example, in a time ruler layer). If
Chris@287 338 * ColourDistinguishes, then the colour is used to distinguish
Chris@287 339 * this layer from other similar layers (e.g. for data layers).
Chris@287 340 * If ColourAndBackgroundSignificant, then the layer should be
Chris@287 341 * given greater weight than ColourDistinguishes layers when
Chris@287 342 * choosing a background colour (e.g. for waveforms). If
Chris@287 343 * ColourHasMeaningfulValue, colours are actually meaningful --
Chris@287 344 * the view will then show selections using unfilled rectangles
Chris@287 345 * instead of translucent filled rectangles, so as not to disturb
Chris@287 346 * the colours underneath.
Chris@183 347 */
Chris@287 348 virtual ColourSignificance getLayerColourSignificance() const = 0;
Chris@183 349
Chris@183 350 /**
Chris@127 351 * This should return true if the layer can be edited by the user.
Chris@127 352 * If this is the case, the appropriate edit tools may be made
Chris@127 353 * available by the application and the layer's drawStart/Drag/End
Chris@127 354 * and editStart/Drag/End methods should be implemented.
Chris@127 355 */
Chris@127 356 virtual bool isLayerEditable() const { return false; }
Chris@127 357
Chris@127 358 /**
Chris@127 359 * Return the proportion of background work complete in drawing
Chris@127 360 * this view, as a percentage -- in most cases this will be the
Chris@127 361 * value returned by pointer from a call to the underlying model's
Chris@226 362 * isReady(int *) call. The view may choose to show a progress
Chris@127 363 * meter if it finds that this returns < 100 at any given moment.
Chris@127 364 */
Chris@916 365 virtual int getCompletion(LayerGeometryProvider *) const { return 100; }
Chris@127 366
Chris@583 367 /**
Chris@583 368 * Return an error string if any errors have occurred while
Chris@583 369 * loading or processing data for the given view. Return the
Chris@583 370 * empty string if no error has occurred.
Chris@583 371 */
Chris@916 372 virtual QString getError(LayerGeometryProvider *) const { return ""; }
Chris@583 373
Chris@127 374 virtual void setObjectName(const QString &name);
Chris@127 375
Chris@127 376 /**
Chris@127 377 * Convert the layer's data (though not those of the model it
Chris@316 378 * refers to) into XML for file output. This class implements the
Chris@316 379 * basic name/type/model-id output; subclasses will typically call
Chris@316 380 * this superclass implementation with extra attributes describing
Chris@316 381 * their particular properties.
Chris@127 382 */
Chris@1406 383 void toXml(QTextStream &stream, QString indent = "",
Chris@1406 384 QString extraAttributes = "") const override;
Chris@127 385
Chris@127 386 /**
Chris@127 387 * Set the particular properties of a layer (those specific to the
Chris@127 388 * subclass) from a set of XML attributes. This is the effective
Chris@316 389 * inverse of the toXml method.
Chris@127 390 */
Chris@127 391 virtual void setProperties(const QXmlAttributes &) = 0;
Chris@127 392
Chris@127 393 /**
Chris@316 394 * Produce XML containing the layer's ID and type. This is used
Chris@316 395 * to refer to the layer in the display section of the SV session
Chris@316 396 * file, for a layer that has already been described in the data
Chris@316 397 * section.
Chris@269 398 */
Chris@316 399 virtual void toBriefXml(QTextStream &stream,
Chris@316 400 QString indent = "",
Chris@316 401 QString extraAttributes = "") const;
Chris@269 402
Chris@269 403 /**
Chris@269 404 * Add a measurement rectangle from the given XML attributes
Chris@269 405 * (presumably taken from a measurement element).
Chris@269 406 * Does not use a command.
Chris@269 407 */
Chris@269 408 virtual void addMeasurementRect(const QXmlAttributes &);
Chris@269 409
Chris@269 410 /**
Chris@127 411 * Indicate that a layer is not currently visible in the given
Chris@127 412 * view and is not expected to become visible in the near future
Chris@127 413 * (for example because the user has explicitly removed or hidden
Chris@127 414 * it). The layer may respond by (for example) freeing any cache
Chris@127 415 * memory it is using, until next time its paint method is called,
Chris@127 416 * when it should set itself un-dormant again.
Chris@131 417 *
Chris@131 418 * A layer class that overrides this function must also call this
Chris@131 419 * class's implementation.
Chris@127 420 */
Chris@916 421 virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant);
Chris@127 422
Chris@127 423 /**
Chris@127 424 * Return whether the layer is dormant (i.e. hidden) in the given
Chris@127 425 * view.
Chris@127 426 */
Chris@916 427 virtual bool isLayerDormant(const LayerGeometryProvider *v) const;
Chris@127 428
Chris@1480 429 /**
Chris@1480 430 * Return the play parameters for this layer, if any. The return
Chris@1480 431 * value is a shared_ptr that can be passed to (e.g.)
Chris@1480 432 * PlayParameterRepository::EditCommand to change the parameters.
Chris@1480 433 */
Chris@1480 434 std::shared_ptr<PlayParameters> getPlayParameters() override;
Chris@127 435
Chris@1391 436 /**
Chris@1391 437 * True if this layer will need to place text labels when it is
Chris@1391 438 * painted. The view will take into account how many layers are
Chris@1391 439 * requesting this, and will provide a distinct y-coord to each
Chris@1391 440 * layer on request via View::getTextLabelHeight().
Chris@1391 441 */
Chris@127 442 virtual bool needsTextLabelHeight() const { return false; }
Chris@127 443
Chris@1389 444 /**
Chris@1389 445 * Return true if the X axis on the layer is time proportional to
Chris@1389 446 * audio frames, false otherwise. Almost all layer types return
Chris@1389 447 * true here: the exceptions are spectrum and slice layers.
Chris@1389 448 */
Chris@217 449 virtual bool hasTimeXAxis() const { return true; }
Chris@217 450
Chris@127 451 /**
Chris@1389 452 * Update the X and Y axis scales, where appropriate, to focus on
Chris@1389 453 * the given rectangular region. This should *only* be overridden
Chris@1389 454 * by layers whose hasTimeXAxis() returns false - the pane handles
Chris@1389 455 * zooming appropriately in every "normal" case.
Chris@1389 456 */
Chris@1389 457 virtual void zoomToRegion(const LayerGeometryProvider *, QRect) {
Chris@1389 458 return;
Chris@1389 459 }
Chris@1389 460
Chris@1389 461 /**
Chris@127 462 * Return the minimum and maximum values for the y axis of the
Chris@127 463 * model in this layer, as well as whether the layer is configured
Chris@127 464 * to use a logarithmic y axis display. Also return the unit for
Chris@127 465 * these values if known.
Chris@127 466 *
Chris@127 467 * This function returns the "normal" extents for the layer, not
Chris@1537 468 * necessarily the extents actually in use in the display (see
Chris@1537 469 * getDisplayExtents).
Chris@127 470 */
Chris@904 471 virtual bool getValueExtents(double &min, double &max,
Chris@127 472 bool &logarithmic, QString &unit) const = 0;
Chris@127 473
Chris@127 474 /**
Chris@1537 475 * Return the minimum and maximum values within the visible area
Chris@1537 476 * for the y axis of this layer.
Chris@1537 477 *
Chris@1537 478 * Return false if the layer has no display extents of its
Chris@1537 479 * own. This could be because the layer is "auto-aligning" against
Chris@1537 480 * another layer with the same units elsewhere in the view, or
Chris@1537 481 * because the layer has no concept of a vertical scale at all.
Chris@127 482 */
Chris@904 483 virtual bool getDisplayExtents(double & /* min */,
Chris@904 484 double & /* max */) const {
Chris@127 485 return false;
Chris@127 486 }
Chris@127 487
Chris@127 488 /**
Chris@127 489 * Set the displayed minimum and maximum values for the y axis to
Chris@127 490 * the given range, if supported. Return false if not supported
Chris@127 491 * on this layer (and set nothing). In most cases, layers that
Chris@127 492 * return false for getDisplayExtents should also return false for
Chris@127 493 * this function.
Chris@127 494 */
Chris@904 495 virtual bool setDisplayExtents(double /* min */,
Chris@904 496 double /* max */) {
Chris@127 497 return false;
Chris@127 498 }
Chris@127 499
Chris@133 500 /**
Chris@1520 501 * Consider using the given value extents and units for this
Chris@1520 502 * layer. This may be called on a new layer when added, to prepare
Chris@1520 503 * it for editing, and the extents are those of the layer
Chris@1520 504 * underneath it. May not be appropriate for most layer types.
Chris@1520 505 */
Chris@1520 506 virtual bool adoptExtents(double /* min */, double /* max */,
Chris@1520 507 QString /* unit */) {
Chris@1520 508 return false;
Chris@1520 509 }
Chris@1520 510
Chris@1520 511 /**
Chris@260 512 * Return the value and unit at the given x coordinate in the
Chris@260 513 * given view. This is for descriptive purposes using the
Chris@260 514 * measurement tool. The default implementation works correctly
Chris@260 515 * if the layer hasTimeXAxis().
Chris@260 516 */
Chris@916 517 virtual bool getXScaleValue(const LayerGeometryProvider *v, int x,
Chris@904 518 double &value, QString &unit) const;
Chris@260 519
Chris@260 520 /**
Chris@260 521 * Return the value and unit at the given y coordinate in the
Chris@260 522 * given view.
Chris@260 523 */
Chris@916 524 virtual bool getYScaleValue(const LayerGeometryProvider *, int /* y */,
Chris@904 525 double &/* value */, QString &/* unit */) const {
Chris@260 526 return false;
Chris@260 527 }
Chris@260 528
Chris@260 529 /**
Chris@274 530 * Return the difference between the values at the given y
Chris@274 531 * coordinates in the given view, and the unit of the difference.
Chris@274 532 * The default implementation just calls getYScaleValue twice and
Chris@274 533 * returns the difference, with the same unit.
Chris@274 534 */
Chris@916 535 virtual bool getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1,
Chris@904 536 double &diff, QString &unit) const;
Chris@274 537
Chris@274 538 /**
Chris@133 539 * Get the number of vertical zoom steps available for this layer.
Chris@133 540 * If vertical zooming is not available, return 0. The meaning of
Chris@133 541 * "zooming" is entirely up to the layer -- changing the zoom
Chris@133 542 * level may cause the layer to reset its display extents or
Chris@180 543 * change another property such as display gain. However, layers
Chris@180 544 * are advised for consistency to treat smaller zoom steps as
Chris@180 545 * "more distant" or "zoomed out" and larger ones as "closer" or
Chris@180 546 * "zoomed in".
Chris@180 547 *
Chris@133 548 * Layers that provide this facility should also emit the
Chris@133 549 * verticalZoomChanged signal if their vertical zoom changes
Chris@133 550 * due to factors other than setVerticalZoomStep being called.
Chris@133 551 */
Chris@248 552 virtual int getVerticalZoomSteps(int & /* defaultStep */) const { return 0; }
Chris@133 553
Chris@133 554 /**
Chris@133 555 * Get the current vertical zoom step. A layer may support finer
Chris@133 556 * control over ranges etc than is available through the integer
Chris@133 557 * zoom step mechanism; if this one does, it should just return
Chris@133 558 * the nearest of the available zoom steps to the current settings.
Chris@133 559 */
Chris@133 560 virtual int getCurrentVerticalZoomStep() const { return 0; }
Chris@133 561
Chris@133 562 /**
Chris@133 563 * Set the vertical zoom step. The meaning of "zooming" is
Chris@133 564 * entirely up to the layer -- changing the zoom level may cause
Chris@133 565 * the layer to reset its display extents or change another
Chris@133 566 * property such as display gain.
Chris@133 567 */
Chris@133 568 virtual void setVerticalZoomStep(int) { }
Chris@133 569
Chris@187 570 /**
Chris@187 571 * Create and return a range mapper for vertical zoom step values.
Chris@187 572 * See the RangeMapper documentation for more details. The
Chris@187 573 * returned value is allocated on the heap and will be deleted by
Chris@187 574 * the caller.
Chris@187 575 */
Chris@187 576 virtual RangeMapper *getNewVerticalZoomRangeMapper() const { return 0; }
Chris@187 577
Chris@947 578 /**
Chris@947 579 * Return true if this layer type can function without a model
Chris@947 580 * being set. If false (the default), the layer will not be loaded
Chris@947 581 * from a session if its model cannot be found.
Chris@947 582 */
Chris@947 583 virtual bool canExistWithoutModel() const { return false; }
Chris@947 584
Chris@127 585 public slots:
Chris@1456 586 /**
Chris@1456 587 * Change the visibility status (dormancy) of the layer in the
Chris@1456 588 * given view.
Chris@1456 589 */
Chris@916 590 void showLayer(LayerGeometryProvider *, bool show);
Chris@127 591
Chris@127 592 signals:
Chris@1481 593 void modelChanged(ModelId);
Chris@1481 594 void modelCompletionChanged(ModelId);
Chris@1481 595 void modelAlignmentCompletionChanged(ModelId);
Chris@1481 596 void modelChangedWithin(ModelId, sv_frame_t startFrame, sv_frame_t endFrame);
Chris@127 597 void modelReplaced();
Chris@127 598
Chris@127 599 void layerParametersChanged();
Chris@197 600 void layerParameterRangesChanged();
Chris@268 601 void layerMeasurementRectsChanged();
Chris@127 602 void layerNameChanged();
Chris@127 603
Chris@133 604 void verticalZoomChanged();
Chris@133 605
Chris@267 606 protected:
Chris@1469 607 void connectSignals(ModelId);
Chris@320 608
Chris@916 609 virtual sv_frame_t alignToReference(LayerGeometryProvider *v, sv_frame_t frame) const;
Chris@916 610 virtual sv_frame_t alignFromReference(LayerGeometryProvider *v, sv_frame_t frame) const;
Chris@916 611 bool clipboardHasDifferentAlignment(LayerGeometryProvider *v, const Clipboard &clip) const;
Chris@359 612
Chris@267 613 struct MeasureRect {
Chris@268 614
Chris@267 615 mutable QRect pixrect;
Chris@268 616 bool haveFrames;
Chris@905 617 sv_frame_t startFrame; // only valid if haveFrames
Chris@905 618 sv_frame_t endFrame; // ditto
Chris@273 619 double startY;
Chris@273 620 double endY;
Chris@268 621
Chris@268 622 bool operator<(const MeasureRect &mr) const;
Chris@316 623 void toXml(QTextStream &stream, QString indent) const;
Chris@267 624 };
Chris@267 625
Chris@268 626 class AddMeasurementRectCommand : public Command
Chris@268 627 {
Chris@268 628 public:
Chris@268 629 AddMeasurementRectCommand(Layer *layer, MeasureRect rect) :
Chris@268 630 m_layer(layer), m_rect(rect) { }
Chris@268 631
Chris@1406 632 QString getName() const override;
Chris@1406 633 void execute() override;
Chris@1406 634 void unexecute() override;
Chris@268 635
Chris@268 636 private:
Chris@268 637 Layer *m_layer;
Chris@268 638 MeasureRect m_rect;
Chris@268 639 };
Chris@268 640
Chris@283 641 class DeleteMeasurementRectCommand : public Command
Chris@283 642 {
Chris@283 643 public:
Chris@283 644 DeleteMeasurementRectCommand(Layer *layer, MeasureRect rect) :
Chris@283 645 m_layer(layer), m_rect(rect) { }
Chris@283 646
Chris@1406 647 QString getName() const override;
Chris@1406 648 void execute() override;
Chris@1406 649 void unexecute() override;
Chris@283 650
Chris@283 651 private:
Chris@283 652 Layer *m_layer;
Chris@283 653 MeasureRect m_rect;
Chris@283 654 };
Chris@283 655
Chris@269 656 void addMeasureRectToSet(const MeasureRect &r) {
Chris@268 657 m_measureRects.insert(r);
Chris@268 658 emit layerMeasurementRectsChanged();
Chris@268 659 }
Chris@268 660
Chris@269 661 void deleteMeasureRectFromSet(const MeasureRect &r) {
Chris@268 662 m_measureRects.erase(r);
Chris@268 663 emit layerMeasurementRectsChanged();
Chris@268 664 }
Chris@268 665
Chris@268 666 typedef std::set<MeasureRect> MeasureRectSet;
Chris@268 667 MeasureRectSet m_measureRects;
Chris@267 668 MeasureRect m_draggingRect;
Chris@267 669 bool m_haveDraggingRect;
Chris@283 670 mutable bool m_haveCurrentMeasureRect;
Chris@283 671 mutable QPoint m_currentMeasureRectPoint;
Chris@272 672
Chris@272 673 // Note that pixrects are only correct for a single view.
Chris@272 674 // So we should update them at the start of the paint procedure
Chris@272 675 // (painting is single threaded) and only use them after that.
Chris@916 676 void updateMeasurePixrects(LayerGeometryProvider *v) const;
Chris@273 677
Chris@916 678 virtual void updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const;
Chris@916 679 virtual void setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const;
Chris@916 680 virtual void setMeasureRectFromPixrect(LayerGeometryProvider *v, MeasureRect &r, QRect pixrect) const;
Chris@272 681
Chris@272 682 // This assumes updateMeasurementPixrects has been called
Chris@272 683 MeasureRectSet::const_iterator findFocusedMeasureRect(QPoint) const;
Chris@267 684
Chris@916 685 void paintMeasurementRect(LayerGeometryProvider *v, QPainter &paint,
Chris@270 686 const MeasureRect &r, bool focus) const;
Chris@268 687
Chris@1315 688 bool valueExtentsMatchMine(LayerGeometryProvider *v) const;
Chris@1315 689
Chris@363 690 QString m_presentationName;
Chris@363 691
Chris@131 692 private:
Chris@131 693 mutable QMutex m_dormancyMutex;
Chris@127 694 mutable std::map<const void *, bool> m_dormancy;
Chris@127 695 };
Chris@127 696
Chris@127 697 #endif
Chris@127 698