From 5c62b80bc48d8305e755afdbb7c288e774dc2185 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 24 May 2015 13:31:18 -0400 Subject: [PATCH] Defined EXPERIMENTAL_SCROLLING LIMITS When it is enabled, the project can scroll up to one-half of a screenful beyond time zero or the maximum track time. I was careful to disable selection of negative times. This is motivated by the smooth scrolling scrub. It behaves more sensibly at the extremes. It can still keep the play indicator centered. Also removed an unused member of ViewInfo. --- src/Experimental.h | 6 ++- src/Printing.cpp | 1 - src/Project.cpp | 81 ++++++++++++++++++++--------- src/TrackPanel.cpp | 24 +++++---- src/ViewInfo.h | 2 +- src/widgets/AttachableScrollBar.cpp | 2 - 6 files changed, 78 insertions(+), 38 deletions(-) diff --git a/src/Experimental.h b/src/Experimental.h index a3308709a..738d5e88b 100755 --- a/src/Experimental.h +++ b/src/Experimental.h @@ -170,7 +170,7 @@ // #define EXPERIMENTAL_NYQUIST_SPLIT_CONTROL // Paul Licameli (PRL) 16 Apr 2015 -//Support for scrubbing in the AudioIO engine, without calls to it +// Support for scrubbing in the AudioIO engine, without calls to it #define EXPERIMENTAL_SCRUBBING_SUPPORT // The following enable parts of the scrubbing user interface. @@ -181,6 +181,10 @@ // You must define EXPERIMENTAL_SCRUBBING_BASIC if you enable this: #define EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL +// Paul Licameli (PRL) 24 May 2015 +// Allow scrolling up to one half of a screenful beyond either end of the project. +// This allows smooth-scrolling scrub to work more reasonably at the ends. +#define EXPERIMENTAL_SCROLLING_LIMITS // Define to include crash reporting #define EXPERIMENTAL_CRASH_REPORT diff --git a/src/Printing.cpp b/src/Printing.cpp index bce31eef9..9e170251d 100644 --- a/src/Printing.cpp +++ b/src/Printing.cpp @@ -86,7 +86,6 @@ bool AudacityPrintout::OnPrintPage(int WXUNUSED(page)) viewInfo.h = 0.0; viewInfo.screen = mTracks->GetEndTime() - viewInfo.h; viewInfo.total = viewInfo.screen; - viewInfo.zoom = viewInfo.lastZoom = width / viewInfo.screen; int y = rulerPageHeight; TrackListIterator iter(mTracks); diff --git a/src/Project.cpp b/src/Project.cpp index d0617c4ee..ef66ccce5 100755 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -174,17 +174,17 @@ ODLock *AudacityProject::msAllProjectDeleteMutex = new ODLock(); const int sbarSpaceWidth = 15; const int sbarControlWidth = 16; const int sbarExtraLen = 1; -const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs +const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs -- in pixels #elif defined(__WXMSW__) const int sbarSpaceWidth = 16; const int sbarControlWidth = 16; const int sbarExtraLen = 0; -const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs +const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs -- in pixels #else // wxGTK, wxMOTIF, wxX11 const int sbarSpaceWidth = 15; const int sbarControlWidth = 15; const int sbarExtraLen = 0; -const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs +const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs -- in pixels #include "Theme.h" #include "AllThemeResources.h" #endif @@ -811,7 +811,6 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mViewInfo.screen = 1.0; mViewInfo.h = 0.0; mViewInfo.zoom = 44100.0 / 512.0; - mViewInfo.lastZoom = mViewInfo.zoom; // Vertical scrollbar mViewInfo.track = NULL; @@ -1461,7 +1460,13 @@ void AudacityProject::OnScrollRightButton(wxScrollEvent & event) // void AudacityProject::TP_ScrollWindow(double scrollto) { - int pos = (int) (scrollto * mViewInfo.zoom * mViewInfo.sbarScale); + double timeOffset = 0; +#ifdef EXPERIMENTAL_SCROLLING_LIMITS + timeOffset = mViewInfo.screen / 2.0; +#endif + int pos = (int) ( + (scrollto + timeOffset) * mViewInfo.zoom * mViewInfo.sbarScale + ); int max = mHsbar->GetRange() - mHsbar->GetThumbSize(); if (pos > max) @@ -1520,18 +1525,29 @@ void AudacityProject::FixScrollbars() int panelWidth, panelHeight; mTrackPanel->GetTracksUsableArea(&panelWidth, &panelHeight); - // Add 1/4 of a screen of blank space to the end of the longest track mViewInfo.screen = ((double) panelWidth) / mViewInfo.zoom; + double additional, lowerBound; +#ifdef EXPERIMENTAL_SCROLLING_LIMITS + // Add 1/2 of a screen of blank space to the end + // and another 1/2 screen before the beginning + // so that any point within the union of the selection and the track duration + // may be scrolled to the midline. + additional = mViewInfo.screen; + lowerBound = - additional / 2.0; +#else + // Formerly just added 1/4 screen at the end + additional = mViewInfo.screen / 4.0; + lowerBound = 0.0; +#endif double LastTime = - wxMax( mTracks->GetEndTime(), mViewInfo.selectedRegion.t1() ); - mViewInfo.total = LastTime + mViewInfo.screen / 4; + std::max( mTracks->GetEndTime(), mViewInfo.selectedRegion.t1() ); + mViewInfo.total = LastTime + additional; // Don't remove time from total that's still on the screen - if (mViewInfo.h > mViewInfo.total - mViewInfo.screen) { - mViewInfo.total = mViewInfo.h + mViewInfo.screen; - } - if (mViewInfo.h < 0.0) { - mViewInfo.h = 0.0; + mViewInfo.total = std::max(mViewInfo.total, mViewInfo.h + mViewInfo.screen); + + if (mViewInfo.h < lowerBound) { + mViewInfo.h = lowerBound; rescroll = true; } @@ -1603,13 +1619,21 @@ void AudacityProject::FixScrollbars() else mViewInfo.sbarScale = 1.0; // use maximum resolution - int scaledSbarH = (int)(mViewInfo.sbarH * mViewInfo.sbarScale); - int scaledSbarScreen = (int)(mViewInfo.sbarScreen * mViewInfo.sbarScale); - int scaledSbarTotal = (int)(mViewInfo.sbarTotal * mViewInfo.sbarScale); + { + int scaledSbarH = (int)(mViewInfo.sbarH * mViewInfo.sbarScale); + int scaledSbarScreen = (int)(mViewInfo.sbarScreen * mViewInfo.sbarScale); + int scaledSbarTotal = (int)(mViewInfo.sbarTotal * mViewInfo.sbarScale); + int offset; +#ifdef EXPERIMENTAL_SCROLLING_LIMITS + offset = scaledSbarScreen / 2; +#else + offset = 0; +#endif - mHsbar->SetScrollbar(scaledSbarH, scaledSbarScreen, scaledSbarTotal, - scaledSbarScreen, TRUE); - mHsbar->Refresh(); + mHsbar->SetScrollbar(scaledSbarH + offset, scaledSbarScreen, scaledSbarTotal, + scaledSbarScreen, TRUE); + mHsbar->Refresh(); + } // Vertical scrollbar mVsbar->SetScrollbar(mViewInfo.vpos / mViewInfo.scrollStep, @@ -1617,7 +1641,6 @@ void AudacityProject::FixScrollbars() totalHeight / mViewInfo.scrollStep, panelHeight / mViewInfo.scrollStep, TRUE); mVsbar->Refresh(); - mViewInfo.lastZoom = mViewInfo.zoom; if (refresh || (rescroll && mViewInfo.screen < mViewInfo.total)) { mTrackPanel->Refresh(false); @@ -1796,16 +1819,26 @@ void AudacityProject::OnScroll(wxScrollEvent & WXUNUSED(event)) { wxInt64 hlast = mViewInfo.sbarH; - mViewInfo.sbarH = (wxInt64) - (mHsbar->GetThumbPosition() / mViewInfo.sbarScale); + double lowerBound; + wxInt64 offset; +#ifdef EXPERIMENTAL_SCROLLING_LIMITS + offset = (0.5 + (mViewInfo.zoom * mViewInfo.screen / 2.0)); + lowerBound = -mViewInfo.screen / 2.0; +#else + offset = 0.0; + lowerBound = 0.0; +#endif + mViewInfo.sbarH = + (wxInt64)(mHsbar->GetThumbPosition() / mViewInfo.sbarScale) - offset; if (mViewInfo.sbarH != hlast) { mViewInfo.h = mViewInfo.sbarH / mViewInfo.zoom; if (mViewInfo.h > mViewInfo.total - mViewInfo.screen) mViewInfo.h = mViewInfo.total - mViewInfo.screen; - if (mViewInfo.h < 0.0) - mViewInfo.h = 0.0; + + if (mViewInfo.h < lowerBound) + mViewInfo.h = lowerBound; } int lastv = mViewInfo.vpos; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 559380bce..5aac0f745 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -1489,7 +1489,11 @@ void TrackPanel::OnPaint(wxPaintEvent & /* event */) // the drawing of the tracks. This prevents flashing of the indicator // at higher magnifications, and keeps the green line still in the middle. indicator = gAudioIO->GetStreamTime(); - mViewInfo->h = std::max(0.0, indicator - mViewInfo->screen / 2.0); + mViewInfo->h = indicator - mViewInfo->screen / 2.0; +#if !defined(EXPERIMENTAL_SCROLLING_LIMITS) + // Can't scroll too far left + mViewInfo->h = std::max(0.0, mViewInfo->h); +#endif } #endif @@ -2409,9 +2413,9 @@ bool TrackPanel::ContinueScrubbing(wxCoord position, bool maySkip) { wxCoord leadPosition = position; double newEnd = - std::max(0.0, - std::min(PositionToTime(leadPosition, GetLeftOffset()), - mTracks->GetEndTime() + std::max(0.0, + std::min(PositionToTime(leadPosition, GetLeftOffset()), + mTracks->GetEndTime() )); if (maySkip) @@ -2710,7 +2714,7 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event, if (startNewSelection) { // mouse is not at an edge, but after // quantization, we could be indicating the selection edge mSelStartValid = true; - mSelStart = PositionToTime(event.m_x, r.x); + mSelStart = std::max(0.0, PositionToTime(event.m_x, r.x)); mStretchStart = nt->NearestBeatTime(mSelStart, ¢erBeat); if (within(qBeat0, centerBeat, 0.1)) { mListener->TP_DisplayStatusMessage( @@ -2801,8 +2805,10 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event, void TrackPanel::StartSelection(int mouseXCoordinate, int trackLeftEdge) { mSelStartValid = true; - mSelStart = mViewInfo->h + ((mouseXCoordinate - trackLeftEdge) - / mViewInfo->zoom); + mSelStart = + std::max(0.0, + mViewInfo->h + ((mouseXCoordinate - trackLeftEdge) + / mViewInfo->zoom)); double s = mSelStart; @@ -2832,7 +2838,7 @@ void TrackPanel::ExtendSelection(int mouseXCoordinate, int trackLeftEdge, // Must be dragging frequency bounds only. return; - double selend = PositionToTime(mouseXCoordinate, trackLeftEdge); + double selend = std::max(0.0, PositionToTime(mouseXCoordinate, trackLeftEdge)); clip_bottom(selend, 0.0); double origSel0, origSel1; @@ -3264,7 +3270,7 @@ void TrackPanel::Stretch(int mouseXCoordinate, int trackLeftEdge, } NoteTrack *pNt = (NoteTrack *) pTrack; - double moveto = PositionToTime(mouseXCoordinate, trackLeftEdge); + double moveto = std::max(0.0, PositionToTime(mouseXCoordinate, trackLeftEdge)); // check to make sure tempo is not higher than 20 beats per second // (In principle, tempo can be higher, but not infinity.) diff --git a/src/ViewInfo.h b/src/ViewInfo.h index 0f2316f39..0a6e069e3 100644 --- a/src/ViewInfo.h +++ b/src/ViewInfo.h @@ -33,7 +33,6 @@ struct ViewInfo { double screen; // screen width in secs double total; // total width in secs double zoom; // pixels per second - double lastZoom; // Current horizontal scroll bar positions, in pixels wxInt64 sbarH; @@ -43,6 +42,7 @@ struct ViewInfo { // Internal wxScrollbar positions are only int in range, so multiply // the above values with the following member to get the actual // scroll bar positions as reported by the horizontal wxScrollbar's members + // i.e. units are scroll increments per pixel double sbarScale; // Vertical scroll step diff --git a/src/widgets/AttachableScrollBar.cpp b/src/widgets/AttachableScrollBar.cpp index 5e3221b12..241201254 100644 --- a/src/widgets/AttachableScrollBar.cpp +++ b/src/widgets/AttachableScrollBar.cpp @@ -64,8 +64,6 @@ void AttachableScrollBar::SetScrollBarFromViewInfo() SetScrollbar(mViewInfo.sbarH, mViewInfo.sbarScreen, mViewInfo.sbarTotal, mViewInfo.sbarScreen, TRUE); - - mViewInfo.lastZoom = mViewInfo.zoom; } // Essentially an int to float conversion.