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