/********************************************************************** Audacity: A Digital Audio Editor CommonCommandFlags.cpp Paul Licameli split from Menus.cpp **********************************************************************/ #include "Audacity.h" #include "CommonCommandFlags.h" #include "Experimental.h" #include #include "AudioIO.h" #include "LabelTrack.h" #include "Menus.h" #include "NoteTrack.h" #include "Project.h" #include "ProjectAudioIO.h" #include "ProjectFileIO.h" #include "ProjectHistory.h" #include "ProjectSettings.h" #include "UndoManager.h" #include "ViewInfo.h" #include "WaveTrack.h" #include "commands/CommandManagerWindowClasses.h" #include "toolbars/ControlToolBar.h" /* This file registers functions implementing many of the tests for enabling of menu items. Sequence of a few of them has minor significance, but for most there is little reason to keep them in one file. Flags used only by one other file might instead be defined only where used. They are collected here because Menus.cpp is too low level to have the dependencies implied by the include directives above -- it would make dependency cycles. */ // Really means, some track is selected, that isn't a time track bool TracksSelectedPred( const AudacityProject &project ) { auto range = TrackList::Get( project ).Selected() - []( const Track *pTrack ){ return track_cast( pTrack ); }; return !range.empty(); }; bool AudioIOBusyPred( const AudacityProject &project ) { return AudioIOBase::Get()->IsAudioTokenActive( ProjectAudioIO::Get( project ).GetAudioIOToken()); }; bool TimeSelectedPred( const AudacityProject &project ) { // This is equivalent to check if there is a valid selection, // so it's used for Zoom to Selection too return !ViewInfo::Get( project ).selectedRegion.isPoint(); }; const CommandFlagOptions cutCopyOptions{ // In reporting the issue with cut or copy, we don't tell the user they could also select some text in a label. []( const wxString &Name ) { // PRL: These strings have hard-coded mention of a certain shortcut key, // thus assuming the default shortcuts. That is questionable. wxString format; #ifdef EXPERIMENTAL_DA // i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade. format = _("You must first select some audio for '%s' to act on.\n\nCtrl + A selects all audio."); #else #ifdef __WXMAC__ // i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade. format = _("Select the audio for %s to use (for example, Cmd + A to Select All) then try again." // No need to explain what a help button is for. // "\n\nClick the Help button to learn more about selection methods." ); #else // i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade. format = _("Select the audio for %s to use (for example, Ctrl + A to Select All) then try again." // No need to explain what a help button is for. // "\n\nClick the Help button to learn more about selection methods." ); #endif return wxString::Format( format, Name ); #endif }, "Selecting_Audio_-_the_basics", XO("No Audio Selected") }; const ReservedCommandFlag // The sequence of these definitions has a minor significance in determining // which user error message has precedence if more than one might apply, so // they should be kept in this sequence in one .cpp file if it is important // to preserve that behavior. If they are dispersed to more than one file, // then the precedence will be unspecified. // The ordering of the flags that only disable the default message is not // significant. AudioIONotBusyFlag{ [](const AudacityProject &project ){ return !AudioIOBusyPred( project ); }, CommandFlagOptions{ []( const wxString& ) { return // This reason will not be shown, because options that require it will be greyed out. _("You can only do this when playing and recording are\nstopped. (Pausing is not sufficient.)"); } } .QuickTest() .Priority( 1 ) }, //lll StereoRequiredFlag{ [](const AudacityProject &project){ // True iff at least one stereo track is selected, i.e., at least // one right channel is selected. // TODO: more-than-two-channels auto range = TrackList::Get( project ).Selected() - &Track::IsLeader; return !range.empty(); }, { []( const wxString& ) { return // This reason will not be shown, because the stereo-to-mono is greyed out if not allowed. _("You must first select some stereo audio to perform this\naction. (You cannot use this with mono.)"); } } }, //lda TimeSelectedFlag{ TimeSelectedPred, cutCopyOptions }, WaveTracksSelectedFlag{ [](const AudacityProject &project){ return !TrackList::Get( project ).Selected().empty(); }, { []( const wxString& ) { return _("You must first select some audio to perform this action.\n(Selecting other kinds of track won't work.)"); } } }, TracksExistFlag{ [](const AudacityProject &project){ return !TrackList::Get( project ).Any().empty(); }, CommandFlagOptions{}.DisableDefaultMessage() }, TracksSelectedFlag{ TracksSelectedPred, { []( const wxString &Name ){ return wxString::Format( // i18n-hint: %s will be replaced by the name of an action, such as "Remove Tracks". _("\"%s\" requires one or more tracks to be selected."), Name ); } } }, TrackPanelHasFocus{ [](const AudacityProject &project){ for (auto w = wxWindow::FindFocus(); w; w = w->GetParent()) { if (dynamic_cast(w)) return true; } return false; }, CommandFlagOptions{}.DisableDefaultMessage() }; //lll const ReservedCommandFlag AudioIOBusyFlag{ AudioIOBusyPred, CommandFlagOptions{}.QuickTest() }, //lll CaptureNotBusyFlag{ [](const AudacityProject &){ auto gAudioIO = AudioIO::Get(); return !( gAudioIO->IsBusy() && gAudioIO->GetNumCaptureChannels() > 0 ); } }, HasWaveDataFlag{ [](const AudacityProject &project){ auto range = TrackList::Get( project ).Any() + [](const WaveTrack *pTrack){ return pTrack->GetEndTime() > pTrack->GetStartTime(); }; return !range.empty(); } }; // jkc const ReservedCommandFlag LabelTracksExistFlag{ [](const AudacityProject &project){ return !TrackList::Get( project ).Any().empty(); } }, UnsavedChangesFlag{ [](const AudacityProject &project){ auto &undoManager = UndoManager::Get( project ); return undoManager.UnsavedChanges() || !ProjectFileIO::Get( project ).IsProjectSaved() ; } }, HasLastEffectFlag{ [](const AudacityProject &project){ return !MenuManager::Get( project ).mLastEffect.empty(); } }, UndoAvailableFlag{ [](const AudacityProject &project){ return ProjectHistory::Get( project ).UndoAvailable(); } }, RedoAvailableFlag{ [](const AudacityProject &project){ return ProjectHistory::Get( project ).RedoAvailable(); } }, ZoomInAvailableFlag{ [](const AudacityProject &project){ return ViewInfo::Get( project ).ZoomInAvailable() && !TrackList::Get( project ).Any().empty() ; } }, ZoomOutAvailableFlag{ [](const AudacityProject &project){ return ViewInfo::Get( project ).ZoomOutAvailable() && !TrackList::Get( project ).Any().empty() ; } }, LabelsSelectedFlag{ [](const AudacityProject &project){ // At least one label track selected, having at least one label // completely within the time selection. const auto &selectedRegion = ViewInfo::Get( project ).selectedRegion; const auto &test = [&]( const LabelTrack *pTrack ){ const auto &labels = pTrack->GetLabels(); return std::any_of( labels.begin(), labels.end(), [&](const LabelStruct &label){ return label.getT0() >= selectedRegion.t0() && label.getT1() <= selectedRegion.t1() ; } ); }; auto range = TrackList::Get( project ).Selected() + test; return !range.empty(); } }, PlayRegionLockedFlag{ [](const AudacityProject &project){ return ViewInfo::Get(project).playRegion.Locked(); } }, //msmeyer PlayRegionNotLockedFlag{ [](const AudacityProject &project){ const auto &playRegion = ViewInfo::Get(project).playRegion; return !playRegion.Locked() && !playRegion.Empty(); } }, //msmeyer WaveTracksExistFlag{ [](const AudacityProject &project){ return !TrackList::Get( project ).Any().empty(); } }, NoteTracksExistFlag{ [](const AudacityProject &project){ return !TrackList::Get( project ).Any().empty(); } }, //gsw NoteTracksSelectedFlag{ [](const AudacityProject &project){ return !TrackList::Get( project ).Selected().empty(); } }, //gsw IsNotSyncLockedFlag{ [](const AudacityProject &project){ return !ProjectSettings::Get( project ).IsSyncLocked(); } }, //awd IsSyncLockedFlag{ [](const AudacityProject &project){ return ProjectSettings::Get( project ).IsSyncLocked(); } }, //awd NotMinimizedFlag{ [](const AudacityProject &project){ const wxWindow *focus = FindProjectFrame( &project ); if (focus) { while (focus && focus->GetParent()) focus = focus->GetParent(); } return (focus && !static_cast(focus)->IsIconized() ); }, CommandFlagOptions{}.QuickTest() }, // prl PausedFlag{ [](const AudacityProject&){ return AudioIOBase::Get()->IsPaused(); }, CommandFlagOptions{}.QuickTest() }, PlayableTracksExistFlag{ [](const AudacityProject &project){ auto &tracks = TrackList::Get( project ); return #ifdef EXPERIMENTAL_MIDI_OUT !tracks.Any().empty() || #endif !tracks.Any().empty() ; } }, AudioTracksSelectedFlag{ [](const AudacityProject &project){ auto &tracks = TrackList::Get( project ); return !tracks.Selected().empty() // even if not EXPERIMENTAL_MIDI_OUT || !tracks.Selected().empty() ; } }, NoAutoSelect{ [](const AudacityProject &){ return true; } } // jkc ; RegisteredMenuItemEnabler stopIfPaused{{ PausedFlag, AudioIONotBusyFlag, []( const AudacityProject &project ){ return MenuManager::Get( project ).mStopIfWasPaused; }, []( AudacityProject &project, CommandFlag ){ if ( MenuManager::Get( project ).mStopIfWasPaused ) TransportActions::StopIfPaused( project ); } }};