annotate view/View.h @ 312:6de6f78b13a1

* Make it possible to drop audio files, layer files, session files and images onto SV panes. Need to do a bit more work on where we expect the dropped file to go, particularly in the case of audio files -- at the moment they're always opened in new panes, but it may be better to by default replace whatever is in the target pane.
author Chris Cannam
date Wed, 10 Oct 2007 15:18:02 +0000
parents 5636eeacc467
children 1517c76cd678
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@127 32 #include <map>
Chris@127 33
Chris@127 34 /**
Chris@127 35 * View is the base class of widgets that display one or more
Chris@127 36 * overlaid views of data against a horizontal time scale.
Chris@127 37 *
Chris@127 38 * A View may have any number of attached Layers, each of which
Chris@127 39 * is expected to have one data Model (although multiple views may
Chris@127 40 * share the same model).
Chris@127 41 *
Chris@127 42 * A View may be panned in time and zoomed, although the
Chris@127 43 * mechanisms for doing so (as well as any other operations and
Chris@127 44 * properties available) depend on the subclass.
Chris@127 45 */
Chris@127 46
Chris@127 47 class View : public QFrame,
Chris@127 48 public XmlExportable
Chris@127 49 {
Chris@127 50 Q_OBJECT
Chris@127 51
Chris@127 52 public:
Chris@127 53 /**
Chris@127 54 * Deleting a View does not delete any of its layers. They should
Chris@127 55 * be managed elsewhere (e.g. by the Document).
Chris@127 56 */
Chris@127 57 virtual ~View();
Chris@127 58
Chris@127 59 /**
Chris@127 60 * Retrieve the first visible sample frame on the widget.
Chris@127 61 * This is a calculated value based on the centre-frame, widget
Chris@127 62 * width and zoom level. The result may be negative.
Chris@127 63 */
Chris@127 64 virtual long getStartFrame() const;
Chris@127 65
Chris@127 66 /**
Chris@127 67 * Set the widget pan based on the given first visible frame. The
Chris@127 68 * frame value may be negative.
Chris@127 69 */
Chris@127 70 virtual void setStartFrame(long);
Chris@127 71
Chris@127 72 /**
Chris@127 73 * Return the centre frame of the visible widget. This is an
Chris@127 74 * exact value that does not depend on the zoom block size. Other
Chris@127 75 * frame values (start, end) are calculated from this based on the
Chris@127 76 * zoom and other factors.
Chris@127 77 */
Chris@127 78 virtual size_t getCentreFrame() const { return m_centreFrame; }
Chris@127 79
Chris@127 80 /**
Chris@127 81 * Set the centre frame of the visible widget.
Chris@127 82 */
Chris@127 83 virtual void setCentreFrame(size_t f) { setCentreFrame(f, true); }
Chris@127 84
Chris@127 85 /**
Chris@127 86 * Retrieve the last visible sample frame on the widget.
Chris@127 87 * This is a calculated value based on the centre-frame, widget
Chris@127 88 * width and zoom level.
Chris@127 89 */
Chris@127 90 virtual size_t getEndFrame() const;
Chris@127 91
Chris@127 92 /**
Chris@127 93 * Return the pixel x-coordinate corresponding to a given sample
Chris@127 94 * frame (which may be negative).
Chris@127 95 */
Chris@127 96 int getXForFrame(long frame) const;
Chris@127 97
Chris@127 98 /**
Chris@127 99 * Return the closest frame to the given pixel x-coordinate.
Chris@127 100 */
Chris@127 101 long getFrameForX(int x) const;
Chris@127 102
Chris@127 103 /**
Chris@127 104 * Return the pixel y-coordinate corresponding to a given
Chris@127 105 * frequency, if the frequency range is as specified. This does
Chris@127 106 * not imply any policy about layer frequency ranges, but it might
Chris@127 107 * be useful for layers to match theirs up if desired.
Chris@127 108 *
Chris@127 109 * Not thread-safe in logarithmic mode. Call only from GUI thread.
Chris@127 110 */
Chris@127 111 float getYForFrequency(float frequency, float minFreq, float maxFreq,
Chris@127 112 bool logarithmic) const;
Chris@127 113
Chris@127 114 /**
Chris@127 115 * Return the closest frequency to the given pixel y-coordinate,
Chris@127 116 * if the frequency range is as specified.
Chris@127 117 *
Chris@127 118 * Not thread-safe in logarithmic mode. Call only from GUI thread.
Chris@127 119 */
Chris@127 120 float getFrequencyForY(int y, float minFreq, float maxFreq,
Chris@127 121 bool logarithmic) const;
Chris@127 122
Chris@127 123 /**
Chris@127 124 * Return the zoom level, i.e. the number of frames per pixel
Chris@127 125 */
Chris@127 126 int getZoomLevel() const;
Chris@127 127
Chris@127 128 /**
Chris@127 129 * Set the zoom level, i.e. the number of frames per pixel. The
Chris@127 130 * centre frame will be unchanged; the start and end frames will
Chris@127 131 * change.
Chris@127 132 */
Chris@127 133 virtual void setZoomLevel(size_t z);
Chris@127 134
Chris@127 135 /**
Chris@127 136 * Zoom in or out.
Chris@127 137 */
Chris@127 138 virtual void zoom(bool in);
Chris@127 139
Chris@127 140 /**
Chris@127 141 * Scroll left or right by a smallish or largish amount.
Chris@127 142 */
Chris@127 143 virtual void scroll(bool right, bool lots);
Chris@127 144
Chris@127 145 virtual void addLayer(Layer *v);
Chris@127 146 virtual void removeLayer(Layer *v); // does not delete the layer
Chris@127 147 virtual int getLayerCount() const { return m_layers.size(); }
Chris@127 148
Chris@127 149 /**
Chris@127 150 * Return a layer, counted in stacking order. That is, layer 0 is
Chris@127 151 * the bottom layer and layer "getLayerCount()-1" is the top one.
Chris@127 152 */
Chris@277 153 virtual Layer *getLayer(int n) {
Chris@285 154 if (n < int(m_layers.size())) return m_layers[n]; else return 0;
Chris@277 155 }
Chris@127 156
Chris@127 157 /**
Chris@268 158 * Return the top layer. This is the same as
Chris@268 159 * getLayer(getLayerCount()-1) if there is at least one layer, and
Chris@268 160 * 0 otherwise.
Chris@268 161 */
Chris@268 162 virtual Layer *getTopLayer() {
Chris@268 163 return m_layers.empty() ? 0 : m_layers[m_layers.size()-1];
Chris@268 164 }
Chris@268 165
Chris@268 166 /**
Chris@127 167 * Return the layer last selected by the user. This is normally
Chris@127 168 * the top layer, the same as getLayer(getLayerCount()-1).
Chris@127 169 * However, if the user has selected the pane itself more recently
Chris@127 170 * than any of the layers on it, this function will return 0. It
Chris@127 171 * will also return 0 if there are no layers.
Chris@127 172 */
Chris@127 173 virtual Layer *getSelectedLayer();
Chris@127 174 virtual const Layer *getSelectedLayer() const;
Chris@127 175
Chris@127 176 virtual void setViewManager(ViewManager *m);
Chris@127 177 virtual ViewManager *getViewManager() const { return m_manager; }
Chris@127 178
Chris@127 179 virtual void setFollowGlobalPan(bool f);
Chris@127 180 virtual bool getFollowGlobalPan() const { return m_followPan; }
Chris@127 181
Chris@127 182 virtual void setFollowGlobalZoom(bool f);
Chris@127 183 virtual bool getFollowGlobalZoom() const { return m_followZoom; }
Chris@127 184
Chris@224 185 virtual bool hasLightBackground() const;
Chris@287 186 virtual QColor getForeground() const;
Chris@287 187 virtual QColor getBackground() const;
Chris@127 188
Chris@127 189 enum TextStyle {
Chris@127 190 BoxedText,
Chris@127 191 OutlinedText
Chris@127 192 };
Chris@127 193
Chris@127 194 virtual void drawVisibleText(QPainter &p, int x, int y,
Chris@267 195 QString text, TextStyle style) const;
Chris@267 196
Chris@270 197 virtual void drawMeasurementRect(QPainter &p, const Layer *,
Chris@270 198 QRect rect, bool focus) const;
Chris@127 199
Chris@127 200 virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const {
Chris@127 201 return false;
Chris@127 202 }
Chris@127 203 virtual bool shouldIlluminateLocalSelection(QPoint &, bool &, bool &) const {
Chris@127 204 return false;
Chris@127 205 }
Chris@127 206
Chris@127 207 virtual void setPlaybackFollow(PlaybackFollowMode m);
Chris@127 208 virtual PlaybackFollowMode getPlaybackFollow() const { return m_followPlay; }
Chris@127 209
Chris@127 210 typedef PropertyContainer::PropertyName PropertyName;
Chris@127 211
Chris@127 212 // We implement the PropertyContainer API, although we don't
Chris@127 213 // actually subclass PropertyContainer. We have our own
Chris@127 214 // PropertyContainer that we can return on request that just
Chris@127 215 // delegates back to us.
Chris@127 216 virtual PropertyContainer::PropertyList getProperties() const;
Chris@127 217 virtual QString getPropertyLabel(const PropertyName &) const;
Chris@127 218 virtual PropertyContainer::PropertyType getPropertyType(const PropertyName &) const;
Chris@127 219 virtual int getPropertyRangeAndValue(const PropertyName &,
Chris@216 220 int *min, int *max, int *deflt) const;
Chris@127 221 virtual QString getPropertyValueLabel(const PropertyName &,
Chris@127 222 int value) const;
Chris@127 223 virtual void setProperty(const PropertyName &, int value);
Chris@127 224 virtual QString getPropertyContainerName() const {
Chris@127 225 return objectName();
Chris@127 226 }
Chris@127 227 virtual QString getPropertyContainerIconName() const = 0;
Chris@127 228
Chris@127 229 virtual size_t getPropertyContainerCount() const;
Chris@127 230
Chris@127 231 virtual const PropertyContainer *getPropertyContainer(size_t i) const;
Chris@127 232 virtual PropertyContainer *getPropertyContainer(size_t i);
Chris@127 233
Chris@229 234 // Render the contents on a wide canvas
Chris@229 235 virtual QImage *toNewImage(size_t f0, size_t f1);
Chris@226 236 virtual QImage *toNewImage();
Chris@229 237 virtual QSize getImageSize(size_t f0, size_t f1);
Chris@229 238 virtual QSize getImageSize();
Chris@226 239
Chris@127 240 virtual int getTextLabelHeight(const Layer *layer, QPainter &) const;
Chris@127 241
Chris@127 242 virtual bool getValueExtents(QString unit, float &min, float &max,
Chris@127 243 bool &log) const;
Chris@127 244
Chris@127 245 virtual QString toXmlString(QString indent = "",
Chris@127 246 QString extraAttributes = "") const;
Chris@127 247
Chris@222 248 // First frame actually in model, to right of scale, if present
Chris@222 249 virtual size_t getFirstVisibleFrame() const;
Chris@222 250 virtual size_t getLastVisibleFrame() const;
Chris@222 251
Chris@127 252 size_t getModelsStartFrame() const;
Chris@127 253 size_t getModelsEndFrame() const;
Chris@127 254
Chris@301 255 //!!!
Chris@301 256 int getAlignedPlaybackFrame() const;
Chris@301 257
Chris@127 258 signals:
Chris@127 259 void propertyContainerAdded(PropertyContainer *pc);
Chris@127 260 void propertyContainerRemoved(PropertyContainer *pc);
Chris@127 261 void propertyContainerPropertyChanged(PropertyContainer *pc);
Chris@197 262 void propertyContainerPropertyRangeChanged(PropertyContainer *pc);
Chris@127 263 void propertyContainerNameChanged(PropertyContainer *pc);
Chris@298 264 void propertyContainerSelected(PropertyContainer *pc);
Chris@127 265 void propertyChanged(PropertyContainer::PropertyName);
Chris@127 266
Chris@211 267 void centreFrameChanged(unsigned long frame,
Chris@211 268 bool globalScroll,
Chris@211 269 PlaybackFollowMode followMode);
Chris@211 270
Chris@222 271 void zoomLevelChanged(unsigned long, bool);
Chris@127 272
Chris@189 273 void contextHelpChanged(const QString &);
Chris@189 274
Chris@127 275 public slots:
Chris@127 276 virtual void modelChanged();
Chris@127 277 virtual void modelChanged(size_t startFrame, size_t endFrame);
Chris@127 278 virtual void modelCompletionChanged();
Chris@127 279 virtual void modelReplaced();
Chris@127 280 virtual void layerParametersChanged();
Chris@197 281 virtual void layerParameterRangesChanged();
Chris@268 282 virtual void layerMeasurementRectsChanged();
Chris@127 283 virtual void layerNameChanged();
Chris@127 284
Chris@211 285 virtual void globalCentreFrameChanged(unsigned long);
Chris@211 286 virtual void viewCentreFrameChanged(View *, unsigned long);
Chris@127 287 virtual void viewManagerPlaybackFrameChanged(unsigned long);
Chris@222 288 virtual void viewZoomLevelChanged(View *, unsigned long, bool);
Chris@127 289
Chris@127 290 virtual void propertyContainerSelected(View *, PropertyContainer *pc);
Chris@127 291
Chris@127 292 virtual void selectionChanged();
Chris@127 293 virtual void toolModeChanged();
Chris@133 294 virtual void overlayModeChanged();
Chris@133 295 virtual void zoomWheelsEnabledChanged();
Chris@127 296
Chris@127 297 protected:
Chris@127 298 View(QWidget *, bool showProgress);
Chris@127 299 virtual void paintEvent(QPaintEvent *e);
Chris@127 300 virtual void drawSelections(QPainter &);
Chris@127 301 virtual bool shouldLabelSelections() const { return true; }
Chris@229 302 virtual bool render(QPainter &paint, int x0, size_t f0, size_t f1);
Chris@127 303
Chris@127 304 typedef std::vector<Layer *> LayerList;
Chris@127 305
Chris@127 306 int getModelsSampleRate() const;
Chris@127 307 bool areLayersScrollable() const;
Chris@127 308 LayerList getScrollableBackLayers(bool testChanged, bool &changed) const;
Chris@127 309 LayerList getNonScrollableFrontLayers(bool testChanged, bool &changed) const;
Chris@127 310 size_t getZoomConstraintBlockSize(size_t blockSize,
Chris@127 311 ZoomConstraint::RoundingDirection dir =
Chris@127 312 ZoomConstraint::RoundNearest) const;
Chris@127 313
Chris@183 314 // True if the top layer(s) use colours for meaningful things. If
Chris@183 315 // this is the case, selections will be shown using unfilled boxes
Chris@183 316 // rather than with a translucent fill.
Chris@183 317 bool areLayerColoursSignificant() const;
Chris@183 318
Chris@217 319 // True if the top layer has a time axis on the x coordinate (this
Chris@217 320 // is generally the case except for spectrum/slice layers). It
Chris@217 321 // will not be possible to make or display selections if this is
Chris@217 322 // false.
Chris@217 323 bool hasTopLayerTimeXAxis() const;
Chris@217 324
Chris@127 325 bool setCentreFrame(size_t f, bool doEmit);
Chris@127 326
Chris@127 327 void checkProgress(void *object);
Chris@127 328
Chris@127 329 size_t m_centreFrame;
Chris@127 330 int m_zoomLevel;
Chris@127 331 bool m_followPan;
Chris@127 332 bool m_followZoom;
Chris@127 333 PlaybackFollowMode m_followPlay;
Chris@127 334 size_t m_playPointerFrame;
Chris@127 335 bool m_lightBackground;
Chris@127 336 bool m_showProgress;
Chris@127 337
Chris@127 338 QPixmap *m_cache;
Chris@127 339 size_t m_cacheCentreFrame;
Chris@127 340 int m_cacheZoomLevel;
Chris@127 341 bool m_selectionCached;
Chris@127 342
Chris@127 343 bool m_deleting;
Chris@127 344
Chris@127 345 LayerList m_layers; // I don't own these, but see dtor note above
Chris@127 346 bool m_haveSelectedLayer;
Chris@127 347
Chris@127 348 // caches for use in getScrollableBackLayers, getNonScrollableFrontLayers
Chris@127 349 mutable LayerList m_lastScrollableBackLayers;
Chris@127 350 mutable LayerList m_lastNonScrollableBackLayers;
Chris@127 351
Chris@127 352 class LayerProgressBar : public QProgressBar {
Chris@127 353 public:
Chris@127 354 LayerProgressBar(QWidget *parent);
Chris@127 355 virtual QString text() const { return m_text; }
Chris@127 356 virtual void setText(QString text) { m_text = text; }
Chris@127 357 protected:
Chris@127 358 QString m_text;
Chris@127 359 };
Chris@127 360
Chris@127 361 typedef std::map<Layer *, LayerProgressBar *> ProgressMap;
Chris@127 362 ProgressMap m_progressBars; // I own the ProgressBars
Chris@127 363
Chris@127 364 ViewManager *m_manager; // I don't own this
Chris@127 365 ViewPropertyContainer *m_propertyContainer; // I own this
Chris@127 366 };
Chris@127 367
Chris@127 368
Chris@127 369 // Use this for delegation, because we can't subclass from
Chris@127 370 // PropertyContainer (which is a QObject) ourselves because of
Chris@127 371 // ambiguity with QFrame parent
Chris@127 372
Chris@127 373 class ViewPropertyContainer : public PropertyContainer
Chris@127 374 {
Chris@127 375 Q_OBJECT
Chris@127 376
Chris@127 377 public:
Chris@127 378 ViewPropertyContainer(View *v);
Chris@127 379 PropertyList getProperties() const { return m_v->getProperties(); }
Chris@127 380 QString getPropertyLabel(const PropertyName &n) const {
Chris@127 381 return m_v->getPropertyLabel(n);
Chris@127 382 }
Chris@127 383 PropertyType getPropertyType(const PropertyName &n) const {
Chris@127 384 return m_v->getPropertyType(n);
Chris@127 385 }
Chris@216 386 int getPropertyRangeAndValue(const PropertyName &n, int *min, int *max,
Chris@216 387 int *deflt) const {
Chris@216 388 return m_v->getPropertyRangeAndValue(n, min, max, deflt);
Chris@127 389 }
Chris@127 390 QString getPropertyValueLabel(const PropertyName &n, int value) const {
Chris@127 391 return m_v->getPropertyValueLabel(n, value);
Chris@127 392 }
Chris@127 393 QString getPropertyContainerName() const {
Chris@127 394 return m_v->getPropertyContainerName();
Chris@127 395 }
Chris@127 396 QString getPropertyContainerIconName() const {
Chris@127 397 return m_v->getPropertyContainerIconName();
Chris@127 398 }
Chris@127 399
Chris@127 400 public slots:
Chris@127 401 virtual void setProperty(const PropertyName &n, int value) {
Chris@127 402 m_v->setProperty(n, value);
Chris@127 403 }
Chris@127 404
Chris@127 405 protected:
Chris@127 406 View *m_v;
Chris@127 407 };
Chris@127 408
Chris@127 409 #endif
Chris@127 410