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/tooltip.h>
31#endif
32
33#include <wx/gbsizer.h>
34
35#include "AllThemeResources.h"
36#include "Decibels.h"
37#include "ToolManager.h"
38#include "ProjectAudioIO.h"
39#include "../widgets/MeterPanel.h"
40
41#if wxUSE_ACCESSIBILITY
42
43class MeterButtonAx : public AButtonAx
44{
45 wxWeakRef<MeterPanel> mAssociatedMeterPanel{nullptr};
46 bool mAccSilent{false};
47public:
48
49 MeterButtonAx(AButton& button, MeterPanel& panel)
50 : AButtonAx(&button)
51 , mAssociatedMeterPanel(&panel)
52 { }
53
54 wxAccStatus GetName(int childId, wxString* name) override
55 {
56 if(childId != wxACC_SELF)
57 return wxACC_NOT_IMPLEMENTED;
58
59 if(mAccSilent)
60 *name = wxEmptyString; // Jaws reads nothing, and nvda reads "unknown"
61 else
62 {
63 const auto button = static_cast<AButton*>(GetWindow());
64
65 *name = button->GetName();
66
67 if(const auto panel = mAssociatedMeterPanel.get())
68 {
69 // translations of strings such as " Monitoring " did not
70 // always retain the leading space. Therefore a space has
71 // been added to ensure at least one space, and stop
72 // words from being merged
73 if(panel->IsMonitoring())
74 *name += wxT(" ") + _(" Monitoring ");
75 else if(panel->IsActive())
76 *name += wxT(" ") + _(" Active ");
77
78 const auto dbRange = panel->GetDBRange();
79 if (dbRange != -1)
80 *name += wxT(" ") + wxString::Format(_(" Peak %2.f dB"), panel->GetPeakHold() * dbRange - dbRange);
81 else
82 *name += wxT(" ") + wxString::Format(_(" Peak %.2f "), panel->GetPeakHold());
83
84 if(panel->IsClipping())
85 *name += wxT(" ") + _(" Clipped ");
86 }
87 }
88 return wxACC_OK;
89 }
90
91 wxAccStatus GetRole(int childId, wxAccRole* role) override
92 {
93 if(childId != wxACC_SELF)
94 return wxACC_NOT_IMPLEMENTED;
95
96 if(mAccSilent)
97 *role = wxROLE_NONE; // Jaws and nvda both read nothing
98 else
99 *role = wxROLE_SYSTEM_PUSHBUTTON;
100 return wxACC_OK;
101 }
102
103 void SetSilent(bool silent)
104 {
105 if(mAccSilent != silent)
106 {
107 mAccSilent = silent;
108 if(!silent)
109 {
110 NotifyEvent(
111 wxACC_EVENT_OBJECT_FOCUS,
112 GetWindow(),
113 wxOBJID_CLIENT,
114 wxACC_SELF);
115 }
116 }
117 }
118};
119
120#endif
121
123
127
128BEGIN_EVENT_TABLE( MeterToolBar, ToolBar )
129 EVT_SIZE( MeterToolBar::OnSize )
131
133{
134 return wxT("CombinedMeter");
135}
136
138{
139 return wxT("PlayMeter");
140}
141
143{
144 return wxT("RecordMeter");
145}
146
147//Standard constructor
149 unsigned whichMeters,
151: ToolBar(project, label, ID, true)
152, mWhichMeters{ whichMeters }
153{
154}
155
157{
158}
159
161{
162 return MeterToolBars{
163 Get(project, true),
164 Get(project, false)
165 };
166}
167
169{
170 return ConstMeterToolBars{
171 Get(project, true),
172 Get(project, false)
173 };
174}
175
177{
178 auto& toolManager = ToolManager::Get(project);
179 const auto &toolBarID = forPlayMeterToolBar ? PlayID() : RecordID();
180 return *static_cast<MeterToolBar*>(toolManager.GetToolBar(toolBarID));
181}
182
183const MeterToolBar & MeterToolBar::Get(const AudacityProject &project, bool forPlayMeterToolBar)
184{
185 return Get(const_cast<AudacityProject&>(project), forPlayMeterToolBar);
186}
187
189{
190 // The combined meter hides by default
192}
193
194void MeterToolBar::Create(wxWindow * parent)
195{
196 ToolBar::Create(parent);
197
198 UpdatePrefs();
199
200 // Simulate a size event to set initial meter placement/size
201 wxSizeEvent dummy;
202 OnSize(dummy);
203}
204
206{
207 MeterPanel::State playState{ false }, recordState{ false };
208
209 auto &projectAudioIO = ProjectAudioIO::Get( mProject );
210 if (mPlayMeter &&
211 projectAudioIO.GetPlaybackMeter() == mPlayMeter->GetMeter())
212 {
213 playState = mPlayMeter->SaveState();
214 projectAudioIO.SetPlaybackMeter( nullptr );
215 }
216
217 if (mRecordMeter &&
218 projectAudioIO.GetCaptureMeter() == mRecordMeter->GetMeter())
219 {
220 recordState = mRecordMeter->SaveState();
221 projectAudioIO.SetCaptureMeter( nullptr );
222 }
223
225
226 mPlayMeter->RestoreState(playState);
227 if( playState.mSaved ){
228 projectAudioIO.SetPlaybackMeter( mPlayMeter->GetMeter() );
229 }
230 mRecordMeter->RestoreState(recordState);
231 if( recordState.mSaved ){
232 projectAudioIO.SetCaptureMeter( mRecordMeter->GetMeter() );
233 }
234}
235
237{
239 SetBackgroundColour( theTheme.Colour( clrMedium ) );
240
242 //JKC: Record on left, playback on right. Left to right flow
243 //(maybe we should do it differently for Arabic language :-) )
246 mRecordSetupButton->SetName(_("Record Meter"));
247 mRecordSetupButton->SetToolTip(XO("Record Meter"));
249 theTheme.Image(bmpRecoloredUpSmall),
250 theTheme.Image(bmpRecoloredUpHiliteSmall),
251 theTheme.Image(bmpRecoloredDownSmall),
252 theTheme.Image(bmpRecoloredHiliteSmall),
253 theTheme.Image(bmpRecoloredUpSmall));
255 mRecordSetupButton->SetButtonType(AButton::Type::FrameButton);
257
259 this,
260 wxID_ANY,
261 true,
262 wxDefaultPosition,
263 wxSize( 260, toolbarSingle) );
264 /* i18n-hint: (noun) The meter that shows the loudness of the audio being recorded.*/
265 mRecordMeter->SetName( XO("Recording Level"));
266 /* i18n-hint: (noun) The meter that shows the loudness of the audio being recorded.
267 This is the name used in screen reader software, where having 'Meter' first
268 apparently is helpful to partially sighted people. */
269 mRecordMeter->SetLabel( XO("Meter-Record") );
270
271#if wxUSE_ACCESSIBILITY
272 auto meterButtonAcc = safenew MeterButtonAx(*mRecordSetupButton, *mRecordMeter);
273#endif
274 mRecordSetupButton->Bind(wxEVT_BUTTON, [=](wxCommandEvent&)
275 {
276#if wxUSE_ACCESSIBILITY
277 meterButtonAcc->SetSilent(true);
278#endif
280 mRecordMeter->ScreenToClient(
281 ClientToScreen(mRecordSetupButton->GetClientRect().GetBottomLeft())
282 )
283 );
284#if wxUSE_ACCESSIBILITY
285 /* if stop/start monitoring was chosen in the menu, then by this point
286 OnMonitoring has been called and variables which affect the accessibility
287 name have been updated so it's now ok for screen readers to read the name of
288 the button */
289 meterButtonAcc->SetSilent(false);
290#endif
291 });
292 }
293
297 mPlaySetupButton->SetName(_("Playback Meter"));
298 mPlaySetupButton->SetToolTip(XO("Playback Meter"));
300 theTheme.Image(bmpRecoloredUpSmall),
301 theTheme.Image(bmpRecoloredUpHiliteSmall),
302 theTheme.Image(bmpRecoloredDownSmall),
303 theTheme.Image(bmpRecoloredHiliteSmall),
304 theTheme.Image(bmpRecoloredUpSmall));
306 mPlaySetupButton->SetButtonType(AButton::Type::FrameButton);
308
309
311 this,
312 wxID_ANY,
313 false,
314 wxDefaultPosition,
315 wxSize( 260, toolbarSingle ) );
316 /* i18n-hint: (noun) The meter that shows the loudness of the audio playing.*/
317 mPlayMeter->SetName( XO("Playback Level"));
318 /* i18n-hint: (noun) The meter that shows the loudness of the audio playing.
319 This is the name used in screen reader software, where having 'Meter' first
320 apparently is helpful to partially sighted people. */
321 mPlayMeter->SetLabel( XO("Meter-Play"));
322
323#if wxUSE_ACCESSIBILITY
324 auto meterButtonAcc = safenew MeterButtonAx(*mPlaySetupButton, *mPlayMeter);
325#endif
326 mPlaySetupButton->Bind(wxEVT_BUTTON, [=](wxCommandEvent&)
327 {
328#if wxUSE_ACCESSIBILITY
329 meterButtonAcc->SetSilent(true);
330#endif
332 mPlayMeter->ScreenToClient(
333 ClientToScreen(mPlaySetupButton->GetClientRect().GetBottomLeft())
334 )
335 );
336#if wxUSE_ACCESSIBILITY
337 meterButtonAcc->SetSilent(false);
338#endif
339 });
340 }
341
342 RebuildLayout(true);
343
345
346 Layout();
347}
348
350{
352
353 // Since the same widget is provides both the Recording Meter as
354 // well as the Playback Meter, we choose an appropriate label
355 // based on which it is
357 ? XO("Recording Meter")
358 : XO("Playback Meter");
359
360 // Set label to pull in language change
362
363 // Give base class a chance
365}
366
368{
369 if ( mPlayMeter )
371
372 if ( mRecordMeter )
374}
375
377{
378 const auto size = GetSize();
379 const auto isHorizontal = size.x > size.y;
380
381 if(!force)
382 {
383 const auto sizerOrientation = mWhichMeters == kCombinedMeter
384 ? (isHorizontal ? wxVERTICAL : wxHORIZONTAL)
385 : (isHorizontal ? wxHORIZONTAL : wxVERTICAL);
386
387 if(mRootSizer->GetOrientation() == sizerOrientation)
388 {
389 Layout();
390 return;
391 }
392 }
393
394 if(mRootSizer != nullptr)
395 GetSizer()->Remove(mRootSizer);
396
397 std::unique_ptr<wxBoxSizer> playBarSizer;
398 std::unique_ptr<wxBoxSizer> recordBarSizer;
400 {
401 playBarSizer = std::make_unique<wxBoxSizer>(isHorizontal ? wxHORIZONTAL : wxVERTICAL);
402 playBarSizer->Add(mPlaySetupButton, 0, wxEXPAND);
403 playBarSizer->Add(mPlayMeter, 1, wxEXPAND);
404 }
406 {
407 recordBarSizer = std::make_unique<wxBoxSizer>(isHorizontal ? wxHORIZONTAL : wxVERTICAL);
408 recordBarSizer->Add(mRecordSetupButton, 0, wxEXPAND);
409 recordBarSizer->Add(mRecordMeter, 1, wxEXPAND);
410 }
411
412 if(playBarSizer && recordBarSizer)
413 {
414 Add(mRootSizer = safenew wxBoxSizer(isHorizontal ? wxVERTICAL : wxHORIZONTAL), 1, wxEXPAND);
415 mRootSizer->Add(playBarSizer.release());
416 mRootSizer->Add(recordBarSizer.release());
417 }
418 else if(playBarSizer)
419 Add(mRootSizer = playBarSizer.release(), 1, wxEXPAND);
420 else if(recordBarSizer)
421 Add(mRootSizer = recordBarSizer.release(), 1, wxEXPAND);
422}
423
424
425void MeterToolBar::OnSize( wxSizeEvent & event)
426{
427 event.Skip();
428
429 if(mRootSizer == nullptr)
430 return;// We can be resized before populating...protect against it
431 RebuildLayout(false);
432}
433
434bool MeterToolBar::Expose( bool show )
435{
436 auto &projectAudioIO = ProjectAudioIO::Get( mProject );
437 if( show ) {
438 if( mPlayMeter ) {
439 projectAudioIO.SetPlaybackMeter( mPlayMeter->GetMeter() );
440 }
441
442 if( mRecordMeter ) {
443 projectAudioIO.SetCaptureMeter( mRecordMeter->GetMeter() );
444 }
445 } else {
446 if( mPlayMeter &&
447 projectAudioIO.GetPlaybackMeter() == mPlayMeter->GetMeter() ) {
448 projectAudioIO.SetPlaybackMeter( nullptr );
449 }
450
451 if( mRecordMeter &&
452 projectAudioIO.GetCaptureMeter() == mRecordMeter->GetMeter() ) {
453 projectAudioIO.SetCaptureMeter( nullptr );
454 }
455 }
456
457 return ToolBar::Expose( show );
458}
459
461{
462 return (mWhichMeters ==
463 (kWithRecordMeter + kWithPlayMeter)) ? 338 : 290;
464}
465
467{
470}
471
473{
476}
477
479{
480 if (adj < 0) {
481 mPlayMeter->Decrease(-adj);
482 }
483 else {
484 mPlayMeter->Increase(adj);
485 }
486
488}
489
491{
492 if (adj < 0) {
493 mRecordMeter->Decrease(-adj);
494 }
495 else {
497 }
498
500}
501
504 return ToolBar::Holder{
506 XO("Recording Meter"), MeterToolBar::RecordID() } }; }
507};
510 return ToolBar::Holder{
512 XO("Playback Meter"), MeterToolBar::PlayID() } }; }
513};
516 return ToolBar::Holder{
519 XO("Combined Meter"), MeterToolBar::ID() } }; }
520};
521
522#include "ToolManager.h"
523
524namespace {
526 /* i18n-hint: Clicking this menu item shows the toolbar
527 with the recording level meters */
529 wxT("ShowRecordMeterTB"), XXO("&Recording Meter Toolbar"),
530 {}, { MeterToolBar::ID() }
531};
533 /* i18n-hint: Clicking this menu item shows the toolbar
534 with the playback level meter */
536 wxT("ShowPlayMeterTB"), XXO("&Playback Meter Toolbar"),
537 {}, { MeterToolBar::ID() }
538};
539//AttachedToolBarMenuItem sAttachment3{
540// /* --i18nhint: Clicking this menu item shows the toolbar
541// which has sound level meters */
542// MeterToolBar::ID(), wxT("ShowMeterTB"), XXO("Co&mbined Meter Toolbar"),
543// { Registry::OrderingHint::After, "ShowPlayMeterTB" },
544// { PlayMeterBarID, RecordMeterBarID }
545//};
546}
547
548// Now define other related menu items
549#include "CommandContext.h"
550
551namespace {
552void OnOutputGain(const CommandContext &context)
553{
554 auto &project = context.project;
555 auto &tb = MeterToolBar::Get( project, true );
556 tb.ShowOutputGainDialog();
557}
558
559void OnOutputGainInc(const CommandContext &context)
560{
561 auto &project = context.project;
562 auto &tb = MeterToolBar::Get( project, true );
563 tb.AdjustOutputGain(1);
564}
565
566void OnOutputGainDec(const CommandContext &context)
567{
568 auto &project = context.project;
569 auto &tb = MeterToolBar::Get( project, true );
570 tb.AdjustOutputGain(-1);
571}
572
573void OnInputGain(const CommandContext &context)
574{
575 auto &project = context.project;
576 auto &tb = MeterToolBar::Get( project, false );
577 tb.ShowInputGainDialog();
578}
579
580void OnInputGainInc(const CommandContext &context)
581{
582 auto &project = context.project;
583 auto &tb = MeterToolBar::Get( project, false );
584 tb.AdjustInputGain(1);
585}
586
587void OnInputGainDec(const CommandContext &context)
588{
589 auto &project = context.project;
590 auto &tb = MeterToolBar::Get( project, false );
591 tb.AdjustInputGain(-1);
592}
593
594using namespace MenuRegistry;
596{
597 static auto menu = std::shared_ptr{
598 Menu( wxT("Mixer"), XXO("Mi&xer"),
599 Command( wxT("OutputGain"), XXO("Ad&just Playback Volume..."),
601 Command( wxT("OutputGainInc"), XXO("&Increase Playback Volume"),
603 Command( wxT("OutputGainDec"), XXO("&Decrease Playback Volume"),
605 Command( wxT("InputGain"), XXO("Adj&ust Recording Volume..."),
607 Command( wxT("InputGainInc"), XXO("I&ncrease Recording Volume"),
609 Command( wxT("InputGainDec"), XXO("D&ecrease Recording Volume"),
611 ) };
612 return menu;
613}
614
616 wxT("Optional/Extra/Part1")
617};
618
619}
wxT("CloseDown"))
END_EVENT_TABLE()
AttachedItem sAttachment1
AttachedItem sAttachment2
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:34
const TranslatableString name
Definition: Distortion.cpp:76
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define _(s)
Definition: Internat.h:73
#define safenew
Definition: MemoryX.h:9
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:165
const auto project
THEME_API Theme theTheme
Definition: Theme.cpp:82
#define toolbarSingle
Definition: ToolBar.h:59
A wxButton with mouse-over behaviour.
Definition: AButton.h:104
void SetButtonType(Type type)
Definition: AButton.cpp:147
void SetImages(const wxImage &up, const wxImage &over, const wxImage &down, const wxImage &overDown, const wxImage &dis)
Definition: AButton.cpp:205
void SetToolTip(const TranslatableString &toolTip)
Definition: AButton.cpp:184
void SetIcon(const wxImage &icon)
Definition: AButton.cpp:226
void SetLabel(const TranslatableString &label)
Definition: AButton.cpp:189
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
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:862
void Decrease(float steps)
Definition: MeterPanel.cpp:888
void Increase(float steps)
Definition: MeterPanel.cpp:877
void UpdateSliderControl()
Definition: MeterPanel.cpp:478
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:91
static Identifier PlayID()
virtual ~MeterToolBar()
void UpdatePrefs() override
void AdjustOutputGain(int adj)
void RegenerateTooltips() override
Definition: MeterToolBar.h:84
void ShowInputGainDialog()
static MeterToolBars GetToolBars(AudacityProject &project)
MeterToolBar(AudacityProject &project, unsigned whichMeters, const TranslatableString &label, Identifier ID)
static Identifier ID()
Methods for MeterToolBar.
void ShowOutputGainDialog()
void OnSize(wxSizeEvent &event)
void AdjustInputGain(int adj)
void ReCreateButtons() override
void Create(wxWindow *parent) override
static Identifier RecordID()
void Populate() override
MeterPanel * mPlayMeter
Definition: MeterToolBar.h:90
void RebuildLayout(bool force)
AButton * mPlaySetupButton
Definition: MeterToolBar.h:89
MeterPanel * mRecordMeter
Definition: MeterToolBar.h:92
void UpdateControls()
static MeterToolBar & Get(AudacityProject &project, bool forPlayMeterToolBar)
wxBoxSizer * mRootSizer
Definition: MeterToolBar.h:88
int GetInitialWidth() override
Resizable toolbars should implement these.
bool ShownByDefault() const override
Whether the toolbar should be shown by default. Default implementation returns true.
unsigned mWhichMeters
Definition: MeterToolBar.h:87
bool Expose(bool show) override
static ProjectAudioIO & Get(AudacityProject &project)
Generates classes whose instances register items at construction.
Definition: Registry.h:388
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:74
AudacityProject & mProject
Definition: ToolBar.h:248
void Add(wxWindow *window, int proportion=0, int flag=wxALIGN_TOP, int border=0, wxObject *userData=NULL)
Definition: ToolBar.cpp:709
virtual void ReCreateButtons()
Definition: ToolBar.cpp:533
void SetLabel(const wxString &label) override
Definition: ToolBar.cpp:408
static void MakeButtonBackgroundsSmall()
Definition: ToolBar.cpp:837
virtual bool Expose(bool show=true)
Definition: ToolBar.cpp:459
wxBoxSizer * GetSizer()
Definition: ToolBar.cpp:701
void UpdatePrefs() override
Definition: ToolBar.cpp:622
virtual void Create(wxWindow *parent)
Definition: ToolBar.cpp:492
wxWindowPtr< ToolBar > Holder
Definition: ToolBar.h:78
static ToolManager & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
void SetLabel(const TranslatableString &label)
constexpr auto Command
Definition: MenuRegistry.h:456
constexpr auto Menu
Items will appear in a main toolbar menu or in a sub-menu.
Definition: MenuRegistry.h:445
std::unique_ptr< detail::IndirectItem< Item > > Indirect(const std::shared_ptr< Item > &ptr)
A convenience function.
Definition: Registry.h:175
void OnOutputGain(const CommandContext &context)
void OnInputGainDec(const CommandContext &context)
void OnInputGainInc(const CommandContext &context)
void OnInputGain(const CommandContext &context)
void OnOutputGainInc(const CommandContext &context)
void OnOutputGainDec(const CommandContext &context)