Audacity 3.2.0
MeterToolBar.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 MeterToolBar.cpp
6
7 Dominic Mazzoni
8 Leland Lucius
9
10 See MeterToolBar.h for details
11
12*******************************************************************//*******************************************************************/
18
19
20
21#include "MeterToolBar.h"
22#include "widgets/AButton.h"
23
24// For compilers that support precompilation, includes "wx/wx.h".
25#include <wx/wxprec.h>
26
27#include <wx/setup.h> // for wxUSE_* macros
28
29#ifndef WX_PRECOMP
30#include <wx/event.h>
31#include <wx/intl.h>
32#include <wx/tooltip.h>
33#endif
34
35#include <wx/gbsizer.h>
36
37#include "AllThemeResources.h"
38#include "Decibels.h"
39#include "ToolManager.h"
40#include "../ProjectAudioIO.h"
41#include "../widgets/MeterPanel.h"
42
43#if wxUSE_ACCESSIBILITY
44
45class MeterButtonAx : public AButtonAx
46{
47 wxWeakRef<MeterPanel> mAssociatedMeterPanel{nullptr};
48 bool mAccSilent{false};
49public:
50
51 MeterButtonAx(AButton& button, MeterPanel& panel)
52 : AButtonAx(&button)
53 , mAssociatedMeterPanel(&panel)
54 { }
55
56 wxAccStatus GetName(int childId, wxString* name) override
57 {
58 if(childId != wxACC_SELF)
59 return wxACC_NOT_IMPLEMENTED;
60
61 if(mAccSilent)
62 *name = wxEmptyString; // Jaws reads nothing, and nvda reads "unknown"
63 else
64 {
65 const auto button = static_cast<AButton*>(GetWindow());
66
67 *name = button->GetName();
68
69 if(const auto panel = mAssociatedMeterPanel.get())
70 {
71 // translations of strings such as " Monitoring " did not
72 // always retain the leading space. Therefore a space has
73 // been added to ensure at least one space, and stop
74 // words from being merged
75 if(panel->IsMonitoring())
76 *name += wxT(" ") + _(" Monitoring ");
77 else if(panel->IsActive())
78 *name += wxT(" ") + _(" Active ");
79
80 const auto dbRange = panel->GetDBRange();
81 if (dbRange != -1)
82 *name += wxT(" ") + wxString::Format(_(" Peak %2.f dB"), panel->GetPeakHold() * dbRange - dbRange);
83 else
84 *name += wxT(" ") + wxString::Format(_(" Peak %.2f "), panel->GetPeakHold());
85
86 if(panel->IsClipping())
87 *name += wxT(" ") + _(" Clipped ");
88 }
89 }
90 return wxACC_OK;
91 }
92
93 wxAccStatus GetRole(int childId, wxAccRole* role) override
94 {
95 if(childId != wxACC_SELF)
96 return wxACC_NOT_IMPLEMENTED;
97
98 if(mAccSilent)
99 *role = wxROLE_NONE; // Jaws and nvda both read nothing
100 else
101 *role = wxROLE_SYSTEM_PUSHBUTTON;
102 return wxACC_OK;
103 }
104
105 void SetSilent(bool silent)
106 {
107 if(mAccSilent != silent)
108 {
109 mAccSilent = silent;
110 if(!silent)
111 {
112 NotifyEvent(
113 wxACC_EVENT_OBJECT_FOCUS,
114 GetWindow(),
115 wxOBJID_CLIENT,
116 wxACC_SELF);
117 }
118 }
119 }
120};
121
122#endif
123
125
129
130BEGIN_EVENT_TABLE( MeterToolBar, ToolBar )
131 EVT_SIZE( MeterToolBar::OnSize )
133
134//Standard constructor
136: ToolBar(project, type, XO("Combined Meter"), wxT("CombinedMeter"), true)
137{
138 if( mType == RecordMeterBarID ){
139 mWhichMeters = kWithRecordMeter;
140 mLabel = XO("Recording Meter");
141 mSection = wxT("RecordMeter");
142 } else if( mType == PlayMeterBarID ){
143 mWhichMeters = kWithPlayMeter;
144 mLabel = XO("Playback Meter");
145 mSection = wxT("PlayMeter");
146 } else {
147 mWhichMeters = kWithPlayMeter | kWithRecordMeter;
148 }
149}
150
152{
153}
154
156{
157 return MeterToolBars{
158 Get(project, true),
159 Get(project, false)
160 };
161}
162
164{
165 return ConstMeterToolBars{
166 Get(project, true),
167 Get(project, false)
168 };
169}
170
171MeterToolBar & MeterToolBar::Get(AudacityProject &project, bool forPlayMeterToolBar)
172{
173 auto& toolManager = ToolManager::Get(project);
174 auto toolBarID = forPlayMeterToolBar ? PlayMeterBarID : RecordMeterBarID;
175
176 return *static_cast<MeterToolBar*>(toolManager.GetToolBar(toolBarID));
177}
178
179const MeterToolBar & MeterToolBar::Get(const AudacityProject &project, bool forPlayMeterToolBar)
180{
181 return Get( const_cast<AudacityProject&>( project ), forPlayMeterToolBar );
182}
183
184void MeterToolBar::Create(wxWindow * parent)
185{
186 ToolBar::Create(parent);
187
188 UpdatePrefs();
189
190 // Simulate a size event to set initial meter placement/size
191 wxSizeEvent dummy;
192 OnSize(dummy);
193}
194
196{
197 MeterPanel::State playState{ false }, recordState{ false };
198
199 auto &projectAudioIO = ProjectAudioIO::Get( mProject );
200 if (mPlayMeter &&
201 projectAudioIO.GetPlaybackMeter() == mPlayMeter->GetMeter())
202 {
203 playState = mPlayMeter->SaveState();
204 projectAudioIO.SetPlaybackMeter( nullptr );
205 }
206
207 if (mRecordMeter &&
208 projectAudioIO.GetCaptureMeter() == mRecordMeter->GetMeter())
209 {
210 recordState = mRecordMeter->SaveState();
211 projectAudioIO.SetCaptureMeter( nullptr );
212 }
213
215
216 mPlayMeter->RestoreState(playState);
217 if( playState.mSaved ){
218 projectAudioIO.SetPlaybackMeter( mPlayMeter->GetMeter() );
219 }
220 mRecordMeter->RestoreState(recordState);
221 if( recordState.mSaved ){
222 projectAudioIO.SetCaptureMeter( mRecordMeter->GetMeter() );
223 }
224}
225
227{
229 SetBackgroundColour( theTheme.Colour( clrMedium ) );
230
232 //JKC: Record on left, playback on right. Left to right flow
233 //(maybe we should do it differently for Arabic language :-) )
236 mRecordSetupButton->SetName(_("Record Meter"));
237 mRecordSetupButton->SetToolTip(XO("Record Meter"));
239 theTheme.Image(bmpRecoloredUpSmall),
240 theTheme.Image(bmpRecoloredUpHiliteSmall),
241 theTheme.Image(bmpRecoloredDownSmall),
242 theTheme.Image(bmpRecoloredHiliteSmall),
243 theTheme.Image(bmpRecoloredUpSmall));
245 mRecordSetupButton->SetButtonType(AButton::Type::FrameButton);
247
249 this,
250 wxID_ANY,
251 true,
252 wxDefaultPosition,
253 wxSize( 260, toolbarSingle) );
254 /* i18n-hint: (noun) The meter that shows the loudness of the audio being recorded.*/
255 mRecordMeter->SetName( XO("Recording Level"));
256 /* i18n-hint: (noun) The meter that shows the loudness of the audio being recorded.
257 This is the name used in screen reader software, where having 'Meter' first
258 apparently is helpful to partially sighted people. */
259 mRecordMeter->SetLabel( XO("Meter-Record") );
260
261#if wxUSE_ACCESSIBILITY
262 auto meterButtonAcc = safenew MeterButtonAx(*mRecordSetupButton, *mRecordMeter);
263#endif
264 mRecordSetupButton->Bind(wxEVT_BUTTON, [=](wxCommandEvent&)
265 {
266#if wxUSE_ACCESSIBILITY
267 meterButtonAcc->SetSilent(true);
268#endif
270 mRecordMeter->ScreenToClient(
271 ClientToScreen(mRecordSetupButton->GetClientRect().GetBottomLeft())
272 )
273 );
274#if wxUSE_ACCESSIBILITY
275 /* if stop/start monitoring was chosen in the menu, then by this point
276 OnMonitoring has been called and variables which affect the accessibility
277 name have been updated so it's now ok for screen readers to read the name of
278 the button */
279 meterButtonAcc->SetSilent(false);
280#endif
281 });
282 }
283
287 mPlaySetupButton->SetName(_("Playback Meter"));
288 mPlaySetupButton->SetToolTip(XO("Playback Meter"));
290 theTheme.Image(bmpRecoloredUpSmall),
291 theTheme.Image(bmpRecoloredUpHiliteSmall),
292 theTheme.Image(bmpRecoloredDownSmall),
293 theTheme.Image(bmpRecoloredHiliteSmall),
294 theTheme.Image(bmpRecoloredUpSmall));
296 mPlaySetupButton->SetButtonType(AButton::Type::FrameButton);
298
299
301 this,
302 wxID_ANY,
303 false,
304 wxDefaultPosition,
305 wxSize( 260, toolbarSingle ) );
306 /* i18n-hint: (noun) The meter that shows the loudness of the audio playing.*/
307 mPlayMeter->SetName( XO("Playback Level"));
308 /* i18n-hint: (noun) The meter that shows the loudness of the audio playing.
309 This is the name used in screen reader software, where having 'Meter' first
310 apparently is helpful to partially sighted people. */
311 mPlayMeter->SetLabel( XO("Meter-Play"));
312
313#if wxUSE_ACCESSIBILITY
314 auto meterButtonAcc = safenew MeterButtonAx(*mPlaySetupButton, *mPlayMeter);
315#endif
316 mPlaySetupButton->Bind(wxEVT_BUTTON, [=](wxCommandEvent&)
317 {
318#if wxUSE_ACCESSIBILITY
319 meterButtonAcc->SetSilent(true);
320#endif
322 mPlayMeter->ScreenToClient(
323 ClientToScreen(mPlaySetupButton->GetClientRect().GetBottomLeft())
324 )
325 );
326#if wxUSE_ACCESSIBILITY
327 meterButtonAcc->SetSilent(false);
328#endif
329 });
330 }
331
332 RebuildLayout(true);
333
335
336 Layout();
337}
338
340{
342
343 // Since the same widget is provides both the Recording Meter as
344 // well as the Playback Meter, we choose an appropriate label
345 // based on which it is
347 ? XO("Recording Meter")
348 : XO("Playback Meter");
349
350 // Set label to pull in language change
352
353 // Give base class a chance
355}
356
358{
359 if ( mPlayMeter )
361
362 if ( mRecordMeter )
364}
365
367{
368 const auto size = GetSize();
369 const auto isHorizontal = size.x > size.y;
370
371 if(!force)
372 {
373 const auto sizerOrientation = mWhichMeters == kCombinedMeter
374 ? (isHorizontal ? wxVERTICAL : wxHORIZONTAL)
375 : (isHorizontal ? wxHORIZONTAL : wxVERTICAL);
376
377 if(mRootSizer->GetOrientation() == sizerOrientation)
378 {
379 Layout();
380 return;
381 }
382 }
383
384 if(mRootSizer != nullptr)
385 GetSizer()->Remove(mRootSizer);
386
387 std::unique_ptr<wxBoxSizer> playBarSizer;
388 std::unique_ptr<wxBoxSizer> recordBarSizer;
390 {
391 playBarSizer = std::make_unique<wxBoxSizer>(isHorizontal ? wxHORIZONTAL : wxVERTICAL);
392 playBarSizer->Add(mPlaySetupButton, 0, wxEXPAND);
393 playBarSizer->Add(mPlayMeter, 1, wxEXPAND);
394 }
396 {
397 recordBarSizer = std::make_unique<wxBoxSizer>(isHorizontal ? wxHORIZONTAL : wxVERTICAL);
398 recordBarSizer->Add(mRecordSetupButton, 0, wxEXPAND);
399 recordBarSizer->Add(mRecordMeter, 1, wxEXPAND);
400 }
401
402 if(playBarSizer && recordBarSizer)
403 {
404 Add(mRootSizer = safenew wxBoxSizer(isHorizontal ? wxVERTICAL : wxHORIZONTAL), 1, wxEXPAND);
405 mRootSizer->Add(playBarSizer.release());
406 mRootSizer->Add(recordBarSizer.release());
407 }
408 else if(playBarSizer)
409 Add(mRootSizer = playBarSizer.release(), 1, wxEXPAND);
410 else if(recordBarSizer)
411 Add(mRootSizer = recordBarSizer.release(), 1, wxEXPAND);
412}
413
414
415void MeterToolBar::OnSize( wxSizeEvent & event)
416{
417 event.Skip();
418
419 if(mRootSizer == nullptr)
420 return;// We can be resized before populating...protect against it
421 RebuildLayout(false);
422}
423
424bool MeterToolBar::Expose( bool show )
425{
426 auto &projectAudioIO = ProjectAudioIO::Get( mProject );
427 if( show ) {
428 if( mPlayMeter ) {
429 projectAudioIO.SetPlaybackMeter( mPlayMeter->GetMeter() );
430 }
431
432 if( mRecordMeter ) {
433 projectAudioIO.SetCaptureMeter( mRecordMeter->GetMeter() );
434 }
435 } else {
436 if( mPlayMeter &&
437 projectAudioIO.GetPlaybackMeter() == mPlayMeter->GetMeter() ) {
438 projectAudioIO.SetPlaybackMeter( nullptr );
439 }
440
441 if( mRecordMeter &&
442 projectAudioIO.GetCaptureMeter() == mRecordMeter->GetMeter() ) {
443 projectAudioIO.SetCaptureMeter( nullptr );
444 }
445 }
446
447 return ToolBar::Expose( show );
448}
449
451{
452 return (mWhichMeters ==
453 (kWithRecordMeter + kWithPlayMeter)) ? 338 : 290;
454}
455
456// The meter's sizing code does not take account of the resizer
457// Hence after docking we need to enlarge the bar (using fit)
458// so that the resizer can be reached.
459void MeterToolBar::SetDocked(ToolDock *dock, bool pushed) {
460 ToolBar::SetDocked(dock, pushed);
461 Fit();
462}
463
465{
468}
469
471{
474}
475
477{
478 if (adj < 0) {
479 mPlayMeter->Decrease(-adj);
480 }
481 else {
482 mPlayMeter->Increase(adj);
483 }
484
486}
487
489{
490 if (adj < 0) {
491 mRecordMeter->Decrease(-adj);
492 }
493 else {
495 }
496
498}
499
501 []( AudacityProject &project ){
502 return ToolBar::Holder{
503 safenew MeterToolBar{ project, RecordMeterBarID } }; }
504};
506 []( AudacityProject &project ){
507 return ToolBar::Holder{
508 safenew MeterToolBar{ project, PlayMeterBarID } }; }
509};
511 []( AudacityProject &project ){
512 return ToolBar::Holder{
513 safenew MeterToolBar{ project, MeterBarID } }; }
514};
515
516#include "ToolManager.h"
517
518namespace {
520 /* i18n-hint: Clicking this menu item shows the toolbar
521 with the recording level meters */
522 RecordMeterBarID, wxT("ShowRecordMeterTB"), XXO("&Recording Meter Toolbar"),
523 {}, { MeterBarID }
524};
526 /* i18n-hint: Clicking this menu item shows the toolbar
527 with the playback level meter */
528 PlayMeterBarID, wxT("ShowPlayMeterTB"), XXO("&Playback Meter Toolbar"),
529 {}, { MeterBarID }
530};
531//AttachedToolBarMenuItem sAttachment3{
532// /* --i18nhint: Clicking this menu item shows the toolbar
533// which has sound level meters */
534// MeterBarID, wxT("ShowMeterTB"), XXO("Co&mbined Meter Toolbar"),
535// { Registry::OrderingHint::After, "ShowPlayMeterTB" },
536// { PlayMeterBarID, RecordMeterBarID }
537//};
538}
wxT("CloseDown"))
END_EVENT_TABLE()
const TranslatableString name
Definition: Distortion.cpp:82
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
static RegisteredToolbarFactory factory2
static RegisteredToolbarFactory factory3
IMPLEMENT_CLASS(MeterToolBar, ToolBar)
static RegisteredToolbarFactory factory1
std::vector< std::reference_wrapper< const MeterToolBar > > ConstMeterToolBars
Definition: MeterToolBar.h:31
constexpr int kWithPlayMeter
Definition: MeterToolBar.h:35
std::vector< std::reference_wrapper< MeterToolBar > > MeterToolBars
Definition: MeterToolBar.h:30
constexpr int kCombinedMeter
Definition: MeterToolBar.h:36
constexpr int kWithRecordMeter
Definition: MeterToolBar.h:34
TranslatableString label
Definition: TagsEditor.cpp:163
THEME_API Theme theTheme
Definition: Theme.cpp:82
#define toolbarSingle
Definition: ToolBar.h:59
@ RecordMeterBarID
Definition: ToolBar.h:75
@ PlayMeterBarID
Definition: ToolBar.h:76
@ MeterBarID
Definition: ToolBar.h:74
A wxButton with mouse-over behaviour.
Definition: AButton.h:104
void SetButtonType(Type type)
Definition: AButton.cpp:150
void SetImages(const wxImage &up, const wxImage &over, const wxImage &down, const wxImage &overDown, const wxImage &dis)
Definition: AButton.cpp:208
void SetToolTip(const TranslatableString &toolTip)
Definition: AButton.cpp:187
void SetIcon(const wxImage &icon)
Definition: AButton.cpp:229
void SetLabel(const TranslatableString &label)
Definition: AButton.cpp:192
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
AudioIO uses this to send sample buffers for real-time display updates.
Definition: Meter.h:16
std::shared_ptr< Meter > GetMeter() const
MeterPanel is a panel that paints the meter used for monitoring or playback.
Definition: MeterPanel.h:104
bool ShowDialog()
Definition: MeterPanel.cpp:864
void Decrease(float steps)
Definition: MeterPanel.cpp:890
void Increase(float steps)
Definition: MeterPanel.cpp:879
void UpdateSliderControl()
Definition: MeterPanel.cpp:476
void ShowMenu(const wxPoint &pos)
State SaveState()
void SetName(const TranslatableString &name)
void RestoreState(const State &state)
A ToolBar that holds the VU Meter.
Definition: MeterToolBar.h:38
AButton * mRecordSetupButton
Definition: MeterToolBar.h:84
virtual ~MeterToolBar()
void UpdatePrefs() override
void AdjustOutputGain(int adj)
void RegenerateTooltips() override
Definition: MeterToolBar.h:77
void ShowInputGainDialog()
static MeterToolBars GetToolBars(AudacityProject &project)
void ShowOutputGainDialog()
void OnSize(wxSizeEvent &event)
void AdjustInputGain(int adj)
void ReCreateButtons() override
void Create(wxWindow *parent) override
void Populate() override
MeterPanel * mPlayMeter
Definition: MeterToolBar.h:83
void RebuildLayout(bool force)
AButton * mPlaySetupButton
Definition: MeterToolBar.h:82
MeterPanel * mRecordMeter
Definition: MeterToolBar.h:85
void UpdateControls()
static MeterToolBar & Get(AudacityProject &project, bool forPlayMeterToolBar)
wxBoxSizer * mRootSizer
Definition: MeterToolBar.h:81
int GetInitialWidth() override
Resizable toolbars should implement these.
virtual void SetDocked(ToolDock *dock, bool pushed) override
bool Expose(bool show) override
static ProjectAudioIO & Get(AudacityProject &project)
wxColour & Colour(int iIndex)
wxImage & Image(int iIndex)
Works with ToolManager and ToolDock to provide a dockable window in which buttons can be placed.
Definition: ToolBar.h:101
AudacityProject & mProject
Definition: ToolBar.h:251
void Add(wxWindow *window, int proportion=0, int flag=wxALIGN_TOP, int border=0, wxObject *userData=NULL)
Definition: ToolBar.cpp:695
virtual void SetDocked(ToolDock *dock, bool pushed)
Definition: ToolBar.cpp:647
virtual void ReCreateButtons()
Definition: ToolBar.cpp:525
void SetLabel(const wxString &label) override
Definition: ToolBar.cpp:407
static void MakeButtonBackgroundsSmall()
Definition: ToolBar.cpp:823
virtual bool Expose(bool show=true)
Definition: ToolBar.cpp:453
wxBoxSizer * GetSizer()
Definition: ToolBar.cpp:687
void UpdatePrefs() override
Definition: ToolBar.cpp:614
virtual void Create(wxWindow *parent)
Definition: ToolBar.cpp:484
wxWindowPtr< ToolBar > Holder
Definition: ToolBar.h:105
A dynamic panel where a ToolBar can be docked.
Definition: ToolDock.h:290
static ToolManager & Get(AudacityProject &project)
void SetLabel(const TranslatableString &label)
AttachedToolBarMenuItem sAttachment2
AttachedToolBarMenuItem sAttachment1