mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-25 08:38:39 +02:00
Preview cursor for Stretch can take left, right, or center form
This commit is contained in:
parent
90eb4ec142
commit
82ce041c75
@ -1359,7 +1359,9 @@ bool TrackPanel::SetCursorByActivity( )
|
|||||||
return true;
|
return true;
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
case IsStretching:
|
case IsStretching:
|
||||||
SetCursor( unsafe ? *mDisabledCursor : *mStretchCursor);
|
SetCursor( unsafe
|
||||||
|
? *mDisabledCursor
|
||||||
|
: *ChooseStretchCursor( mStretchState.mMode ) );
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
@ -1627,13 +1629,14 @@ void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t,
|
|||||||
switch( boundary) {
|
switch( boundary) {
|
||||||
case SBNone:
|
case SBNone:
|
||||||
case SBLeft:
|
case SBLeft:
|
||||||
case SBRight:
|
case SBRight: {
|
||||||
if ( HitTestStretch(t, rect, event)) {
|
if ( auto stretchMode = HitTestStretch( t, rect, event ) ) {
|
||||||
tip = _("Click and drag to stretch within selected region.");
|
tip = _("Click and drag to stretch within selected region.");
|
||||||
*ppCursor = mStretchCursor.get();
|
*ppCursor = ChooseStretchCursor( stretchMode );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2070,7 +2073,7 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
|
|||||||
|
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
mStretchState = StretchState{};
|
mStretchState = StretchState{};
|
||||||
bool stretch = HitTestStretch(pTrack, rect, event);
|
auto stretch = HitTestStretch( pTrack, rect, event, &mStretchState );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool bShiftDown = event.ShiftDown();
|
bool bShiftDown = event.ShiftDown();
|
||||||
@ -2238,12 +2241,6 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
|
|||||||
const auto nt = static_cast<NoteTrack *>(pTrack);
|
const auto nt = static_cast<NoteTrack *>(pTrack);
|
||||||
// find nearest beat to sel0, sel1
|
// find nearest beat to sel0, sel1
|
||||||
double minPeriod = 0.05; // minimum beat period
|
double minPeriod = 0.05; // minimum beat period
|
||||||
mStretchState.mBeatCenter = { 0, 0 };
|
|
||||||
|
|
||||||
mStretchState.mBeat0 =
|
|
||||||
nt->NearestBeatTime( mViewInfo->selectedRegion.t0() );
|
|
||||||
mStretchState.mBeat1 =
|
|
||||||
nt->NearestBeatTime( mViewInfo->selectedRegion.t1() );
|
|
||||||
|
|
||||||
// If there is not (almost) a beat to stretch that is slower
|
// If there is not (almost) a beat to stretch that is slower
|
||||||
// than 20 beats per second, don't stretch
|
// than 20 beats per second, don't stretch
|
||||||
@ -2256,49 +2253,30 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
|
|||||||
|
|
||||||
if (startNewSelection) { // mouse is not at an edge, but after
|
if (startNewSelection) { // mouse is not at an edge, but after
|
||||||
// quantization, we could be indicating the selection edge
|
// quantization, we could be indicating the selection edge
|
||||||
mSelStartValid = true;
|
if ( stretch == stretchLeft ) {
|
||||||
mSelStart = std::max(0.0, mViewInfo->PositionToTime(event.m_x, rect.x));
|
|
||||||
mStretchState.mBeatCenter = nt->NearestBeatTime( mSelStart );
|
|
||||||
if ( within( mStretchState.mBeat0.second,
|
|
||||||
mStretchState.mBeatCenter.second, 0.1 ) ) {
|
|
||||||
mListener->TP_DisplayStatusMessage(
|
mListener->TP_DisplayStatusMessage(
|
||||||
_("Click and drag to stretch selected region."));
|
_("Click and drag to stretch selected region."));
|
||||||
SetCursor(*mStretchLeftCursor);
|
SetCursor(*mStretchLeftCursor);
|
||||||
// mStretchMode = stretchLeft;
|
// mStretchMode = stretchLeft;
|
||||||
mSelStart = mViewInfo->selectedRegion.t1();
|
|
||||||
// condition that implies stretchLeft
|
|
||||||
startNewSelection = false;
|
startNewSelection = false;
|
||||||
}
|
}
|
||||||
else if ( within( mStretchState.mBeat1.second,
|
else if ( stretchRight ) {
|
||||||
mStretchState.mBeatCenter.second, 0.1 ) ) {
|
|
||||||
mListener->TP_DisplayStatusMessage(
|
mListener->TP_DisplayStatusMessage(
|
||||||
_("Click and drag to stretch selected region."));
|
_("Click and drag to stretch selected region."));
|
||||||
SetCursor(*mStretchRightCursor);
|
SetCursor(*mStretchRightCursor);
|
||||||
// mStretchMode = stretchRight;
|
// mStretchMode = stretchRight;
|
||||||
mSelStart = mViewInfo->selectedRegion.t0();
|
|
||||||
// condition that implies stretchRight
|
|
||||||
startNewSelection = false;
|
startNewSelection = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startNewSelection) {
|
mStretchState.mMode = stretch;
|
||||||
mStretchState.mMode = stretchCenter;
|
if ( mStretchState.mMode == stretchCenter ) {
|
||||||
mStretchState.mLeftBeats =
|
mStretchState.mLeftBeats =
|
||||||
mStretchState.mBeat1.second - mStretchState.mBeatCenter.second;
|
mStretchState.mBeat1.second - mStretchState.mBeatCenter.second;
|
||||||
mStretchState.mRightBeats =
|
mStretchState.mRightBeats =
|
||||||
mStretchState.mBeatCenter.second - mStretchState.mBeat0.second;
|
mStretchState.mBeatCenter.second - mStretchState.mBeat0.second;
|
||||||
}
|
}
|
||||||
else if (mSelStartValid && mViewInfo->selectedRegion.t1() == mSelStart) {
|
else if (mStretchState.mMode == stretchLeft) {
|
||||||
// note that at this point, mSelStart is at the opposite
|
|
||||||
// end of the selection from the cursor. If the cursor is
|
|
||||||
// over sel0, then mSelStart is at sel1.
|
|
||||||
mStretchState.mMode = stretchLeft;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mStretchState.mMode = stretchRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mStretchState.mMode == stretchLeft) {
|
|
||||||
mStretchState.mLeftBeats = 0;
|
mStretchState.mLeftBeats = 0;
|
||||||
mStretchState.mRightBeats =
|
mStretchState.mRightBeats =
|
||||||
mStretchState.mBeat1.second - mStretchState.mBeat0.second;
|
mStretchState.mBeat1.second - mStretchState.mBeat0.second;
|
||||||
@ -2789,6 +2767,50 @@ void TrackPanel::ResetFreqSelectionPin(double hintFrequency, bool logF)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
|
|
||||||
|
wxCursor *TrackPanel::ChooseStretchCursor( StretchEnum mode )
|
||||||
|
{
|
||||||
|
switch ( mode ) {
|
||||||
|
case stretchCenter: return mStretchCursor.get();
|
||||||
|
case stretchLeft: return mStretchLeftCursor.get();
|
||||||
|
case stretchRight: return mStretchRightCursor.get();
|
||||||
|
default: return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto TrackPanel::ChooseStretchMode
|
||||||
|
( const wxMouseEvent &event, const wxRect &rect, const ViewInfo &viewInfo,
|
||||||
|
const NoteTrack *nt, StretchState *pState ) -> StretchEnum
|
||||||
|
{
|
||||||
|
// Assume x coordinate is in the selection and y is appropriate for stretch
|
||||||
|
// -- and then decide whether x is near enough to either edge or neither.
|
||||||
|
|
||||||
|
Maybe< StretchState > state;
|
||||||
|
if ( !pState )
|
||||||
|
state.create(), pState = state.get();
|
||||||
|
|
||||||
|
if ( nt ) {
|
||||||
|
pState->mBeat0 =
|
||||||
|
nt->NearestBeatTime( viewInfo.selectedRegion.t0() );
|
||||||
|
pState->mBeat1 =
|
||||||
|
nt->NearestBeatTime( viewInfo.selectedRegion.t1() );
|
||||||
|
|
||||||
|
auto selStart = std::max(0.0, viewInfo.PositionToTime(event.m_x, rect.x));
|
||||||
|
pState->mBeatCenter = nt->NearestBeatTime( selStart );
|
||||||
|
|
||||||
|
if ( within( pState->mBeat0.second, pState->mBeatCenter.second, 0.1 ) )
|
||||||
|
return stretchLeft;
|
||||||
|
else if ( within( pState->mBeat1.second, pState->mBeatCenter.second, 0.1 ) )
|
||||||
|
return stretchRight;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pState->mBeat0 = pState->mBeat1 = pState->mBeatCenter = { 0, 0 };
|
||||||
|
return stretchNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stretchCenter;
|
||||||
|
}
|
||||||
|
|
||||||
void TrackPanel::Stretch(int mouseXCoordinate, int trackLeftEdge,
|
void TrackPanel::Stretch(int mouseXCoordinate, int trackLeftEdge,
|
||||||
Track *pTrack)
|
Track *pTrack)
|
||||||
{
|
{
|
||||||
@ -6799,14 +6821,17 @@ int TrackPanel::DetermineToolToUse( ToolsToolBar * pTtb, const wxMouseEvent & ev
|
|||||||
|
|
||||||
|
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
bool TrackPanel::HitTestStretch(Track *track, const wxRect &rect, const wxMouseEvent & event)
|
auto TrackPanel::HitTestStretch
|
||||||
|
( const Track *track, const wxRect &rect, const wxMouseEvent & event,
|
||||||
|
StretchState *pState )
|
||||||
|
-> StretchEnum
|
||||||
{
|
{
|
||||||
// later, we may want a different policy, but for now, stretch is
|
// later, we may want a different policy, but for now, stretch is
|
||||||
// selected when the cursor is near the center of the track and
|
// selected when the cursor is near the center of the track and
|
||||||
// within the selection
|
// within the selection
|
||||||
if (!track || !track->GetSelected() || track->GetKind() != Track::Note ||
|
if (!track || !track->GetSelected() || track->GetKind() != Track::Note ||
|
||||||
IsUnsafe()) {
|
IsUnsafe()) {
|
||||||
return false;
|
return stretchNone;
|
||||||
}
|
}
|
||||||
int center = rect.y + rect.height / 2;
|
int center = rect.y + rect.height / 2;
|
||||||
int distance = abs(event.m_y - center);
|
int distance = abs(event.m_y - center);
|
||||||
@ -6815,8 +6840,14 @@ bool TrackPanel::HitTestStretch(Track *track, const wxRect &rect, const wxMouseE
|
|||||||
wxInt64 rightSel = mViewInfo->TimeToPosition(mViewInfo->selectedRegion.t1(), rect.x);
|
wxInt64 rightSel = mViewInfo->TimeToPosition(mViewInfo->selectedRegion.t1(), rect.x);
|
||||||
// Something is wrong if right edge comes before left edge
|
// Something is wrong if right edge comes before left edge
|
||||||
wxASSERT(!(rightSel < leftSel));
|
wxASSERT(!(rightSel < leftSel));
|
||||||
return (leftSel <= event.m_x && event.m_x <= rightSel &&
|
|
||||||
distance < yTolerance);
|
if (leftSel <= event.m_x && event.m_x <= rightSel &&
|
||||||
|
distance < yTolerance)
|
||||||
|
return ChooseStretchMode
|
||||||
|
( event, rect, *mViewInfo,
|
||||||
|
static_cast< const NoteTrack * >( track ), pState );
|
||||||
|
|
||||||
|
return stretchNone;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -320,6 +320,7 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
|||||||
// part shrinks, keeping the leftmost and rightmost boundaries
|
// part shrinks, keeping the leftmost and rightmost boundaries
|
||||||
// fixed.
|
// fixed.
|
||||||
enum StretchEnum {
|
enum StretchEnum {
|
||||||
|
stretchNone = 0, // false value!
|
||||||
stretchLeft,
|
stretchLeft,
|
||||||
stretchCenter,
|
stretchCenter,
|
||||||
stretchRight
|
stretchRight
|
||||||
@ -337,7 +338,13 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
|||||||
double mRightBeats {}; // how many beats from cursor to right
|
double mRightBeats {}; // how many beats from cursor to right
|
||||||
} mStretchState;
|
} mStretchState;
|
||||||
|
|
||||||
virtual bool HitTestStretch(Track *track, const wxRect &rect, const wxMouseEvent & event);
|
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);
|
virtual void Stretch(int mouseXCoordinate, int trackLeftEdge, Track *pTrack);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user