annotate layer/Layer.h @ 1605:ae2d5f8ff005

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