From d9d3f955703ed309a76c02fb8f60654c8dffddb0 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 5 Jan 2019 16:26:09 -0500 Subject: [PATCH] Several nonmodal top level window tools register their menu items... ... removing link dependencies on them from src/menus, so they are now suitable for moving out into modules. They are: Mixer Board Karaoke (also called Lyrics) History Contrast Plot Spectrum Their header files are now no longer included anywhere but in their own implementation files! --- src/FreqWindow.cpp | 54 +++++++++++++++++++++ src/HistoryWindow.cpp | 83 +++++++++++++++++++++++++++++++++ src/LyricsWindow.cpp | 44 ++++++++++++++++++ src/Menus.cpp | 35 ++++++++++++++ src/MixerBoard.cpp | 42 +++++++++++++++++ src/effects/Contrast.cpp | 56 +++++++++++++++++++++- src/menus/PluginMenus.cpp | 53 +-------------------- src/menus/ViewMenus.cpp | 98 +-------------------------------------- 8 files changed, 315 insertions(+), 150 deletions(-) diff --git a/src/FreqWindow.cpp b/src/FreqWindow.cpp index 2ff939d20..c029ce377 100644 --- a/src/FreqWindow.cpp +++ b/src/FreqWindow.cpp @@ -67,11 +67,13 @@ the mouse around. #include "ShuttleGui.h" #include "AColor.h" +#include "CommonCommandFlags.h" #include "FFT.h" #include "PitchName.h" #include "prefs/GUISettings.h" #include "Prefs.h" #include "Project.h" +#include "ProjectWindow.h" #include "WaveClip.h" #include "ViewInfo.h" #include "AllThemeResources.h" @@ -1137,3 +1139,55 @@ void FreqPlot::OnMouseEvent(wxMouseEvent & event) freqWindow->PlotMouseEvent(event); } +// Remaining code hooks this add-on into the application +#include "commands/CommandContext.h" +#include "commands/CommandManager.h" +#include "commands/ScreenshotCommand.h" + +namespace { + +AudacityProject::AttachedWindows::RegisteredFactory sFrequencyWindowKey{ + []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { + auto &window = ProjectWindow::Get( parent ); + return safenew FrequencyPlotDialog( + &window, -1, parent, XO("Frequency Analysis"), + wxPoint{ 150, 150 } + ); + } +}; + +// Define our extra menu item that invokes that factory +struct Handler : CommandHandlerObject { + void OnPlotSpectrum(const CommandContext &context) + { + auto &project = context.project; + auto freqWindow = + &project.AttachedWindows::Get< FrequencyPlotDialog >( sFrequencyWindowKey ); + + if( ScreenshotCommand::MayCapture( freqWindow ) ) + return; + freqWindow->Show(true); + freqWindow->Raise(); + freqWindow->SetFocus(); + } +}; + +CommandHandlerObject &findCommandHandler(AudacityProject &) { + // Handler is not stateful. Doesn't need a factory registered with + // AudacityProject. + static Handler instance; + return instance; +} + +// Register that menu item + +using namespace MenuTable; +AttachedItem sAttachment{ wxT("Analyze/Analyzers/Windows"), + ( FinderScope{ findCommandHandler }, + Command( wxT("PlotSpectrum"), XXO("Plot Spectrum..."), + &Handler::OnPlotSpectrum, + AudioIONotBusyFlag() | WaveTracksSelectedFlag() | TimeSelectedFlag() ) ) +}; + +} + diff --git a/src/HistoryWindow.cpp b/src/HistoryWindow.cpp index 3b0801233..d84ea2d2f 100644 --- a/src/HistoryWindow.cpp +++ b/src/HistoryWindow.cpp @@ -35,6 +35,7 @@ undo memory so as to free up space. #include "AudioIO.h" #include "Clipboard.h" +#include "CommonCommandFlags.h" #include "../images/Arrow.xpm" #include "../images/Empty9x16.xpm" #include "UndoManager.h" @@ -316,3 +317,85 @@ void HistoryDialog::OnSize(wxSizeEvent & WXUNUSED(event)) if (mList->GetItemCount() > 0) mList->EnsureVisible(mSelected); } + +// Remaining code hooks this add-on into the application +#include "commands/CommandContext.h" +#include "commands/CommandManager.h" + +namespace { + +// History window attached to each project is built on demand by: +AudacityProject::AttachedWindows::RegisteredFactory sHistoryWindowKey{ + []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { + auto &undoManager = UndoManager::Get( parent ); + return safenew HistoryDialog( &parent, &undoManager ); + } +}; + +// Define our extra menu item that invokes that factory +struct Handler : CommandHandlerObject { + void OnHistory(const CommandContext &context) + { + auto &project = context.project; + + auto historyWindow = &project.AttachedWindows::Get( sHistoryWindowKey ); + historyWindow->Show(); + historyWindow->Raise(); + } +}; + +CommandHandlerObject &findCommandHandler(AudacityProject &) { + // Handler is not stateful. Doesn't need a factory registered with + // AudacityProject. + static Handler instance; + return instance; +} + +// Register that menu item + +using namespace MenuTable; +AttachedItem sAttachment{ wxT("View/Windows"), + // History window should be available either for UndoAvailableFlag + // or RedoAvailableFlag, + // but we can't make the AddItem flags and mask have both, + // because they'd both have to be true for the + // command to be enabled. + // If user has Undone the entire stack, RedoAvailableFlag is on + // but UndoAvailableFlag is off. + // If user has done things but not Undone anything, + // RedoAvailableFlag is off but UndoAvailableFlag is on. + // So in either of those cases, + // (AudioIONotBusyFlag | UndoAvailableFlag | RedoAvailableFlag) mask + // would fail. + // The only way to fix this in the current architecture + // is to hack in special cases for RedoAvailableFlag + // in AudacityProject::UpdateMenus() (ugly) + // and CommandManager::HandleCommandEntry() (*really* ugly -- + // shouldn't know about particular command names and flags). + // Here's the hack that would be necessary in + // AudacityProject::UpdateMenus(), if somebody decides to do it: + // // Because EnableUsingFlags requires all the flag bits match the + // // corresponding mask bits, + // // "UndoHistory" specifies only + // // AudioIONotBusyFlag | UndoAvailableFlag, because that + // // covers the majority of cases where it should be enabled. + // // If history is not empty but we've Undone the whole stack, + // // we also want to enable, + // // to show the Redo's on stack. + // // "UndoHistory" might already be enabled, + // // but add this check for RedoAvailableFlag. + // if (flags & RedoAvailableFlag) + // GetCommandManager()->Enable(wxT("UndoHistory"), true); + // So for now, enable the command regardless of stack. + // It will just show empty sometimes. + // FOR REDESIGN, + // clearly there are some limitations with the flags/mask bitmaps. + + /* i18n-hint: Clicking this menu item shows the various editing steps + that have been taken.*/ + ( FinderScope{ findCommandHandler }, + Command( wxT("UndoHistory"), XXO("&History..."), &Handler::OnHistory, + AudioIONotBusyFlag() ) ) +}; + +} diff --git a/src/LyricsWindow.cpp b/src/LyricsWindow.cpp index 75914fc6b..157501190 100644 --- a/src/LyricsWindow.cpp +++ b/src/LyricsWindow.cpp @@ -12,6 +12,7 @@ #include "LyricsWindow.h" #include "Lyrics.h" #include "AudioIOBase.h" +#include "CommonCommandFlags.h" #include "Prefs.h" // for RTL_WORKAROUND #include "Project.h" #include "ProjectAudioIO.h" @@ -167,3 +168,46 @@ void LyricsWindow::OnTimer(wxCommandEvent &event) // Let other listeners get the notification event.Skip(); } + +// Remaining code hooks this add-on into the application +#include "commands/CommandContext.h" +#include "commands/CommandManager.h" + +namespace { + +// Lyrics window attached to each project is built on demand by: +AudacityProject::AttachedWindows::RegisteredFactory sLyricsWindowKey{ + []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { + return safenew LyricsWindow( &parent ); + } +}; + +// Define our extra menu item that invokes that factory +struct Handler : CommandHandlerObject { + void OnKaraoke(const CommandContext &context) + { + auto &project = context.project; + + auto lyricsWindow = &project.AttachedWindows::Get( sLyricsWindowKey ); + lyricsWindow->Show(); + lyricsWindow->Raise(); + } +}; + +CommandHandlerObject &findCommandHandler(AudacityProject &) { + // Handler is not stateful. Doesn't need a factory registered with + // AudacityProject. + static Handler instance; + return instance; +} + +// Register that menu item + +using namespace MenuTable; +AttachedItem sAttachment{ wxT("View/Windows"), + ( FinderScope{ findCommandHandler }, + Command( wxT("Karaoke"), XXO("&Karaoke..."), &Handler::OnKaraoke, + LabelTracksExistFlag() ) ) +}; + +} diff --git a/src/Menus.cpp b/src/Menus.cpp index 23f38d0b4..7edc7dabe 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -42,6 +42,7 @@ #include "widgets/AudacityMessageBox.h" #include "widgets/ErrorDialog.h" +#include #include #include @@ -1000,7 +1001,38 @@ static const auto menuTree = MenuTable::Items( MenuPathStart ); namespace { + +// Once only, cause initial population of preferences for the ordering +// of some menu items that used to be given in tables but are now separately +// registered in several .cpp files; the sequence of registration depends +// on unspecified accidents of static initialization order across +// compilation units, so we need something specific here to preserve old +// default appearance of menus. +// But this needs only to mention some strings -- there is no compilation or +// link dependency of this source file on those other implementation files. +void InitializeMenuOrdering() +{ + using Pair = std::pair; + static const Pair pairs [] = { + {wxT("/View/Windows"), wxT("UndoHistory,Karaoke,MixerBoard")}, + {wxT("/Analyze/Analyzers/Windows"), wxT("ContrastAnalyser,PlotSpectrum")}, + }; + + bool doFlush = false; + for (auto pair : pairs) { + const auto key = wxString{'/'} + MenuPathStart + pair.first; + if ( gPrefs->Read(key).empty() ) { + gPrefs->Write( key, pair.second ); + doFlush = true; + } + } + + if (doFlush) + gPrefs->Flush(); +} + using namespace MenuTable; + struct MenuItemVisitor : MenuVisitor { MenuItemVisitor( AudacityProject &proj, CommandManager &man ) @@ -1102,6 +1134,9 @@ struct MenuItemVisitor : MenuVisitor void MenuCreator::CreateMenusAndCommands(AudacityProject &project) { + static std::once_flag flag; + std::call_once( flag, InitializeMenuOrdering ); + auto &commandManager = CommandManager::Get( project ); // The list of defaults to exclude depends on diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 7f4557124..b68902b5d 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -33,6 +33,7 @@ #include "NoteTrack.h" #endif +#include "CommonCommandFlags.h" #include "KeyboardCapture.h" #include "Prefs.h" // for RTL_WORKAROUND #include "Project.h" @@ -1484,5 +1485,46 @@ void MixerBoardFrame::Recreate( AudacityProject *pProject ) this->SetSize( siz2 ); } +// Remaining code hooks this add-on into the application +#include "commands/CommandContext.h" +namespace { + +// Mixer board window attached to each project is built on demand by: +AudacityProject::AttachedWindows::RegisteredFactory sMixerBoardKey{ + []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { + return safenew MixerBoardFrame( &parent ); + } +}; + +// Define our extra menu item that invokes that factory +struct Handler : CommandHandlerObject { + void OnMixerBoard(const CommandContext &context) + { + auto &project = context.project; + + auto mixerBoardFrame = &project.AttachedWindows::Get( sMixerBoardKey ); + mixerBoardFrame->Show(); + mixerBoardFrame->Raise(); + mixerBoardFrame->SetFocus(); + } +}; + +CommandHandlerObject &findCommandHandler(AudacityProject &) { + // Handler is not stateful. Doesn't need a factory registered with + // AudacityProject. + static Handler instance; + return instance; +} + +// Register that menu item + +using namespace MenuTable; +AttachedItem sAttachment{ wxT("View/Windows"), + ( FinderScope{ findCommandHandler }, + Command( wxT("MixerBoard"), XXO("&Mixer Board..."), &Handler::OnMixerBoard, + PlayableTracksExistFlag()) ) +}; + +} diff --git a/src/effects/Contrast.cpp b/src/effects/Contrast.cpp index ba67e5687..2a64815fa 100644 --- a/src/effects/Contrast.cpp +++ b/src/effects/Contrast.cpp @@ -12,11 +12,12 @@ #include "../Audacity.h" #include "Contrast.h" +#include "../CommonCommandFlags.h" #include "../WaveTrack.h" #include "../Prefs.h" #include "../Project.h" #include "../ProjectSettings.h" -#include "../ProjectWindowBase.h" +#include "../ProjectWindow.h" #include "../ShuttleGui.h" #include "../FileNames.h" #include "../ViewInfo.h" @@ -648,3 +649,56 @@ void ContrastDialog::OnReset(wxCommandEvent & /*event*/) mPassFailText->ChangeValue(wxT("")); mDiffText->ChangeValue(wxT("")); } + +// Remaining code hooks this add-on into the application +#include "commands/CommandContext.h" +#include "commands/CommandManager.h" +#include "../commands/ScreenshotCommand.h" + +namespace { + +// Contrast window attached to each project is built on demand by: +AudacityProject::AttachedWindows::RegisteredFactory sContrastDialogKey{ + []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { + auto &window = ProjectWindow::Get( parent ); + return safenew ContrastDialog( + &window, -1, XO("Contrast Analysis (WCAG 2 compliance)"), + wxPoint{ 150, 150 } + ); + } +}; + +// Define our extra menu item that invokes that factory +struct Handler : CommandHandlerObject { + void OnContrast(const CommandContext &context) + { + auto &project = context.project; + auto contrastDialog = + &project.AttachedWindows::Get< ContrastDialog >( sContrastDialogKey ); + + contrastDialog->CentreOnParent(); + if( ScreenshotCommand::MayCapture( contrastDialog ) ) + return; + contrastDialog->Show(); + } +}; + +CommandHandlerObject &findCommandHandler(AudacityProject &) { + // Handler is not stateful. Doesn't need a factory registered with + // AudacityProject. + static Handler instance; + return instance; +} + +// Register that menu item + +using namespace MenuTable; +AttachedItem sAttachment{ wxT("Analyze/Analyzers/Windows"), + ( FinderScope{ findCommandHandler }, + Command( wxT("ContrastAnalyser"), XXO("Contrast..."), + &Handler::OnContrast, + AudioIONotBusyFlag() | WaveTracksSelectedFlag() | TimeSelectedFlag(), + wxT("Ctrl+Shift+T") ) ) +}; + +} diff --git a/src/menus/PluginMenus.cpp b/src/menus/PluginMenus.cpp index 60473a51a..3e8a34c6c 100644 --- a/src/menus/PluginMenus.cpp +++ b/src/menus/PluginMenus.cpp @@ -5,7 +5,6 @@ #include "../BatchProcessDialog.h" #include "../Benchmark.h" #include "../CommonCommandFlags.h" -#include "../FreqWindow.h" #include "../Menus.h" #include "../PluginManager.h" #include "../Prefs.h" @@ -16,7 +15,6 @@ #include "../commands/CommandContext.h" #include "../commands/CommandManager.h" #include "../commands/ScreenshotCommand.h" -#include "../effects/Contrast.h" #include "../effects/EffectManager.h" #include "../effects/EffectUI.h" #include "../effects/RealtimeEffectManager.h" @@ -25,26 +23,6 @@ // private helper classes and functions namespace { -AudacityProject::AttachedWindows::RegisteredFactory sContrastDialogKey{ - []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { - auto &window = ProjectWindow::Get( parent ); - return safenew ContrastDialog( - &window, -1, XO("Contrast Analysis (WCAG 2 compliance)"), - wxPoint{ 150, 150 } - ); - } -}; - -AudacityProject::AttachedWindows::RegisteredFactory sFrequencyWindowKey{ - []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { - auto &window = ProjectWindow::Get( parent ); - return safenew FrequencyPlotDialog( - &window, -1, parent, XO("Frequency Analysis"), - wxPoint{ 150, 150 } - ); - } -}; - AudacityProject::AttachedWindows::RegisteredFactory sMacrosWindowKey{ []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { auto &window = ProjectWindow::Get( parent ); @@ -456,31 +434,6 @@ void OnManageAnalyzers(const CommandContext &context) DoManagePluginsMenu(project, EffectTypeAnalyze); } -void OnContrast(const CommandContext &context) -{ - auto &project = context.project; - auto contrastDialog = - &project.AttachedWindows::Get< ContrastDialog >( sContrastDialogKey ); - - contrastDialog->CentreOnParent(); - if( ScreenshotCommand::MayCapture( contrastDialog ) ) - return; - contrastDialog->Show(); -} - -void OnPlotSpectrum(const CommandContext &context) -{ - auto &project = context.project; - auto freqWindow = - &project.AttachedWindows::Get< FrequencyPlotDialog >( sFrequencyWindowKey ); - - if( ScreenshotCommand::MayCapture( freqWindow ) ) - return; - freqWindow->Show(true); - freqWindow->Raise(); - freqWindow->SetFocus(); -} - void OnManageTools(const CommandContext &context ) { auto &project = context.project; @@ -852,11 +805,7 @@ MenuTable::BaseItemSharedPtr AnalyzeMenu() #endif Section( "Analyzers", - Command( wxT("ContrastAnalyser"), XXO("Contrast..."), FN(OnContrast), - AudioIONotBusyFlag() | WaveTracksSelectedFlag() | TimeSelectedFlag(), - wxT("Ctrl+Shift+T") ), - Command( wxT("PlotSpectrum"), XXO("Plot Spectrum..."), FN(OnPlotSpectrum), - AudioIONotBusyFlag() | WaveTracksSelectedFlag() | TimeSelectedFlag() ), + Items( "Windows" ), // Delayed evaluation: [](AudacityProject&) diff --git a/src/menus/ViewMenus.cpp b/src/menus/ViewMenus.cpp index e8ab97110..ce570c21b 100644 --- a/src/menus/ViewMenus.cpp +++ b/src/menus/ViewMenus.cpp @@ -2,10 +2,7 @@ #include "../Experimental.h" #include "../CommonCommandFlags.h" -#include "../HistoryWindow.h" -#include "../LyricsWindow.h" #include "../Menus.h" -#include "../MixerBoard.h" #include "../Prefs.h" #include "../Project.h" #include "../ProjectHistory.h" @@ -31,25 +28,6 @@ // private helper classes and functions namespace { -AudacityProject::AttachedWindows::RegisteredFactory sMixerBoardKey{ - []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { - return safenew MixerBoardFrame( &parent ); - } -}; - -AudacityProject::AttachedWindows::RegisteredFactory sHistoryWindowKey{ - []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { - auto &undoManager = UndoManager::Get( parent ); - return safenew HistoryDialog( &parent, &undoManager ); - } -}; - -AudacityProject::AttachedWindows::RegisteredFactory sLyricsWindowKey{ - []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { - return safenew LyricsWindow( &parent ); - } -}; - double GetZoomOfSelection( const AudacityProject &project ) { auto &viewInfo = ViewInfo::Get( project ); @@ -325,34 +303,6 @@ void OnGoSelEnd(const CommandContext &context) selectedRegion.t1() - ((viewInfo.GetScreenEndTime() - viewInfo.h) / 2)); } -void OnHistory(const CommandContext &context) -{ - auto &project = context.project; - - auto historyWindow = &project.AttachedWindows::Get( sHistoryWindowKey ); - historyWindow->Show(); - historyWindow->Raise(); -} - -void OnKaraoke(const CommandContext &context) -{ - auto &project = context.project; - - auto lyricsWindow = &project.AttachedWindows::Get( sLyricsWindowKey ); - lyricsWindow->Show(); - lyricsWindow->Raise(); -} - -void OnMixerBoard(const CommandContext &context) -{ - auto &project = context.project; - - auto mixerBoardFrame = &project.AttachedWindows::Get( sMixerBoardKey ); - mixerBoardFrame->Show(); - mixerBoardFrame->Raise(); - mixerBoardFrame->SetFocus(); -} - void OnShowExtraMenus(const CommandContext &context) { auto &project = context.project; @@ -487,53 +437,7 @@ MenuTable::BaseItemSharedPtr ViewMenu() ) ), - Section( "Windows", - // History window should be available either for UndoAvailableFlag - // or RedoAvailableFlag, - // but we can't make the AddItem flags and mask have both, - // because they'd both have to be true for the - // command to be enabled. - // If user has Undone the entire stack, RedoAvailableFlag is on - // but UndoAvailableFlag is off. - // If user has done things but not Undone anything, - // RedoAvailableFlag is off but UndoAvailableFlag is on. - // So in either of those cases, - // (AudioIONotBusyFlag | UndoAvailableFlag | RedoAvailableFlag) mask - // would fail. - // The only way to fix this in the current architecture - // is to hack in special cases for RedoAvailableFlag - // in AudacityProject::UpdateMenus() (ugly) - // and CommandManager::HandleCommandEntry() (*really* ugly -- - // shouldn't know about particular command names and flags). - // Here's the hack that would be necessary in - // AudacityProject::UpdateMenus(), if somebody decides to do it: - // // Because EnableUsingFlags requires all the flag bits match the - // // corresponding mask bits, - // // "UndoHistory" specifies only - // // AudioIONotBusyFlag | UndoAvailableFlag, because that - // // covers the majority of cases where it should be enabled. - // // If history is not empty but we've Undone the whole stack, - // // we also want to enable, - // // to show the Redo's on stack. - // // "UndoHistory" might already be enabled, - // // but add this check for RedoAvailableFlag. - // if (flags & RedoAvailableFlag) - // GetCommandManager()->Enable(wxT("UndoHistory"), true); - // So for now, enable the command regardless of stack. - // It will just show empty sometimes. - // FOR REDESIGN, - // clearly there are some limitations with the flags/mask bitmaps. - - /* i18n-hint: Clicking this menu item shows the various editing steps - that have been taken.*/ - Command( wxT("UndoHistory"), XXO("&History..."), FN(OnHistory), - AudioIONotBusyFlag() ), - - Command( wxT("Karaoke"), XXO("&Karaoke..."), FN(OnKaraoke), - LabelTracksExistFlag() ), - Command( wxT("MixerBoard"), XXO("&Mixer Board..."), FN(OnMixerBoard), - PlayableTracksExistFlag() ) - ), + Section( "Windows" ), Section( "", //////////////////////////////////////////////////////////////////////////