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