1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-16 08:09:32 +02:00

Reimplement the play/record indicator in the ruler as an overlay...

... fixing the lag between the green line and the triangle for scrolling play
This commit is contained in:
Paul Licameli 2016-05-08 16:54:02 -04:00
parent d8e42b0af4
commit f9dd6b4066
4 changed files with 120 additions and 109 deletions

View File

@ -30,30 +30,26 @@ namespace {
{
return (m >= l && m < h);
}
enum { IndicatorMediumWidth = 13 };
}
PlayIndicatorOverlay::PlayIndicatorOverlay(AudacityProject *project)
: mProject(project)
, mLastIndicatorX(-1)
, mNewIndicatorX(-1)
PlayIndicatorOverlayBase::PlayIndicatorOverlayBase(AudacityProject *project, bool isMaster)
: mProject(project)
, mIsMaster(isMaster)
{
mProject->Connect(EVT_TRACK_PANEL_TIMER,
wxCommandEventHandler(PlayIndicatorOverlay::OnTimer),
NULL,
this);
}
PlayIndicatorOverlay::~PlayIndicatorOverlay()
PlayIndicatorOverlayBase::~PlayIndicatorOverlayBase()
{
mProject->Disconnect(EVT_TRACK_PANEL_TIMER,
wxCommandEventHandler(PlayIndicatorOverlay::OnTimer),
NULL,
this);
}
std::pair<wxRect, bool> PlayIndicatorOverlay::DoGetRectangle(wxSize size)
std::pair<wxRect, bool> PlayIndicatorOverlayBase::DoGetRectangle(wxSize size)
{
wxRect rect(mLastIndicatorX, 0, 1, size.GetHeight());
auto width = mIsMaster ? 1 : IndicatorMediumWidth;
// May be excessive height, but little matter
wxRect rect(mLastIndicatorX - width / 2, 0, width, size.GetHeight());
return std::make_pair(
rect,
mLastIndicatorX != mNewIndicatorX
@ -61,56 +57,75 @@ std::pair<wxRect, bool> PlayIndicatorOverlay::DoGetRectangle(wxSize size)
}
void PlayIndicatorOverlay::Draw(OverlayPanel &panel, wxDC &dc)
void PlayIndicatorOverlayBase::Draw(OverlayPanel &panel, wxDC &dc)
{
TrackPanel &tp = static_cast<TrackPanel&>(panel);
TrackPanelCellIterator begin(&tp, true);
TrackPanelCellIterator end(&tp, false);
// Set play/record color
bool rec = (gAudioIO->GetNumCaptureChannels() > 0);
AColor::IndicatorColor(&dc, !rec);
mLastIndicatorX = mNewIndicatorX;
if (!between_incexc(0, mLastIndicatorX, dc.GetSize().GetWidth()))
return;
const ZoomInfo &viewInfo = mProject->GetZoomInfo();
TrackPanel *const trackPanel = mProject->GetTrackPanel();
if(auto tp = dynamic_cast<TrackPanel*>(&panel)) {
wxASSERT(mIsMaster);
double pos = viewInfo.PositionToTime(mLastIndicatorX, trackPanel->GetLeftOffset());
TrackPanelCellIterator begin(tp, true);
TrackPanelCellIterator end(tp, false);
// Set play/record color
bool rec = (gAudioIO->GetNumCaptureChannels() > 0);
AColor::IndicatorColor(&dc, !rec);
mProject->GetRulerPanel()->DrawIndicator(pos, rec);
// Draw indicator in all visible tracks
for (; begin != end; ++begin)
{
TrackPanelCellIterator::value_type data(*begin);
Track *const pTrack = data.first;
if (!pTrack)
continue;
// Don't draw the indicator in label tracks
if (pTrack->GetKind() == Track::Label)
// Draw indicator in all visible tracks
for (; begin != end; ++begin)
{
continue;
}
TrackPanelCellIterator::value_type data(*begin);
Track *const pTrack = data.first;
if (!pTrack)
continue;
// Draw the NEW indicator in its NEW location
// AColor::Line includes both endpoints so use GetBottom()
const wxRect &rect = data.second;
AColor::Line(dc,
mLastIndicatorX,
rect.GetTop(),
mLastIndicatorX,
rect.GetBottom());
// Don't draw the indicator in label tracks
if (pTrack->GetKind() == Track::Label)
{
continue;
}
// Draw the NEW indicator in its NEW location
// AColor::Line includes both endpoints so use GetBottom()
const wxRect &rect = data.second;
AColor::Line(dc,
mLastIndicatorX,
rect.GetTop(),
mLastIndicatorX,
rect.GetBottom());
}
}
else if(auto ruler = dynamic_cast<AdornedRulerPanel*>(&panel)) {
wxASSERT(!mIsMaster);
ruler->DoDrawIndicator(&dc, mLastIndicatorX, !rec, IndicatorMediumWidth, false);
}
else
wxASSERT(false);
}
void PlayIndicatorOverlay::Erase(wxDC &dc, wxDC &src)
PlayIndicatorOverlay::PlayIndicatorOverlay(AudacityProject *project)
: PlayIndicatorOverlayBase(project, true)
{
Overlay::Erase(dc, src);
mProject->GetRulerPanel()->ClearIndicator();
mProject->Connect(EVT_TRACK_PANEL_TIMER,
wxCommandEventHandler(PlayIndicatorOverlay::OnTimer),
NULL,
this);
}
PlayIndicatorOverlay::~PlayIndicatorOverlay()
{
if (mPartner) {
auto ruler = mProject->GetRulerPanel();
if(ruler)
ruler->RemoveOverlay(mPartner.get());
}
mProject->Disconnect(EVT_TRACK_PANEL_TIMER,
wxCommandEventHandler(PlayIndicatorOverlay::OnTimer),
NULL,
this);
}
void PlayIndicatorOverlay::OnTimer(wxCommandEvent &event)
@ -118,6 +133,15 @@ void PlayIndicatorOverlay::OnTimer(wxCommandEvent &event)
// Let other listeners get the notification
event.Skip();
// Ensure that there is an overlay attached to the ruler
if (!mPartner) {
auto ruler = mProject->GetRulerPanel();
if (ruler) {
mPartner = std::make_unique<PlayIndicatorOverlayBase>(mProject, false);
ruler->AddOverlay(mPartner.get());
}
}
if (!mProject->IsAudioActive()) {
const auto &scrubber = mProject->GetScrubber();
if (scrubber.HasStartedScrubbing())
@ -158,4 +182,7 @@ void PlayIndicatorOverlay::OnTimer(wxCommandEvent &event)
mNewIndicatorX = viewInfo.TimeToPosition(playPos, mProject->GetTrackPanel()->GetLeftOffset());
}
if(mPartner)
mPartner->Update(mNewIndicatorX);
}

View File

@ -12,28 +12,44 @@ Paul Licameli split from TrackPanel.cpp
#define __AUDACITY_PLAY_INDICATOR_OVERLAY__
#include <wx/event.h>
#include "../../MemoryX.h"
#include "../../widgets/Overlay.h"
class AudacityProject;
class PlayIndicatorOverlay final : public wxEvtHandler, public Overlay
// Common class for overlaying track panel or ruler
class PlayIndicatorOverlayBase : public wxEvtHandler, public Overlay
{
public:
PlayIndicatorOverlayBase(AudacityProject *project, bool isMaster);
virtual ~PlayIndicatorOverlayBase();
void Update(int newIndicatorX) { mNewIndicatorX = newIndicatorX; }
private:
std::pair<wxRect, bool> DoGetRectangle(wxSize size) override;
void Draw(OverlayPanel &panel, wxDC &dc) override;
protected:
AudacityProject *const mProject;
const bool mIsMaster;
int mLastIndicatorX { -1 };
int mNewIndicatorX { -1 };
};
// Master object for track panel, creates the other object for the ruler
class PlayIndicatorOverlay final : public PlayIndicatorOverlayBase
{
public:
PlayIndicatorOverlay(AudacityProject *project);
virtual ~PlayIndicatorOverlay();
private:
std::pair<wxRect, bool> DoGetRectangle(wxSize size) override;
void Draw(OverlayPanel &panel, wxDC &dc) override;
void Erase(wxDC &dc, wxDC &src) override;
void OnTimer(wxCommandEvent &event);
AudacityProject *mProject;
int mLastIndicatorX;
int mNewIndicatorX;
std::unique_ptr<PlayIndicatorOverlayBase> mPartner;
};
#endif

View File

@ -1813,9 +1813,10 @@ AdornedRulerPanel::AdornedRulerPanel(AudacityProject* parent,
mLeftOffset = 0;
mIndTime = -1;
mIndType = -1;
mQuickPlayInd = false;
mLastQuickPlayX = -1;
mPlayRegionStart = -1;
mPlayRegionLock = false;
mPlayRegionEnd = -1;
@ -2131,12 +2132,6 @@ void AdornedRulerPanel::OnPaint(wxPaintEvent & WXUNUSED(evt))
DoDrawMarks(&backDC, true);
if (mIndType >= 0)
{
const bool scrub = mProject->GetScrubber().HasStartedScrubbing();
DoDrawIndicator(&backDC, mIndTime, mIndType != 0, IndicatorMediumWidth, false);
}
DoDrawPlayRegion(&backDC);
DoDrawPushbuttons(&backDC);
@ -3466,39 +3461,12 @@ void AdornedRulerPanel::SetLeftOffset(int offset)
mRuler.SetUseZoomInfo(offset, mViewInfo);
}
//
//This draws the little triangular indicator on the
//AdornedRulerPanel.
//
void AdornedRulerPanel::ClearIndicator()
{
mIndType = -1;
Refresh();
}
void AdornedRulerPanel::DrawIndicator( double time, bool rec )
{
mIndTime = time;
if (mIndTime < 0)
{
ClearIndicator();
return;
}
mIndType = ( rec ? 0 : 1 );
Refresh();
}
// Draws the play/recording position indicator.
void AdornedRulerPanel::DoDrawIndicator
(wxDC * dc, double time, bool playing, int width, bool scrub)
(wxDC * dc, wxCoord xx, bool playing, int width, bool scrub)
{
ADCChanger changer(dc); // Undo pen and brush changes at function exit
const int x = Time2Pos(time);
AColor::IndicatorColor( dc, playing );
wxPoint tri[ 3 ];
@ -3510,26 +3478,26 @@ void AdornedRulerPanel::DoDrawIndicator
auto yy = mShowScrubbing
? mScrubZone.y
: (mInner.GetBottom() + 1) - 1 /* bevel */ - height;
tri[ 0 ].x = x - IndicatorOffset;
tri[ 0 ].x = xx - IndicatorOffset;
tri[ 0 ].y = yy;
tri[ 1 ].x = x - IndicatorOffset;
tri[ 1 ].x = xx - IndicatorOffset;
tri[ 1 ].y = yy + height;
tri[ 2 ].x = x - IndicatorHalfWidth;
tri[ 2 ].x = xx - IndicatorHalfWidth;
tri[ 2 ].y = yy + height / 2;
dc->DrawPolygon( 3, tri );
tri[ 0 ].x = tri[ 1 ].x = x + IndicatorOffset;
tri[ 2 ].x = x + IndicatorHalfWidth;
tri[ 0 ].x = tri[ 1 ].x = xx + IndicatorOffset;
tri[ 2 ].x = xx + IndicatorHalfWidth;
dc->DrawPolygon( 3, tri );
}
else {
// Down pointing triangle
auto height = IndicatorHeightForWidth(width);
const int IndicatorHalfWidth = width / 2;
tri[ 0 ].x = x - IndicatorHalfWidth;
tri[ 0 ].x = xx - IndicatorHalfWidth;
tri[ 0 ].y = mInner.y;
tri[ 1 ].x = x + IndicatorHalfWidth;
tri[ 1 ].x = xx + IndicatorHalfWidth;
tri[ 1 ].y = mInner.y;
tri[ 2 ].x = x;
tri[ 2 ].x = xx;
tri[ 2 ].y = mInner.y + height;
dc->DrawPolygon( 3, tri );
}
@ -3591,7 +3559,7 @@ void AdornedRulerPanel::DrawQuickPlayIndicator(wxDC * dc, bool repainting)
auto scrub = mPrevZone == StatusChoice::EnteringScrubZone ||
mProject->GetScrubber().HasStartedScrubbing();
auto width = scrub ? IndicatorBigWidth() : IndicatorSmallWidth;
DoDrawIndicator(dc, mQuickPlayPos, true, width, scrub);
DoDrawIndicator(dc, Time2Pos(mQuickPlayPos), true, width, scrub);
}
void AdornedRulerPanel::SetPlayRegion(double playRegionStart,

View File

@ -299,9 +299,7 @@ public:
void SetLeftOffset(int offset);
void DrawIndicator(double time, bool rec);
void DrawSelection();
void ClearIndicator();
void SetPlayRegion(double playRegionStart, double playRegionEnd);
void ClearPlayRegion();
@ -380,7 +378,10 @@ private:
void DoDrawEdge(wxDC *dc);
void DoDrawMarks(wxDC * dc, bool /*text */ );
void DoDrawSelection(wxDC * dc);
void DoDrawIndicator(wxDC * dc, double time, bool playing, int width, bool scrub);
public:
void DoDrawIndicator(wxDC * dc, wxCoord xx, bool playing, int width, bool scrub);
private:
void DoEraseIndicator(wxDC *dc, int x);
QuickPlayIndicatorOverlay *GetOverlay();
void DrawQuickPlayIndicator(wxDC * dc /*NULL to DELETE old only*/, bool repainting = false);
@ -440,7 +441,6 @@ private:
int mLeftOffset; // Number of pixels before we hit the 'zero position'.
int mIndType; // -1 = No indicator, 0 = Record, 1 = Play
double mIndTime;
bool mQuickPlayInd;
double mQuickPlayPos;