Chris@127: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@127: Chris@127: /* Chris@127: Sonic Visualiser Chris@127: An audio file viewer and annotation editor. Chris@127: Centre for Digital Music, Queen Mary, University of London. Chris@182: This file copyright 2006 Chris Cannam and QMUL. Chris@127: Chris@127: This program is free software; you can redistribute it and/or Chris@127: modify it under the terms of the GNU General Public License as Chris@127: published by the Free Software Foundation; either version 2 of the Chris@127: License, or (at your option) any later version. See the file Chris@127: COPYING included with this distribution for more information. Chris@127: */ Chris@127: Chris@1407: #ifndef SV_LAYER_H Chris@1407: #define SV_LAYER_H Chris@127: Chris@128: #include "base/PropertyContainer.h" Chris@128: #include "base/XmlExportable.h" Chris@128: #include "base/Selection.h" Chris@127: Chris@1469: #include "data/model/Model.h" Chris@1469: Chris@376: #include "widgets/CommandHistory.h" Chris@376: Chris@523: #include "system/System.h" Chris@523: Chris@127: #include Chris@127: #include Chris@127: #include Chris@131: #include Chris@299: #include Chris@127: Chris@127: #include Chris@268: #include Chris@127: Chris@552: #include Chris@552: Chris@127: class ZoomConstraint; Chris@127: class QPainter; Chris@127: class View; Chris@916: class LayerGeometryProvider; Chris@127: class QMouseEvent; Chris@127: class Clipboard; Chris@187: class RangeMapper; Chris@127: Chris@127: /** Chris@127: * The base class for visual representations of the data found in a Chris@127: * Model. Layers are expected to be able to draw themselves onto a Chris@127: * View, and may also be editable. Chris@127: */ Chris@127: Chris@127: class Layer : public PropertyContainer, Chris@1266: public XmlExportable Chris@127: { Chris@127: Q_OBJECT Chris@127: Chris@127: public: Chris@127: Layer(); Chris@127: virtual ~Layer(); Chris@127: Chris@1469: /** Chris@1469: * Return the ID of the model represented in this layer. Chris@1469: */ Chris@1469: virtual ModelId getModel() const = 0; Chris@947: Chris@137: /** Chris@137: * Return a zoom constraint object defining the supported zoom Chris@137: * levels for this layer. If this returns zero, the layer will Chris@137: * support any integer zoom level. Chris@137: */ Chris@127: virtual const ZoomConstraint *getZoomConstraint() const { return 0; } Chris@137: Chris@137: /** Chris@137: * Return true if this layer can handle zoom levels other than Chris@137: * those supported by its zoom constraint (presumably less Chris@137: * efficiently or accurately than the officially supported zoom Chris@137: * levels). If true, the layer will unenthusistically accept any Chris@137: * integer zoom level from 1 to the maximum returned by its zoom Chris@137: * constraint. Chris@137: */ Chris@137: virtual bool supportsOtherZoomLevels() const { return true; } Chris@137: Chris@389: /** Chris@389: * Paint the given rectangle of this layer onto the given view Chris@389: * using the given painter, superimposing it on top of any Chris@916: * existing material in that view. The LayerGeometryProvider (an Chris@916: * interface implemented by View) is provided here because it is Chris@916: * possible for one layer to exist in more than one view, so the Chris@916: * dimensions of the view may vary from one paint call to another Chris@916: * (without any view having been resized). Chris@389: */ Chris@916: virtual void paint(LayerGeometryProvider *, QPainter &, QRect) const = 0; Chris@127: Chris@389: /** Chris@389: * Enable or disable synchronous painting. If synchronous Chris@389: * painting is enabled, a call to paint() must complete painting Chris@389: * the entire rectangle before it returns. If synchronous Chris@389: * painting is disabled (which should be the default), the paint() Chris@389: * call may defer painting some regions if data is not yet Chris@389: * available, by calling back on its view to schedule another Chris@389: * update. Synchronous painting is necessary when rendering to an Chris@389: * image. Simple layer types will always paint synchronously, and Chris@389: * so may ignore this. Chris@389: */ Chris@389: virtual void setSynchronousPainting(bool /* synchronous */) { } Chris@389: Chris@127: enum VerticalPosition { Chris@1266: PositionTop, PositionMiddle, PositionBottom Chris@127: }; Chris@127: virtual VerticalPosition getPreferredTimeRulerPosition() const { Chris@1266: return PositionMiddle; Chris@127: } Chris@127: virtual VerticalPosition getPreferredFrameCountPosition() const { Chris@1266: return PositionBottom; Chris@127: } Chris@224: virtual bool hasLightBackground() const { Chris@224: return true; Chris@224: } Chris@127: Chris@1406: QString getPropertyContainerIconName() const override; Chris@127: Chris@1406: QString getPropertyContainerName() const override { Chris@363: if (m_presentationName != "") return m_presentationName; Chris@1266: else return objectName(); Chris@127: } Chris@127: Chris@363: virtual void setPresentationName(QString name); Chris@363: Chris@127: virtual QString getLayerPresentationName() const; Chris@299: virtual QPixmap getLayerPresentationPixmap(QSize) const { return QPixmap(); } Chris@127: Chris@916: virtual int getVerticalScaleWidth(LayerGeometryProvider *, bool detailed, Chris@607: QPainter &) const = 0; Chris@607: Chris@916: virtual void paintVerticalScale(LayerGeometryProvider *, bool /* detailed */, Chris@607: QPainter &, QRect) const { } Chris@127: Chris@1390: virtual int getHorizontalScaleHeight(LayerGeometryProvider *, QPainter &) const { return 0; } Chris@1390: Chris@916: virtual bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint /* cursorPos */, Chris@127: std::vector &) const { Chris@127: return false; Chris@127: } Chris@916: virtual void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const { } Chris@127: Chris@916: virtual void paintMeasurementRects(LayerGeometryProvider *, QPainter &, Chris@272: bool showFocus, QPoint focusPoint) const; Chris@272: Chris@916: virtual bool nearestMeasurementRectChanged(LayerGeometryProvider *, QPoint prev, Chris@272: QPoint now) const; Chris@267: Chris@916: virtual QString getFeatureDescription(LayerGeometryProvider *, QPoint &) const { Chris@1266: return ""; Chris@127: } Chris@127: Chris@909: virtual QString getLabelPreceding(sv_frame_t /* frame */) const { Chris@552: return ""; Chris@552: } Chris@552: Chris@127: enum SnapType { Chris@1266: SnapLeft, Chris@1266: SnapRight, Chris@1266: SnapNeighbouring Chris@127: }; Chris@127: Chris@127: /** Chris@127: * Adjust the given frame to snap to the nearest feature, if Chris@127: * possible. Chris@127: * Chris@127: * If snap is SnapLeft or SnapRight, adjust the frame to match Chris@127: * that of the nearest feature in the given direction regardless Chris@1431: * of how far away it is. If snap is SnapNeighbouring, adjust the Chris@1431: * frame to that of the nearest feature in either direction if it Chris@1431: * is close, and leave it alone (returning false) otherwise. Chris@1431: * SnapNeighbouring should always choose the same feature that Chris@1431: * would be used in an editing operation through calls to Chris@1431: * editStart etc. Chris@127: * Chris@127: * Return true if a suitable feature was found and frame adjusted Chris@180: * accordingly. Return false if no suitable feature was available Chris@517: * (and leave frame unmodified). If returning true, also return Chris@517: * the resolution of the model in this layer in sample frames. Chris@127: */ Chris@916: virtual bool snapToFeatureFrame(LayerGeometryProvider * /* v */, Chris@1266: sv_frame_t & /* frame */, Chris@1266: int &resolution, Chris@1266: SnapType /* snap */) const { Chris@1266: resolution = 1; Chris@1266: return false; Chris@127: } Chris@127: Chris@517: /** Chris@517: * Adjust the given frame to snap to the next feature that has Chris@517: * "effectively" the same value as the feature prior to the given Chris@517: * frame, if possible. Chris@517: * Chris@517: * The snap type must be SnapLeft (snap to the time of the next Chris@517: * feature prior to the one preceding the given frame that has a Chris@517: * similar value to it) or SnapRight (snap to the time of the next Chris@517: * feature following the given frame that has a similar value to Chris@517: * the feature preceding it). Other values are not permitted. Chris@517: * Chris@517: * Return true if a suitable feature was found and frame adjusted Chris@517: * accordingly. Return false if no suitable feature was available Chris@517: * (and leave frame unmodified). If returning true, also return Chris@517: * the resolution of the model in this layer in sample frames. Chris@517: */ Chris@916: virtual bool snapToSimilarFeature(LayerGeometryProvider * /* v */, Chris@904: sv_frame_t & /* source frame */, Chris@805: int &resolution, Chris@517: SnapType /* snap */) const { Chris@1266: resolution = 1; Chris@1266: return false; Chris@517: } Chris@517: Chris@335: // Draw, erase, and edit modes: Chris@127: // Chris@127: // Layer needs to get actual mouse events, I guess. Draw mode is Chris@127: // probably the easier. Chris@127: Chris@916: virtual void drawStart(LayerGeometryProvider *, QMouseEvent *) { } Chris@916: virtual void drawDrag(LayerGeometryProvider *, QMouseEvent *) { } Chris@916: virtual void drawEnd(LayerGeometryProvider *, QMouseEvent *) { } Chris@127: Chris@916: virtual void eraseStart(LayerGeometryProvider *, QMouseEvent *) { } Chris@916: virtual void eraseDrag(LayerGeometryProvider *, QMouseEvent *) { } Chris@916: virtual void eraseEnd(LayerGeometryProvider *, QMouseEvent *) { } Chris@335: Chris@916: virtual void editStart(LayerGeometryProvider *, QMouseEvent *) { } Chris@916: virtual void editDrag(LayerGeometryProvider *, QMouseEvent *) { } Chris@916: virtual void editEnd(LayerGeometryProvider *, QMouseEvent *) { } Chris@127: Chris@916: virtual void splitStart(LayerGeometryProvider *, QMouseEvent *) { } Chris@916: virtual void splitEnd(LayerGeometryProvider *, QMouseEvent *) { } Chris@916: virtual void addNote(LayerGeometryProvider *, QMouseEvent *) { }; gyorgyf@635: Chris@267: // Measurement rectangle (or equivalent). Unlike draw and edit, Chris@267: // the base Layer class can provide working implementations of Chris@267: // these for most situations. Chris@267: // Chris@916: virtual void measureStart(LayerGeometryProvider *, QMouseEvent *); Chris@916: virtual void measureDrag(LayerGeometryProvider *, QMouseEvent *); Chris@916: virtual void measureEnd(LayerGeometryProvider *, QMouseEvent *); Chris@916: virtual void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *); Chris@267: Chris@283: virtual bool haveCurrentMeasureRect() const { Chris@283: return m_haveCurrentMeasureRect; Chris@283: } Chris@283: virtual void deleteCurrentMeasureRect(); // using a command Chris@283: Chris@255: /** Chris@255: * Open an editor on the item under the mouse (e.g. on Chris@255: * double-click). If there is no item or editing is not Chris@255: * supported, return false. Chris@255: */ Chris@916: virtual bool editOpen(LayerGeometryProvider *, QMouseEvent *) { return false; } Chris@127: Chris@905: virtual void moveSelection(Selection, sv_frame_t /* newStartFrame */) { } Chris@127: virtual void resizeSelection(Selection, Selection /* newSize */) { } Chris@127: virtual void deleteSelection(Selection) { } Chris@127: Chris@916: virtual void copy(LayerGeometryProvider *, Selection, Clipboard & /* to */) { } Chris@127: Chris@127: /** Chris@127: * Paste from the given clipboard onto the layer at the given Chris@127: * frame offset. If interactive is true, the layer may ask the Chris@127: * user about paste options through a dialog if desired, and may Chris@127: * return false if the user cancelled the paste operation. This Chris@127: * function should return true if a paste actually occurred. Chris@127: */ Chris@916: virtual bool paste(LayerGeometryProvider *, Chris@359: const Clipboard & /* from */, Chris@904: sv_frame_t /* frameOffset */, Chris@127: bool /* interactive */) { return false; } Chris@127: Chris@127: // Text mode: Chris@127: // Chris@127: // Label nearest feature. We need to get the feature coordinates Chris@127: // and current label from the layer, and then the pane can pop up Chris@127: // a little text entry dialog at the right location. Or we edit Chris@127: // in place? Probably the dialog is easier. Chris@127: Chris@127: /** Chris@127: * This should return true if the layer can safely be scrolled Chris@127: * automatically by a given view (simply copying the existing data Chris@127: * and then refreshing the exposed area) without altering its Chris@127: * meaning. For the view widget as a whole this is usually not Chris@127: * possible because of invariant (non-scrolling) material Chris@127: * displayed over the top, but the widget may be able to optimise Chris@127: * scrolling better if it is known that individual views can be Chris@127: * scrolled safely in this way. Chris@127: */ Chris@916: virtual bool isLayerScrollable(const LayerGeometryProvider *) const { return true; } Chris@127: Chris@127: /** Chris@127: * This should return true if the layer completely obscures any Chris@127: * underlying layers. It's used to determine whether the view can Chris@127: * safely draw any selection rectangles under the layer instead of Chris@127: * over it, in the case where the layer is not scrollable and Chris@127: * therefore needs to be redrawn each time (so that the selection Chris@127: * rectangle can be cached). Chris@127: */ Chris@127: virtual bool isLayerOpaque() const { return false; } Chris@127: Chris@287: enum ColourSignificance { Chris@287: ColourAbsent, Chris@287: ColourIrrelevant, Chris@287: ColourDistinguishes, Chris@287: ColourAndBackgroundSignificant, Chris@287: ColourHasMeaningfulValue Chris@287: }; Chris@287: Chris@127: /** Chris@287: * This should return the degree of meaning associated with colour Chris@287: * in this layer. Chris@287: * Chris@287: * If ColourAbsent, the layer does not use colour. If Chris@287: * ColourIrrelevant, the layer is coloured and the colour may be Chris@287: * set by the user, but it doesn't really matter what the colour Chris@287: * is (for example, in a time ruler layer). If Chris@287: * ColourDistinguishes, then the colour is used to distinguish Chris@287: * this layer from other similar layers (e.g. for data layers). Chris@287: * If ColourAndBackgroundSignificant, then the layer should be Chris@287: * given greater weight than ColourDistinguishes layers when Chris@287: * choosing a background colour (e.g. for waveforms). If Chris@287: * ColourHasMeaningfulValue, colours are actually meaningful -- Chris@287: * the view will then show selections using unfilled rectangles Chris@287: * instead of translucent filled rectangles, so as not to disturb Chris@287: * the colours underneath. Chris@183: */ Chris@287: virtual ColourSignificance getLayerColourSignificance() const = 0; Chris@183: Chris@183: /** Chris@127: * This should return true if the layer can be edited by the user. Chris@127: * If this is the case, the appropriate edit tools may be made Chris@127: * available by the application and the layer's drawStart/Drag/End Chris@127: * and editStart/Drag/End methods should be implemented. Chris@127: */ Chris@127: virtual bool isLayerEditable() const { return false; } Chris@127: Chris@127: /** Chris@127: * Return the proportion of background work complete in drawing Chris@127: * this view, as a percentage -- in most cases this will be the Chris@127: * value returned by pointer from a call to the underlying model's Chris@226: * isReady(int *) call. The view may choose to show a progress Chris@127: * meter if it finds that this returns < 100 at any given moment. Chris@127: */ Chris@916: virtual int getCompletion(LayerGeometryProvider *) const { return 100; } Chris@127: Chris@583: /** Chris@583: * Return an error string if any errors have occurred while Chris@583: * loading or processing data for the given view. Return the Chris@583: * empty string if no error has occurred. Chris@583: */ Chris@916: virtual QString getError(LayerGeometryProvider *) const { return ""; } Chris@583: Chris@127: virtual void setObjectName(const QString &name); Chris@127: Chris@127: /** Chris@127: * Convert the layer's data (though not those of the model it Chris@316: * refers to) into XML for file output. This class implements the Chris@316: * basic name/type/model-id output; subclasses will typically call Chris@316: * this superclass implementation with extra attributes describing Chris@316: * their particular properties. Chris@127: */ Chris@1406: void toXml(QTextStream &stream, QString indent = "", Chris@1406: QString extraAttributes = "") const override; Chris@127: Chris@127: /** Chris@127: * Set the particular properties of a layer (those specific to the Chris@127: * subclass) from a set of XML attributes. This is the effective Chris@316: * inverse of the toXml method. Chris@127: */ Chris@127: virtual void setProperties(const QXmlAttributes &) = 0; Chris@127: Chris@127: /** Chris@316: * Produce XML containing the layer's ID and type. This is used Chris@316: * to refer to the layer in the display section of the SV session Chris@316: * file, for a layer that has already been described in the data Chris@316: * section. Chris@269: */ Chris@316: virtual void toBriefXml(QTextStream &stream, Chris@316: QString indent = "", Chris@316: QString extraAttributes = "") const; Chris@269: Chris@269: /** Chris@269: * Add a measurement rectangle from the given XML attributes Chris@269: * (presumably taken from a measurement element). Chris@269: * Does not use a command. Chris@269: */ Chris@269: virtual void addMeasurementRect(const QXmlAttributes &); Chris@269: Chris@269: /** Chris@127: * Indicate that a layer is not currently visible in the given Chris@127: * view and is not expected to become visible in the near future Chris@127: * (for example because the user has explicitly removed or hidden Chris@127: * it). The layer may respond by (for example) freeing any cache Chris@127: * memory it is using, until next time its paint method is called, Chris@127: * when it should set itself un-dormant again. Chris@131: * Chris@131: * A layer class that overrides this function must also call this Chris@131: * class's implementation. Chris@127: */ Chris@916: virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant); Chris@127: Chris@127: /** Chris@127: * Return whether the layer is dormant (i.e. hidden) in the given Chris@127: * view. Chris@127: */ Chris@916: virtual bool isLayerDormant(const LayerGeometryProvider *v) const; Chris@127: Chris@1480: /** Chris@1480: * Return the play parameters for this layer, if any. The return Chris@1480: * value is a shared_ptr that can be passed to (e.g.) Chris@1480: * PlayParameterRepository::EditCommand to change the parameters. Chris@1480: */ Chris@1480: std::shared_ptr getPlayParameters() override; Chris@127: Chris@1391: /** Chris@1391: * True if this layer will need to place text labels when it is Chris@1391: * painted. The view will take into account how many layers are Chris@1391: * requesting this, and will provide a distinct y-coord to each Chris@1391: * layer on request via View::getTextLabelHeight(). Chris@1391: */ Chris@127: virtual bool needsTextLabelHeight() const { return false; } Chris@127: Chris@1389: /** Chris@1389: * Return true if the X axis on the layer is time proportional to Chris@1389: * audio frames, false otherwise. Almost all layer types return Chris@1389: * true here: the exceptions are spectrum and slice layers. Chris@1389: */ Chris@217: virtual bool hasTimeXAxis() const { return true; } Chris@217: Chris@127: /** Chris@1389: * Update the X and Y axis scales, where appropriate, to focus on Chris@1389: * the given rectangular region. This should *only* be overridden Chris@1389: * by layers whose hasTimeXAxis() returns false - the pane handles Chris@1389: * zooming appropriately in every "normal" case. Chris@1389: */ Chris@1389: virtual void zoomToRegion(const LayerGeometryProvider *, QRect) { Chris@1389: return; Chris@1389: } Chris@1389: Chris@1389: /** Chris@127: * Return the minimum and maximum values for the y axis of the Chris@127: * model in this layer, as well as whether the layer is configured Chris@127: * to use a logarithmic y axis display. Also return the unit for Chris@127: * these values if known. Chris@127: * Chris@127: * This function returns the "normal" extents for the layer, not Chris@127: * necessarily the extents actually in use in the display. Chris@127: */ Chris@904: virtual bool getValueExtents(double &min, double &max, Chris@127: bool &logarithmic, QString &unit) const = 0; Chris@127: Chris@127: /** Chris@127: * Return the minimum and maximum values within the displayed Chris@127: * range for the y axis, if only a subset of the whole range of Chris@127: * the model (returned by getValueExtents) is being displayed. Chris@127: * Return false if the layer is not imposing a particular display Chris@127: * extent (using the normal layer extents or deferring to whatever Chris@127: * is in use for the same units elsewhere in the view). Chris@127: */ Chris@904: virtual bool getDisplayExtents(double & /* min */, Chris@904: double & /* max */) const { Chris@127: return false; Chris@127: } Chris@127: Chris@127: /** Chris@127: * Set the displayed minimum and maximum values for the y axis to Chris@127: * the given range, if supported. Return false if not supported Chris@127: * on this layer (and set nothing). In most cases, layers that Chris@127: * return false for getDisplayExtents should also return false for Chris@127: * this function. Chris@127: */ Chris@904: virtual bool setDisplayExtents(double /* min */, Chris@904: double /* max */) { Chris@127: return false; Chris@127: } Chris@127: Chris@133: /** Chris@260: * Return the value and unit at the given x coordinate in the Chris@260: * given view. This is for descriptive purposes using the Chris@260: * measurement tool. The default implementation works correctly Chris@260: * if the layer hasTimeXAxis(). Chris@260: */ Chris@916: virtual bool getXScaleValue(const LayerGeometryProvider *v, int x, Chris@904: double &value, QString &unit) const; Chris@260: Chris@260: /** Chris@260: * Return the value and unit at the given y coordinate in the Chris@260: * given view. Chris@260: */ Chris@916: virtual bool getYScaleValue(const LayerGeometryProvider *, int /* y */, Chris@904: double &/* value */, QString &/* unit */) const { Chris@260: return false; Chris@260: } Chris@260: Chris@260: /** Chris@274: * Return the difference between the values at the given y Chris@274: * coordinates in the given view, and the unit of the difference. Chris@274: * The default implementation just calls getYScaleValue twice and Chris@274: * returns the difference, with the same unit. Chris@274: */ Chris@916: virtual bool getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1, Chris@904: double &diff, QString &unit) const; Chris@274: Chris@274: /** Chris@133: * Get the number of vertical zoom steps available for this layer. Chris@133: * If vertical zooming is not available, return 0. The meaning of Chris@133: * "zooming" is entirely up to the layer -- changing the zoom Chris@133: * level may cause the layer to reset its display extents or Chris@180: * change another property such as display gain. However, layers Chris@180: * are advised for consistency to treat smaller zoom steps as Chris@180: * "more distant" or "zoomed out" and larger ones as "closer" or Chris@180: * "zoomed in". Chris@180: * Chris@133: * Layers that provide this facility should also emit the Chris@133: * verticalZoomChanged signal if their vertical zoom changes Chris@133: * due to factors other than setVerticalZoomStep being called. Chris@133: */ Chris@248: virtual int getVerticalZoomSteps(int & /* defaultStep */) const { return 0; } Chris@133: Chris@133: /** Chris@133: * Get the current vertical zoom step. A layer may support finer Chris@133: * control over ranges etc than is available through the integer Chris@133: * zoom step mechanism; if this one does, it should just return Chris@133: * the nearest of the available zoom steps to the current settings. Chris@133: */ Chris@133: virtual int getCurrentVerticalZoomStep() const { return 0; } Chris@133: Chris@133: /** Chris@133: * Set the vertical zoom step. The meaning of "zooming" is Chris@133: * entirely up to the layer -- changing the zoom level may cause Chris@133: * the layer to reset its display extents or change another Chris@133: * property such as display gain. Chris@133: */ Chris@133: virtual void setVerticalZoomStep(int) { } Chris@133: Chris@187: /** Chris@187: * Create and return a range mapper for vertical zoom step values. Chris@187: * See the RangeMapper documentation for more details. The Chris@187: * returned value is allocated on the heap and will be deleted by Chris@187: * the caller. Chris@187: */ Chris@187: virtual RangeMapper *getNewVerticalZoomRangeMapper() const { return 0; } Chris@187: Chris@947: /** Chris@947: * Return true if this layer type can function without a model Chris@947: * being set. If false (the default), the layer will not be loaded Chris@947: * from a session if its model cannot be found. Chris@947: */ Chris@947: virtual bool canExistWithoutModel() const { return false; } Chris@947: Chris@127: public slots: Chris@1456: /** Chris@1456: * Change the visibility status (dormancy) of the layer in the Chris@1456: * given view. Chris@1456: */ Chris@916: void showLayer(LayerGeometryProvider *, bool show); Chris@127: Chris@127: signals: Chris@127: void modelChanged(); Chris@127: void modelCompletionChanged(); Chris@320: void modelAlignmentCompletionChanged(); Chris@906: void modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame); Chris@127: void modelReplaced(); Chris@127: Chris@127: void layerParametersChanged(); Chris@197: void layerParameterRangesChanged(); Chris@268: void layerMeasurementRectsChanged(); Chris@127: void layerNameChanged(); Chris@127: Chris@133: void verticalZoomChanged(); Chris@133: Chris@267: protected: Chris@1469: void connectSignals(ModelId); Chris@320: Chris@916: virtual sv_frame_t alignToReference(LayerGeometryProvider *v, sv_frame_t frame) const; Chris@916: virtual sv_frame_t alignFromReference(LayerGeometryProvider *v, sv_frame_t frame) const; Chris@916: bool clipboardHasDifferentAlignment(LayerGeometryProvider *v, const Clipboard &clip) const; Chris@359: Chris@267: struct MeasureRect { Chris@268: Chris@267: mutable QRect pixrect; Chris@268: bool haveFrames; Chris@905: sv_frame_t startFrame; // only valid if haveFrames Chris@905: sv_frame_t endFrame; // ditto Chris@273: double startY; Chris@273: double endY; Chris@268: Chris@268: bool operator<(const MeasureRect &mr) const; Chris@316: void toXml(QTextStream &stream, QString indent) const; Chris@267: }; Chris@267: Chris@268: class AddMeasurementRectCommand : public Command Chris@268: { Chris@268: public: Chris@268: AddMeasurementRectCommand(Layer *layer, MeasureRect rect) : Chris@268: m_layer(layer), m_rect(rect) { } Chris@268: Chris@1406: QString getName() const override; Chris@1406: void execute() override; Chris@1406: void unexecute() override; Chris@268: Chris@268: private: Chris@268: Layer *m_layer; Chris@268: MeasureRect m_rect; Chris@268: }; Chris@268: Chris@283: class DeleteMeasurementRectCommand : public Command Chris@283: { Chris@283: public: Chris@283: DeleteMeasurementRectCommand(Layer *layer, MeasureRect rect) : Chris@283: m_layer(layer), m_rect(rect) { } Chris@283: Chris@1406: QString getName() const override; Chris@1406: void execute() override; Chris@1406: void unexecute() override; Chris@283: Chris@283: private: Chris@283: Layer *m_layer; Chris@283: MeasureRect m_rect; Chris@283: }; Chris@283: Chris@269: void addMeasureRectToSet(const MeasureRect &r) { Chris@268: m_measureRects.insert(r); Chris@268: emit layerMeasurementRectsChanged(); Chris@268: } Chris@268: Chris@269: void deleteMeasureRectFromSet(const MeasureRect &r) { Chris@268: m_measureRects.erase(r); Chris@268: emit layerMeasurementRectsChanged(); Chris@268: } Chris@268: Chris@268: typedef std::set MeasureRectSet; Chris@268: MeasureRectSet m_measureRects; Chris@267: MeasureRect m_draggingRect; Chris@267: bool m_haveDraggingRect; Chris@283: mutable bool m_haveCurrentMeasureRect; Chris@283: mutable QPoint m_currentMeasureRectPoint; Chris@272: Chris@272: // Note that pixrects are only correct for a single view. Chris@272: // So we should update them at the start of the paint procedure Chris@272: // (painting is single threaded) and only use them after that. Chris@916: void updateMeasurePixrects(LayerGeometryProvider *v) const; Chris@273: Chris@916: virtual void updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const; Chris@916: virtual void setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const; Chris@916: virtual void setMeasureRectFromPixrect(LayerGeometryProvider *v, MeasureRect &r, QRect pixrect) const; Chris@272: Chris@272: // This assumes updateMeasurementPixrects has been called Chris@272: MeasureRectSet::const_iterator findFocusedMeasureRect(QPoint) const; Chris@267: Chris@916: void paintMeasurementRect(LayerGeometryProvider *v, QPainter &paint, Chris@270: const MeasureRect &r, bool focus) const; Chris@268: Chris@1315: bool valueExtentsMatchMine(LayerGeometryProvider *v) const; Chris@1315: Chris@363: QString m_presentationName; Chris@363: Chris@131: private: Chris@131: mutable QMutex m_dormancyMutex; Chris@127: mutable std::map m_dormancy; Chris@127: }; Chris@127: Chris@127: #endif Chris@127: