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 :-) )
248 mRecordSetupButton->SetName(_("Record Meter"));
249 mRecordSetupButton->SetToolTip(XO("Record Meter"));
251 theTheme.Image(bmpRecoloredUpSmall),
252 theTheme.Image(bmpRecoloredUpHiliteSmall),
253 theTheme.Image(bmpRecoloredDownSmall),
254 theTheme.Image(bmpRecoloredHiliteSmall),
255 theTheme.Image(bmpRecoloredUpSmall));
257 mRecordSetupButton->SetButtonType(AButton::Type::FrameButton);
258 mRecordSetupButton->SetMinSize({25, 25});
259 mRecordSetupButton->SetMaxSize({25, 25});
260
262 this,
263 wxID_ANY,
264 true,
265 wxDefaultPosition,
266 wxSize( 260, 25) );
267 /* i18n-hint: (noun) The meter that shows the loudness of the audio being recorded.*/
268 mRecordMeter->SetName( XO("Recording Level"));
269 /* i18n-hint: (noun) The meter that shows the loudness of the audio being recorded.
270 This is the name used in screen reader software, where having 'Meter' first
271 apparently is helpful to partially sighted people. */
272 mRecordMeter->SetLabel( XO("Meter-Record") );
273
274#if wxUSE_ACCESSIBILITY
275 auto meterButtonAcc = safenew MeterButtonAx(*mRecordSetupButton, *mRecordMeter);
276#endif
277 mRecordSetupButton->Bind(wxEVT_BUTTON, [=](wxCommandEvent&)
278 {
279#if wxUSE_ACCESSIBILITY
280 meterButtonAcc->SetSilent(true);
281#endif
283 mRecordMeter->ScreenToClient(
284 ClientToScreen(mRecordSetupButton->GetClientRect().GetBottomLeft())
285 )
286 );
287#if wxUSE_ACCESSIBILITY
288 /* if stop/start monitoring was chosen in the menu, then by this point
289 OnMonitoring has been called and variables which affect the accessibility
290 name have been updated so it's now ok for screen readers to read the name of
291 the button */
292 meterButtonAcc->SetSilent(false);
293#endif
294 });
295 }
296
302 mPlaySetupButton->SetName(_("Playback Meter"));
303 mPlaySetupButton->SetToolTip(XO("Playback Meter"));
305 theTheme.Image(bmpRecoloredUpSmall),
306 theTheme.Image(bmpRecoloredUpHiliteSmall),
307 theTheme.Image(bmpRecoloredDownSmall),
308 theTheme.Image(bmpRecoloredHiliteSmall),
309 theTheme.Image(bmpRecoloredUpSmall));
311 mPlaySetupButton->SetButtonType(AButton::Type::FrameButton);
312 mPlaySetupButton->SetMinSize({25, 25});
313 mPlaySetupButton->SetMaxSize({25, 25});
314
315
317 this,
318 wxID_ANY,
319 false,
320 wxDefaultPosition,
321 wxSize( 260, 25 ) );
322 /* i18n-hint: (noun) The meter that shows the loudness of the audio playing.*/
323 mPlayMeter->SetName( XO("Playback Level"));
324 /* i18n-hint: (noun) The meter that shows the loudness of the audio playing.
325 This is the name used in screen reader software, where having 'Meter' first
326 apparently is helpful to partially sighted people. */
327 mPlayMeter->SetLabel( XO("Meter-Play"));
328
329#if wxUSE_ACCESSIBILITY
330 auto meterButtonAcc = safenew MeterButtonAx(*mPlaySetupButton, *mPlayMeter);
331#endif
332 mPlaySetupButton->Bind(wxEVT_BUTTON, [=](wxCommandEvent&)
333 {
334#if wxUSE_ACCESSIBILITY
335 meterButtonAcc->SetSilent(true);
336#endif
338 mPlayMeter->ScreenToClient(
339 ClientToScreen(mPlaySetupButton->GetClientRect().GetBottomLeft())
340 )
341 );
342#if wxUSE_ACCESSIBILITY
343 meterButtonAcc->SetSilent(false);
344#endif
345 });
346 }
347
348 RebuildLayout(true);
349
351
352 Layout();
353}
354
356{
358
359 // Since the same widget is provides both the Recording Meter as
360 // well as the Playback Meter, we choose an appropriate label
361 // based on which it is
363 ? XO("Recording Meter")
364 : XO("Playback Meter");
365
366 // Set label to pull in language change
368
369 // Give base class a chance
371}
372
374{
375 if ( mPlayMeter )
377
378 if ( mRecordMeter )
380}
381
383{
384 const auto size = GetSize();
385 const auto isHorizontal = size.x > size.y;
386
387 if(!force)
388 {
389 const auto sizerOrientation = mWhichMeters == kCombinedMeter
390 ? (isHorizontal ? wxVERTICAL : wxHORIZONTAL)
391 : (isHorizontal ? wxHORIZONTAL : wxVERTICAL);
392
393 if(mRootSizer->GetOrientation() == sizerOrientation)
394 {
395 Layout();
396 return;
397 }
398 }
399
400 if(mRootSizer != nullptr)
401 GetSizer()->Remove(mRootSizer);
402
403 std::unique_ptr<wxBoxSizer> playBarSizer;
404 std::unique_ptr<wxBoxSizer> recordBarSizer;
406 {
407 playBarSizer = std::make_unique<wxBoxSizer>(isHorizontal ? wxHORIZONTAL : wxVERTICAL);
408 playBarSizer->Add(mPlaySetupButton, 0, wxEXPAND | wxRIGHT, 2);
409 playBarSizer->Add(mPlayMeter, 1, wxEXPAND);
410 }
412 {
413 recordBarSizer = std::make_unique<wxBoxSizer>(isHorizontal ? wxHORIZONTAL : wxVERTICAL);
414 recordBarSizer->Add(mRecordSetupButton, 0, wxEXPAND | wxRIGHT, 2);
415 recordBarSizer->Add(mRecordMeter, 1, wxEXPAND);
416 }
417
418 if(playBarSizer && recordBarSizer)
419 {
420 Add(mRootSizer = safenew wxBoxSizer(isHorizontal ? wxVERTICAL : wxHORIZONTAL), 1, wxEXPAND | wxALL, 2);
421 mRootSizer->Add(playBarSizer.release());
422 mRootSizer->Add(recordBarSizer.release());
423 }
424 else if(playBarSizer)
425 Add(mRootSizer = playBarSizer.release(), 1, wxEXPAND | wxALL, 2);
426 else if(recordBarSizer)
427 Add(mRootSizer = recordBarSizer.release(), 1, wxEXPAND | wxALL, 2);
428}
429
430
431void MeterToolBar::OnSize( wxSizeEvent & event)
432{
433 event.Skip();
434
435 if(mRootSizer == nullptr)
436 return;// We can be resized before populating...protect against it
437 RebuildLayout(false);
438}
439
440bool MeterToolBar::Expose( bool show )
441{
442 auto &projectAudioIO = ProjectAudioIO::Get( mProject );
443 if( show ) {
444 if( mPlayMeter ) {
445 projectAudioIO.SetPlaybackMeter( mPlayMeter->GetMeter() );
446 }
447
448 if( mRecordMeter ) {
449 projectAudioIO.SetCaptureMeter( mRecordMeter->GetMeter() );
450 }
451 } else {
452 if( mPlayMeter &&
453 projectAudioIO.GetPlaybackMeter() == mPlayMeter->GetMeter() ) {
454 projectAudioIO.SetPlaybackMeter( nullptr );
455 }
456
457 if( mRecordMeter &&
458 projectAudioIO.GetCaptureMeter() == mRecordMeter->GetMeter() ) {
459 projectAudioIO.SetCaptureMeter( nullptr );
460 }
461 }
462
463 return ToolBar::Expose( show );
464}
465
467{
468 return (mWhichMeters ==
469 (kWithRecordMeter + kWithPlayMeter)) ? 338 : 290;
470}
471
473{
476}
477
479{
482}
483
485{
486 if (adj < 0) {
487 mPlayMeter->Decrease(-adj);
488 }
489 else {
490 mPlayMeter->Increase(adj);
491 }
492
494}
495
497{
498 if (adj < 0) {
499 mRecordMeter->Decrease(-adj);
500 }
501 else {
503 }
504
506}
507
510 return ToolBar::Holder{
512 XO("Recording Meter"), MeterToolBar::RecordID() } }; }
513};
516 return ToolBar::Holder{
518 XO("Playback Meter"), MeterToolBar::PlayID() } }; }
519};
522 return ToolBar::Holder{
525 XO("Combined Meter"), MeterToolBar::ID() } }; }
526};
527
528#include "ToolManager.h"
529
530namespace {
532 /* i18n-hint: Clicking this menu item shows the toolbar
533 with the recording level meters */
535 wxT("ShowRecordMeterTB"), XXO("&Recording Meter Toolbar"),
536 {}, { MeterToolBar::ID() }
537};
539 /* i18n-hint: Clicking this menu item shows the toolbar
540 with the playback level meter */
542 wxT("ShowPlayMeterTB"), XXO("&Playback Meter Toolbar"),
543 {}, { MeterToolBar::ID() }
544};
545//AttachedToolBarMenuItem sAttachment3{
546// /* --i18nhint: Clicking this menu item shows the toolbar
547// which has sound level meters */
548// MeterToolBar::ID(), wxT("ShowMeterTB"), XXO("Co&mbined Meter Toolbar"),
549// { Registry::OrderingHint::After, "ShowPlayMeterTB" },
550// { PlayMeterBarID, RecordMeterBarID }
551//};
552}
553
554// Now define other related menu items
555#include "CommandContext.h"
556
557namespace {
558void OnOutputGain(const CommandContext &context)
559{
560 auto &project = context.project;
561 auto &tb = MeterToolBar::Get( project, true );
562 tb.ShowOutputGainDialog();
563}
564
565void OnOutputGainInc(const CommandContext &context)
566{
567 auto &project = context.project;
568 auto &tb = MeterToolBar::Get( project, true );
569 tb.AdjustOutputGain(1);
570}
571
572void OnOutputGainDec(const CommandContext &context)
573{
574 auto &project = context.project;
575 auto &tb = MeterToolBar::Get( project, true );
576 tb.AdjustOutputGain(-1);
577}
578
579void OnInputGain(const CommandContext &context)
580{
581 auto &project = context.project;
582 auto &tb = MeterToolBar::Get( project, false );
583 tb.ShowInputGainDialog();
584}
585
586void OnInputGainInc(const CommandContext &context)
587{
588 auto &project = context.project;
589 auto &tb = MeterToolBar::Get( project, false );
590 tb.AdjustInputGain(1);
591}
592
593void OnInputGainDec(const CommandContext &context)
594{
595 auto &project = context.project;
596 auto &tb = MeterToolBar::Get( project, false );
597 tb.AdjustInputGain(-1);
598}
599
600using namespace MenuRegistry;
602{
603 static auto menu = std::shared_ptr{
604 Menu( wxT("Mixer"), XXO("Mi&xer"),
605 Command( wxT("OutputGain"), XXO("Ad&just Playback Volume..."),
607 Command( wxT("OutputGainInc"), XXO("&Increase Playback Volume"),
609 Command( wxT("OutputGainDec"), XXO("&Decrease Playback Volume"),
611 Command( wxT("InputGain"), XXO("Adj&ust Recording Volume..."),
613 Command( wxT("InputGainInc"), XXO("I&ncrease Recording Volume"),
615 Command( wxT("InputGainDec"), XXO("D&ecrease Recording Volume"),
617 ) };
618 return menu;
619}
620
622 wxT("Optional/Extra/Part1")
623};
624
625}
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: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:165
const auto project
THEME_API Theme theTheme
Definition: Theme.cpp:82
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:219
void SetToolTip(const TranslatableString &toolTip)
Definition: AButton.cpp:198
@ FrameButton
Definition: AButton.h:114
void SetIcon(const wxImage &icon)
Definition: AButton.cpp:240
void SetLabel(const TranslatableString &label)
Definition: AButton.cpp:203
void SetFrameMid(int mid)
Definition: AButton.cpp:158
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:91
bool ShowDialog()
Definition: MeterPanel.cpp:803
void Decrease(float steps)
Definition: MeterPanel.cpp:829
void Increase(float steps)
Definition: MeterPanel.cpp:818
void UpdateSliderControl()
Definition: MeterPanel.cpp:410
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:77
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: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:81
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)