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:
parent
d8e42b0af4
commit
f9dd6b4066
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user