mirror of
https://github.com/cookiengineer/audacity
synced 2025-09-15 15:50:54 +02:00
TrackPanel no longer implements the selection tool or MIDI stretch...
This one's big! Also restores the effect of ctrl-click on label track. Also adds ESC key handling for the Stretch.
This commit is contained in:
parent
efdb9889b1
commit
770b3b52ef
@ -1238,6 +1238,8 @@
|
||||
5E7396691DAFDB5600BA0A4D /* LabelDefaultClickHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396631DAFDB5600BA0A4D /* LabelDefaultClickHandle.cpp */; };
|
||||
5E73966A1DAFDB5600BA0A4D /* LabelGlyphHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396651DAFDB5600BA0A4D /* LabelGlyphHandle.cpp */; };
|
||||
5E73966B1DAFDB5600BA0A4D /* LabelTextHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396671DAFDB5600BA0A4D /* LabelTextHandle.cpp */; };
|
||||
5E73966E1DAFDB8500BA0A4D /* StretchHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E73966C1DAFDB8500BA0A4D /* StretchHandle.cpp */; };
|
||||
5E7396711DAFDB9D00BA0A4D /* SelectHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E73966F1DAFDB9D00BA0A4D /* SelectHandle.cpp */; };
|
||||
5E74D2E31CC4429700D88B0B /* EditCursorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */; };
|
||||
5E74D2E41CC4429700D88B0B /* PlayIndicatorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */; };
|
||||
5E74D2E51CC4429700D88B0B /* Scrubbing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2E11CC4429700D88B0B /* Scrubbing.cpp */; };
|
||||
@ -3085,6 +3087,10 @@
|
||||
5E7396661DAFDB5600BA0A4D /* LabelGlyphHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelGlyphHandle.h; sourceTree = "<group>"; };
|
||||
5E7396671DAFDB5600BA0A4D /* LabelTextHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LabelTextHandle.cpp; sourceTree = "<group>"; };
|
||||
5E7396681DAFDB5600BA0A4D /* LabelTextHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelTextHandle.h; sourceTree = "<group>"; };
|
||||
5E73966C1DAFDB8500BA0A4D /* StretchHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StretchHandle.cpp; sourceTree = "<group>"; };
|
||||
5E73966D1DAFDB8500BA0A4D /* StretchHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StretchHandle.h; sourceTree = "<group>"; };
|
||||
5E73966F1DAFDB9D00BA0A4D /* SelectHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectHandle.cpp; sourceTree = "<group>"; };
|
||||
5E7396701DAFDB9D00BA0A4D /* SelectHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectHandle.h; sourceTree = "<group>"; };
|
||||
5E74D2D91CC4427B00D88B0B /* TrackPanelCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelCell.h; sourceTree = "<group>"; };
|
||||
5E74D2DA1CC4427B00D88B0B /* TrackPanelCellIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelCellIterator.h; sourceTree = "<group>"; };
|
||||
5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditCursorOverlay.cpp; sourceTree = "<group>"; };
|
||||
@ -5797,6 +5803,7 @@
|
||||
5E7396451DAFD8F200BA0A4D /* EnvelopeHandle.cpp */,
|
||||
5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */,
|
||||
5E74D2E11CC4429700D88B0B /* Scrubbing.cpp */,
|
||||
5E73966F1DAFDB9D00BA0A4D /* SelectHandle.cpp */,
|
||||
5E73964E1DAFD98400BA0A4D /* SliderHandle.cpp */,
|
||||
5E7396421DAFD8C600BA0A4D /* TimeShiftHandle.cpp */,
|
||||
5E7396571DAFDA3600BA0A4D /* TrackButtonHandles.cpp */,
|
||||
@ -5812,6 +5819,7 @@
|
||||
5E7396461DAFD8F200BA0A4D /* EnvelopeHandle.h */,
|
||||
5E74D2E01CC4429700D88B0B /* PlayIndicatorOverlay.h */,
|
||||
5E74D2E21CC4429700D88B0B /* Scrubbing.h */,
|
||||
5E7396701DAFDB9D00BA0A4D /* SelectHandle.h */,
|
||||
5E73964F1DAFD98400BA0A4D /* SliderHandle.h */,
|
||||
5E7396431DAFD8C600BA0A4D /* TimeShiftHandle.h */,
|
||||
5E7396581DAFDA3600BA0A4D /* TrackButtonHandles.h */,
|
||||
@ -5851,6 +5859,8 @@
|
||||
5EA0181E1EC7B226001F2996 /* NoteTrackUI.cpp */,
|
||||
5EA0181F1EC7B226001F2996 /* NoteTrackVRulerControls.cpp */,
|
||||
5EA018201EC7B226001F2996 /* NoteTrackVRulerControls.h */,
|
||||
5E73966C1DAFDB8500BA0A4D /* StretchHandle.cpp */,
|
||||
5E73966D1DAFDB8500BA0A4D /* StretchHandle.h */,
|
||||
);
|
||||
path = ui;
|
||||
sourceTree = "<group>";
|
||||
@ -7657,6 +7667,7 @@
|
||||
1790B15109883BFD008A330A /* StereoToMono.cpp in Sources */,
|
||||
1790B15209883BFD008A330A /* ToneGen.cpp in Sources */,
|
||||
5E74D2E31CC4429700D88B0B /* EditCursorOverlay.cpp in Sources */,
|
||||
5E7396711DAFDB9D00BA0A4D /* SelectHandle.cpp in Sources */,
|
||||
1790B15309883BFD008A330A /* TruncSilence.cpp in Sources */,
|
||||
1790B15409883BFD008A330A /* TwoPassSimpleMono.cpp in Sources */,
|
||||
1790B15809883BFD008A330A /* Wahwah.cpp in Sources */,
|
||||
@ -7787,6 +7798,7 @@
|
||||
283B3D4D0BC21EBE00FA01D5 /* FileDialog.cpp in Sources */,
|
||||
2809C4B80BCB7E560006010F /* FileIO.cpp in Sources */,
|
||||
285DE1FA0BF03C7800A20DF0 /* Screenshot.cpp in Sources */,
|
||||
5E73966E1DAFDB8500BA0A4D /* StretchHandle.cpp in Sources */,
|
||||
2801A6460BF9268700648258 /* ImportQT.cpp in Sources */,
|
||||
2891B2870C531D2C0044FBE3 /* FindClipping.cpp in Sources */,
|
||||
283AA0EB0C56ED08002CBD34 /* ErrorDialog.cpp in Sources */,
|
||||
|
@ -569,6 +569,8 @@ audacity_SOURCES = \
|
||||
tracks/playabletrack/notetrack/ui/NoteTrackUI.cpp \
|
||||
tracks/playabletrack/notetrack/ui/NoteTrackVRulerControls.cpp \
|
||||
tracks/playabletrack/notetrack/ui/NoteTrackVRulerControls.h \
|
||||
tracks/playabletrack/notetrack/ui/StretchHandle.cpp \
|
||||
tracks/playabletrack/notetrack/ui/StretchHandle.h \
|
||||
tracks/playabletrack/ui/PlayableTrackButtonHandles.cpp \
|
||||
tracks/playabletrack/ui/PlayableTrackButtonHandles.h \
|
||||
tracks/playabletrack/wavetrack/ui/CutlineHandle.cpp \
|
||||
@ -601,6 +603,8 @@ audacity_SOURCES = \
|
||||
tracks/ui/PlayIndicatorOverlay.h \
|
||||
tracks/ui/Scrubbing.cpp \
|
||||
tracks/ui/Scrubbing.h \
|
||||
tracks/ui/SelectHandle.cpp \
|
||||
tracks/ui/SelectHandle.h \
|
||||
tracks/ui/SliderHandle.cpp \
|
||||
tracks/ui/SliderHandle.h \
|
||||
tracks/ui/TimeShiftHandle.cpp \
|
||||
|
@ -104,6 +104,9 @@ simplifies construction of menu items.
|
||||
#include "toolbars/DeviceToolBar.h"
|
||||
#include "toolbars/MixerToolBar.h"
|
||||
#include "toolbars/TranscriptionToolBar.h"
|
||||
|
||||
#include "tracks/ui/SelectHandle.h"
|
||||
|
||||
#include "widgets/LinkingHtmlWindow.h"
|
||||
|
||||
#include "Experimental.h"
|
||||
@ -5879,7 +5882,7 @@ void AudacityProject::DoNextPeakFrequency(bool up)
|
||||
}
|
||||
|
||||
if (pTrack) {
|
||||
mTrackPanel->SnapCenterOnce(pTrack, up);
|
||||
SelectHandle::Instance().SnapCenterOnce(mViewInfo, pTrack, up);
|
||||
mTrackPanel->Refresh(false);
|
||||
ModifyState(false);
|
||||
}
|
||||
|
@ -2224,6 +2224,8 @@ void AudacityProject::OnToolBarUpdate(wxCommandEvent & event)
|
||||
// The projects tracklist has been updated
|
||||
void AudacityProject::OnTrackListUpdated(wxCommandEvent & event)
|
||||
{
|
||||
GetSelectionState().TrackListUpdated( *GetTracks() );
|
||||
|
||||
mViewInfo.track = NULL;
|
||||
|
||||
event.Skip();
|
||||
|
1904
src/TrackPanel.cpp
1904
src/TrackPanel.cpp
File diff suppressed because it is too large
Load Diff
206
src/TrackPanel.h
206
src/TrackPanel.h
@ -336,115 +336,27 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
||||
virtual MixerBoard* GetMixerBoard();
|
||||
|
||||
virtual bool IsAudioActive();
|
||||
virtual bool IsUnsafe();
|
||||
virtual void HandleTrackSpecificMouseEvent(wxMouseEvent & event);
|
||||
|
||||
virtual void ScrollDuringDrag();
|
||||
|
||||
// Working out where to dispatch the event to.
|
||||
virtual int DetermineToolToUse( ToolsToolBar * pTtb, const wxMouseEvent & event);
|
||||
#ifdef USE_MIDI
|
||||
// data for NoteTrack interactive stretch operations:
|
||||
// Stretching applies to a selected region after quantizing the
|
||||
// region to beat boundaries (subbeat stretching is not supported,
|
||||
// but maybe it should be enabled with shift or ctrl or something)
|
||||
// Stretching can drag the left boundary (the right stays fixed),
|
||||
// the right boundary (the left stays fixed), or the center (splits
|
||||
// the selection into two parts: when left part grows, the right
|
||||
// part shrinks, keeping the leftmost and rightmost boundaries
|
||||
// fixed.
|
||||
enum StretchEnum {
|
||||
stretchNone = 0, // false value!
|
||||
stretchLeft,
|
||||
stretchCenter,
|
||||
stretchRight
|
||||
};
|
||||
struct StretchState {
|
||||
StretchEnum mMode { stretchCenter }; // remembers what to drag
|
||||
|
||||
using QuantizedTimeAndBeat = std::pair< double, double >;
|
||||
|
||||
bool mStretching {}; // true between mouse down and mouse up
|
||||
double mOrigT0 {};
|
||||
double mOrigT1 {};
|
||||
QuantizedTimeAndBeat mBeatCenter { 0, 0 };
|
||||
QuantizedTimeAndBeat mBeat0 { 0, 0 };
|
||||
QuantizedTimeAndBeat mBeat1 { 0, 0 };
|
||||
double mLeftBeats {}; // how many beats from left to cursor
|
||||
double mRightBeats {}; // how many beats from cursor to right
|
||||
} mStretchState;
|
||||
|
||||
virtual StretchEnum HitTestStretch
|
||||
( const Track *track, const wxRect &rect, const wxMouseEvent & event,
|
||||
StretchState *pState = nullptr );
|
||||
wxCursor *ChooseStretchCursor( StretchEnum mode );
|
||||
static StretchEnum ChooseStretchMode
|
||||
( const wxMouseEvent &event, const wxRect &rect, const ViewInfo &viewInfo,
|
||||
const NoteTrack *nt, StretchState *pState = nullptr );
|
||||
virtual void Stretch(int mouseXCoordinate, int trackLeftEdge, Track *pTrack);
|
||||
#endif
|
||||
|
||||
// AS: Selection handling
|
||||
|
||||
public:
|
||||
size_t GetTrackCount() const;
|
||||
size_t GetSelectedTrackCount() const;
|
||||
|
||||
protected:
|
||||
virtual void HandleSelect(wxMouseEvent & event);
|
||||
virtual void SelectionHandleDrag(wxMouseEvent &event, Track *pTrack);
|
||||
|
||||
virtual void SelectionHandleClick(wxMouseEvent &event,
|
||||
Track* pTrack, wxRect rect);
|
||||
virtual void StartSelection (int mouseXCoordinate, int trackLeftEdge);
|
||||
virtual void ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
|
||||
Track *pTrack);
|
||||
virtual void UpdateSelectionDisplay();
|
||||
|
||||
public:
|
||||
virtual void UpdateAccessibility();
|
||||
void MessageForScreenReader(const wxString& message);
|
||||
|
||||
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||
public:
|
||||
void SnapCenterOnce (const WaveTrack *pTrack, bool up);
|
||||
protected:
|
||||
void StartSnappingFreqSelection (const WaveTrack *pTrack);
|
||||
void MoveSnappingFreqSelection (int mouseYCoordinate,
|
||||
int trackTopEdge,
|
||||
int trackHeight, Track *pTrack);
|
||||
void StartFreqSelection (int mouseYCoordinate, int trackTopEdge,
|
||||
int trackHeight, Track *pTrack);
|
||||
void ExtendFreqSelection(int mouseYCoordinate, int trackTopEdge,
|
||||
int trackHeight);
|
||||
void ResetFreqSelectionPin(double hintFrequency, bool logF);
|
||||
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// AS: Cursor handling
|
||||
virtual bool SetCursorByActivity( );
|
||||
virtual void SetCursorAndTipWhenSelectTool
|
||||
( Track * t, const wxMouseEvent & event, const wxRect &rect, bool bMultiToolMode, wxString &tip, const wxCursor ** ppCursor );
|
||||
virtual void SetCursorAndTipByTool( int tool, const wxMouseEvent & event, wxString &tip );
|
||||
|
||||
public:
|
||||
virtual void HandleCursor(wxMouseEvent & event);
|
||||
|
||||
protected:
|
||||
virtual void MaySetOnDemandTip( Track * t, wxString &tip );
|
||||
|
||||
// MM: Handle mouse wheel rotation
|
||||
virtual void HandleWheelRotation(wxMouseEvent & event);
|
||||
|
||||
public:
|
||||
virtual void MakeParentRedrawScrollbars();
|
||||
|
||||
protected:
|
||||
// AS: Pushing the state preserves state for Undo operations.
|
||||
virtual void MakeParentPushState(const wxString &desc, const wxString &shortDesc); // use UndoPush::AUTOSAVE
|
||||
virtual void MakeParentPushState(const wxString &desc, const wxString &shortDesc,
|
||||
UndoPush flags);
|
||||
virtual void MakeParentModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after
|
||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||
|
||||
@ -558,42 +470,12 @@ protected:
|
||||
|
||||
bool mRefreshBacking;
|
||||
|
||||
SelectedRegion mInitialSelection;
|
||||
SelectionState &GetSelectionState();
|
||||
std::unique_ptr<SelectionStateChanger> mSelectionStateChanger{};
|
||||
|
||||
bool mSelStartValid;
|
||||
double mSelStart;
|
||||
|
||||
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||
enum eFreqSelMode {
|
||||
FREQ_SEL_INVALID,
|
||||
|
||||
FREQ_SEL_SNAPPING_CENTER,
|
||||
FREQ_SEL_PINNED_CENTER,
|
||||
FREQ_SEL_DRAG_CENTER,
|
||||
|
||||
FREQ_SEL_FREE,
|
||||
FREQ_SEL_TOP_FREE,
|
||||
FREQ_SEL_BOTTOM_FREE,
|
||||
} mFreqSelMode;
|
||||
// Following holds:
|
||||
// the center for FREQ_SEL_PINNED_CENTER,
|
||||
// the ratio of top to center (== center to bottom) for FREQ_SEL_DRAG_CENTER,
|
||||
// a frequency boundary for FREQ_SEL_FREE, FREQ_SEL_TOP_FREE, or
|
||||
// FREQ_SEL_BOTTOM_FREE,
|
||||
// and is ignored otherwise.
|
||||
double mFreqSelPin;
|
||||
const WaveTrack *mFreqSelTrack = NULL;
|
||||
std::unique_ptr<SpectrumAnalyst> mFrequencySnapper;
|
||||
|
||||
protected:
|
||||
|
||||
#endif
|
||||
|
||||
Track *mCapturedTrack;
|
||||
wxRect mCapturedRect;
|
||||
|
||||
bool mRedrawAfterStop;
|
||||
|
||||
wxMouseEvent mLastMouseEvent;
|
||||
@ -601,72 +483,13 @@ protected:
|
||||
int mMouseMostRecentX;
|
||||
int mMouseMostRecentY;
|
||||
|
||||
// Handles snapping the selection boundaries or track boundaries to
|
||||
// line up with existing tracks or labels. mSnapLeft and mSnapRight
|
||||
// are the horizontal index of pixels to display user feedback
|
||||
// guidelines so the user knows when such snapping is taking place.
|
||||
std::unique_ptr<SnapManager> mSnapManager;
|
||||
|
||||
wxInt64 mSnapLeft { -1 };
|
||||
wxInt64 mSnapRight { -1 };
|
||||
|
||||
public:
|
||||
wxInt64 GetSnapLeft () const
|
||||
{
|
||||
return mSnapLeft ;
|
||||
}
|
||||
wxInt64 GetSnapRight() const
|
||||
{
|
||||
return mSnapRight;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||
void HandleCenterFrequencyCursor
|
||||
(bool shiftDown, wxString &tip, const wxCursor ** ppCursor);
|
||||
|
||||
void HandleCenterFrequencyClick
|
||||
(bool shiftDown, const WaveTrack *pTrack, double value);
|
||||
|
||||
double PositionToFrequency(const WaveTrack *wt,
|
||||
bool maySnap,
|
||||
wxInt64 mouseYCoordinate,
|
||||
wxInt64 trackTopEdge,
|
||||
int trackHeight) const;
|
||||
wxInt64 FrequencyToPosition(const WaveTrack *wt,
|
||||
double frequency,
|
||||
wxInt64 trackTopEdge,
|
||||
int trackHeight) const;
|
||||
#endif
|
||||
|
||||
enum SelectionBoundary {
|
||||
SBNone,
|
||||
SBLeft, SBRight,
|
||||
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||
SBBottom, SBTop, SBCenter, SBWidth,
|
||||
#endif
|
||||
};
|
||||
SelectionBoundary ChooseTimeBoundary
|
||||
(double selend, bool onlyWithinSnapDistance,
|
||||
wxInt64 *pPixelDist = NULL, double *pPinValue = NULL) const;
|
||||
SelectionBoundary ChooseBoundary
|
||||
(const wxMouseEvent & event, const Track *pTrack,
|
||||
const wxRect &rect,
|
||||
bool mayDragWidth,
|
||||
bool onlyWithinSnapDistance,
|
||||
double *pPinValue = NULL) const;
|
||||
|
||||
bool mAutoScrolling;
|
||||
|
||||
public:
|
||||
// Old enumeration of click-and-drag states, which will shrink and disappear
|
||||
// as UIHandle subclasses take over the repsonsibilities.
|
||||
enum MouseCaptureEnum
|
||||
{
|
||||
IsUncaptured=0, // This is the normal state for the mouse
|
||||
IsUncaptured = 0,
|
||||
IsClosing,
|
||||
IsSelecting,
|
||||
IsMuting,
|
||||
IsSoloing,
|
||||
IsMinimizing,
|
||||
@ -674,24 +497,6 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
enum MouseCaptureEnum mMouseCapture;
|
||||
|
||||
virtual void SetCapturedTrack( Track * t, enum MouseCaptureEnum MouseCapture=IsUncaptured );
|
||||
|
||||
std::unique_ptr<wxCursor>
|
||||
mArrowCursor, mSelectCursor,
|
||||
mEnvelopeCursor, // doubles as the center frequency cursor
|
||||
// for spectral selection
|
||||
mDisabledCursor, mAdjustLeftSelectionCursor, mAdjustRightSelectionCursor;
|
||||
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||
std::unique_ptr<wxCursor>
|
||||
mBottomFrequencyCursor, mTopFrequencyCursor, mBandWidthCursor;
|
||||
#endif
|
||||
#ifdef USE_MIDI
|
||||
std::unique_ptr<wxCursor>
|
||||
mStretchCursor, mStretchLeftCursor, mStretchRightCursor;
|
||||
#endif
|
||||
|
||||
friend class TrackPanelAx;
|
||||
|
||||
#if wxUSE_ACCESSIBILITY
|
||||
@ -707,8 +512,6 @@ protected:
|
||||
|
||||
static wxString gSoloPref;
|
||||
|
||||
protected:
|
||||
|
||||
// The screenshot class needs to access internals
|
||||
friend class ScreenshotCommand;
|
||||
|
||||
@ -765,11 +568,4 @@ enum : int {
|
||||
//the bottom of a track that can be used for vertical track resizing.
|
||||
#define TRACK_RESIZE_REGION 5
|
||||
|
||||
//This constant determines the size of the horizontal region (in pixels) around
|
||||
//the right and left selection bounds that can be used for horizontal selection adjusting
|
||||
//(or, vertical distance around top and bottom bounds in spectrograms,
|
||||
// for vertical selection adjusting)
|
||||
#define SELECTION_RESIZE_REGION 3
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -15,8 +15,12 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "LabelGlyphHandle.h"
|
||||
#include "LabelTextHandle.h"
|
||||
|
||||
#include "../../ui/SelectHandle.h"
|
||||
|
||||
#include "../../../HitTestResult.h"
|
||||
#include "../../../Project.h"
|
||||
#include "../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../toolbars/ToolsToolBar.h"
|
||||
|
||||
HitTestResult LabelTrack::HitTest
|
||||
(const TrackPanelMouseEvent &evt,
|
||||
@ -37,6 +41,12 @@ HitTestResult LabelTrack::HitTest
|
||||
// Missed glyph, try text box
|
||||
// This hit test does not define its own messages or cursor
|
||||
HitTestResult defaultResult = Track::HitTest(evt, pProject);
|
||||
if (!defaultResult.handle) {
|
||||
// In case of multi tool, default to selection.
|
||||
const ToolsToolBar *const pTtb = pProject->GetToolsToolBar();
|
||||
if (pTtb->IsDown(multiTool))
|
||||
defaultResult = SelectHandle::HitTest(evt, pProject, this);
|
||||
}
|
||||
result = LabelTextHandle::HitTest(event, this);
|
||||
if (result.handle)
|
||||
// Use any cursor or status message change from catchall,
|
||||
|
@ -17,12 +17,49 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "NoteTrackVRulerControls.h"
|
||||
|
||||
#include "../../../../HitTestResult.h"
|
||||
#include "../../../../Project.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../ui/SelectHandle.h"
|
||||
#include "StretchHandle.h"
|
||||
#include "../../../../toolbars/ToolsToolBar.h"
|
||||
|
||||
HitTestResult NoteTrack::HitTest
|
||||
(const TrackPanelMouseEvent &event,
|
||||
const AudacityProject *pProject)
|
||||
{
|
||||
return Track::HitTest(event, pProject);
|
||||
const ToolsToolBar *const pTtb = pProject->GetToolsToolBar();
|
||||
|
||||
// If the cursor is in the hot zone for stretching, that takes precedence
|
||||
// over selection, but it didn't take precedence over other hits.
|
||||
// That was the old logic, and maybe I tried too hard to preserve it just so.
|
||||
// PRL.
|
||||
|
||||
// Eligible for stretch?
|
||||
HitTestResult result1;
|
||||
#ifdef USE_MIDI
|
||||
StretchHandle::StretchState state;
|
||||
result1 = StretchHandle::HitTest( event, pProject, this, state );
|
||||
#endif
|
||||
|
||||
// But some other non-select tool like zoom may take priority.
|
||||
HitTestResult result = Track::HitTest(event, pProject);
|
||||
if (result.preview.cursor &&
|
||||
!(result1.preview.cursor && pTtb->GetCurrentTool() == selectTool))
|
||||
return result;
|
||||
|
||||
if (pTtb->IsDown(multiTool)) {
|
||||
// Default to selection
|
||||
if (!result1.preview.cursor &&
|
||||
NULL != (result =
|
||||
SelectHandle::HitTest(event, pProject, this)).preview.cursor)
|
||||
return result;
|
||||
}
|
||||
|
||||
// Do stretch!
|
||||
if (result1.preview.cursor)
|
||||
return result1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TrackControls *NoteTrack::GetControls()
|
||||
|
339
src/tracks/playabletrack/notetrack/ui/StretchHandle.cpp
Normal file
339
src/tracks/playabletrack/notetrack/ui/StretchHandle.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
StretchHandle.cpp
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "../../../../Audacity.h"
|
||||
|
||||
#ifdef USE_MIDI
|
||||
|
||||
#include "StretchHandle.h"
|
||||
|
||||
#include "../../../../HitTestResult.h"
|
||||
#include "../../../../NoteTrack.h"
|
||||
#include "../../../../Project.h"
|
||||
#include "../../../../RefreshCode.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../UndoManager.h"
|
||||
#include "../../../../../images/Cursors.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
StretchHandle::StretchHandle()
|
||||
{
|
||||
}
|
||||
|
||||
StretchHandle &StretchHandle::Instance()
|
||||
{
|
||||
static StretchHandle instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
HitTestPreview StretchHandle::HitPreview( StretchEnum stretchMode, bool unsafe )
|
||||
{
|
||||
static auto disabledCursor =
|
||||
::MakeCursor(wxCURSOR_NO_ENTRY, DisabledCursorXpm, 16, 16);
|
||||
static auto stretchLeftCursor =
|
||||
::MakeCursor(wxCURSOR_BULLSEYE, StretchLeftCursorXpm, 16, 16);
|
||||
static auto stretchRightCursor =
|
||||
::MakeCursor(wxCURSOR_BULLSEYE, StretchRightCursorXpm, 16, 16);
|
||||
static auto stretchCursor =
|
||||
::MakeCursor(wxCURSOR_BULLSEYE, StretchCursorXpm, 16, 16);
|
||||
|
||||
if (unsafe) {
|
||||
return { _(""), &*disabledCursor };
|
||||
}
|
||||
else {
|
||||
wxCursor *pCursor = NULL;
|
||||
switch (stretchMode) {
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case stretchLeft:
|
||||
pCursor = &*stretchLeftCursor; break;
|
||||
case stretchCenter:
|
||||
pCursor = &*stretchCursor; break;
|
||||
case stretchRight:
|
||||
pCursor = &*stretchRightCursor; break;
|
||||
}
|
||||
return {
|
||||
_("Click and drag to stretch selected region."),
|
||||
pCursor
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
HitTestResult StretchHandle::HitTest
|
||||
( const TrackPanelMouseEvent &evt, const AudacityProject *pProject,
|
||||
NoteTrack *pTrack, StretchState &stretchState)
|
||||
{
|
||||
const wxMouseEvent &event = evt.event;
|
||||
|
||||
// later, we may want a different policy, but for now, stretch is
|
||||
// selected when the cursor is near the center of the track and
|
||||
// within the selection
|
||||
|
||||
const ViewInfo &viewInfo = pProject->GetViewInfo();
|
||||
const bool unsafe = pProject->IsAudioActive();
|
||||
if (!pTrack || !pTrack->GetSelected() || pTrack->GetKind() != Track::Note)
|
||||
return {};
|
||||
|
||||
const wxRect &rect = evt.rect;
|
||||
int center = rect.y + rect.height / 2;
|
||||
int distance = abs(event.m_y - center);
|
||||
const int yTolerance = 10;
|
||||
wxInt64 leftSel = viewInfo.TimeToPosition(viewInfo.selectedRegion.t0(), rect.x);
|
||||
wxInt64 rightSel = viewInfo.TimeToPosition(viewInfo.selectedRegion.t1(), rect.x);
|
||||
// Something is wrong if right edge comes before left edge
|
||||
wxASSERT(!(rightSel < leftSel));
|
||||
if (!(leftSel <= event.m_x && event.m_x <= rightSel &&
|
||||
distance < yTolerance))
|
||||
return {};
|
||||
|
||||
// find nearest beat to sel0, sel1
|
||||
static const double minPeriod = 0.05; // minimum beat period
|
||||
stretchState.mBeatCenter = { 0, 0 };
|
||||
|
||||
auto t0 = viewInfo.selectedRegion.t0();
|
||||
stretchState.mBeat0 = pTrack->NearestBeatTime( t0 );
|
||||
stretchState.mOrigSel0Quantized = stretchState.mBeat0.first;
|
||||
|
||||
auto t1 = viewInfo.selectedRegion.t1();
|
||||
stretchState.mBeat1 = pTrack->NearestBeatTime( t1 );
|
||||
stretchState.mOrigSel1Quantized = stretchState.mBeat1.first;
|
||||
|
||||
// If there is not (almost) a beat to stretch that is slower
|
||||
// than 20 beats per second, don't stretch
|
||||
if ( within( stretchState.mBeat0.second,
|
||||
stretchState.mBeat1.second, 0.9 ) ||
|
||||
( stretchState.mBeat1.first - stretchState.mBeat0.first ) /
|
||||
( stretchState.mBeat1.second - stretchState.mBeat0.second )
|
||||
< minPeriod )
|
||||
return {};
|
||||
|
||||
auto selStart = viewInfo.PositionToTime( event.m_x, rect.x );
|
||||
stretchState.mBeatCenter = pTrack->NearestBeatTime( selStart );
|
||||
bool startNewSelection = true;
|
||||
if ( within( stretchState.mBeat0.second,
|
||||
stretchState.mBeatCenter.second, 0.1 ) ) {
|
||||
stretchState.mMode = stretchLeft;
|
||||
stretchState.mLeftBeats = 0;
|
||||
stretchState.mRightBeats =
|
||||
stretchState.mBeat1.second - stretchState.mBeat0.second;
|
||||
}
|
||||
else if ( within( stretchState.mBeat1.second,
|
||||
stretchState.mBeatCenter.second, 0.1 ) ) {
|
||||
stretchState.mMode = stretchRight;
|
||||
stretchState.mLeftBeats =
|
||||
stretchState.mBeat1.second - stretchState.mBeat0.second;
|
||||
stretchState.mRightBeats = 0;
|
||||
}
|
||||
else {
|
||||
stretchState.mMode = stretchCenter;
|
||||
stretchState.mLeftBeats =
|
||||
stretchState.mBeat1.second - stretchState.mBeatCenter.second;
|
||||
stretchState.mRightBeats =
|
||||
stretchState.mBeatCenter.second - stretchState.mBeat0.second;
|
||||
}
|
||||
|
||||
return {
|
||||
HitPreview( stretchState.mMode, unsafe ),
|
||||
&Instance()
|
||||
};
|
||||
}
|
||||
|
||||
StretchHandle::~StretchHandle()
|
||||
{
|
||||
}
|
||||
|
||||
UIHandle::Result StretchHandle::Click
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
const bool unsafe = pProject->IsAudioActive();
|
||||
const wxMouseEvent &event = evt.event;
|
||||
|
||||
if (unsafe ||
|
||||
event.LeftDClick() ||
|
||||
!event.LeftDown() ||
|
||||
evt.pCell == NULL)
|
||||
return Cancelled;
|
||||
|
||||
|
||||
mLeftEdge = evt.rect.GetLeft();
|
||||
mpTrack = static_cast<NoteTrack*>(evt.pCell);
|
||||
ViewInfo &viewInfo = pProject->GetViewInfo();
|
||||
|
||||
// We must have hit if we got here, but repeat some
|
||||
// calculations that set members
|
||||
HitTest( evt, pProject, mpTrack, mStretchState );
|
||||
|
||||
viewInfo.selectedRegion.setTimes
|
||||
( mStretchState.mBeat0.first, mStretchState.mBeat1.first );
|
||||
|
||||
// Full refresh since the label area may need to indicate
|
||||
// newly selected tracks. (I'm really not sure if the label area
|
||||
// needs to be refreshed or how to just refresh non-label areas.-RBD)
|
||||
|
||||
return RefreshAll | UpdateSelection;
|
||||
}
|
||||
|
||||
UIHandle::Result StretchHandle::Drag
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
const bool unsafe = pProject->IsAudioActive();
|
||||
if (unsafe) {
|
||||
this->Cancel(pProject);
|
||||
return RefreshAll | Cancelled;
|
||||
}
|
||||
|
||||
const wxMouseEvent &event = evt.event;
|
||||
const int x = event.m_x;
|
||||
|
||||
Track *clickedTrack =
|
||||
static_cast<CommonTrackPanelCell*>(evt.pCell)->FindTrack();
|
||||
|
||||
if (clickedTrack == NULL && mpTrack != NULL)
|
||||
clickedTrack = mpTrack;
|
||||
Stretch(pProject, x, mLeftEdge, clickedTrack);
|
||||
return RefreshAll;
|
||||
}
|
||||
|
||||
HitTestPreview StretchHandle::Preview
|
||||
(const TrackPanelMouseEvent &, const AudacityProject *pProject)
|
||||
{
|
||||
const bool unsafe = pProject->IsAudioActive();
|
||||
return HitPreview( mStretchState.mMode, unsafe );
|
||||
}
|
||||
|
||||
UIHandle::Result StretchHandle::Release
|
||||
(const TrackPanelMouseEvent &, AudacityProject *pProject,
|
||||
wxWindow *)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
|
||||
const bool unsafe = pProject->IsAudioActive();
|
||||
if (unsafe) {
|
||||
this->Cancel(pProject);
|
||||
return RefreshAll | Cancelled;
|
||||
}
|
||||
|
||||
bool left;
|
||||
ViewInfo &viewInfo = pProject->GetViewInfo();
|
||||
if ( pProject->IsSyncLocked() &&
|
||||
( ( left = mStretchState.mMode == stretchLeft ) ||
|
||||
mStretchState.mMode == stretchRight ) ) {
|
||||
SyncLockedTracksIterator syncIter( pProject->GetTracks() );
|
||||
for ( auto track = syncIter.StartWith( mpTrack ); track != nullptr;
|
||||
track = syncIter.Next() ) {
|
||||
if ( track != mpTrack ) {
|
||||
if ( left ) {
|
||||
auto origT0 = mStretchState.mOrigSel0Quantized;
|
||||
auto diff = viewInfo.selectedRegion.t0() - origT0;
|
||||
if ( diff > 0)
|
||||
track->SyncLockAdjust( origT0 + diff, origT0 );
|
||||
else
|
||||
track->SyncLockAdjust( origT0, origT0 - diff );
|
||||
track->Offset( diff );
|
||||
}
|
||||
else {
|
||||
auto origT1 = mStretchState.mOrigSel1Quantized;
|
||||
auto diff = viewInfo.selectedRegion.t1() - origT1;
|
||||
track->SyncLockAdjust( origT1, origT1 + diff );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* i18n-hint: (noun) The track that is used for MIDI notes which can be
|
||||
dragged to change their duration.*/
|
||||
pProject->PushState(_("Stretch Note Track"),
|
||||
/* i18n-hint: In the history list, indicates a MIDI note has
|
||||
been dragged to change its duration (stretch it). Using either past
|
||||
or present tense is fine here. If unsure, go for whichever is
|
||||
shorter.*/
|
||||
_("Stretch"),
|
||||
UndoPush::CONSOLIDATE | UndoPush::AUTOSAVE);
|
||||
return RefreshAll;
|
||||
}
|
||||
|
||||
UIHandle::Result StretchHandle::Cancel(AudacityProject *pProject)
|
||||
{
|
||||
pProject->RollbackState();
|
||||
return RefreshCode::RefreshNone;
|
||||
}
|
||||
|
||||
void StretchHandle::Stretch(AudacityProject *pProject, int mouseXCoordinate, int trackLeftEdge,
|
||||
Track *pTrack)
|
||||
{
|
||||
ViewInfo &viewInfo = pProject->GetViewInfo();
|
||||
TrackList *const trackList = pProject->GetTracks();
|
||||
|
||||
if (pTrack == NULL && mpTrack != NULL)
|
||||
pTrack = mpTrack;
|
||||
|
||||
if (!pTrack || pTrack->GetKind() != Track::Note) {
|
||||
return;
|
||||
}
|
||||
|
||||
NoteTrack *pNt = static_cast<NoteTrack *>(pTrack);
|
||||
double moveto =
|
||||
std::max(0.0, viewInfo.PositionToTime(mouseXCoordinate, trackLeftEdge));
|
||||
|
||||
auto t1 = viewInfo.selectedRegion.t1();
|
||||
auto t0 = viewInfo.selectedRegion.t0();
|
||||
double dur, left_dur, right_dur;
|
||||
|
||||
// check to make sure tempo is not higher than 20 beats per second
|
||||
// (In principle, tempo can be higher, but not infinity.)
|
||||
double minPeriod = 0.05; // minimum beat period
|
||||
|
||||
// make sure target duration is not too short
|
||||
// Take quick exit if so, without changing the selection.
|
||||
switch ( mStretchState.mMode ) {
|
||||
case stretchLeft: {
|
||||
dur = t1 - moveto;
|
||||
if (dur < mStretchState.mRightBeats * minPeriod)
|
||||
return;
|
||||
pNt->StretchRegion
|
||||
( mStretchState.mBeat0, mStretchState.mBeat1, dur );
|
||||
pNt->Offset( moveto - t0 );
|
||||
mStretchState.mBeat0.first = moveto;
|
||||
viewInfo.selectedRegion.setT0(moveto);
|
||||
break;
|
||||
}
|
||||
case stretchRight: {
|
||||
dur = moveto - t0;
|
||||
if (dur < mStretchState.mLeftBeats * minPeriod)
|
||||
return;
|
||||
pNt->StretchRegion
|
||||
( mStretchState.mBeat0, mStretchState.mBeat1, dur );
|
||||
viewInfo.selectedRegion.setT1(moveto);
|
||||
mStretchState.mBeat1.first = moveto;
|
||||
viewInfo.selectedRegion.setT0(moveto);
|
||||
break;
|
||||
}
|
||||
case stretchCenter: {
|
||||
left_dur = moveto - t0;
|
||||
right_dur = t1 - moveto;
|
||||
if ( left_dur < mStretchState.mLeftBeats * minPeriod ||
|
||||
right_dur < mStretchState.mRightBeats * minPeriod )
|
||||
return;
|
||||
pNt->StretchRegion
|
||||
( mStretchState.mBeatCenter, mStretchState.mBeat1, right_dur );
|
||||
pNt->StretchRegion
|
||||
( mStretchState.mBeat0, mStretchState.mBeatCenter, left_dur );
|
||||
mStretchState.mBeatCenter.first = moveto;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
wxASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
98
src/tracks/playabletrack/notetrack/ui/StretchHandle.h
Normal file
98
src/tracks/playabletrack/notetrack/ui/StretchHandle.h
Normal file
@ -0,0 +1,98 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
StretchHandle.h
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_STRETCH_HANDLE__
|
||||
#define __AUDACITY_STRETCH_HANDLE__
|
||||
|
||||
#include "../../../../UIHandle.h"
|
||||
|
||||
#include "../../../../MemoryX.h"
|
||||
|
||||
class Alg_seq;
|
||||
struct HitTestResult;
|
||||
class NoteTrack;
|
||||
class Track;
|
||||
class ViewInfo;
|
||||
class wxCursor;
|
||||
|
||||
class StretchHandle : public UIHandle
|
||||
{
|
||||
public:
|
||||
enum StretchEnum {
|
||||
stretchNone = 0, // false value!
|
||||
stretchLeft,
|
||||
stretchCenter,
|
||||
stretchRight
|
||||
};
|
||||
|
||||
// Stretching applies to a selected region after quantizing the
|
||||
// region to beat boundaries (subbeat stretching is not supported,
|
||||
// but maybe it should be enabled with shift or ctrl or something)
|
||||
// Stretching can drag the left boundary (the right stays fixed),
|
||||
// the right boundary (the left stays fixed), or the center (splits
|
||||
// the selection into two parts: when left part grows, the right
|
||||
// part shrinks, keeping the leftmost and rightmost boundaries
|
||||
// fixed.
|
||||
struct StretchState {
|
||||
StretchEnum mMode { stretchCenter }; // remembers what to drag
|
||||
|
||||
using QuantizedTimeAndBeat = std::pair< double, double >;
|
||||
|
||||
QuantizedTimeAndBeat mBeatCenter { 0, 0 };
|
||||
QuantizedTimeAndBeat mBeat0 { 0, 0 };
|
||||
QuantizedTimeAndBeat mBeat1 { 0, 0 };
|
||||
double mLeftBeats {}; // how many beats from left to cursor
|
||||
double mRightBeats {}; // how many beats from cursor to right
|
||||
|
||||
double mOrigSel0Quantized { -1 }, mOrigSel1Quantized { -1 };
|
||||
};
|
||||
|
||||
private:
|
||||
StretchHandle();
|
||||
StretchHandle(const StretchHandle&);
|
||||
StretchHandle &operator=(const StretchHandle&);
|
||||
static StretchHandle& Instance();
|
||||
static HitTestPreview HitPreview(StretchEnum stretchMode, bool unsafe);
|
||||
|
||||
public:
|
||||
static HitTestResult HitTest
|
||||
( const TrackPanelMouseEvent &event, const AudacityProject *pProject,
|
||||
NoteTrack *pTrack, StretchState &state );
|
||||
|
||||
virtual ~StretchHandle();
|
||||
|
||||
virtual Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
|
||||
virtual Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
|
||||
virtual HitTestPreview Preview
|
||||
(const TrackPanelMouseEvent &event, const AudacityProject *pProject);
|
||||
|
||||
virtual Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent);
|
||||
|
||||
virtual Result Cancel(AudacityProject *pProject);
|
||||
|
||||
bool StopsOnKeystroke() override { return true; }
|
||||
|
||||
private:
|
||||
void Stretch
|
||||
(AudacityProject *pProject, int mouseXCoordinate, int trackLeftEdge, Track *pTrack);
|
||||
|
||||
NoteTrack *mpTrack{};
|
||||
int mLeftEdge{ -1 };
|
||||
|
||||
StretchState mStretchState{};
|
||||
};
|
||||
|
||||
#endif
|
@ -18,6 +18,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../../../toolbars/ToolsToolBar.h"
|
||||
|
||||
#include "CutlineHandle.h"
|
||||
#include "../../../ui/SelectHandle.h"
|
||||
#include "../../../ui/EnvelopeHandle.h"
|
||||
#include "SampleHandle.h"
|
||||
#include "../../../ui/TimeShiftHandle.h"
|
||||
@ -26,6 +27,11 @@ HitTestResult WaveTrack::HitTest
|
||||
(const TrackPanelMouseEvent &event,
|
||||
const AudacityProject *pProject)
|
||||
{
|
||||
// FIXME: Should similar logic apply to NoteTrack (#if defined(USE_MIDI)) ?
|
||||
// From here on the order in which we hit test determines
|
||||
// which tool takes priority in the rare cases where it
|
||||
// could be more than one.
|
||||
|
||||
// This hit was always tested first no matter which tool:
|
||||
HitTestResult result = CutlineHandle::HitTest(event.event, event.rect, pProject, this);
|
||||
if (result.preview.cursor)
|
||||
@ -51,6 +57,10 @@ HitTestResult WaveTrack::HitTest
|
||||
else if (NULL != (result =
|
||||
SampleHandle::HitTest(event.event, event.rect, pProject, this)).preview.cursor)
|
||||
;
|
||||
else if (NULL != (result =
|
||||
SelectHandle::HitTest(event, pProject, this)).preview.cursor)
|
||||
// default of all other hit tests
|
||||
;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
1437
src/tracks/ui/SelectHandle.cpp
Normal file
1437
src/tracks/ui/SelectHandle.cpp
Normal file
File diff suppressed because it is too large
Load Diff
153
src/tracks/ui/SelectHandle.h
Normal file
153
src/tracks/ui/SelectHandle.h
Normal file
@ -0,0 +1,153 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
SelectHandle.h
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_SELECT_HANDLE__
|
||||
#define __AUDACITY_SELECT_HANDLE__
|
||||
|
||||
#include "../../UIHandle.h"
|
||||
#include "../../SelectedRegion.h"
|
||||
|
||||
#include "../../MemoryX.h"
|
||||
#include <vector>
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/gdicmn.h>
|
||||
|
||||
struct HitTestResult;
|
||||
class SelectionStateChanger;
|
||||
class SnapManager;
|
||||
class SpectrumAnalyst;
|
||||
class Track;
|
||||
class ViewInfo;
|
||||
class WaveTrack;
|
||||
|
||||
class SelectHandle : public wxEvtHandler, public UIHandle
|
||||
{
|
||||
SelectHandle();
|
||||
SelectHandle(const SelectHandle&);
|
||||
SelectHandle &operator=(const SelectHandle&);
|
||||
|
||||
public:
|
||||
static SelectHandle& Instance();
|
||||
|
||||
// This always hits, but details of the hit vary with mouse position and
|
||||
// key state.
|
||||
static HitTestResult HitTest
|
||||
(const TrackPanelMouseEvent &event, const AudacityProject *pProject, const Track *pTrack);
|
||||
|
||||
virtual ~SelectHandle();
|
||||
|
||||
virtual Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
|
||||
virtual Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject);
|
||||
|
||||
virtual HitTestPreview Preview
|
||||
(const TrackPanelMouseEvent &event, const AudacityProject *pProject);
|
||||
|
||||
virtual Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent);
|
||||
|
||||
virtual Result Cancel(AudacityProject*);
|
||||
|
||||
virtual void DrawExtras
|
||||
(DrawingPass pass,
|
||||
wxDC * dc, const wxRegion &updateRegion, const wxRect &panelRect);
|
||||
|
||||
void OnProjectChange(AudacityProject *pProject) override;
|
||||
|
||||
// Receives timer event notifications, to implement auto-scroll
|
||||
void OnTimer(wxCommandEvent &event);
|
||||
|
||||
private:
|
||||
void Connect(AudacityProject *pProject);
|
||||
void Disconnect();
|
||||
|
||||
void StartSelection
|
||||
(AudacityProject *pProject, int mouseXCoordinate, int trackLeftEdge);
|
||||
void AdjustSelection
|
||||
(ViewInfo &viewInfo, int mouseXCoordinate, int trackLeftEdge,
|
||||
Track *pTrack);
|
||||
|
||||
void StartFreqSelection
|
||||
(ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge,
|
||||
int trackHeight, Track *pTrack);
|
||||
void AdjustFreqSelection
|
||||
(ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge,
|
||||
int trackHeight);
|
||||
|
||||
void HandleCenterFrequencyClick
|
||||
(const ViewInfo &viewInfo, bool shiftDown,
|
||||
const WaveTrack *pTrack, double value);
|
||||
void StartSnappingFreqSelection
|
||||
(const ViewInfo &viewInfo, const WaveTrack *pTrack);
|
||||
void MoveSnappingFreqSelection
|
||||
(AudacityProject *pProject, ViewInfo &viewInfo, int mouseYCoordinate,
|
||||
int trackTopEdge,
|
||||
int trackHeight, Track *pTrack);
|
||||
public:
|
||||
// This is needed to implement a command assignable to keystrokes
|
||||
void SnapCenterOnce
|
||||
(ViewInfo &viewInfo, const WaveTrack *pTrack, bool up);
|
||||
private:
|
||||
//void ResetFreqSelectionPin
|
||||
// (const ViewInfo &viewInfo, double hintFrequency, bool logF);
|
||||
|
||||
|
||||
Track *mpTrack;
|
||||
wxRect mRect;
|
||||
SelectedRegion mInitialSelection;
|
||||
|
||||
// Handles snapping the selection boundaries or track boundaries to
|
||||
// line up with existing tracks or labels. mSnapLeft and mSnapRight
|
||||
// are the horizontal index of pixels to display user feedback
|
||||
// guidelines so the user knows when such snapping is taking place.
|
||||
std::unique_ptr<SnapManager> mSnapManager;
|
||||
wxInt64 mSnapLeft;
|
||||
wxInt64 mSnapRight;
|
||||
|
||||
bool mSelStartValid;
|
||||
double mSelStart;
|
||||
|
||||
int mSelectionBoundary;
|
||||
|
||||
enum eFreqSelMode {
|
||||
FREQ_SEL_INVALID,
|
||||
|
||||
FREQ_SEL_SNAPPING_CENTER,
|
||||
FREQ_SEL_PINNED_CENTER,
|
||||
FREQ_SEL_DRAG_CENTER,
|
||||
|
||||
FREQ_SEL_FREE,
|
||||
FREQ_SEL_TOP_FREE,
|
||||
FREQ_SEL_BOTTOM_FREE,
|
||||
} mFreqSelMode;
|
||||
const WaveTrack *mFreqSelTrack {};
|
||||
// Following holds:
|
||||
// the center for FREQ_SEL_PINNED_CENTER,
|
||||
// the ratio of top to center (== center to bottom) for FREQ_SEL_DRAG_CENTER,
|
||||
// a frequency boundary for FREQ_SEL_FREE, FREQ_SEL_TOP_FREE, or
|
||||
// FREQ_SEL_BOTTOM_FREE,
|
||||
// and is ignored otherwise.
|
||||
double mFreqSelPin;
|
||||
std::unique_ptr<SpectrumAnalyst> mFrequencySnapper;
|
||||
|
||||
int mMostRecentX, mMostRecentY;
|
||||
|
||||
bool mAutoScrolling;
|
||||
|
||||
AudacityProject *mConnectedProject;
|
||||
|
||||
std::unique_ptr<SelectionStateChanger> mSelectionStateChanger;
|
||||
};
|
||||
|
||||
#endif
|
@ -17,6 +17,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../Project.h"
|
||||
#include "../../toolbars/ToolsToolBar.h"
|
||||
|
||||
#include "../ui/SelectHandle.h"
|
||||
#include "EnvelopeHandle.h"
|
||||
#include "../playabletrack/wavetrack/ui/SampleHandle.h"
|
||||
#include "ZoomHandle.h"
|
||||
@ -40,10 +41,10 @@ HitTestResult Track::HitTest
|
||||
return ZoomHandle::HitAnywhere(event.event, pProject);
|
||||
case slideTool:
|
||||
return TimeShiftHandle::HitAnywhere(pProject);
|
||||
|
||||
case selectTool:
|
||||
return SelectHandle::HitTest(event, pProject, this);
|
||||
|
||||
default:
|
||||
// cases not yet implemented
|
||||
// fallthru
|
||||
;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
@ -234,6 +234,7 @@
|
||||
<ClCompile Include="..\..\..\src\tracks\playabletrack\notetrack\ui\NoteTrackControls.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\playabletrack\notetrack\ui\NoteTrackUI.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\playabletrack\notetrack\ui\NoteTrackVRulerControls.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\playabletrack\notetrack\ui\StretchHandle.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\playabletrack\ui\PlayableTrackButtonHandles.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\playabletrack\wavetrack\ui\CutlineHandle.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\playabletrack\wavetrack\ui\SampleHandle.cpp" />
|
||||
@ -251,6 +252,7 @@
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\EnvelopeHandle.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\PlayIndicatorOverlay.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\Scrubbing.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\SelectHandle.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\SliderHandle.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\TimeShiftHandle.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\TrackButtonHandles.cpp" />
|
||||
@ -505,6 +507,7 @@
|
||||
<ClInclude Include="..\..\..\src\TrackPanelMouseEvent.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\playabletrack\notetrack\ui\NoteTrackControls.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\playabletrack\notetrack\ui\NoteTrackVRulerControls.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\playabletrack\notetrack\ui\StretchHandle.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\playabletrack\ui\PlayableTrackButtonHandles.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\playabletrack\wavetrack\ui\CutlineHandle.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\playabletrack\wavetrack\ui\SampleHandle.h" />
|
||||
@ -515,6 +518,7 @@
|
||||
<ClInclude Include="..\..\..\src\tracks\labeltrack\ui\LabelDefaultClickHandle.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\labeltrack\ui\LabelGlyphHandle.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\labeltrack\ui\LabelTextHandle.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\SelectHandle.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\BackgroundCell.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\CommonTrackPanelCell.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\labeltrack\ui\LabelTrackControls.h" />
|
||||
@ -1203,4 +1207,4 @@
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\ny.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
@ -1040,6 +1040,12 @@
|
||||
<ClCompile Include="..\..\..\src\tracks\labeltrack\ui\LabelDefaultClickHandle.cpp">
|
||||
<Filter>src\tracks\labeltrack\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\SelectHandle.cpp">
|
||||
<Filter>src\tracks\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\tracks\playabletrack\notetrack\ui\StretchHandle.cpp">
|
||||
<Filter>src\tracks\playabletrack\notetrack\ui</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\AboutDialog.h">
|
||||
@ -2071,6 +2077,12 @@
|
||||
<ClInclude Include="..\..\..\src\tracks\labeltrack\ui\LabelDefaultClickHandle.h">
|
||||
<Filter>src\tracks\labeltrack\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\SelectHandle.h">
|
||||
<Filter>src\tracks\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\tracks\playabletrack\notetrack\ui\StretchHandle.h">
|
||||
<Filter>src\tracks\playabletrack\notetrack\ui</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\audacity.ico">
|
||||
@ -2294,4 +2306,4 @@
|
||||
<Filter>plug-ins</Filter>
|
||||
</copy>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user