diff --git a/src/Menus.cpp b/src/Menus.cpp index 9a3aebb43..6b8e41078 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -1775,6 +1775,9 @@ void MenuCreator::CreateMenusAndCommands(AudacityProject &project) c->BeginMenu(_("&Help")); + c->AddItem( wxT("QuickFix"), XXO("&Quick Fix..."), FN(OnQuickFix), + AlwaysEnabledFlag ); + // DA: Emphasise it is the Audacity Manual (No separate DA manual). #ifdef EXPERIMENTAL_DA // 'Getting Started' rather than 'Quick Help' for DarkAudacity. @@ -9407,6 +9410,14 @@ void MenuCommandHandler::OnQuickHelp(const CommandContext &context) wxT("Quick_Help")); } + +void MenuCommandHandler::OnQuickFix(const CommandContext &context) +{ + auto &project = context.project; + QuickFixDialog dlg( &project ); + dlg.ShowModal(); +} + void MenuCommandHandler::OnManual(const CommandContext &context) { auto &project = context.project; diff --git a/src/Menus.h b/src/Menus.h index c0ca5435a..0baf0de2a 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -520,6 +520,7 @@ void OnManageTools(const CommandContext &context ); void OnAbout(const CommandContext &context ); void OnQuickHelp(const CommandContext &context ); +void OnQuickFix(const CommandContext &context ); void OnManual(const CommandContext &context ); void OnCheckForUpdates(const CommandContext &context ); void MayCheckForUpdates(AudacityProject &project); diff --git a/src/widgets/HelpSystem.cpp b/src/widgets/HelpSystem.cpp index 077c90817..2ca6d5a26 100644 --- a/src/widgets/HelpSystem.cpp +++ b/src/widgets/HelpSystem.cpp @@ -367,3 +367,179 @@ void HelpSystem::ShowHelp(wxWindow *parent, bModal ); } + +#include "../ShuttleGui.h" +// These three are all for the OnReloadPreferences command. +#include "../Project.h" +#include "../commands/CommandContext.h" +#include "../Menus.h" + +#define FixButtonID 7001 +#define HelpButtonID 7011 +#define FakeButtonID 7021 + +BEGIN_EVENT_TABLE(QuickFixDialog, wxDialogWrapper) + EVT_BUTTON(wxID_OK, QuickFixDialog::OnOk) + EVT_BUTTON(wxID_CANCEL, QuickFixDialog::OnCancel) + EVT_BUTTON(wxID_HELP, QuickFixDialog::OnHelp) + EVT_COMMAND_RANGE(FixButtonID, HelpButtonID-1, wxEVT_BUTTON, QuickFixDialog::OnFix) + EVT_COMMAND_RANGE(HelpButtonID, FakeButtonID-1, wxEVT_BUTTON, QuickFixDialog::OnHelp) +END_EVENT_TABLE(); + +QuickFixDialog::QuickFixDialog(wxWindow * pParent) : + wxDialogWrapper(pParent, wxID_ANY, _("Do you have these problems?"), + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE ) +{ + const long SNAP_OFF = 0; + + gPrefs->Read(wxT("/GUI/SyncLockTracks"), &mbSyncLocked, false); + mbInSnapTo = gPrefs->Read(wxT("/SnapTo"), SNAP_OFF) !=0; + gPrefs->Read(wxT("/AudioIO/SoundActivatedRecord"), &mbSoundActivated, false); + + ShuttleGui S(this, eIsCreating); + PopulateOrExchange(S); + + Fit(); + auto sz = GetSize(); + SetMinSize( sz ); + SetMaxSize( sz ); + + // The close button has the cancel id and acts exactly the same as cancel. + wxButton * pWin = (wxButton*)FindWindowById( wxID_CANCEL ); + if( pWin ) + pWin->SetFocus( ); + Center(); +} + +void QuickFixDialog::AddStuck( ShuttleGui & S, bool & bBool, wxString Pref, wxString Prompt, wxString Help ) +{ + mItem++; + if( !bBool) + return; + S.AddFixedText( Prompt ); + S.Id(FixButtonID + mItem).AddButton( _("Fix") )->SetClientData( safenew wxStringClientData(Pref)); + + { + // Replace standard Help button with smaller icon button. + // bs->AddButton(safenew wxButton(parent, wxID_HELP)); + auto b = safenew wxBitmapButton(S.GetParent(), HelpButtonID+mItem, theTheme.Bitmap( bmpHelpIcon )); + b->SetToolTip( _("Help") ); + b->SetLabel(_("Help")); // for screen readers + b->SetClientData( safenew wxStringClientData( Help )); + S.AddWindow( b ); + } +} + +void QuickFixDialog::PopulateOrExchange(ShuttleGui & S) +{ + + S.StartVerticalLay(1); + S.StartStatic( _("Quick Fixes")); + + // These aren't all possible modes one can be stuck in, but they are some of them. + bool bStuckInMode = mbSyncLocked || mbInSnapTo || mbSoundActivated; + + if( !bStuckInMode ){ + SetLabel(_("Nothing to do")); + S.AddFixedText(_("No quick, easily fixed problems were found")); + } + else { + S.StartMultiColumn(3, wxALIGN_CENTER); + { + mItem = -1; + + // Use # in the URLs to ensure we go to the online version of help. + // Local help may well not be installed. + AddStuck( S, mbSyncLocked, "/GUI/SyncLockTracks", _("Clocks on the Tracks"), "Quick_Fix#sync_lock" ); + AddStuck( S, mbInSnapTo, "/SnapTo", _("Can't select precisely"), "Quick_Fix#snap_to" ); + AddStuck( S, mbSoundActivated, "/AudioIO/SoundActivatedRecord", _("Recording stops and starts"), "Quick_Fix#sound_activated_recording" ); + } + S.EndMultiColumn(); + } + S.EndStatic(); + + S.StartHorizontalLay(wxALIGN_CENTER_HORIZONTAL, 0); + S.AddStandardButtons(eCloseButton + (bStuckInMode ? 0 : eHelpButton)); + S.EndHorizontalLay(); + + S.EndVerticalLay(); + + wxButton * pBtn = (wxButton*)FindWindowById( wxID_HELP ); + if( pBtn ) + pBtn->SetClientData( safenew wxStringClientData( "Quick_Fix#" )); + +} + +void QuickFixDialog::OnOk(wxCommandEvent &event) +{ + (void)event;// Compiler food + EndModal(wxID_OK); +} + +void QuickFixDialog::OnCancel(wxCommandEvent &event) +{ + (void)event;// Compiler food + EndModal(wxID_CANCEL); +} + +wxString QuickFixDialog::StringFromEvent( wxCommandEvent &event ) +{ + wxButton * pBtn = (wxButton*)event.GetEventObject(); + if( !pBtn ){ + wxFAIL_MSG( "Event Object not found"); + return ""; + } + wxStringClientData * pStrCd = (wxStringClientData*)(pBtn->GetClientData()); + if( !pStrCd ){ + wxFAIL_MSG( "Client Data not found"); + return ""; + } + wxString Str = pStrCd->GetData(); + if( Str.IsEmpty()){ + wxFAIL_MSG( "String data empty"); + return ""; + } + return Str; +} + +void QuickFixDialog::OnHelp(wxCommandEvent &event) +{ + HelpSystem::ShowHelp(this, StringFromEvent( event ), true); +} + +void QuickFixDialog::OnFix(wxCommandEvent &event) +{ + wxString Str = StringFromEvent( event ); + gPrefs->Write( Str, 0); + gPrefs->Flush(); + + AudacityProject & project = *GetActiveProject(); + + if( &project == nullptr) + (void)0;// Compiler food. + // Sadly SnapTo has to be handled specially, as it is not part of the standard + // preference dialogs. + else if( Str == "/SnapTo" ) + { + project.SetSnapTo( 0 ); + } + else + { + // This is overkill (aka slow), as all preferences are reloaded and all + // toolbars recreated. + // Overkill probably doesn't matter, as this command is infrequently used. + CommandContext context( project ); + GetMenuCommandHandler(project).OnReloadPreferences( context ); + } + + // Change the label after doing the fix, as the fix may take a second or two. + wxButton * pBtn = (wxButton*)event.GetEventObject(); + if( pBtn ) + pBtn->SetLabel( _("Fixed") ); + + // The close button has the cancel id and acts exactly the same as cancel. + wxButton * pWin = (wxButton*)FindWindowById( wxID_CANCEL ); + if( pWin ) + pWin->SetFocus( ); +} \ No newline at end of file diff --git a/src/widgets/HelpSystem.h b/src/widgets/HelpSystem.h index a12b84c5b..354f0b67d 100644 --- a/src/widgets/HelpSystem.h +++ b/src/widgets/HelpSystem.h @@ -101,4 +101,35 @@ public: }; +class ShuttleGui; + +/** @brief Class which makes a dialog for displaying quick fixes to common issues. + * + * This class originated with the 'Stuck in a mode' problem, where far too many + * users get into a mode without realising, and don't know how to get out. + * It is a band-aid, and we should do more towards a full and proper solution + * where there are fewer special modes, and they don't persisit. + */ +class QuickFixDialog : public wxDialogWrapper +{ +public: + QuickFixDialog(wxWindow * pParent); + void Populate(); + void PopulateOrExchange(ShuttleGui & S); + void AddStuck( ShuttleGui & S, bool & bBool, wxString Pref, wxString Prompt, wxString Help ); + + void OnOk(wxCommandEvent &event); + void OnCancel(wxCommandEvent &event); + void OnHelp(wxCommandEvent &event); + void OnFix(wxCommandEvent &event); + + wxString StringFromEvent( wxCommandEvent &event ); + + int mItem; + bool mbSyncLocked; + bool mbInSnapTo; + bool mbSoundActivated; + DECLARE_EVENT_TABLE() +}; + #endif // __AUDACITY_HELPSYSTEM__