Audacity  2.2.2
PlayIndicatorOverlay.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 PlayIndicatorOverlay.cpp
6 
7 Paul Licameli split from TrackPanel.cpp
8 
9 **********************************************************************/
10 
11 #include "../../Audacity.h"
12 #include "PlayIndicatorOverlay.h"
13 
14 #include "../../AColor.h"
15 #include "../../AudioIO.h"
16 #include "../../Project.h"
17 #include "../../TrackPanel.h"
18 #include "../../TrackPanelCell.h"
19 #include "../../TrackPanelCellIterator.h"
20 #include "../../widgets/Ruler.h"
21 #include "Scrubbing.h"
22 
23 #include <wx/dc.h>
24 
25 #include <algorithm>
26 
27 namespace {
28  template < class LOW, class MID, class HIGH >
29  bool between_incexc(LOW l, MID m, HIGH h)
30  {
31  return (m >= l && m < h);
32  }
33 
34  enum { IndicatorMediumWidth = 13 };
35 }
36 
38 : mProject(project)
39 , mIsMaster(isMaster)
40 {
41 }
42 
44 {
45 }
46 
47 std::pair<wxRect, bool> PlayIndicatorOverlayBase::DoGetRectangle(wxSize size)
48 {
49  auto width = mIsMaster ? 1 : IndicatorMediumWidth;
50 
51  // May be excessive height, but little matter
52  wxRect rect(mLastIndicatorX - width / 2, 0, width, size.GetHeight());
53  return {
54  rect,
57  };
58 }
59 
60 
62 {
63  // Set play/record color
64  bool rec = gAudioIO->IsCapturing();
65  AColor::IndicatorColor(&dc, !rec);
66 
67  if (mIsMaster
69  // Detect transition to recording during punch and roll; make ruler
70  // change its button color too
71  const auto ruler = mProject->GetRulerPanel();
72  ruler->UpdateButtonStates();
73  ruler->Refresh();
74  }
76 
78  if (!between_incexc(0, mLastIndicatorX, dc.GetSize().GetWidth()))
79  return;
80 
81  if(auto tp = dynamic_cast<TrackPanel*>(&panel)) {
82  wxASSERT(mIsMaster);
83 
84  // Draw indicator in all visible tracks
85  for ( const auto &data : tp->Cells() )
86  {
87  Track *const pTrack = dynamic_cast<Track*>(data.first.get());
88  if (!pTrack)
89  continue;
90 
91  // Don't draw the indicator in label tracks
92  if (pTrack->GetKind() == Track::Label)
93  {
94  continue;
95  }
96 
97  // Draw the NEW indicator in its NEW location
98  // AColor::Line includes both endpoints so use GetBottom()
99  const wxRect &rect = data.second;
100  AColor::Line(dc,
102  rect.GetTop(),
104  rect.GetBottom());
105  }
106  }
107  else if(auto ruler = dynamic_cast<AdornedRulerPanel*>(&panel)) {
108  wxASSERT(!mIsMaster);
109 
110  ruler->DoDrawIndicator(&dc, mLastIndicatorX, !rec, IndicatorMediumWidth, false, false);
111  }
112  else
113  wxASSERT(false);
114 }
115 
117 : PlayIndicatorOverlayBase(project, true)
118 {
119  mProject->Bind(EVT_TRACK_PANEL_TIMER,
121  this);
122 }
123 
125 {
126  if (mPartner) {
127  auto ruler = mProject->GetRulerPanel();
128  if(ruler)
129  ruler->RemoveOverlay(mPartner.get());
130  }
131 }
132 
133 void PlayIndicatorOverlay::OnTimer(wxCommandEvent &event)
134 {
135  // Let other listeners get the notification
136  event.Skip();
137 
138  // Ensure that there is an overlay attached to the ruler
139  if (!mPartner) {
140  auto ruler = mProject->GetRulerPanel();
141  if (ruler) {
142  mPartner = std::make_unique<PlayIndicatorOverlayBase>(mProject, false);
143  ruler->AddOverlay(mPartner.get());
144  }
145  }
146 
147  auto trackPanel = mProject->GetTrackPanel();
148  int width;
149  trackPanel->GetTracksUsableArea(&width, nullptr);
150 
151  if (!mProject->IsAudioActive()) {
152  mNewIndicatorX = -1;
153  mNewIsCapturing = false;
154  const auto &scrubber = mProject->GetScrubber();
155  if (scrubber.HasMark()) {
156  auto position = scrubber.GetScrubStartPosition();
157  const auto offset = trackPanel->GetLeftOffset();
158  if(position >= trackPanel->GetLeftOffset() &&
159  position < offset + width)
160  mNewIndicatorX = position;
161  }
162  }
163  else {
164  ViewInfo &viewInfo = mProject->GetViewInfo();
165 
166  // Calculate the horizontal position of the indicator
167  const double playPos = viewInfo.mRecentStreamTime;
168 
170  const Mode mode = mProject->GetPlaybackScroller().GetMode();
171  const bool pinned = ( mode == Mode::Pinned || mode == Mode::Right );
172 
173  // Use a small tolerance to avoid flicker of play head pinned all the way
174  // left or right
175  const auto tolerance = pinned ? 1.5 * kTimerInterval / 1000.0 : 0;
176  bool onScreen = playPos >= 0.0 &&
177  between_incexc(viewInfo.h - tolerance,
178  playPos,
179  mProject->GetScreenEndTime() + tolerance);
180 
181  // This displays the audio time, too...
183 
184  // BG: Scroll screen if option is set
185  if( viewInfo.bUpdateTrackIndicator &&
186  playPos >= 0 && !onScreen ) {
187  // msmeyer: But only if not playing looped or in one-second mode
188  // PRL: and not scrolling with play/record head fixed
189  if (!pinned &&
192  !gAudioIO->IsPaused())
193  {
194  auto newPos = playPos;
195  if (playPos < viewInfo.h) {
196  // This is possible when scrubbing backwards.
197  // We want to page leftward by (at least) a whole screen, not
198  // just a little bit equal to the scrubbing poll interval
199  // duration.
200  newPos = viewInfo.OffsetTimeByPixels( newPos, -width );
201  newPos = std::max( newPos, mProject->ScrollingLowerBoundTime() );
202  }
203  mProject->TP_ScrollWindow(newPos);
204  // Might yet be off screen, check it
205  onScreen = playPos >= 0.0 &&
206  between_incexc(viewInfo.h,
207  playPos,
209  }
210  }
211 
212  // Always update scrollbars even if not scrolling the window. This is
213  // important when NEW audio is recorded, because this can change the
214  // length of the project and therefore the appearance of the scrollbar.
216 
217  if (onScreen)
218  mNewIndicatorX = viewInfo.TimeToPosition(playPos, trackPanel->GetLeftOffset());
219  else
220  mNewIndicatorX = -1;
221 
223  }
224 
225  if(mPartner)
226  mPartner->Update(mNewIndicatorX);
227 }
bool IsPaused() const
Find out if playback / recording is currently paused.
Definition: AudioIO.cpp:2713
bool bUpdateTrackIndicator
Definition: ViewInfo.h:182
ViewInfo is used mainly to hold the zooming, selection and scroll information. It also has some statu...
Definition: ViewInfo.h:141
Scrubber & GetScrubber()
Definition: Project.h:805
std::unique_ptr< PlayIndicatorOverlayBase > mPartner
bool IsCapturing() const
Definition: AudioIO.cpp:5704
double OffsetTimeByPixels(double time, wxInt64 offset, bool ignoreFisheye=false) const
Definition: ViewInfo.h:77
PlayIndicatorOverlayBase(AudacityProject *project, bool isMaster)
bool RemoveOverlay(Overlay *pOverlay)
double h
Definition: ViewInfo.h:47
void TP_RedrawScrollbars() override
Definition: Project.cpp:5488
virtual int GetKind() const
Definition: Track.h:338
AudacityProject *const mProject
static void IndicatorColor(wxDC *dc, bool bIsNotRecording)
Definition: AColor.cpp:367
void GetTracksUsableArea(int *width, int *height) const
Definition: TrackPanel.cpp:414
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:176
void TP_ScrollWindow(double scrollto) override
Definition: Project.cpp:1890
const int kTimerInterval
double ScrollingLowerBoundTime() const
Definition: Project.cpp:1851
AdornedRulerPanel * GetRulerPanel()
Definition: Project.cpp:1471
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:102
wxInt64 TimeToPosition(double time, wxInt64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ViewInfo.cpp:59
bool IsAudioActive() const
Definition: Project.cpp:1486
PlayIndicatorOverlay(AudacityProject *project)
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
PlayMode mLastPlayMode
Definition: Project.h:559
std::pair< wxRect, bool > DoGetRectangle(wxSize size) override
AudioIO * gAudioIO
Definition: AudioIO.cpp:483
PlaybackScroller & GetPlaybackScroller()
Definition: Project.h:836
double GetScreenEndTime() const
Definition: Menus.cpp:6799
double mRecentStreamTime
Definition: ViewInfo.h:189
void OnTimer(wxCommandEvent &event)
TrackPanel * GetTrackPanel()
Definition: Project.h:308
void TP_DisplaySelection() override
Definition: Project.cpp:5417
wxCoord GetScrubStartPosition() const
Definition: Scrubbing.h:92
const ViewInfo & GetViewInfo() const
Definition: Project.h:208
void Draw(OverlayPanel &panel, wxDC &dc) override
void UpdateButtonStates()
Definition: Ruler.cpp:3284