Audacity  3.0.3
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 
12 #include "PlayIndicatorOverlay.h"
13 
14 #include "AColor.h"
15 #include "../../AdornedRulerPanel.h"
16 #include "AllThemeResources.h"
17 #include "../../AudioIO.h"
18 #include "Project.h"
19 #include "../../ProjectAudioIO.h"
20 #include "../../ProjectAudioManager.h"
21 #include "../../ProjectWindow.h"
22 #include "Theme.h"
23 #include "../../Track.h"
24 #include "../../TrackPanel.h"
25 #include "ViewInfo.h"
26 #include "Scrubbing.h"
27 #include "TrackView.h"
28 
29 #include <wx/dc.h>
30 
31 #include <algorithm>
32 
33 namespace {
34  template < class LOW, class MID, class HIGH >
35  bool between_incexc(LOW l, MID m, HIGH h)
36  {
37  return (m >= l && m < h);
38  }
39 
40  enum { IndicatorMediumWidth = 13 };
41 }
42 
44 : mProject(project)
45 , mIsMaster(isMaster)
46 {
47 }
48 
50 {
51 }
52 
54 {
55  return 10;
56 }
57 
58 namespace {
59 // Returns the appropriate bitmap, and panel-relative coordinates for its
60 // upper left corner.
61 std::pair< wxPoint, wxBitmap > GetIndicatorBitmap( AudacityProject &project,
62  wxCoord xx, bool playing)
63 {
64  bool pinned = Scrubber::Get( project ).IsTransportingPinned();
65  wxBitmap & bmp = theTheme.Bitmap( pinned ?
66  (playing ? bmpPlayPointerPinned : bmpRecordPointerPinned) :
67  (playing ? bmpPlayPointer : bmpRecordPointer)
68  );
69  const int IndicatorHalfWidth = bmp.GetWidth() / 2;
70  return {
71  { xx - IndicatorHalfWidth - 1,
72  AdornedRulerPanel::Get(project).GetInnerRect().y },
73  bmp
74  };
75 }
76 }
77 
78 std::pair<wxRect, bool> PlayIndicatorOverlayBase::DoGetRectangle(wxSize size)
79 {
80  wxCoord width = 1, xx = mLastIndicatorX;
81 
82  if ( !mIsMaster ) {
83  auto gAudioIO = AudioIO::Get();
84  bool rec = gAudioIO->IsCapturing();
85  auto pair = GetIndicatorBitmap( *mProject, xx, !rec );
86  xx = pair.first.x;
87  width = pair.second.GetWidth();
88  }
89 
90  // May be excessive height, but little matter
91  wxRect rect( xx, 0, width, size.GetHeight());
92  return {
93  rect,
96  };
97 }
98 
99 
101 {
102  // Set play/record color
103  auto gAudioIO = AudioIO::Get();
104  bool rec = gAudioIO->IsCapturing();
105  AColor::IndicatorColor(&dc, !rec);
106 
107  if (mIsMaster
109  // Detect transition to recording during punch and roll; make ruler
110  // change its button color too
112  ruler.UpdateButtonStates();
113  ruler.Refresh();
114  }
116 
118  if (!between_incexc(0, mLastIndicatorX, dc.GetSize().GetWidth()))
119  return;
120 
121  if(auto tp = dynamic_cast<TrackPanel*>(&panel)) {
122  wxASSERT(mIsMaster);
123 
124  AColor::Line(dc, mLastIndicatorX, tp->GetRect().GetTop(), mLastIndicatorX, tp->GetRect().GetBottom());
125  }
126  else if(auto ruler = dynamic_cast<AdornedRulerPanel*>(&panel)) {
127  wxASSERT(!mIsMaster);
128 
129  auto pair = GetIndicatorBitmap( *mProject, mLastIndicatorX, !rec );
130  dc.DrawBitmap( pair.second, pair.first.x, pair.first.y );
131  }
132  else
133  wxASSERT(false);
134 }
135 
137  []( AudacityProject &parent ){
138  auto result = std::make_shared< PlayIndicatorOverlay >( &parent );
139  TrackPanel::Get( parent ).AddOverlay( result );
140  return result;
141  }
142 };
143 
145 : PlayIndicatorOverlayBase(project, true)
146 {
147  ProjectWindow::Get( *mProject ).GetPlaybackScroller().Bind(
148  EVT_TRACK_PANEL_TIMER,
150  this);
151 }
152 
153 void PlayIndicatorOverlay::OnTimer(wxCommandEvent &event)
154 {
155  // Let other listeners get the notification
156  event.Skip();
157 
158  // Ensure that there is an overlay attached to the ruler
159  if (!mPartner) {
161  mPartner = std::make_shared<PlayIndicatorOverlayBase>(mProject, false);
162  ruler.AddOverlay( mPartner );
163  }
164 
165  const auto &viewInfo = ViewInfo::Get( *mProject );
166  auto width = viewInfo.GetTracksUsableWidth();
167 
168  if (!ProjectAudioIO::Get( *mProject ).IsAudioActive()) {
169  mNewIndicatorX = -1;
170  mNewIsCapturing = false;
171  const auto &scrubber = Scrubber::Get( *mProject );
172  if (scrubber.HasMark()) {
173  auto position = scrubber.GetScrubStartPosition();
174  const auto offset = viewInfo.GetLeftOffset();
175  if(position >= viewInfo.GetLeftOffset() &&
176  position < offset + width)
177  mNewIndicatorX = position;
178  }
179  }
180  else {
181  auto &window = ProjectWindow::Get( *mProject );
182  auto &scroller = window.GetPlaybackScroller();
183  // Calculate the horizontal position of the indicator
184  const double playPos = scroller.GetRecentStreamTime();
185 
187  const Mode mode = scroller.GetMode();
188  const bool pinned = ( mode == Mode::Pinned || mode == Mode::Right );
189 
190  // Use a small tolerance to avoid flicker of play head pinned all the way
191  // left or right
192  const auto tolerance = pinned ? 1.5 * kTimerInterval / 1000.0 : 0;
193  bool onScreen = playPos >= 0.0 &&
194  between_incexc(viewInfo.h - tolerance,
195  playPos,
196  viewInfo.GetScreenEndTime() + tolerance);
197 
198  auto gAudioIO = AudioIO::Get();
199  const auto &scrubber = Scrubber::Get( *mProject );
200 
201  // BG: Scroll screen if option is set
202  if( viewInfo.bUpdateTrackIndicator &&
203  playPos >= 0 && !onScreen ) {
204  // msmeyer: But only if not playing looped or in one-second mode
205  // PRL: and not scrolling with play/record head fixed
206  auto mode = ProjectAudioManager::Get( *mProject ).GetLastPlayMode();
207  if (!pinned &&
208  mode != PlayMode::oneSecondPlay &&
209  !gAudioIO->IsPaused() &&
210  // Bug 2656 allow scrolling when paused in
211  // scrubbing/play-at-speed.
212  // ONLY do this additional test if scrubbing/play-at-speed
213  // is active.
214  (!scrubber.IsScrubbing() || !scrubber.IsPaused())
215  )
216  {
217  auto newPos = playPos;
218  if (playPos < viewInfo.h) {
219  // This is possible when scrubbing backwards.
220  // We want to page leftward by (at least) a whole screen, not
221  // just a little bit equal to the scrubbing poll interval
222  // duration.
223  newPos = viewInfo.OffsetTimeByPixels( newPos, -width );
224  newPos = std::max( newPos, window.ScrollingLowerBoundTime() );
225  }
226  window.TP_ScrollWindow(newPos);
227  // Might yet be off screen, check it
228  onScreen = playPos >= 0.0 &&
229  between_incexc(viewInfo.h,
230  playPos,
231  viewInfo.GetScreenEndTime());
232  }
233  }
234 
235  // Always update scrollbars even if not scrolling the window. This is
236  // important when NEW audio is recorded, because this can change the
237  // length of the project and therefore the appearance of the scrollbar.
238  window.TP_RedrawScrollbars();
239 
240  if (onScreen)
242  viewInfo.TimeToPosition(playPos, viewInfo.GetLeftOffset());
243  else
244  mNewIndicatorX = -1;
245 
246  mNewIsCapturing = gAudioIO->IsCapturing();
247  }
248 
249  if(mPartner)
250  mPartner->Update(mNewIndicatorX);
251 }
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
ViewInfo::Get
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:241
Scrubber::Get
static Scrubber & Get(AudacityProject &project)
Definition: Scrubbing.cpp:201
AdornedRulerPanel
This is an Audacity Specific ruler panel which additionally has border, selection markers,...
Definition: AdornedRulerPanel.h:27
Scrubber::IsTransportingPinned
bool IsTransportingPinned() const
ProjectAudioManager::Get
static ProjectAudioManager & Get(AudacityProject &project)
Definition: ProjectAudioManager.cpp:55
AllThemeResources.h
TrackView.h
Project.h
AColor::IndicatorColor
static void IndicatorColor(wxDC *dc, bool bIsNotRecording)
Definition: AColor.cpp:380
anonymous_namespace{PlayIndicatorOverlay.cpp}::between_incexc
bool between_incexc(LOW l, MID m, HIGH h)
Definition: PlayIndicatorOverlay.cpp:35
AColor::Line
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:109
AdornedRulerPanel::GetInnerRect
wxRect GetInnerRect() const
Definition: AdornedRulerPanel.h:53
PlayIndicatorOverlayBase::PlayIndicatorOverlayBase
PlayIndicatorOverlayBase(AudacityProject *project, bool isMaster)
Definition: PlayIndicatorOverlay.cpp:43
ProjectWindow::GetPlaybackScroller
PlaybackScroller & GetPlaybackScroller()
Definition: ProjectWindow.h:90
TrackPanel::Get
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:227
PlayIndicatorOverlayBase::mProject
AudacityProject *const mProject
Definition: PlayIndicatorOverlay.h:41
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:535
ProjectAudioIO::Get
static ProjectAudioIO & Get(AudacityProject &project)
Definition: ProjectAudioIO.cpp:22
PlayIndicatorOverlay::mPartner
std::shared_ptr< PlayIndicatorOverlayBase > mPartner
Definition: PlayIndicatorOverlay.h:59
PlayIndicatorOverlayBase::~PlayIndicatorOverlayBase
virtual ~PlayIndicatorOverlayBase()
Definition: PlayIndicatorOverlay.cpp:49
anonymous_namespace{TimeTrackVRulerControls.cpp}::ruler
Ruler & ruler()
Definition: TimeTrackVRulerControls.cpp:34
TrackPanel
The TrackPanel class coordinates updates and operations on the main part of the screen which contains...
Definition: TrackPanel.h:66
ClientData::Site::RegisteredFactory
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:266
ProjectAudioIO::IsAudioActive
bool IsAudioActive() const
Definition: ProjectAudioIO.cpp:51
PlayIndicatorOverlayBase::SequenceNumber
unsigned SequenceNumber() const override
This number determines an ordering of overlays, so that those with higher numbers overpaint those wit...
Definition: PlayIndicatorOverlay.cpp:53
ThemeBase::Bitmap
wxBitmap & Bitmap(int iIndex)
Definition: Theme.cpp:1209
PlayIndicatorOverlayBase::mNewIsCapturing
bool mNewIsCapturing
Definition: PlayIndicatorOverlay.h:45
ProjectAudioManager::GetLastPlayMode
PlayMode GetLastPlayMode() const
Definition: ProjectAudioManager.h:122
AdornedRulerPanel::Get
static AdornedRulerPanel & Get(AudacityProject &project)
Definition: AdornedRulerPanel.cpp:899
IndicatorMediumWidth
@ IndicatorMediumWidth
Definition: AdornedRulerPanel.cpp:76
anonymous_namespace{PlayIndicatorOverlay.cpp}::GetIndicatorBitmap
std::pair< wxPoint, wxBitmap > GetIndicatorBitmap(AudacityProject &project, wxCoord xx, bool playing)
Definition: PlayIndicatorOverlay.cpp:61
PlayIndicatorOverlayBase
Definition: PlayIndicatorOverlay.h:27
ProjectWindow::PlaybackScroller::Mode
Mode
Definition: ProjectWindow.h:65
Theme.h
Scrubbing.h
@0::kTimerInterval
@ kTimerInterval
PlayIndicatorOverlay.h
PlayIndicatorOverlayBase::DoGetRectangle
std::pair< wxRect, bool > DoGetRectangle(wxSize size) override
Definition: PlayIndicatorOverlay.cpp:78
ViewInfo.h
theTheme
THEME_API Theme theTheme
Definition: Theme.cpp:79
PlayIndicatorOverlayBase::mLastIndicatorX
int mLastIndicatorX
Definition: PlayIndicatorOverlay.h:43
PlayIndicatorOverlayBase::mLastIsCapturing
bool mLastIsCapturing
Definition: PlayIndicatorOverlay.h:46
PlayIndicatorOverlay::PlayIndicatorOverlay
PlayIndicatorOverlay(AudacityProject *project)
Definition: PlayIndicatorOverlay.cpp:144
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
PlayMode::oneSecondPlay
@ oneSecondPlay
PlayIndicatorOverlayBase::mIsMaster
const bool mIsMaster
Definition: PlayIndicatorOverlay.h:42
OverlayPanel
Definition: OverlayPanel.h:18
OverlayPanel::AddOverlay
void AddOverlay(const std::weak_ptr< Overlay > &pOverlay)
Definition: OverlayPanel.cpp:24
sOverlayKey
static const AudacityProject::AttachedObjects::RegisteredFactory sOverlayKey
Definition: PlayIndicatorOverlay.cpp:136
AudioIO::Get
static AudioIO * Get()
Definition: AudioIO.cpp:141
PlayIndicatorOverlayBase::mNewIndicatorX
int mNewIndicatorX
Definition: PlayIndicatorOverlay.h:44
AColor.h
PlayIndicatorOverlay::OnTimer
void OnTimer(wxCommandEvent &event)
Definition: PlayIndicatorOverlay.cpp:153
PlayIndicatorOverlayBase::Draw
void Draw(OverlayPanel &panel, wxDC &dc) override
Definition: PlayIndicatorOverlay.cpp:100