Audacity 3.2.0
ScrubUI.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ScrubUI.cpp
6
7 Paul Licameli split from Scrubbing.cpp
8
9 **********************************************************************/
10
11#include "ScrubUI.h"
12
13#include "Scrubbing.h"
14#include "../../widgets/Overlay.h"
15#include "ClientData.h"
16#include "../../AdornedRulerPanel.h"
17#include "Project.h"
18#include "../../ProjectWindow.h"
19#include "../../ProjectWindows.h"
20#include "../../TrackPanel.h"
21
22#include <wx/dcclient.h>
23#include <wx/windowptr.h>
24
26// class ScrubbingOverlay is responsible for drawing the speed numbers
27
28// Specialist in drawing the scrub speed, and listening for certain events
30 : public Overlay
31 , public ClientData::Base
32{
33public:
34 explicit
36
37private:
38 unsigned SequenceNumber() const override;
39 std::pair<wxRect, bool> DoGetRectangle(wxSize size) override;
40 void Draw(OverlayPanel &panel, wxDC &dc) override;
41
43
44 const Scrubber &GetScrubber() const;
46
49
52};
53
55 : mProject(project)
56 , mLastScrubRect()
57 , mNextScrubRect()
58 , mLastScrubSpeedText()
59 , mNextScrubSpeedText()
60{
63}
64
66{
67 return 40;
68}
69
70std::pair<wxRect, bool> ScrubbingOverlay::DoGetRectangle(wxSize)
71{
72 wxRect rect(mLastScrubRect);
73 const bool outdated =
75 (!mLastScrubRect.IsEmpty() && !GetScrubber().ShouldDrawScrubSpeed()) ||
77 return std::make_pair(
78 rect,
79 outdated
80 );
81}
82
84{
87
88 Scrubber &scrubber = GetScrubber();
89 if (!scrubber.ShouldDrawScrubSpeed())
90 return;
91
92 static const wxFont labelFont(24, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
93 dc.SetFont(labelFont);
94
95 // These two colors were previously saturated red and green. However
96 // we have a rule to try to only use red for reserved purposes of
97 // (a) Recording
98 // (b) Error alerts
99 // So they were changed to 'orange' and 'lime'.
100 static const wxColour clrNoScroll(215, 162, 0), clrScroll(0, 204, 153);
101 if (scrubber.IsScrollScrubbing())
102 dc.SetTextForeground(clrScroll);
103 else
104 dc.SetTextForeground(clrNoScroll);
105
106 dc.DrawText(mLastScrubSpeedText, mLastScrubRect.GetX(), mLastScrubRect.GetY());
107}
108
110{
111 Scrubber &scrubber = GetScrubber();
112 const auto isScrubbing = scrubber.IsScrubbing();
114 auto position = ::wxGetMousePosition();
115
116 if (scrubber.IsSpeedPlaying() || scrubber.IsKeyboardScrubbing())
117 return;
118
119 {
120 if(scrubber.HasMark()) {
121 auto xx = ruler.ScreenToClient(position).x;
122 ruler.UpdateQuickPlayPos( xx );
123
124 if (!isScrubbing)
125 // Really start scrub if motion is far enough
126 scrubber.MaybeStartScrubbing(xx);
127 }
128
129 if (!isScrubbing) {
130 mNextScrubRect = wxRect();
131 return;
132 }
133 else
134 ruler.DrawBothOverlays();
135 }
136
137 if (!scrubber.ShouldDrawScrubSpeed()) {
138 mNextScrubRect = wxRect();
139 }
140 else {
141 auto &trackPanel = GetProjectPanel( *mProject );
142 auto &viewInfo = ViewInfo::Get( *mProject );
143 int panelWidth, panelHeight;
144 trackPanel.GetSize(&panelWidth, &panelHeight);
145
146 // Where's the mouse?
147 position = trackPanel.ScreenToClient(position);
148
149 const bool seeking = scrubber.Seeks() || scrubber.TemporarilySeeks();
150
151 // Find the text
152 const double maxScrubSpeed = GetScrubber().GetMaxScrubSpeed();
153 const double speed =
154 scrubber.IsScrollScrubbing()
155 ? scrubber.FindScrubSpeed( seeking,
157 .PositionToTime(position.x, viewInfo.GetLeftOffset()))
158 : maxScrubSpeed;
159
160 const wxChar *format =
161 scrubber.IsScrollScrubbing()
162 ? seeking
163 ? wxT("%+.2fX")
164 : wxT("%+.2f")
165 : wxT("%.2f");
166
167 mNextScrubSpeedText = wxString::Format(format, speed);
168
169 // Find the origin for drawing text
170 wxCoord width, height;
171 {
172 wxClientDC dc( &trackPanel );
173 static const wxFont labelFont(24, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
174 dc.SetFont(labelFont);
175 dc.GetTextExtent(mNextScrubSpeedText, &width, &height);
176 }
177 const auto xx =
178 std::max(0, std::min(panelWidth - width, position.x - width / 2));
179
180 // Put the text above the cursor, if it fits.
181 enum { offset = 20 };
182 auto yy = position.y - height + offset;
183 if (yy < 0)
184 yy += height + 2 * offset;
185 yy = std::max(0, std::min(panelHeight - height, yy));
186
187 mNextScrubRect = wxRect(xx, yy, width, height);
188 }
189}
190
192{
193 return Scrubber::Get( *mProject );
194}
195
197{
198 return Scrubber::Get( *mProject );
199}
200
202 []( AudacityProject &parent ){
203 auto result = std::make_shared< ScrubbingOverlay >( &parent );
204 TrackPanel::Get( parent ).AddOverlay( result );
205 return result;
206 }
207};
208
210// class ScrubForwarder intercepts some mouse events of the main window
211
212// I need this because I can't push the scrubber as an event handler
213// in two places at once.
215 : public wxEvtHandler
216 , public ClientData::Base
217{
219 : mProject{ project }
220 {
221 mWindow = &ProjectWindow::Get( project );
222 if ( mWindow )
223 mWindow->PushEventHandler( this );
224 mRuler = &AdornedRulerPanel::Get( project );
225 mScrubber = Scrubber::Get( project ).shared_from_this();
226 }
227
229 {
230 if ( mWindow )
231 mWindow->PopEventHandler();
232 }
233
235 wxWindowPtr<wxWindow> mWindow;
236 wxWeakRef<AdornedRulerPanel> mRuler;
237 std::weak_ptr<Scrubber> mScrubber;
238
239 void OnMouse(wxMouseEvent &event);
240 DECLARE_EVENT_TABLE()
241};
242
243void ScrubForwarder::OnMouse(wxMouseEvent &event)
244{
245 auto pScrubber = mScrubber.lock();
246 if ( !pScrubber || !mRuler ) {
247 event.Skip();
248 return;
249 }
250
251 auto &scrubber = *pScrubber;
252
253 auto &ruler = *mRuler;
254 const auto &state = ::wxGetMouseState();
255 const auto &position = state.GetPosition();
256 scrubber.SetMayDragToSeek(
257 ruler.GetScreenRect().Contains(position) );
258
259 /*
260 auto trackPanel = mProject->GetTrackPanel();
261 if (trackPanel &&
262 trackPanel->GetScreenRect().Contains(position))
263 return true;
264 */
265
266 //auto ruler = scrubber.mProject->GetRulerPanel();
267 auto isScrubbing = scrubber.IsScrubbing();
268 if (isScrubbing && !event.HasAnyModifiers()) {
269 if(event.LeftDown() && scrubber.MayDragToSeek()) {
270 // This event handler may catch mouse transitions that are missed
271 // by the polling of mouse state by the timer.
272 scrubber.SetSeekPress( true );
273 }
274 else if (event.m_wheelRotation) {
275 double steps = event.m_wheelRotation /
276 (event.m_wheelDelta > 0 ? (double)event.m_wheelDelta : 120.0);
277 scrubber.HandleScrollWheel(steps);
278 }
279 else
280 event.Skip();
281 }
282 else
283 event.Skip();
284}
285
286BEGIN_EVENT_TABLE(ScrubForwarder, wxEvtHandler)
287 EVT_MOUSE_EVENTS(ScrubForwarder::OnMouse)
289
290static const AudacityProject::AttachedObjects::RegisteredFactory sForwarderKey{
291 []( AudacityProject &parent ){
292 return std::make_shared< ScrubForwarder >( parent );
293 }
294};
wxT("CloseDown"))
END_EVENT_TABLE()
Utility ClientData::Site to register hooks into a host class that attach client data.
int min(int a, int b)
int format
Definition: ExportPCM.cpp:56
AUDACITY_DLL_API wxWindow & GetProjectPanel(AudacityProject &project)
Get the main sub-window of the project frame that displays track data.
static const AudacityProject::AttachedObjects::RegisteredFactory sForwarderKey
Definition: ScrubUI.cpp:290
static const AudacityProject::AttachedObjects::RegisteredFactory sOverlayKey
Definition: ScrubUI.cpp:201
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:89
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:266
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
A move-only handle representing a connection to a Publisher.
Definition: Observer.h:70
void AddOverlay(const std::weak_ptr< Overlay > &pOverlay)
PlaybackScroller & GetPlaybackScroller()
static ProjectWindow & Get(AudacityProject &project)
bool ShouldDrawScrubSpeed()
bool IsKeyboardScrubbing() const
Definition: Scrubbing.h:81
bool Seeks() const
bool MaybeStartScrubbing(wxCoord xx)
double GetMaxScrubSpeed() const
Definition: Scrubbing.h:111
bool IsScrollScrubbing() const
Definition: Scrubbing.h:93
bool TemporarilySeeks() const
bool IsScrubbing() const
static Scrubber & Get(AudacityProject &project)
Definition: Scrubbing.cpp:187
bool IsSpeedPlaying() const
Definition: Scrubbing.h:77
double FindScrubSpeed(bool seeking, double time) const
bool HasMark() const
Definition: Scrubbing.h:89
ScrubbingOverlay(AudacityProject *project)
Definition: ScrubUI.cpp:54
wxString mLastScrubSpeedText
Definition: ScrubUI.cpp:51
wxString mNextScrubSpeedText
Definition: ScrubUI.cpp:51
const Scrubber & GetScrubber() const
Definition: ScrubUI.cpp:191
unsigned SequenceNumber() const override
This number determines an ordering of overlays, so that those with higher numbers overpaint those wit...
Definition: ScrubUI.cpp:65
std::pair< wxRect, bool > DoGetRectangle(wxSize size) override
Definition: ScrubUI.cpp:70
void OnTimer(Observer::Message)
Definition: ScrubUI.cpp:109
AudacityProject * mProject
Definition: ScrubUI.cpp:47
Observer::Subscription mSubscription
Definition: ScrubUI.cpp:48
wxRect mNextScrubRect
Definition: ScrubUI.cpp:50
wxRect mLastScrubRect
Definition: ScrubUI.cpp:50
void Draw(OverlayPanel &panel, wxDC &dc) override
Definition: ScrubUI.cpp:83
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:230
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
A convenient default parameter for class template Site.
Definition: ClientData.h:28
Default message type for Publisher.
Definition: Observer.h:26
AudacityProject & mProject
Definition: ScrubUI.cpp:234
wxWindowPtr< wxWindow > mWindow
Definition: ScrubUI.cpp:235
wxWeakRef< AdornedRulerPanel > mRuler
Definition: ScrubUI.cpp:236
std::weak_ptr< Scrubber > mScrubber
Definition: ScrubUI.cpp:237
void OnMouse(wxMouseEvent &event)
Definition: ScrubUI.cpp:243
ScrubForwarder(AudacityProject &project)
Definition: ScrubUI.cpp:218