annotate view/View.h @ 855:57efeb75880d

Simplify some logic where loop was used with an unconditional "break" that meant it could only happen once (from coverity scan)
author Chris Cannam
date Wed, 03 Sep 2014 12:05:45 +0100
parents 532302d04571
children 99373ca20caf a1226b3b7925
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@127 7 This file copyright 2006 Chris Cannam.
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@226 16 #ifndef _VIEW_H_
Chris@226 17 #define _VIEW_H_
Chris@127 18
Chris@127 19 #include <QFrame>
Chris@127 20 #include <QProgressBar>
Chris@127 21
Chris@127 22 #include "base/ZoomConstraint.h"
Chris@127 23 #include "base/PropertyContainer.h"
Chris@128 24 #include "ViewManager.h"
Chris@127 25 #include "base/XmlExportable.h"
Chris@127 26
Chris@127 27 // #define DEBUG_VIEW_WIDGET_PAINT 1
Chris@127 28
Chris@127 29 class Layer;
Chris@127 30 class ViewPropertyContainer;
Chris@127 31
Chris@797 32 class QPushButton;
Chris@797 33
Chris@127 34 #include <map>
Chris@315 35 #include <set>
Chris@127 36
Chris@127 37 /**
Chris@127 38 * View is the base class of widgets that display one or more
Chris@127 39 * overlaid views of data against a horizontal time scale.
Chris@127 40 *
Chris@127 41 * A View may have any number of attached Layers, each of which
Chris@127 42 * is expected to have one data Model (although multiple views may
Chris@127 43 * share the same model).
Chris@127 44 *
Chris@127 45 * A View may be panned in time and zoomed, although the
Chris@127 46 * mechanisms for doing so (as well as any other operations and
Chris@127 47 * properties available) depend on the subclass.
Chris@127 48 */
Chris@127 49
Chris@127 50 class View : public QFrame,
Chris@127 51 public XmlExportable
Chris@127 52 {
Chris@127 53 Q_OBJECT
Chris@127 54
Chris@127 55 public:
Chris@127 56 /**
Chris@127 57 * Deleting a View does not delete any of its layers. They should
Chris@127 58 * be managed elsewhere (e.g. by the Document).
Chris@127 59 */
Chris@127 60 virtual ~View();
Chris@127 61
Chris@127 62 /**
Chris@127 63 * Retrieve the first visible sample frame on the widget.
Chris@127 64 * This is a calculated value based on the centre-frame, widget
Chris@127 65 * width and zoom level. The result may be negative.
Chris@127 66 */
Chris@806 67 int getStartFrame() const;
Chris@127 68
Chris@127 69 /**
Chris@127 70 * Set the widget pan based on the given first visible frame. The
Chris@127 71 * frame value may be negative.
Chris@127 72 */
Chris@806 73 void setStartFrame(int);
Chris@127 74
Chris@127 75 /**
Chris@127 76 * Return the centre frame of the visible widget. This is an
Chris@127 77 * exact value that does not depend on the zoom block size. Other
Chris@127 78 * frame values (start, end) are calculated from this based on the
Chris@127 79 * zoom and other factors.
Chris@127 80 */
Chris@806 81 int getCentreFrame() const { return m_centreFrame; }
Chris@127 82
Chris@127 83 /**
Chris@127 84 * Set the centre frame of the visible widget.
Chris@127 85 */
Chris@806 86 void setCentreFrame(int f) { setCentreFrame(f, true); }
Chris@127 87
Chris@127 88 /**
Chris@127 89 * Retrieve the last visible sample frame on the widget.
Chris@127 90 * This is a calculated value based on the centre-frame, widget
Chris@127 91 * width and zoom level.
Chris@127 92 */
Chris@806 93 int getEndFrame() const;
Chris@127 94
Chris@127 95 /**
Chris@127 96 * Return the pixel x-coordinate corresponding to a given sample
Chris@127 97 * frame (which may be negative).
Chris@127 98 */
Chris@806 99 int getXForFrame(int frame) const;
Chris@127 100
Chris@127 101 /**
Chris@127 102 * Return the closest frame to the given pixel x-coordinate.
Chris@127 103 */
Chris@806 104 int getFrameForX(int x) const;
Chris@127 105
Chris@127 106 /**
Chris@127 107 * Return the pixel y-coordinate corresponding to a given
Chris@127 108 * frequency, if the frequency range is as specified. This does
Chris@127 109 * not imply any policy about layer frequency ranges, but it might
Chris@127 110 * be useful for layers to match theirs up if desired.
Chris@127 111 *
Chris@127 112 * Not thread-safe in logarithmic mode. Call only from GUI thread.
Chris@127 113 */
Chris@127 114 float getYForFrequency(float frequency, float minFreq, float maxFreq,
Chris@127 115 bool logarithmic) const;
Chris@127 116
Chris@127 117 /**
Chris@127 118 * Return the closest frequency to the given pixel y-coordinate,
Chris@127 119 * if the frequency range is as specified.
Chris@127 120 *
Chris@127 121 * Not thread-safe in logarithmic mode. Call only from GUI thread.
Chris@127 122 */
Chris@127 123 float getFrequencyForY(int y, float minFreq, float maxFreq,
Chris@127 124 bool logarithmic) const;
Chris@127 125
Chris@127 126 /**
Chris@127 127 * Return the zoom level, i.e. the number of frames per pixel
Chris@127 128 */
Chris@127 129 int getZoomLevel() const;
Chris@127 130
Chris@127 131 /**
Chris@127 132 * Set the zoom level, i.e. the number of frames per pixel. The
Chris@127 133 * centre frame will be unchanged; the start and end frames will
Chris@127 134 * change.
Chris@127 135 */
Chris@806 136 virtual void setZoomLevel(int z);
Chris@127 137
Chris@127 138 /**
Chris@127 139 * Zoom in or out.
Chris@127 140 */
Chris@127 141 virtual void zoom(bool in);
Chris@127 142
Chris@127 143 /**
Chris@127 144 * Scroll left or right by a smallish or largish amount.
Chris@127 145 */
Chris@510 146 virtual void scroll(bool right, bool lots, bool doEmit = true);
Chris@127 147
Chris@834 148 /**
Chris@834 149 * Add a layer to the view. (Normally this should be handled
Chris@834 150 * through some command abstraction instead of using this function
Chris@834 151 * directly.)
Chris@834 152 */
Chris@127 153 virtual void addLayer(Layer *v);
Chris@834 154
Chris@834 155 /**
Chris@834 156 * Remove a layer from the view. Does not delete the
Chris@834 157 * layer. (Normally this should be handled through some command
Chris@834 158 * abstraction instead of using this function directly.)
Chris@834 159 */
Chris@834 160 virtual void removeLayer(Layer *v);
Chris@834 161
Chris@834 162 /**
Chris@834 163 * Return the number of layers, regardless of whether visible or
Chris@834 164 * dormant, i.e. invisible, in this view.
Chris@834 165 */
Chris@835 166 virtual int getLayerCount() const { return m_layerStack.size(); }
Chris@127 167
Chris@127 168 /**
Chris@834 169 * Return the nth layer, counted in stacking order. That is,
Chris@834 170 * layer 0 is the bottom layer and layer "getLayerCount()-1" is
Chris@834 171 * the top one. The returned layer may be visible or it may be
Chris@834 172 * dormant, i.e. invisible.
Chris@127 173 */
Chris@277 174 virtual Layer *getLayer(int n) {
Chris@835 175 if (n < int(m_layerStack.size())) return m_layerStack[n];
Chris@835 176 else return 0;
Chris@277 177 }
Chris@127 178
Chris@127 179 /**
Chris@835 180 * Return the nth layer, counted in the order they were
Chris@835 181 * added. Unlike the stacking order used in getLayer(), which
Chris@835 182 * changes each time a layer is selected, this ordering remains
Chris@835 183 * fixed. The returned layer may be visible or it may be dormant,
Chris@835 184 * i.e. invisible.
Chris@268 185 */
Chris@835 186 virtual Layer *getFixedOrderLayer(int n) {
Chris@835 187 if (n < int(m_fixedOrderLayers.size())) return m_fixedOrderLayers[n];
Chris@835 188 else return 0;
Chris@268 189 }
Chris@268 190
Chris@268 191 /**
Chris@834 192 * Return the layer currently active for tool interaction. This is
Chris@834 193 * the topmost non-dormant (i.e. visible) layer in the view. If
Chris@834 194 * there are no visible layers in the view, return 0.
Chris@834 195 */
Chris@834 196 virtual Layer *getInteractionLayer();
Chris@834 197
Chris@841 198 virtual const Layer *getInteractionLayer() const;
Chris@841 199
Chris@834 200 /**
Chris@835 201 * Return the layer most recently selected by the user. This is
Chris@835 202 * the layer that any non-tool-driven commands should operate on,
Chris@835 203 * in the case where this view is the "current" one.
Chris@835 204 *
Chris@835 205 * If the user has selected the view itself more recently than any
Chris@835 206 * of the layers on it, this function will return 0, and any
Chris@835 207 * non-tool-driven layer commands should be deactivated while this
Chris@835 208 * view is current. It will also return 0 if there are no layers
Chris@835 209 * in the view.
Chris@834 210 *
Chris@834 211 * Note that, unlike getInteractionLayer(), this could return an
Chris@834 212 * invisible (dormant) layer.
Chris@127 213 */
Chris@127 214 virtual Layer *getSelectedLayer();
Chris@834 215
Chris@127 216 virtual const Layer *getSelectedLayer() const;
Chris@127 217
Chris@835 218 /**
Chris@835 219 * Return the "top" layer in the view, whether visible or dormant.
Chris@835 220 * This is the same as getLayer(getLayerCount()-1) if there is at
Chris@835 221 * least one layer, and 0 otherwise.
Chris@835 222 *
Chris@835 223 * For most purposes involving interaction or commands, you
Chris@835 224 * probably want either getInteractionLayer() or
Chris@835 225 * getSelectedLayer() instead.
Chris@835 226 */
Chris@835 227 virtual Layer *getTopLayer() {
Chris@835 228 return m_layerStack.empty() ? 0 : m_layerStack[m_layerStack.size()-1];
Chris@835 229 }
Chris@835 230
Chris@127 231 virtual void setViewManager(ViewManager *m);
Chris@806 232 virtual void setViewManager(ViewManager *m, int initialFrame);
Chris@127 233 virtual ViewManager *getViewManager() const { return m_manager; }
Chris@127 234
Chris@127 235 virtual void setFollowGlobalPan(bool f);
Chris@127 236 virtual bool getFollowGlobalPan() const { return m_followPan; }
Chris@127 237
Chris@127 238 virtual void setFollowGlobalZoom(bool f);
Chris@127 239 virtual bool getFollowGlobalZoom() const { return m_followZoom; }
Chris@127 240
Chris@224 241 virtual bool hasLightBackground() const;
Chris@287 242 virtual QColor getForeground() const;
Chris@287 243 virtual QColor getBackground() const;
Chris@127 244
Chris@127 245 enum TextStyle {
Chris@127 246 BoxedText,
Chris@630 247 OutlinedText,
Chris@630 248 OutlinedItalicText
Chris@127 249 };
Chris@127 250
Chris@127 251 virtual void drawVisibleText(QPainter &p, int x, int y,
Chris@267 252 QString text, TextStyle style) const;
Chris@267 253
Chris@270 254 virtual void drawMeasurementRect(QPainter &p, const Layer *,
Chris@270 255 QRect rect, bool focus) const;
Chris@127 256
Chris@741 257 virtual bool shouldShowFeatureLabels() const {
Chris@741 258 return m_manager && m_manager->shouldShowFeatureLabels();
Chris@741 259 }
Chris@127 260 virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const {
Chris@127 261 return false;
Chris@127 262 }
Chris@127 263 virtual bool shouldIlluminateLocalSelection(QPoint &, bool &, bool &) const {
Chris@127 264 return false;
Chris@127 265 }
Chris@127 266
Chris@127 267 virtual void setPlaybackFollow(PlaybackFollowMode m);
Chris@127 268 virtual PlaybackFollowMode getPlaybackFollow() const { return m_followPlay; }
Chris@127 269
Chris@127 270 typedef PropertyContainer::PropertyName PropertyName;
Chris@127 271
Chris@127 272 // We implement the PropertyContainer API, although we don't
Chris@127 273 // actually subclass PropertyContainer. We have our own
Chris@127 274 // PropertyContainer that we can return on request that just
Chris@127 275 // delegates back to us.
Chris@127 276 virtual PropertyContainer::PropertyList getProperties() const;
Chris@127 277 virtual QString getPropertyLabel(const PropertyName &) const;
Chris@127 278 virtual PropertyContainer::PropertyType getPropertyType(const PropertyName &) const;
Chris@127 279 virtual int getPropertyRangeAndValue(const PropertyName &,
Chris@216 280 int *min, int *max, int *deflt) const;
Chris@127 281 virtual QString getPropertyValueLabel(const PropertyName &,
Chris@127 282 int value) const;
Chris@127 283 virtual void setProperty(const PropertyName &, int value);
Chris@127 284 virtual QString getPropertyContainerName() const {
Chris@127 285 return objectName();
Chris@127 286 }
Chris@127 287 virtual QString getPropertyContainerIconName() const = 0;
Chris@127 288
Chris@806 289 virtual int getPropertyContainerCount() const;
Chris@127 290
Chris@837 291 // The 0th property container is the view's own; the rest are the
Chris@837 292 // layers in fixed-order series
Chris@806 293 virtual const PropertyContainer *getPropertyContainer(int i) const;
Chris@806 294 virtual PropertyContainer *getPropertyContainer(int i);
Chris@127 295
Chris@229 296 // Render the contents on a wide canvas
Chris@806 297 virtual QImage *toNewImage(int f0, int f1);
Chris@226 298 virtual QImage *toNewImage();
Chris@806 299 virtual QSize getImageSize(int f0, int f1);
Chris@229 300 virtual QSize getImageSize();
Chris@226 301
Chris@127 302 virtual int getTextLabelHeight(const Layer *layer, QPainter &) const;
Chris@127 303
Chris@127 304 virtual bool getValueExtents(QString unit, float &min, float &max,
Chris@127 305 bool &log) const;
Chris@127 306
Chris@316 307 virtual void toXml(QTextStream &stream, QString indent = "",
Chris@316 308 QString extraAttributes = "") const;
Chris@127 309
Chris@222 310 // First frame actually in model, to right of scale, if present
Chris@806 311 virtual int getFirstVisibleFrame() const;
Chris@806 312 virtual int getLastVisibleFrame() const;
Chris@222 313
Chris@806 314 int getModelsStartFrame() const;
Chris@806 315 int getModelsEndFrame() const;
Chris@127 316
Chris@315 317 typedef std::set<Model *> ModelSet;
Chris@315 318 ModelSet getModels();
Chris@315 319
Chris@301 320 //!!!
Chris@320 321 Model *getAligningModel() const;
Chris@806 322 int alignFromReference(int) const;
Chris@806 323 int alignToReference(int) const;
Chris@301 324 int getAlignedPlaybackFrame() const;
Chris@301 325
Chris@127 326 signals:
Chris@127 327 void propertyContainerAdded(PropertyContainer *pc);
Chris@127 328 void propertyContainerRemoved(PropertyContainer *pc);
Chris@127 329 void propertyContainerPropertyChanged(PropertyContainer *pc);
Chris@197 330 void propertyContainerPropertyRangeChanged(PropertyContainer *pc);
Chris@127 331 void propertyContainerNameChanged(PropertyContainer *pc);
Chris@298 332 void propertyContainerSelected(PropertyContainer *pc);
Chris@127 333 void propertyChanged(PropertyContainer::PropertyName);
Chris@127 334
Chris@336 335 void layerModelChanged();
Chris@336 336
Chris@806 337 void centreFrameChanged(int frame,
Chris@211 338 bool globalScroll,
Chris@211 339 PlaybackFollowMode followMode);
Chris@211 340
Chris@806 341 void zoomLevelChanged(int, bool);
Chris@127 342
Chris@189 343 void contextHelpChanged(const QString &);
Chris@189 344
Chris@127 345 public slots:
Chris@127 346 virtual void modelChanged();
Chris@806 347 virtual void modelChangedWithin(int startFrame, int endFrame);
Chris@127 348 virtual void modelCompletionChanged();
Chris@320 349 virtual void modelAlignmentCompletionChanged();
Chris@127 350 virtual void modelReplaced();
Chris@127 351 virtual void layerParametersChanged();
Chris@197 352 virtual void layerParameterRangesChanged();
Chris@268 353 virtual void layerMeasurementRectsChanged();
Chris@127 354 virtual void layerNameChanged();
Chris@127 355
Chris@806 356 virtual void globalCentreFrameChanged(int);
Chris@806 357 virtual void viewCentreFrameChanged(View *, int);
Chris@806 358 virtual void viewManagerPlaybackFrameChanged(int);
Chris@806 359 virtual void viewZoomLevelChanged(View *, int, bool);
Chris@127 360
Chris@127 361 virtual void propertyContainerSelected(View *, PropertyContainer *pc);
Chris@127 362
Chris@127 363 virtual void selectionChanged();
Chris@127 364 virtual void toolModeChanged();
Chris@133 365 virtual void overlayModeChanged();
Chris@133 366 virtual void zoomWheelsEnabledChanged();
Chris@127 367
Chris@797 368 virtual void cancelClicked();
Chris@797 369
Chris@555 370 virtual void progressCheckStalledTimerElapsed();
Chris@555 371
Chris@127 372 protected:
Chris@127 373 View(QWidget *, bool showProgress);
Chris@127 374 virtual void paintEvent(QPaintEvent *e);
Chris@127 375 virtual void drawSelections(QPainter &);
Chris@127 376 virtual bool shouldLabelSelections() const { return true; }
Chris@806 377 virtual bool render(QPainter &paint, int x0, int f0, int f1);
Chris@339 378 virtual void setPaintFont(QPainter &paint);
Chris@339 379
Chris@127 380 typedef std::vector<Layer *> LayerList;
Chris@127 381
Chris@127 382 int getModelsSampleRate() const;
Chris@127 383 bool areLayersScrollable() const;
Chris@127 384 LayerList getScrollableBackLayers(bool testChanged, bool &changed) const;
Chris@127 385 LayerList getNonScrollableFrontLayers(bool testChanged, bool &changed) const;
Chris@806 386 int getZoomConstraintBlockSize(int blockSize,
Chris@127 387 ZoomConstraint::RoundingDirection dir =
Chris@127 388 ZoomConstraint::RoundNearest) const;
Chris@127 389
Chris@183 390 // True if the top layer(s) use colours for meaningful things. If
Chris@183 391 // this is the case, selections will be shown using unfilled boxes
Chris@183 392 // rather than with a translucent fill.
Chris@183 393 bool areLayerColoursSignificant() const;
Chris@183 394
Chris@217 395 // True if the top layer has a time axis on the x coordinate (this
Chris@217 396 // is generally the case except for spectrum/slice layers). It
Chris@217 397 // will not be possible to make or display selections if this is
Chris@217 398 // false.
Chris@217 399 bool hasTopLayerTimeXAxis() const;
Chris@217 400
Chris@806 401 bool setCentreFrame(int f, bool doEmit);
Chris@127 402
Chris@806 403 void movePlayPointer(int f);
Chris@511 404
Chris@127 405 void checkProgress(void *object);
Chris@384 406 int getProgressBarWidth() const; // if visible
Chris@127 407
Chris@806 408 int m_centreFrame;
Chris@127 409 int m_zoomLevel;
Chris@127 410 bool m_followPan;
Chris@127 411 bool m_followZoom;
Chris@127 412 PlaybackFollowMode m_followPlay;
Chris@789 413 bool m_followPlayIsDetached;
Chris@808 414 int m_playPointerFrame;
Chris@127 415 bool m_lightBackground;
Chris@127 416 bool m_showProgress;
Chris@127 417
Chris@127 418 QPixmap *m_cache;
Chris@806 419 int m_cacheCentreFrame;
Chris@127 420 int m_cacheZoomLevel;
Chris@127 421 bool m_selectionCached;
Chris@127 422
Chris@127 423 bool m_deleting;
Chris@127 424
Chris@835 425 LayerList m_layerStack; // I don't own these, but see dtor note above
Chris@835 426 LayerList m_fixedOrderLayers;
Chris@127 427 bool m_haveSelectedLayer;
Chris@127 428
Chris@583 429 QString m_lastError;
Chris@583 430
Chris@127 431 // caches for use in getScrollableBackLayers, getNonScrollableFrontLayers
Chris@127 432 mutable LayerList m_lastScrollableBackLayers;
Chris@127 433 mutable LayerList m_lastNonScrollableBackLayers;
Chris@127 434
Chris@555 435 struct ProgressBarRec {
Chris@797 436 QPushButton *cancel;
Chris@555 437 QProgressBar *bar;
Chris@555 438 int lastCheck;
Chris@555 439 QTimer *checkTimer;
Chris@555 440 };
Chris@555 441 typedef std::map<Layer *, ProgressBarRec> ProgressMap;
Chris@127 442 ProgressMap m_progressBars; // I own the ProgressBars
Chris@127 443
Chris@127 444 ViewManager *m_manager; // I don't own this
Chris@127 445 ViewPropertyContainer *m_propertyContainer; // I own this
Chris@127 446 };
Chris@127 447
Chris@127 448
Chris@127 449 // Use this for delegation, because we can't subclass from
Chris@127 450 // PropertyContainer (which is a QObject) ourselves because of
Chris@127 451 // ambiguity with QFrame parent
Chris@127 452
Chris@127 453 class ViewPropertyContainer : public PropertyContainer
Chris@127 454 {
Chris@127 455 Q_OBJECT
Chris@127 456
Chris@127 457 public:
Chris@127 458 ViewPropertyContainer(View *v);
Chris@728 459 virtual ~ViewPropertyContainer();
Chris@728 460
Chris@127 461 PropertyList getProperties() const { return m_v->getProperties(); }
Chris@127 462 QString getPropertyLabel(const PropertyName &n) const {
Chris@127 463 return m_v->getPropertyLabel(n);
Chris@127 464 }
Chris@127 465 PropertyType getPropertyType(const PropertyName &n) const {
Chris@127 466 return m_v->getPropertyType(n);
Chris@127 467 }
Chris@216 468 int getPropertyRangeAndValue(const PropertyName &n, int *min, int *max,
Chris@216 469 int *deflt) const {
Chris@216 470 return m_v->getPropertyRangeAndValue(n, min, max, deflt);
Chris@127 471 }
Chris@127 472 QString getPropertyValueLabel(const PropertyName &n, int value) const {
Chris@127 473 return m_v->getPropertyValueLabel(n, value);
Chris@127 474 }
Chris@127 475 QString getPropertyContainerName() const {
Chris@127 476 return m_v->getPropertyContainerName();
Chris@127 477 }
Chris@127 478 QString getPropertyContainerIconName() const {
Chris@127 479 return m_v->getPropertyContainerIconName();
Chris@127 480 }
Chris@127 481
Chris@127 482 public slots:
Chris@127 483 virtual void setProperty(const PropertyName &n, int value) {
Chris@127 484 m_v->setProperty(n, value);
Chris@127 485 }
Chris@127 486
Chris@127 487 protected:
Chris@127 488 View *m_v;
Chris@127 489 };
Chris@127 490
Chris@127 491 #endif
Chris@127 492