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@1270: #ifndef SV_VIEW_MANAGER_H Chris@1270: #define SV_VIEW_MANAGER_H Chris@127: Chris@127: #include Chris@127: #include Chris@292: #include Chris@127: Chris@127: #include Chris@127: Chris@376: #include "base/ViewManagerBase.h" Chris@128: #include "base/Selection.h" Chris@128: #include "base/Command.h" Chris@128: #include "base/Clipboard.h" Chris@902: #include "base/BaseTypes.h" Chris@1327: #include "base/ZoomLevel.h" Chris@127: Chris@127: class AudioPlaySource; Chris@1210: class AudioRecordTarget; Chris@127: class Model; Chris@127: Chris@211: enum PlaybackFollowMode { Chris@815: Chris@815: /** Chris@815: * View scrolls continuously during playback, keeping the playback Chris@815: * position at the centre. Chris@815: */ Chris@211: PlaybackScrollContinuous, Chris@815: Chris@815: /** Chris@815: * View follows playback page-by-page, but dragging the view Chris@815: * relocates playback to the centre frame. This is the classic Chris@815: * Sonic Visualiser behaviour. Chris@815: */ Chris@815: PlaybackScrollPageWithCentre, Chris@815: Chris@815: /** Chris@815: * View follows playback page-by-page, and the play head is moved Chris@815: * (by the user) separately from dragging the view. This is Chris@815: * roughly the behaviour of a typical DAW or audio editor. Chris@815: */ Chris@211: PlaybackScrollPage, Chris@815: Chris@815: /** Chris@815: * View is detached from playback. It doesn't follow playback, and Chris@815: * dragging the view does not affect the play head. Chris@815: */ Chris@211: PlaybackIgnore Chris@211: }; Chris@211: Chris@211: class View; Chris@211: Chris@127: /** Chris@127: * The ViewManager manages properties that may need to be synchronised Chris@127: * between separate Views. For example, it handles signals associated Chris@127: * with changes to the global pan and zoom, and it handles selections. Chris@127: * Chris@127: * Views should be implemented in such a way as to work Chris@127: * correctly whether they are supplied with a ViewManager or not. Chris@127: */ Chris@127: Chris@376: class ViewManager : public ViewManagerBase Chris@127: { Chris@127: Q_OBJECT Chris@127: Chris@127: public: Chris@127: ViewManager(); Chris@127: virtual ~ViewManager(); Chris@127: Chris@1406: void setAudioPlaySource(AudioPlaySource *source) override; Chris@1406: void setAudioRecordTarget(AudioRecordTarget *target) override; Chris@127: Chris@127: bool isPlaying() const; Chris@1210: bool isRecording() const; Chris@127: Chris@902: sv_frame_t getGlobalCentreFrame() const; // the set method is a slot Chris@1327: ZoomLevel getGlobalZoom() const; Chris@127: Chris@902: sv_frame_t getPlaybackFrame() const; // the set method is a slot Chris@127: Chris@301: // Only meaningful in solo mode, and used for optional alignment feature Chris@301: Model *getPlaybackModel() const; Chris@301: void setPlaybackModel(Model *); Chris@301: Chris@1406: sv_frame_t alignPlaybackFrameToReference(sv_frame_t) const override; Chris@1406: sv_frame_t alignReferenceToPlaybackFrame(sv_frame_t) const override; Chris@333: Chris@127: bool haveInProgressSelection() const; Chris@127: const Selection &getInProgressSelection(bool &exclusive) const; Chris@127: void setInProgressSelection(const Selection &selection, bool exclusive); Chris@127: void clearInProgressSelection(); Chris@127: Chris@1406: const MultiSelection &getSelection() const override; Chris@127: Chris@1406: const MultiSelection::SelectionList &getSelections() const override; Chris@127: void setSelection(const Selection &selection); Chris@127: void addSelection(const Selection &selection); Chris@127: void removeSelection(const Selection &selection); Chris@127: void clearSelections(); Chris@1406: sv_frame_t constrainFrameToSelection(sv_frame_t frame) const override; Chris@127: Chris@127: /** Chris@762: * Adding a selection normally emits the selectionChangedByUser Chris@762: * signal. Call this to add a selection without emitting that signal. Chris@762: * This is used in session file load, for example. Chris@762: */ Chris@762: void addSelectionQuietly(const Selection &selection); Chris@762: Chris@762: /** Chris@127: * Return the selection that contains a given frame. Chris@127: * If defaultToFollowing is true, and if the frame is not in a Chris@127: * selected area, return the next selection after the given frame. Chris@127: * Return the empty selection if no appropriate selection is found. Chris@127: */ Chris@1406: Selection getContainingSelection(sv_frame_t frame, bool defaultToFollowing) const override; Chris@127: Chris@127: Clipboard &getClipboard() { return m_clipboard; } Chris@127: Chris@127: enum ToolMode { Chris@1266: NavigateMode, Chris@1266: SelectMode, Chris@711: EditMode, Chris@1266: DrawMode, Chris@1266: EraseMode, Chris@1266: MeasureMode, Chris@1266: NoteEditMode //GF: Tonioni: this tool mode will be context sensitive. Chris@127: }; Chris@127: ToolMode getToolMode() const { return m_toolMode; } Chris@127: void setToolMode(ToolMode mode); Chris@127: Chris@711: /// Override the tool mode for a specific view Chris@711: void setToolModeFor(const View *v, ToolMode mode); Chris@711: /// Return override mode if it exists for this view or global mode otherwise Chris@711: ToolMode getToolModeFor(const View *v) const; Chris@711: /// Clear all current view-specific overrides Chris@711: void clearToolModeOverrides(); Chris@711: Chris@1406: bool getPlayLoopMode() const override { return m_playLoopMode; } Chris@127: void setPlayLoopMode(bool on); Chris@127: Chris@1406: bool getPlaySelectionMode() const override { return m_playSelectionMode; } Chris@127: void setPlaySelectionMode(bool on); Chris@127: Chris@1406: bool getPlaySoloMode() const override { return m_playSoloMode; } Chris@301: void setPlaySoloMode(bool on); Chris@301: Chris@1406: bool getAlignMode() const override { return m_alignMode; } Chris@314: void setAlignMode(bool on); Chris@314: Chris@326: void setIlluminateLocalFeatures(bool i) { m_illuminateLocalFeatures = i; } Chris@326: void setShowWorkTitle(bool show) { m_showWorkTitle = show; } matthiasm@822: void setShowDuration(bool show) { m_showDuration = show; } Chris@326: Chris@224: /** Chris@224: * The sample rate that is used for playback. This is usually the Chris@224: * rate of the main model, but not always. Models whose rates Chris@224: * differ from this will play back at the wrong speed -- there is Chris@224: * no per-model resampler. Chris@224: */ Chris@902: sv_samplerate_t getPlaybackSampleRate() const; Chris@224: Chris@224: /** Chris@224: * The sample rate of the audio output device. If the playback Chris@224: * sample rate differs from this, everything will be resampled at Chris@1181: * the output stage (but not before). Chris@224: */ Chris@1181: sv_samplerate_t getDeviceSampleRate() const; Chris@224: Chris@224: /** Chris@224: * The sample rate of the current main model. This may in theory Chris@224: * differ from the playback sample rate, in which case even the Chris@224: * main model will play at the wrong speed. Chris@224: */ Chris@902: sv_samplerate_t getMainModelSampleRate() const { return m_mainModelSampleRate; } Chris@224: Chris@902: void setMainModelSampleRate(sv_samplerate_t sr) { m_mainModelSampleRate = sr; } Chris@127: Chris@894: /** Chris@894: * Take a "design pixel" size and scale it for the actual Chris@894: * display. This is relevant to hi-dpi systems that do not do Chris@894: * pixel doubling (i.e. Windows and Linux rather than OS/X). Chris@894: */ Chris@1270: static int scalePixelSize(int pixels); Chris@894: Chris@127: enum OverlayMode { Chris@127: NoOverlays, Chris@741: GlobalOverlays, Chris@741: StandardOverlays, Chris@127: AllOverlays Chris@127: }; Chris@127: void setOverlayMode(OverlayMode mode); Chris@127: OverlayMode getOverlayMode() const { return m_overlayMode; } Chris@127: Chris@607: void setShowCentreLine(bool show); Chris@607: bool shouldShowCentreLine() const { return m_showCentreLine; } Chris@607: Chris@607: bool shouldShowDuration() const { matthiasm@822: return m_overlayMode != NoOverlays && m_showDuration; Chris@189: } Chris@189: bool shouldShowFrameCount() const { Chris@607: return m_showCentreLine && shouldShowDuration(); Chris@607: } Chris@607: bool shouldShowVerticalScale() const { Chris@189: return m_overlayMode != NoOverlays; Chris@189: } Chris@607: bool shouldShowVerticalColourScale() const { Chris@607: return m_overlayMode == AllOverlays; Chris@189: } Chris@1281: bool shouldShowHorizontalValueScale() const { // for layers where x != time Chris@1281: return m_overlayMode != NoOverlays; Chris@1281: } Chris@189: bool shouldShowSelectionExtents() const { Chris@741: return m_overlayMode != NoOverlays && m_overlayMode != GlobalOverlays; Chris@189: } Chris@189: bool shouldShowLayerNames() const { Chris@189: return m_overlayMode == AllOverlays; Chris@189: } Chris@195: bool shouldShowScaleGuides() const { Chris@195: return m_overlayMode != NoOverlays; Chris@195: } Chris@326: bool shouldShowWorkTitle() const { Chris@326: return m_showWorkTitle; Chris@326: } Chris@326: bool shouldIlluminateLocalFeatures() const { Chris@326: return m_illuminateLocalFeatures; Chris@326: } Chris@741: bool shouldShowFeatureLabels() const { Chris@741: return m_overlayMode != NoOverlays && m_overlayMode != GlobalOverlays; Chris@741: } Chris@189: Chris@133: void setZoomWheelsEnabled(bool enable); Chris@133: bool getZoomWheelsEnabled() const { return m_zoomWheelsEnabled; } Chris@133: Chris@1468: /** Chris@1468: * Enable or disable opportunistic editing. This allows certain Chris@1468: * edits while not in edit modes - e.g. double-click on an item Chris@1468: * while in navigate mode to open an edit dialog. It is enabled by Chris@1468: * default, but it may be undesirable if the application is Chris@1468: * intended to be "read-only". Chris@1468: * Chris@1468: * This setting makes no difference to behaviour when actually in Chris@1468: * editing modes. Chris@1468: * Chris@1468: * Unlike some other options, this is considered to be Chris@1468: * application-build-specific and is not restored from settings. Chris@1468: */ Chris@1468: void setOpportunisticEditingEnabled(bool enable); Chris@1468: bool getOpportunisticEditingEnabled() const { Chris@1468: return m_opportunisticEditingEnabled; Chris@1468: } Chris@1468: Chris@292: void setGlobalDarkBackground(bool dark); Chris@292: bool getGlobalDarkBackground() const; Chris@292: Chris@127: signals: Chris@211: /** Emitted when user causes the global centre frame to change. */ Chris@902: void globalCentreFrameChanged(sv_frame_t frame); Chris@127: Chris@211: /** Emitted when user scrolls a view, but doesn't affect global centre. */ Chris@902: void viewCentreFrameChanged(View *v, sv_frame_t frame); Chris@211: Chris@211: /** Emitted when a view zooms. */ Chris@1327: void viewZoomLevelChanged(View *v, ZoomLevel zoom, bool locked); Chris@133: Chris@127: /** Emitted when the playback frame changes. */ Chris@902: void playbackFrameChanged(sv_frame_t frame); Chris@127: Chris@1210: /** Emitted when the output or record levels change. Values in range 0.0 -> 1.0. */ Chris@1210: void monitoringLevelsChanged(float left, float right); Chris@127: Chris@731: /** Emitted whenever the selection has changed. */ Chris@127: void selectionChanged(); Chris@127: Chris@731: /** Emitted when the selection has been changed through an Chris@731: * explicit selection-editing action. *Not* emitted when the Chris@731: * selection has been changed through undo or redo. */ Chris@731: void selectionChangedByUser(); Chris@731: Chris@127: /** Emitted when the in-progress (rubberbanding) selection has changed. */ Chris@127: void inProgressSelectionChanged(); Chris@127: Chris@127: /** Emitted when the tool mode has been changed. */ Chris@127: void toolModeChanged(); Chris@127: Chris@127: /** Emitted when the play loop mode has been changed. */ Chris@127: void playLoopModeChanged(); Chris@177: void playLoopModeChanged(bool); Chris@127: Chris@127: /** Emitted when the play selection mode has been changed. */ Chris@127: void playSelectionModeChanged(); Chris@177: void playSelectionModeChanged(bool); Chris@127: Chris@301: /** Emitted when the play solo mode has been changed. */ Chris@301: void playSoloModeChanged(); Chris@301: void playSoloModeChanged(bool); Chris@301: Chris@314: /** Emitted when the alignment mode has been changed. */ Chris@314: void alignModeChanged(); Chris@314: void alignModeChanged(bool); Chris@314: Chris@127: /** Emitted when the overlay mode has been changed. */ Chris@127: void overlayModeChanged(); Chris@127: Chris@607: /** Emitted when the centre line visibility has been changed. */ Chris@607: void showCentreLineChanged(); Chris@607: Chris@133: /** Emitted when the zoom wheels have been toggled. */ Chris@133: void zoomWheelsEnabledChanged(); Chris@133: Chris@1468: /** Emitted when editing-enabled has been toggled. */ Chris@1468: void opportunisticEditingEnabledChanged(); Chris@1468: Chris@502: /** Emitted when any loggable activity has occurred. */ Chris@502: void activity(QString); Chris@502: Chris@211: public slots: Chris@902: void viewCentreFrameChanged(sv_frame_t, bool, PlaybackFollowMode); Chris@1327: void viewZoomLevelChanged(ZoomLevel, bool); Chris@902: void setGlobalCentreFrame(sv_frame_t); Chris@902: void setPlaybackFrame(sv_frame_t); Chris@689: void playStatusChanged(bool playing); Chris@1210: void recordStatusChanged(bool recording); Chris@211: Chris@127: protected slots: Chris@127: void checkPlayStatus(); Chris@902: void seek(sv_frame_t); Chris@806: //!!! void considerZoomChange(void *, int, bool); Chris@127: Chris@127: protected: Chris@127: AudioPlaySource *m_playSource; Chris@1210: AudioRecordTarget *m_recordTarget; Chris@1210: Chris@902: sv_frame_t m_globalCentreFrame; Chris@1327: ZoomLevel m_globalZoom; Chris@902: mutable sv_frame_t m_playbackFrame; Chris@301: Model *m_playbackModel; //!!! Chris@902: sv_samplerate_t m_mainModelSampleRate; Chris@127: Chris@127: float m_lastLeft; Chris@127: float m_lastRight; Chris@127: Chris@127: MultiSelection m_selections; Chris@127: Selection m_inProgressSelection; Chris@127: bool m_inProgressExclusive; Chris@127: Chris@127: Clipboard m_clipboard; Chris@127: Chris@127: ToolMode m_toolMode; Chris@711: std::map m_toolModeOverrides; Chris@127: Chris@127: bool m_playLoopMode; Chris@127: bool m_playSelectionMode; Chris@301: bool m_playSoloMode; Chris@314: bool m_alignMode; Chris@127: Chris@762: void setSelections(const MultiSelection &ms, bool quietly = false); Chris@127: void signalSelectionChange(); Chris@127: Chris@127: class SetSelectionCommand : public Command Chris@127: { Chris@127: public: Chris@1266: SetSelectionCommand(ViewManager *vm, const MultiSelection &ms); Chris@1266: virtual ~SetSelectionCommand(); Chris@1406: void execute() override; Chris@1406: void unexecute() override; Chris@1406: QString getName() const override; Chris@127: Chris@127: protected: Chris@1266: ViewManager *m_vm; Chris@1266: MultiSelection m_oldSelection; Chris@1266: MultiSelection m_newSelection; Chris@127: }; Chris@127: Chris@127: OverlayMode m_overlayMode; Chris@133: bool m_zoomWheelsEnabled; Chris@1468: bool m_opportunisticEditingEnabled; Chris@607: bool m_showCentreLine; Chris@326: bool m_illuminateLocalFeatures; Chris@326: bool m_showWorkTitle; matthiasm@822: bool m_showDuration; Chris@292: Chris@292: QPalette m_lightPalette; Chris@292: QPalette m_darkPalette; Chris@127: }; Chris@127: Chris@127: #endif Chris@127: