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. 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_VIEW_H 17 #define SV_VIEW_H 18 19 #include <QFrame> 20 #include <QProgressBar> 21 22 #include "layer/LayerGeometryProvider.h" 23 24 #include "base/ZoomConstraint.h" 25 #include "base/PropertyContainer.h" 26 #include "ViewManager.h" 27 #include "base/XmlExportable.h" 28 #include "base/BaseTypes.h" 29 30 #include "data/model/Model.h" 31 32 // #define DEBUG_VIEW_WIDGET_PAINT 1 33 34 class Layer; 35 class ViewPropertyContainer; 36 37 class QPushButton; 38 39 #include <map> 40 #include <set> 41 42 /** 43 * View is the base class of widgets that display one or more 44 * overlaid views of data against a horizontal time scale. 45 * 46 * A View may have any number of attached Layers, each of which 47 * is expected to have one data Model (although multiple views may 48 * share the same model). 49 * 50 * A View may be panned in time and zoomed, although the 51 * mechanisms for doing so (as well as any other operations and 52 * properties available) depend on the subclass. 53 */ 54 55 class View : public QFrame, 56 public XmlExportable, 57 public LayerGeometryProvider 58 { 59 Q_OBJECT 60 61 public: 62 /** 63 * Deleting a View does not delete any of its layers. They should 64 * be managed elsewhere (e.g. by the Document). 65 */ 66 virtual ~View(); 67 68 /** 69 * Retrieve the id of this object. Views have their own unique 70 * ids, but ViewProxy objects share the id of their View. 71 */ getId()72 int getId() const override { return m_id; } 73 74 /** 75 * Retrieve the first visible sample frame on the widget. 76 * This is a calculated value based on the centre-frame, widget 77 * width and zoom level. The result may be negative. 78 */ 79 sv_frame_t getStartFrame() const override; 80 81 /** 82 * Set the widget pan based on the given first visible frame. The 83 * frame value may be negative. 84 */ 85 void setStartFrame(sv_frame_t); 86 87 /** 88 * Return the centre frame of the visible widget. This is an 89 * exact value that does not depend on the zoom block size. Other 90 * frame values (start, end) are calculated from this based on the 91 * zoom and other factors. 92 */ getCentreFrame()93 sv_frame_t getCentreFrame() const override { return m_centreFrame; } 94 95 /** 96 * Set the centre frame of the visible widget. 97 */ setCentreFrame(sv_frame_t f)98 void setCentreFrame(sv_frame_t f) { setCentreFrame(f, true); } 99 100 /** 101 * Retrieve the last visible sample frame on the widget. 102 * This is a calculated value based on the centre-frame, widget 103 * width and zoom level. 104 */ 105 sv_frame_t getEndFrame() const override; 106 107 /** 108 * Return the pixel x-coordinate corresponding to a given sample 109 * frame. The frame is permitted to be negative, and the result 110 * may be outside the currently visible area. But this should not 111 * be called with frame values very far away from the currently 112 * visible area, as that could lead to overflow. In that situation 113 * an error will be logged and 0 returned. 114 */ 115 int getXForFrame(sv_frame_t frame) const override; 116 117 /** 118 * Return the closest frame to the given pixel x-coordinate. 119 */ 120 sv_frame_t getFrameForX(int x) const override; 121 122 /** 123 * Return the closest pixel x-coordinate corresponding to a given 124 * view x-coordinate. Default is no scaling, ViewProxy handles 125 * scaling case. 126 */ getXForViewX(int viewx)127 int getXForViewX(int viewx) const override { return viewx; } 128 129 /** 130 * Return the closest view x-coordinate corresponding to a given 131 * pixel x-coordinate. Default is no scaling, ViewProxy handles 132 * scaling case. 133 */ getViewXForX(int x)134 int getViewXForX(int x) const override { return x; } 135 136 /** 137 * Return the pixel y-coordinate corresponding to a given 138 * frequency, if the frequency range is as specified. This does 139 * not imply any policy about layer frequency ranges, but it might 140 * be useful for layers to match theirs up if desired. 141 * 142 * Not thread-safe in logarithmic mode. Call only from GUI thread. 143 */ 144 double getYForFrequency(double frequency, double minFreq, double maxFreq, 145 bool logarithmic) const override; 146 147 /** 148 * Return the closest frequency to the given pixel y-coordinate, 149 * if the frequency range is as specified. 150 * 151 * Not thread-safe in logarithmic mode. Call only from GUI thread. 152 */ 153 double getFrequencyForY(double y, double minFreq, double maxFreq, 154 bool logarithmic) const override; 155 156 /** 157 * Return the zoom level, i.e. the number of frames per pixel or 158 * pixels per frame 159 */ 160 ZoomLevel getZoomLevel() const override; 161 162 /** 163 * Set the zoom level, i.e. the number of frames per pixel or 164 * pixels per frame. The centre frame will be unchanged; the 165 * start and end frames will change. 166 */ 167 virtual void setZoomLevel(ZoomLevel z); 168 169 /** 170 * Zoom in or out. 171 */ 172 virtual void zoom(bool in); 173 174 /** 175 * Scroll left or right by a smallish or largish amount. 176 */ 177 virtual void scroll(bool right, bool lots, bool doEmit = true); 178 179 /** 180 * Add a layer to the view. (Normally this should be handled 181 * through some command abstraction instead of using this function 182 * directly.) 183 */ 184 virtual void addLayer(Layer *v); 185 186 /** 187 * Remove a layer from the view. Does not delete the 188 * layer. (Normally this should be handled through some command 189 * abstraction instead of using this function directly.) 190 */ 191 virtual void removeLayer(Layer *v); 192 193 /** 194 * Return the number of layers, regardless of whether visible or 195 * dormant, i.e. invisible, in this view. 196 */ getLayerCount()197 virtual int getLayerCount() const { return int(m_layerStack.size()); } 198 199 /** 200 * Return the nth layer, counted in stacking order. That is, 201 * layer 0 is the bottom layer and layer "getLayerCount()-1" is 202 * the top one. The returned layer may be visible or it may be 203 * dormant, i.e. invisible. 204 */ getLayer(int n)205 virtual Layer *getLayer(int n) { 206 if (in_range_for(m_layerStack, n)) return m_layerStack[n]; 207 else return 0; 208 } 209 210 /** 211 * Return the nth layer, counted in the order they were 212 * added. Unlike the stacking order used in getLayer(), which 213 * changes each time a layer is selected, this ordering remains 214 * fixed. The returned layer may be visible or it may be dormant, 215 * i.e. invisible. 216 */ getFixedOrderLayer(int n)217 virtual Layer *getFixedOrderLayer(int n) { 218 if (n < int(m_fixedOrderLayers.size())) return m_fixedOrderLayers[n]; 219 else return 0; 220 } 221 222 /** 223 * Return the layer currently active for tool interaction. This is 224 * the topmost non-dormant (i.e. visible) layer in the view. If 225 * there are no visible layers in the view, return 0. 226 */ 227 virtual Layer *getInteractionLayer(); 228 229 virtual const Layer *getInteractionLayer() const; 230 231 /** 232 * Return the layer most recently selected by the user. This is 233 * the layer that any non-tool-driven commands should operate on, 234 * in the case where this view is the "current" one. 235 * 236 * If the user has selected the view itself more recently than any 237 * of the layers on it, this function will return 0, and any 238 * non-tool-driven layer commands should be deactivated while this 239 * view is current. It will also return 0 if there are no layers 240 * in the view. 241 * 242 * Note that, unlike getInteractionLayer(), this could return an 243 * invisible (dormant) layer. 244 */ 245 virtual Layer *getSelectedLayer(); 246 247 virtual const Layer *getSelectedLayer() const; 248 249 /** 250 * Return the "top" layer in the view, whether visible or dormant. 251 * This is the same as getLayer(getLayerCount()-1) if there is at 252 * least one layer, and 0 otherwise. 253 * 254 * For most purposes involving interaction or commands, you 255 * probably want either getInteractionLayer() or 256 * getSelectedLayer() instead. 257 */ getTopLayer()258 virtual Layer *getTopLayer() { 259 return m_layerStack.empty() ? 0 : m_layerStack[m_layerStack.size()-1]; 260 } 261 262 virtual void setViewManager(ViewManager *m); 263 virtual void setViewManager(ViewManager *m, sv_frame_t initialFrame); getViewManager()264 ViewManager *getViewManager() const override { return m_manager; } 265 266 virtual void setFollowGlobalPan(bool f); getFollowGlobalPan()267 virtual bool getFollowGlobalPan() const { return m_followPan; } 268 269 virtual void setFollowGlobalZoom(bool f); getFollowGlobalZoom()270 virtual bool getFollowGlobalZoom() const { return m_followZoom; } 271 272 bool hasLightBackground() const override; 273 QColor getForeground() const override; 274 QColor getBackground() const override; 275 276 void drawMeasurementRect(QPainter &p, const Layer *, 277 QRect rect, bool focus) const override; 278 shouldShowFeatureLabels()279 bool shouldShowFeatureLabels() const override { 280 return m_manager && m_manager->shouldShowFeatureLabels(); 281 } shouldIlluminateLocalFeatures(const Layer *,QPoint &)282 bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const override { 283 return false; 284 } shouldIlluminateLocalSelection(QPoint &,bool &,bool &)285 virtual bool shouldIlluminateLocalSelection(QPoint &, bool &, bool &) const { 286 return false; 287 } 288 289 virtual void setPlaybackFollow(PlaybackFollowMode m); getPlaybackFollow()290 virtual PlaybackFollowMode getPlaybackFollow() const { return m_followPlay; } 291 292 typedef PropertyContainer::PropertyName PropertyName; 293 294 // We implement the PropertyContainer API, although we don't 295 // actually subclass PropertyContainer. We have our own 296 // PropertyContainer that we can return on request that just 297 // delegates back to us. 298 virtual PropertyContainer::PropertyList getProperties() const; 299 virtual QString getPropertyLabel(const PropertyName &) const; 300 virtual PropertyContainer::PropertyType getPropertyType(const PropertyName &) const; 301 virtual int getPropertyRangeAndValue(const PropertyName &, 302 int *min, int *max, int *deflt) const; 303 virtual QString getPropertyValueLabel(const PropertyName &, 304 int value) const; 305 virtual void setProperty(const PropertyName &, int value); getPropertyContainerName()306 virtual QString getPropertyContainerName() const { 307 return objectName(); 308 } 309 virtual QString getPropertyContainerIconName() const = 0; 310 311 virtual int getPropertyContainerCount() const; 312 313 // The 0th property container is the view's own; the rest are the 314 // layers in fixed-order series 315 virtual const PropertyContainer *getPropertyContainer(int i) const; 316 virtual PropertyContainer *getPropertyContainer(int i); 317 318 /** 319 * Render the view contents to a new QImage (which may be wider 320 * than the visible View). 321 */ 322 virtual QImage *renderToNewImage(); 323 324 /** 325 * Render the view contents between the given frame extents to a 326 * new QImage (which may be wider than the visible View). 327 */ 328 virtual QImage *renderPartToNewImage(sv_frame_t f0, sv_frame_t f1); 329 330 /** 331 * Calculate and return the size of image that will be generated 332 * by renderToNewImage(). 333 */ 334 virtual QSize getRenderedImageSize(); 335 336 /** 337 * Calculate and return the size of image that will be generated 338 * by renderPartToNewImage(f0, f1). 339 */ 340 virtual QSize getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1); 341 342 /** 343 * Render the view contents to a new SVG file. 344 */ 345 virtual bool renderToSvgFile(QString filename); 346 347 /** 348 * Render the view contents between the given frame extents to a 349 * new SVG file. 350 */ 351 virtual bool renderPartToSvgFile(QString filename, 352 sv_frame_t f0, sv_frame_t f1); 353 354 /** 355 * Return the visible vertical extents for the given unit, if any. 356 * Overridden from LayerGeometryProvider (see docs there). 357 */ 358 bool getVisibleExtentsForUnit(QString unit, double &min, double &max, 359 bool &log) const override; 360 361 /** 362 * Return some visible vertical extents and unit. That is, if at 363 * least one non-dormant layer has a non-empty unit and returns 364 * some values from its getDisplayExtents() method, return the 365 * extents and unit from the topmost of those. Otherwise return 366 * false. 367 */ 368 bool getVisibleExtentsForAnyUnit(double &min, double &max, 369 bool &logarithmic, QString &unit) const; 370 371 int getTextLabelYCoord(const Layer *layer, QPainter &) const override; 372 373 void toXml(QTextStream &stream, QString indent = "", 374 QString extraAttributes = "") const override; 375 376 // First frame actually in model, to right of scale, if present 377 virtual sv_frame_t getFirstVisibleFrame() const; 378 virtual sv_frame_t getLastVisibleFrame() const; 379 380 sv_frame_t getModelsStartFrame() const override; 381 sv_frame_t getModelsEndFrame() const override; 382 383 /** 384 * To be called from a layer, to obtain the extent of the surface 385 * that the layer is currently painting to. This may be the extent 386 * of the view (if 1x display scaling is in effect) or of a larger 387 * cached pixmap (if greater display scaling is in effect). 388 */ 389 QRect getPaintRect() const override; 390 getPaintSize()391 QSize getPaintSize() const override { return getPaintRect().size(); } getPaintWidth()392 int getPaintWidth() const override { return getPaintRect().width(); } getPaintHeight()393 int getPaintHeight() const override { return getPaintRect().height(); } 394 395 double scaleSize(double size) const override; 396 int scalePixelSize(int size) const override; 397 double scalePenWidth(double width) const override; 398 QPen scalePen(QPen pen) const override; 399 400 typedef std::set<ModelId> ModelSet; 401 ModelSet getModels(); 402 403 //!!!??? poor name, probably poor api, consider this setUseAligningProxy(bool uap)404 void setUseAligningProxy(bool uap) { 405 m_useAligningProxy = uap; 406 } 407 408 //!!! 409 ModelId getAligningModel() const; 410 void getAligningAndReferenceModels(ModelId &aligning, ModelId &reference) const; 411 sv_frame_t alignFromReference(sv_frame_t) const; 412 sv_frame_t alignToReference(sv_frame_t) const; 413 sv_frame_t getAlignedPlaybackFrame() const; 414 updatePaintRect(QRect r)415 void updatePaintRect(QRect r) override { update(r); } 416 getView()417 View *getView() override { return this; } getView()418 const View *getView() const override { return this; } 419 420 signals: 421 void propertyContainerAdded(PropertyContainer *pc); 422 void propertyContainerRemoved(PropertyContainer *pc); 423 void propertyContainerPropertyChanged(PropertyContainer *pc); 424 void propertyContainerPropertyRangeChanged(PropertyContainer *pc); 425 void propertyContainerNameChanged(PropertyContainer *pc); 426 void propertyContainerSelected(PropertyContainer *pc); 427 void propertyChanged(PropertyContainer::PropertyName); 428 429 void layerModelChanged(); 430 431 void cancelButtonPressed(Layer *); 432 433 void centreFrameChanged(sv_frame_t frame, 434 bool globalScroll, 435 PlaybackFollowMode followMode); 436 437 void zoomLevelChanged(ZoomLevel level, bool locked); 438 439 void contextHelpChanged(const QString &); 440 441 public slots: 442 virtual void modelChanged(ModelId); 443 virtual void modelChangedWithin(ModelId, sv_frame_t startFrame, sv_frame_t endFrame); 444 virtual void modelCompletionChanged(ModelId); 445 virtual void modelAlignmentCompletionChanged(ModelId); 446 virtual void modelReplaced(); 447 virtual void layerParametersChanged(); 448 virtual void layerParameterRangesChanged(); 449 virtual void layerMeasurementRectsChanged(); 450 virtual void layerNameChanged(); 451 452 virtual void globalCentreFrameChanged(sv_frame_t); 453 virtual void viewCentreFrameChanged(View *, sv_frame_t); 454 virtual void viewManagerPlaybackFrameChanged(sv_frame_t); 455 virtual void viewZoomLevelChanged(View *, ZoomLevel, bool); 456 457 /** 458 * A property container has been selected, for example in the 459 * associated property stack. The property container may be a 460 * layer, in which case the effect should be to raise that layer 461 * to the front of the view and select it; or it may be the view's 462 * own property container, in which case the effect is to switch 463 * to a mode in which no layer is selected. 464 * 465 * (This is the main slot for raising a layer.) 466 */ 467 virtual void propertyContainerSelected(View *, PropertyContainer *pc); 468 469 virtual void selectionChanged(); 470 virtual void toolModeChanged(); 471 virtual void overlayModeChanged(); 472 virtual void zoomWheelsEnabledChanged(); 473 474 virtual void cancelClicked(); 475 476 virtual void progressCheckStalledTimerElapsed(); 477 478 protected: 479 View(QWidget *, bool showProgress); 480 481 int m_id; 482 483 void paintEvent(QPaintEvent *e) override; 484 virtual void drawSelections(QPainter &); shouldLabelSelections()485 virtual bool shouldLabelSelections() const { return true; } 486 virtual void drawPlayPointer(QPainter &); 487 virtual bool render(QPainter &paint, int x0, sv_frame_t f0, sv_frame_t f1); 488 virtual void setPaintFont(QPainter &paint); 489 scaledSize(const QSize & s,int factor)490 QSize scaledSize(const QSize &s, int factor) { 491 return QSize(s.width() * factor, s.height() * factor); 492 } scaledRect(const QRect & r,int factor)493 QRect scaledRect(const QRect &r, int factor) { 494 return QRect(r.x() * factor, r.y() * factor, 495 r.width() * factor, r.height() * factor); 496 } 497 498 typedef std::vector<Layer *> LayerList; 499 500 sv_samplerate_t getModelsSampleRate() const; 501 bool areLayersScrollable() const; 502 LayerList getScrollableBackLayers(bool testChanged, bool &changed) const; 503 LayerList getNonScrollableFrontLayers(bool testChanged, bool &changed) const; 504 505 Layer *getScaleProvidingLayerForUnit(QString unit) const; 506 507 ZoomLevel getZoomConstraintLevel(ZoomLevel level, 508 ZoomConstraint::RoundingDirection dir = 509 ZoomConstraint::RoundNearest) const; 510 511 // These three are slow, intended for indexing GUI thumbwheel stuff 512 int countZoomLevels() const; 513 int getZoomLevelIndex(ZoomLevel level) const; 514 ZoomLevel getZoomLevelByIndex(int ix) const; 515 516 // True if the top layer(s) use colours for meaningful things. If 517 // this is the case, selections will be shown using unfilled boxes 518 // rather than with a translucent fill. 519 bool areLayerColoursSignificant() const; 520 521 // True if the top layer has a time axis on the x coordinate (this 522 // is generally the case except for spectrum/slice layers). It 523 // will not be possible to make or display selections if this is 524 // false. 525 bool hasTopLayerTimeXAxis() const; 526 527 bool setCentreFrame(sv_frame_t f, bool doEmit); 528 529 void movePlayPointer(sv_frame_t f); 530 531 void checkProgress(ModelId); 532 void checkAlignmentProgress(ModelId); 533 534 int getProgressBarWidth() const; // if visible 535 536 int effectiveDevicePixelRatio() const; 537 538 sv_frame_t m_centreFrame; 539 ZoomLevel m_zoomLevel; 540 bool m_followPan; 541 bool m_followZoom; 542 PlaybackFollowMode m_followPlay; 543 bool m_followPlayIsDetached; 544 sv_frame_t m_playPointerFrame; 545 bool m_lightBackground; 546 bool m_showProgress; 547 548 QPixmap *m_cache; // I own this 549 QPixmap *m_buffer; // I own this 550 bool m_cacheValid; 551 sv_frame_t m_cacheCentreFrame; 552 ZoomLevel m_cacheZoomLevel; 553 bool m_selectionCached; 554 555 bool m_deleting; 556 557 LayerList m_layerStack; // I don't own these, but see dtor note above 558 LayerList m_fixedOrderLayers; 559 bool m_haveSelectedLayer; 560 561 bool m_useAligningProxy; 562 563 QString m_lastError; 564 565 // caches for use in getScrollableBackLayers, getNonScrollableFrontLayers 566 mutable LayerList m_lastScrollableBackLayers; 567 mutable LayerList m_lastNonScrollableBackLayers; 568 569 struct ProgressBarRec { 570 QPushButton *cancel; 571 QProgressBar *bar; 572 int lastStallCheckValue; 573 QTimer *stallCheckTimer; 574 }; 575 typedef std::map<Layer *, ProgressBarRec> ProgressMap; 576 ProgressMap m_progressBars; // I own the ProgressBarRecs and their contents 577 578 struct AlignmentProgressBarRec { 579 ModelId alignedModel; 580 QProgressBar *bar; 581 }; 582 AlignmentProgressBarRec m_alignmentProgressBar; 583 584 ViewManager *m_manager; // I don't own this 585 ViewPropertyContainer *m_propertyContainer; // I own this 586 }; 587 588 589 // Use this for delegation, because we can't subclass from 590 // PropertyContainer (which is a QObject) ourselves because of 591 // ambiguity with QFrame parent 592 593 class ViewPropertyContainer : public PropertyContainer 594 { 595 Q_OBJECT 596 597 public: 598 ViewPropertyContainer(View *v); 599 virtual ~ViewPropertyContainer(); 600 getProperties()601 PropertyList getProperties() const override { return m_v->getProperties(); } getPropertyLabel(const PropertyName & n)602 QString getPropertyLabel(const PropertyName &n) const override { 603 return m_v->getPropertyLabel(n); 604 } getPropertyType(const PropertyName & n)605 PropertyType getPropertyType(const PropertyName &n) const override { 606 return m_v->getPropertyType(n); 607 } getPropertyRangeAndValue(const PropertyName & n,int * min,int * max,int * deflt)608 int getPropertyRangeAndValue(const PropertyName &n, int *min, int *max, 609 int *deflt) const override { 610 return m_v->getPropertyRangeAndValue(n, min, max, deflt); 611 } getPropertyValueLabel(const PropertyName & n,int value)612 QString getPropertyValueLabel(const PropertyName &n, int value) const override { 613 return m_v->getPropertyValueLabel(n, value); 614 } getPropertyContainerName()615 QString getPropertyContainerName() const override { 616 return m_v->getPropertyContainerName(); 617 } getPropertyContainerIconName()618 QString getPropertyContainerIconName() const override { 619 return m_v->getPropertyContainerIconName(); 620 } 621 622 public slots: setProperty(const PropertyName & n,int value)623 void setProperty(const PropertyName &n, int value) override { 624 m_v->setProperty(n, value); 625 } 626 627 protected: 628 View *m_v; 629 }; 630 631 #endif 632 633