mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-17 00:20:06 +02:00
Draw scrub speed like cursor or indicator: without a full refresh.
This commit is contained in:
parent
9ba6e03bd4
commit
4cc064df8e
@ -1047,40 +1047,7 @@ void TrackPanel::OnTimer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
||||||
// Call ContinueScrubbing() here rather than in SelectionHandleDrag()
|
TimerUpdateScrubbing();
|
||||||
// so that even without drag events, we can instruct the play head to
|
|
||||||
// keep approaching the mouse cursor, when its maximum speed is limited.
|
|
||||||
|
|
||||||
// Thus scrubbing relies mostly on periodic polling of mouse and keys,
|
|
||||||
// not event notifications. But there are a few event handlers that
|
|
||||||
// leave messages for this routine, in mScrubSeekPress and in mScrubHasFocus.
|
|
||||||
if (IsScrubbing())
|
|
||||||
{
|
|
||||||
wxMouseState state(::wxGetMouseState());
|
|
||||||
wxCoord position = state.GetX();
|
|
||||||
const bool seek = mScrubSeekPress || PollIsSeeking();
|
|
||||||
ScreenToClient(&position, NULL);
|
|
||||||
if (ContinueScrubbing(position, mScrubHasFocus, seek))
|
|
||||||
mScrubSeekPress = false;
|
|
||||||
// else, if seek requested, try again at a later time when we might
|
|
||||||
// enqueue a long enough stutter
|
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
|
||||||
if (mSmoothScrollingScrub)
|
|
||||||
// Redraw with every timer tick, to keep the indicator centered.
|
|
||||||
Refresh(false);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (mScrubSpeedDisplayCountdown > 0) {
|
|
||||||
--mScrubSpeedDisplayCountdown;
|
|
||||||
if (mScrubSpeedDisplayCountdown == kOneSecondCountdown ||
|
|
||||||
mScrubSpeedDisplayCountdown == 0)
|
|
||||||
// Show or hide the maximum speed.
|
|
||||||
Refresh(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Check whether we were playing or recording, but the stream has stopped.
|
// Check whether we were playing or recording, but the stream has stopped.
|
||||||
@ -7303,21 +7270,141 @@ void TrackPanel::DrawEverythingElse(wxDC * dc,
|
|||||||
AColor::Line(*dc, (int)mSnapRight, 0, mSnapRight, 30000);
|
AColor::Line(*dc, (int)mSnapRight, 0, mSnapRight, 30000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
|
||||||
if (IsScrubbing())
|
|
||||||
DrawScrubSpeed(*dc);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
||||||
void TrackPanel::DrawScrubSpeed(wxDC &dc)
|
bool TrackPanel::ShouldDrawScrubSpeed()
|
||||||
{
|
{
|
||||||
// Halt scrubbing and associated display when some other program
|
return IsScrubbing() &&
|
||||||
// has focus
|
mScrubHasFocus &&
|
||||||
if (!mScrubHasFocus)
|
((!PollIsSeeking() && mScrubSpeedDisplayCountdown > 0)
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||||
|
// Draw always for scroll-scrub and for scroll-seek
|
||||||
|
|| mSmoothScrollingScrub
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::TimerUpdateScrubbing()
|
||||||
|
{
|
||||||
|
if (!IsScrubbing()) {
|
||||||
|
mNextScrubRect = wxRect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call ContinueScrubbing() here in the timer handler
|
||||||
|
// rather than in SelectionHandleDrag()
|
||||||
|
// so that even without drag events, we can instruct the play head to
|
||||||
|
// keep approaching the mouse cursor, when its maximum speed is limited.
|
||||||
|
|
||||||
|
// Thus scrubbing relies mostly on periodic polling of mouse and keys,
|
||||||
|
// not event notifications. But there are a few event handlers that
|
||||||
|
// leave messages for this routine, in mScrubSeekPress and in mScrubHasFocus.
|
||||||
|
wxMouseState state(::wxGetMouseState());
|
||||||
|
wxCoord position = state.GetX();
|
||||||
|
const bool seek = mScrubSeekPress || PollIsSeeking();
|
||||||
|
ScreenToClient(&position, NULL);
|
||||||
|
if (ContinueScrubbing(position, mScrubHasFocus, seek))
|
||||||
|
mScrubSeekPress = false;
|
||||||
|
// else, if seek requested, try again at a later time when we might
|
||||||
|
// enqueue a long enough stutter
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||||
|
if (mSmoothScrollingScrub)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (mScrubSpeedDisplayCountdown > 0)
|
||||||
|
--mScrubSpeedDisplayCountdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ShouldDrawScrubSpeed()) {
|
||||||
|
mNextScrubRect = wxRect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int panelWidth, panelHeight;
|
||||||
|
GetSize(&panelWidth, &panelHeight);
|
||||||
|
|
||||||
|
// Where's the mouse?
|
||||||
|
int xx, yy;
|
||||||
|
::wxGetMousePosition(&xx, &yy);
|
||||||
|
ScreenToClient(&xx, &yy);
|
||||||
|
|
||||||
|
const bool seeking = PollIsSeeking();
|
||||||
|
|
||||||
|
// Find the text
|
||||||
|
const double speed =
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||||
|
mSmoothScrollingScrub
|
||||||
|
? seeking
|
||||||
|
? FindSeekSpeed(mViewInfo->PositionToTime(xx, GetLeftOffset()))
|
||||||
|
: FindScrubSpeed(mViewInfo->PositionToTime(xx, GetLeftOffset()))
|
||||||
|
:
|
||||||
|
#endif
|
||||||
|
mMaxScrubSpeed;
|
||||||
|
|
||||||
|
const wxChar *format =
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||||
|
mSmoothScrollingScrub
|
||||||
|
? seeking
|
||||||
|
? wxT("%+.2fX")
|
||||||
|
: wxT("%+.2f")
|
||||||
|
:
|
||||||
|
#endif
|
||||||
|
wxT("%.2f");
|
||||||
|
|
||||||
|
mScrubSpeedText = wxString::Format(format, speed);
|
||||||
|
|
||||||
|
// Find the origin for drawing text
|
||||||
|
wxCoord width, height;
|
||||||
|
{
|
||||||
|
wxClientDC dc(this);
|
||||||
|
DisableAntialiasing(dc);
|
||||||
|
static const wxFont labelFont(24, wxSWISS, wxNORMAL, wxNORMAL);
|
||||||
|
dc.SetFont(labelFont);
|
||||||
|
dc.GetTextExtent(mScrubSpeedText, &width, &height);
|
||||||
|
}
|
||||||
|
xx = std::max(0, std::min(panelWidth - width, xx - width / 2));
|
||||||
|
|
||||||
|
// Put the text above the cursor, if it fits.
|
||||||
|
enum { offset = 20 };
|
||||||
|
yy -= height + offset;
|
||||||
|
if (yy < 0)
|
||||||
|
yy += height + 2 * offset;
|
||||||
|
yy = std::max(0, std::min(panelHeight - height, yy));
|
||||||
|
|
||||||
|
mNextScrubRect = wxRect(xx, yy, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<wxRect, bool> TrackPanel::GetScrubSpeedRectangle()
|
||||||
|
{
|
||||||
|
const bool outdated =
|
||||||
|
(mLastScrubRect != mNextScrubRect) ||
|
||||||
|
(!mLastScrubRect.IsEmpty() && !ShouldDrawScrubSpeed());
|
||||||
|
return std::make_pair(
|
||||||
|
mLastScrubRect,
|
||||||
|
outdated
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::UndrawScrubSpeed(wxDC & dc)
|
||||||
|
{
|
||||||
|
if (!mLastScrubRect.IsEmpty())
|
||||||
|
dc.Blit(
|
||||||
|
mLastScrubRect.GetX(), mLastScrubRect.GetY(),
|
||||||
|
mLastScrubRect.GetWidth(), mLastScrubRect.GetHeight(),
|
||||||
|
&mBackingDC,
|
||||||
|
mLastScrubRect.GetX(), mLastScrubRect.GetY());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::DoDrawScrubSpeed(wxDC &dc)
|
||||||
|
{
|
||||||
|
if (!ShouldDrawScrubSpeed())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mLastScrubRect = mNextScrubRect;
|
||||||
const bool seeking = PollIsSeeking();
|
const bool seeking = PollIsSeeking();
|
||||||
if (// Draw for (non-scroll) scrub, sometimes, but never for seek
|
if (// Draw for (non-scroll) scrub, sometimes, but never for seek
|
||||||
(!seeking && mScrubSpeedDisplayCountdown > 0)
|
(!seeking && mScrubSpeedDisplayCountdown > 0)
|
||||||
@ -7327,52 +7414,9 @@ void TrackPanel::DrawScrubSpeed(wxDC &dc)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
) {
|
) {
|
||||||
int panelWidth, panelHeight;
|
|
||||||
GetSize(&panelWidth, &panelHeight);
|
|
||||||
|
|
||||||
// Where's the mouse?
|
|
||||||
int xx, yy;
|
|
||||||
::wxGetMousePosition(&xx, &yy);
|
|
||||||
ScreenToClient(&xx, &yy);
|
|
||||||
|
|
||||||
// Find the text
|
|
||||||
const double speed =
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
|
||||||
mSmoothScrollingScrub
|
|
||||||
? seeking
|
|
||||||
? FindSeekSpeed(mViewInfo->PositionToTime(xx, GetLeftOffset()))
|
|
||||||
: FindScrubSpeed(mViewInfo->PositionToTime(xx, GetLeftOffset()))
|
|
||||||
:
|
|
||||||
#endif
|
|
||||||
mMaxScrubSpeed;
|
|
||||||
|
|
||||||
const wxChar *format =
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
|
||||||
mSmoothScrollingScrub
|
|
||||||
? seeking
|
|
||||||
? wxT("%+.2fX")
|
|
||||||
: wxT("%+.2f")
|
|
||||||
:
|
|
||||||
#endif
|
|
||||||
wxT("%.2f");
|
|
||||||
|
|
||||||
wxString text(wxString::Format(format, speed));
|
|
||||||
|
|
||||||
static const wxFont labelFont(24, wxSWISS, wxNORMAL, wxNORMAL);
|
static const wxFont labelFont(24, wxSWISS, wxNORMAL, wxNORMAL);
|
||||||
dc.SetFont(labelFont);
|
dc.SetFont(labelFont);
|
||||||
|
|
||||||
// Find the origin for drawing text
|
|
||||||
wxCoord width, height;
|
|
||||||
dc.GetTextExtent(text, &width, &height);
|
|
||||||
xx = std::max(0, std::min(panelWidth - width, xx - width / 2));
|
|
||||||
|
|
||||||
// Put the text above the cursor, if it fits.
|
|
||||||
enum { offset = 20 };
|
|
||||||
yy -= height + offset;
|
|
||||||
if (yy < 0)
|
|
||||||
yy += height + 2 * offset;
|
|
||||||
yy = std::max(0, std::min(panelHeight - height, yy));
|
|
||||||
|
|
||||||
// These two colors were previously saturated red and green. However
|
// These two colors were previously saturated red and green. However
|
||||||
// we have a rule to try to only use red for reserved purposes of
|
// we have a rule to try to only use red for reserved purposes of
|
||||||
// (a) Recording
|
// (a) Recording
|
||||||
@ -7386,7 +7430,7 @@ void TrackPanel::DrawScrubSpeed(wxDC &dc)
|
|||||||
#endif
|
#endif
|
||||||
dc.SetTextForeground(clrNoScroll);
|
dc.SetTextForeground(clrNoScroll);
|
||||||
|
|
||||||
DrawText(dc, text, xx, yy);
|
DrawText(dc, mScrubSpeedText, mLastScrubRect.GetX(), mLastScrubRect.GetY());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -7595,10 +7639,20 @@ void TrackPanel::DrawOverlays(bool repaint)
|
|||||||
bool isOutdated = false;
|
bool isOutdated = false;
|
||||||
|
|
||||||
// Determine which overlays are outdated.
|
// Determine which overlays are outdated.
|
||||||
enum { n_pairs = 2 };
|
enum {
|
||||||
|
n_pairs =
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
||||||
|
3
|
||||||
|
#else
|
||||||
|
2
|
||||||
|
#endif
|
||||||
|
};
|
||||||
std::pair<wxRect, bool> pairs[n_pairs] = {
|
std::pair<wxRect, bool> pairs[n_pairs] = {
|
||||||
GetIndicatorRectangle(),
|
GetIndicatorRectangle(),
|
||||||
GetCursorRectangle(),
|
GetCursorRectangle(),
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
||||||
|
GetScrubSpeedRectangle(),
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -7638,6 +7692,13 @@ void TrackPanel::DrawOverlays(bool repaint)
|
|||||||
DisableAntialiasing(dc);
|
DisableAntialiasing(dc);
|
||||||
UndrawCursor(dc);
|
UndrawCursor(dc);
|
||||||
}
|
}
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
||||||
|
if (repaint || pairs[2].second) {
|
||||||
|
wxClientDC dc(this);
|
||||||
|
DisableAntialiasing(dc);
|
||||||
|
UndrawScrubSpeed(dc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (repaint || pairs[0].second) {
|
if (repaint || pairs[0].second) {
|
||||||
wxClientDC dc(this);
|
wxClientDC dc(this);
|
||||||
@ -7649,6 +7710,13 @@ void TrackPanel::DrawOverlays(bool repaint)
|
|||||||
DisableAntialiasing(dc);
|
DisableAntialiasing(dc);
|
||||||
DoDrawCursor(dc);
|
DoDrawCursor(dc);
|
||||||
}
|
}
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
||||||
|
if (repaint || pairs[2].second) {
|
||||||
|
wxClientDC dc(this);
|
||||||
|
DisableAntialiasing(dc);
|
||||||
|
DoDrawScrubSpeed(dc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw a three-level highlight gradient around the focused track.
|
/// Draw a three-level highlight gradient around the focused track.
|
||||||
|
@ -263,6 +263,15 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel {
|
|||||||
virtual void UndrawCursor(wxDC & dc);
|
virtual void UndrawCursor(wxDC & dc);
|
||||||
virtual void DoDrawCursor(wxDC & dc);
|
virtual void DoDrawCursor(wxDC & dc);
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
||||||
|
bool ShouldDrawScrubSpeed();
|
||||||
|
virtual void TimerUpdateScrubbing();
|
||||||
|
// Second member of pair indicates whether the cursor is out of date:
|
||||||
|
virtual std::pair<wxRect, bool> GetScrubSpeedRectangle();
|
||||||
|
virtual void UndrawScrubSpeed(wxDC & dc);
|
||||||
|
virtual void DoDrawScrubSpeed(wxDC & dc);
|
||||||
|
#endif
|
||||||
|
|
||||||
virtual void ScrollDuringDrag();
|
virtual void ScrollDuringDrag();
|
||||||
|
|
||||||
// Working out where to dispatch the event to.
|
// Working out where to dispatch the event to.
|
||||||
@ -535,9 +544,6 @@ protected:
|
|||||||
const wxRect & clip);
|
const wxRect & clip);
|
||||||
virtual void DrawOutside(Track *t, wxDC *dc, const wxRect & rec,
|
virtual void DrawOutside(Track *t, wxDC *dc, const wxRect & rec,
|
||||||
const wxRect &trackRect);
|
const wxRect &trackRect);
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
|
|
||||||
void DrawScrubSpeed(wxDC &dc);
|
|
||||||
#endif
|
|
||||||
virtual void DrawZooming(wxDC* dc, const wxRect & clip);
|
virtual void DrawZooming(wxDC* dc, const wxRect & clip);
|
||||||
|
|
||||||
virtual void HighlightFocusedTrack (wxDC* dc, const wxRect &rect);
|
virtual void HighlightFocusedTrack (wxDC* dc, const wxRect &rect);
|
||||||
@ -797,6 +803,9 @@ protected:
|
|||||||
int mScrubSpeedDisplayCountdown;
|
int mScrubSpeedDisplayCountdown;
|
||||||
bool mScrubHasFocus;
|
bool mScrubHasFocus;
|
||||||
bool mScrubSeekPress;
|
bool mScrubSeekPress;
|
||||||
|
|
||||||
|
wxRect mLastScrubRect, mNextScrubRect;
|
||||||
|
wxString mScrubSpeedText;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|
||||||
|
Loading…
x
Reference in New Issue
Block a user