Audacity  3.0.3
PrefsDialog.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  PrefsDialog.cpp
6 
7  Joshua Haberman
8  James Crook
9 
10 *******************************************************************//*******************************************************************/
16 
17 
18 #include "PrefsDialog.h"
19 
20 #include <wx/app.h>
21 #include <wx/setup.h> // for wxUSE_* macros
22 #include <wx/defs.h>
23 #include <wx/button.h>
24 #include <wx/dialog.h>
25 #include <wx/event.h>
26 #include <wx/font.h>
27 #include <wx/gdicmn.h>
28 #include <wx/intl.h>
29 #include <wx/listbox.h>
30 #include <wx/sizer.h>
31 
32 #include <wx/listbook.h>
33 
34 #include <wx/treebook.h>
35 #include <wx/treectrl.h>
36 
37 #include "AudioIOBase.h"
38 #include "Prefs.h"
39 #include "ProjectWindows.h"
40 #include "../ShuttleGui.h"
41 #include "../commands/CommandManager.h"
42 
43 #include "PrefsPanel.h"
44 
45 #include "../widgets/HelpSystem.h"
46 
47 #if wxUSE_ACCESSIBILITY
48 #include "../widgets/WindowAccessible.h"
49 #endif
50 
51 
52 #if wxUSE_ACCESSIBILITY
53 
54 #ifndef __WXMAC__
55 
56 // Just an alias
57 using TreeCtrlAx = WindowAccessible;
58 
59 #else
60 
61 // utility functions
62 namespace {
63  template< typename Result, typename Fn >
64  Result VisitItems( const wxTreeCtrl &ctrl, Fn fn )
65  {
66  // Do preorder visit of items in the tree until satisfying a test
67  std::vector< wxTreeItemId > stack;
68  stack.push_back( ctrl.GetRootItem() );
69  unsigned position = 0;
70  while ( !stack.empty() ) {
71  auto itemId = stack.back();
72  auto pair = fn( itemId, position );
73  if ( pair.first )
74  return pair.second;
75 
76  wxTreeItemIdValue cookie;
77  auto childId = ctrl.GetFirstChild( itemId, cookie );
78  if ( childId )
79  stack.push_back( childId );
80  else do {
81  auto &id = stack.back();
82  if ( !!( id = ctrl.GetNextSibling( id ) ) )
83  break;
84  } while ( stack.pop_back(), !stack.empty() );
85 
86  ++position;
87  }
88  return {};
89  }
90 
91  unsigned FindItemPosition( const wxTreeCtrl &ctrl, wxTreeItemId id )
92  {
93  // Return the 1-based count of the item's position in the pre-order
94  // visit of the items in the tree (not counting the root item which we
95  // assume is a dummy that never matches id)
96  return VisitItems<unsigned>( ctrl,
97  [=]( wxTreeItemId itemId, unsigned position ){
98  return std::make_pair( itemId == id, position ); } );
99  }
100 
101  wxTreeItemId FindItem( const wxTreeCtrl &ctrl, int nn )
102  {
103  // The inverse of the function above
104  return VisitItems<wxTreeItemId>( ctrl,
105  [=]( wxTreeItemId itemId, unsigned position ){
106  return std::make_pair( nn == position, itemId ); } );
107  }
108 }
109 
110 // Define a custom class
111 class TreeCtrlAx final
112  : public WindowAccessible
113 {
114 public:
115  TreeCtrlAx(wxTreeCtrl * ctrl);
116  virtual ~ TreeCtrlAx();
117 
118  wxAccStatus GetChild(int childId, wxAccessible** child) override;
119 
120  wxAccStatus GetChildCount(int* childCount) override;
121 
122  wxAccStatus GetDefaultAction(int childId, wxString *actionName) override;
123 
124  // Returns the description for this object or a child.
125  wxAccStatus GetDescription(int childId, wxString *description) override;
126 
127  // Gets the window with the keyboard focus.
128  // If childId is 0 and child is NULL, no object in
129  // this subhierarchy has the focus.
130  // If this object has the focus, child should be 'this'.
131  wxAccStatus GetFocus(int *childId, wxAccessible **child) override;
132 
133  // Returns help text for this object or a child, similar to tooltip text.
134  wxAccStatus GetHelpText(int childId, wxString *helpText) override;
135 
136  // Returns the keyboard shortcut for this object or child.
137  // Return e.g. ALT+K
138  wxAccStatus GetKeyboardShortcut(int childId, wxString *shortcut) override;
139 
140  // Returns the rectangle for this object (id = 0) or a child element (id > 0).
141  // rect is in screen coordinates.
142  wxAccStatus GetLocation(wxRect& rect, int elementId) override;
143 
144  // Gets the name of the specified object.
145  wxAccStatus GetName(int childId, wxString *name) override;
146 
147  // Returns a role constant.
148  wxAccStatus GetRole(int childId, wxAccRole *role) override;
149 
150  // Gets a variant representing the selected children
151  // of this object.
152  // Acceptable values:
153  // - a null variant (IsNull() returns TRUE)
154  // - a list variant (GetType() == wxT("list"))
155  // - an integer representing the selected child element,
156  // or 0 if this object is selected (GetType() == wxT("long"))
157  // - a "void*" pointer to a wxAccessible child object
158  //wxAccStatus GetSelections(wxVariant *selections) override;
159  // leave unimplemented
160 
161  // Returns a state constant.
162  wxAccStatus GetState(int childId, long* state) override;
163 
164  // Returns a localized string representing the value for the object
165  // or child.
166  wxAccStatus GetValue(int childId, wxString* strValue) override;
167 
168  // Navigates from fromId to toId/toObject
169  // wxAccStatus Navigate(wxNavDir navDir, int fromId, int* toId, wxAccessible** toObject) override;
170 
171  // Modify focus or selection
172  wxAccStatus Select(int childId, wxAccSelectionFlags selectFlags) override;
173 
174 private:
175  wxTreeCtrl *GetCtrl() { return static_cast<wxTreeCtrl*>( GetWindow() ); }
176 };
177 
178 TreeCtrlAx::TreeCtrlAx( wxTreeCtrl *ctrl )
179 : WindowAccessible{ ctrl }
180 {
181 }
182 
183 TreeCtrlAx::~TreeCtrlAx() = default;
184 
185 wxAccStatus TreeCtrlAx::GetChild( int childId, wxAccessible** child )
186 {
187  if( childId == wxACC_SELF )
188  {
189  *child = this;
190  }
191  else
192  {
193  *child = NULL;
194  }
195 
196  return wxACC_OK;
197 }
198 
199 wxAccStatus TreeCtrlAx::GetChildCount(int* childCount)
200 {
201  auto ctrl = GetCtrl();
202  if (!ctrl)
203  return wxACC_FAIL;
204 
205  *childCount = ctrl->GetCount();
206  return wxACC_OK;
207 }
208 
209 wxAccStatus TreeCtrlAx::GetDefaultAction(int WXUNUSED(childId), wxString* actionName)
210 {
211  actionName->clear();
212 
213  return wxACC_OK;
214 }
215 
216 // Returns the description for this object or a child.
217 wxAccStatus TreeCtrlAx::GetDescription( int WXUNUSED(childId), wxString *description )
218 {
219  description->clear();
220 
221  return wxACC_OK;
222 }
223 
224 // This isn't really used yet by wxWidgets as patched by Audacity for
225 // Mac accessibility, as of Audacity 2.3.2, but here it is anyway, keeping the
226 // analogy with TrackPanelAx
227 wxAccStatus TreeCtrlAx::GetFocus( int *childId, wxAccessible **child )
228 {
229  auto ctrl = GetCtrl();
230  if (!ctrl)
231  return wxACC_FAIL;
232 
233  auto item = ctrl->GetFocusedItem();
234  auto id = FindItemPosition( *ctrl, item );
235  *childId = id;
236  *child = nullptr;
237  return wxACC_OK;
238 }
239 
240 // Returns help text for this object or a child, similar to tooltip text.
241 wxAccStatus TreeCtrlAx::GetHelpText( int WXUNUSED(childId), wxString *helpText )
242 {
243  helpText->clear();
244 
245  return wxACC_OK;
246 }
247 
248 // Returns the keyboard shortcut for this object or child.
249 // Return e.g. ALT+K
250 wxAccStatus TreeCtrlAx::GetKeyboardShortcut( int WXUNUSED(childId), wxString *shortcut )
251 {
252  shortcut->clear();
253 
254  return wxACC_OK;
255 }
256 
257 wxAccStatus TreeCtrlAx::GetLocation( wxRect& rect, int elementId )
258 {
259  auto ctrl = GetCtrl();
260  if (!ctrl)
261  return wxACC_FAIL;
262 
263  if (elementId == wxACC_SELF)
264  rect = ctrl->GetRect();
265  else {
266  auto item = FindItem( *ctrl, elementId );
267  if ( !( item && ctrl->GetBoundingRect( item, rect ) ) )
268  return wxACC_INVALID_ARG;
269  }
270  rect.SetPosition( ctrl->GetParent()->ClientToScreen( rect.GetPosition() ) );
271  return wxACC_OK;
272 }
273 
274 wxAccStatus TreeCtrlAx::GetName(int childId, wxString* name)
275 {
276  if ( childId == wxACC_SELF )
277  return WindowAccessible::GetName( childId, name );
278  else {
279  auto ctrl = GetCtrl();
280  if (!ctrl)
281  return wxACC_FAIL;
282 
283  auto item = FindItem( *ctrl, childId );
284  if ( item ) {
285  *name = ctrl->GetItemText( item );
286  return wxACC_OK;
287  }
288  else
289  return wxACC_INVALID_ARG;
290  }
291 }
292 
293 wxAccStatus TreeCtrlAx::GetRole( int childId, wxAccRole* role )
294 {
295  // Not sure if this correct, but it is analogous with what we use in
296  // TrackPanel
297  *role =
298  childId == wxACC_SELF ? wxROLE_SYSTEM_PANE : wxROLE_SYSTEM_STATICTEXT;
299  return wxACC_OK;
300 }
301 
302 // Returns a state constant.
303 wxAccStatus TreeCtrlAx::GetState(int childId, long* state)
304 {
305  auto ctrl = GetCtrl();
306  if (!ctrl)
307  return wxACC_FAIL;
308 
309  *state = wxACC_STATE_SYSTEM_FOCUSABLE | wxACC_STATE_SYSTEM_SELECTABLE;
310 
311  if ( childId != wxACC_SELF ) {
312  auto item = FindItem( *ctrl, childId );
313  if (item) {
314  if( item == ctrl->GetFocusedItem() )
315  *state |= wxACC_STATE_SYSTEM_FOCUSED;
316 
317  if( item == ctrl->GetSelection() )
318  *state |= wxACC_STATE_SYSTEM_SELECTED;
319  }
320  }
321 
322  return wxACC_OK;
323 }
324 
325 // Returns a localized string representing the value for the object
326 // or child.
327 wxAccStatus TreeCtrlAx::GetValue(int childId, wxString* strValue)
328 {
329  *strValue = wxString{};
330  return wxACC_OK;
331 }
332 
333 //wxAccStatus TreeCtrlAx::Navigate(
334 // wxNavDir navDir, int fromId, int* toId, wxAccessible** toObject)
335 //{
336 // to do
337 //}
338 
339 // Modify focus or selection
340 wxAccStatus TreeCtrlAx::Select(int childId, wxAccSelectionFlags selectFlags)
341 {
342  auto ctrl = GetCtrl();
343  if (!ctrl)
344  return wxACC_FAIL;
345 
346  if (childId != wxACC_SELF) {
347  int childCount;
348  GetChildCount( &childCount );
349  if (childId > childCount)
350  return wxACC_FAIL;
351 
352  auto item = FindItem( *ctrl, childId );
353  if ( item ) {
354  if (selectFlags == wxACC_SEL_TAKEFOCUS)
355  ctrl->SetFocusedItem( item );
356  else if (selectFlags == wxACC_SEL_TAKESELECTION)
357  ctrl->SelectItem( item );
358  else
359  return wxACC_NOT_IMPLEMENTED;
360  return wxACC_OK;
361  }
362  }
363 
364  return wxACC_NOT_IMPLEMENTED;
365 }
366 
367 #endif
368 
369 #endif
370 
371 
372 BEGIN_EVENT_TABLE(PrefsDialog, wxDialogWrapper)
373  EVT_BUTTON(wxID_OK, PrefsDialog::OnOK)
374  EVT_BUTTON(wxID_CANCEL, PrefsDialog::OnCancel)
375  EVT_BUTTON(wxID_PREVIEW, PrefsDialog::OnPreview)
376  EVT_BUTTON(wxID_HELP, PrefsDialog::OnHelp)
377  EVT_TREE_KEY_DOWN(wxID_ANY, PrefsDialog::OnTreeKeyDown) // Handles key events when tree has focus
379 
380 
381 class wxTreebookExt final : public wxTreebook
382 {
383 public:
384  wxTreebookExt( wxWindow *parent,
385  wxWindowID id, const TranslatableString &titlePrefix)
386  : wxTreebook( parent, id )
387  , mTitlePrefix(titlePrefix)
388  {;};
389  ~wxTreebookExt(){;};
390  int ChangeSelection(size_t n) override;
391  int SetSelection(size_t n) override;
392  const TranslatableString mTitlePrefix;
393 };
394 
395 
396 int wxTreebookExt::ChangeSelection(size_t n) {
397  int i = wxTreebook::ChangeSelection(n);
398  wxString Temp = GetPageText( n );
399  static_cast<wxDialog*>(GetParent())->SetTitle( Temp );
400  static_cast<wxDialog*>(GetParent())->SetName( Temp );
401  return i;
402 };
403 
404 int wxTreebookExt::SetSelection(size_t n)
405 {
406  int i = wxTreebook::SetSelection(n);
407  auto Temp = mTitlePrefix.Translation() + wxT(" ") + GetPageText( n );
408  static_cast<wxDialog*>(GetParent())->SetTitle( Temp );
409  static_cast<wxDialog*>(GetParent())->SetName( Temp );
410 
411  PrefsPanel *const panel = static_cast<PrefsPanel *>(GetPage(n));
412  const bool showHelp = (!panel->HelpPageName().empty());
413  const bool showPreview = panel->ShowsPreviewButton();
414  wxWindow *const helpButton = wxWindow::FindWindowById(wxID_HELP, GetParent());
415  wxWindow *const previewButton = wxWindow::FindWindowById(wxID_PREVIEW, GetParent());
416 
417  if (helpButton) {
418  if (showHelp) {
419  wxAcceleratorEntry entries[1];
420 #if defined(__WXMAC__)
421  // Is there a standard shortcut on Mac?
422 #else
423  entries[0].Set(wxACCEL_NORMAL, (int) WXK_F1, wxID_HELP);
424 #endif
425  wxAcceleratorTable accel(1, entries);
426  this->SetAcceleratorTable(accel);
427  }
428  else {
429  this->SetAcceleratorTable(wxNullAcceleratorTable);
430  }
431 
432  const bool changed = helpButton->Show(showHelp);
433  if (changed)
434  GetParent()->Layout();
435  }
436 
437  if (previewButton) { // might still be NULL during population
438  const bool changed = previewButton->Show(showPreview);
439  if (changed)
440  GetParent()->Layout();
441  }
442 
443  return i;
444 }
445 
447  wxWindow * parent, AudacityProject *pProject,
448  const TranslatableString &titlePrefix,
449  PrefsPanel::Factories &factories)
450 : wxDialogWrapper(parent, wxID_ANY, XO("Audacity Preferences"),
451  wxDefaultPosition,
452  wxDefaultSize,
453  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
454 , mFactories(factories)
455 , mTitlePrefix(titlePrefix)
456 {
457  wxASSERT(factories.size() > 0);
458  const bool uniquePage = (factories.size() == 1);
459  SetLayoutDirection(wxLayout_LeftToRight);
460 
461  ShuttleGui S(this, eIsCreating);
462 
463  S.StartVerticalLay(true);
464  {
465  wxASSERT(factories.size() > 0);
466  if (!uniquePage) {
467  mCategories = safenew wxTreebookExt(S.GetParent(), wxID_ANY, mTitlePrefix);
468 #if wxUSE_ACCESSIBILITY
469  // so that name can be set on a standard control
470  mCategories->GetTreeCtrl()->SetAccessible(
471  safenew TreeCtrlAx(mCategories->GetTreeCtrl()));
472 #endif
473  // RJH: Prevent NVDA from reading "treeCtrl"
474  mCategories->GetTreeCtrl()->SetName(_("Category"));
475  S.StartHorizontalLay(wxALIGN_LEFT | wxEXPAND, true);
476  {
477  S.Prop(1)
478  .Position(wxEXPAND)
480 
481  {
482  typedef std::pair<int, int> IntPair;
483  std::vector<IntPair> stack;
484  int iPage = 0;
485  for (auto it = factories.begin(), end = factories.end();
486  it != end; ++it, ++iPage)
487  {
488  const auto &node = *it;
489  const auto &factory = node.factory;
490  wxWindow *const w = factory(mCategories, wxID_ANY, pProject);
491  if (stack.empty())
492  // Parameters are: AddPage(page, name, IsSelected, imageId).
493  mCategories->AddPage(w, w->GetName(), false, 0);
494  else {
495  IntPair &top = *stack.rbegin();
496  mCategories->InsertSubPage(top.first, w, w->GetName(), false, 0);
497  if (--top.second == 0) {
498  // Expand all nodes before the layout calculation
499  mCategories->ExpandNode(top.first, true);
500  stack.pop_back();
501  }
502  }
503  if (node.nChildren > 0)
504  stack.push_back(IntPair(iPage, node.nChildren));
505  }
506  }
507  }
508  S.EndHorizontalLay();
509  }
510  else {
511  // TODO: Look into getting rid of mUniquePage and instead
512  // adding into mCategories, so there is just one page in mCategories.
513  // And then hiding the treebook.
514 
515  // Unique page, don't show the factory
516  const auto &node = factories[0];
517  const auto &factory = node.factory;
518  mUniquePage = factory(S.GetParent(), wxID_ANY, pProject);
519  wxWindow * uniquePageWindow = S.Prop(1)
520  .Position(wxEXPAND)
522  // We're not in the wxTreebook, so add the accelerator here
523  wxAcceleratorEntry entries[1];
524 #if defined(__WXMAC__)
525  // Is there a standard shortcut on Mac?
526 #else
527  entries[0].Set(wxACCEL_NORMAL, (int) WXK_F1, wxID_HELP);
528 #endif
529  wxAcceleratorTable accel(1, entries);
530  uniquePageWindow->SetAcceleratorTable(accel);
531  }
532  }
533  S.EndVerticalLay();
534 
536 
538  wxWindow *const previewButton =
539  wxWindow::FindWindowById(wxID_PREVIEW, GetParent());
540  previewButton->Show(false);
541  }
542 
543 #if defined(__WXGTK__)
544  if (mCategories)
545  mCategories->GetTreeCtrl()->EnsureVisible(mCategories->GetTreeCtrl()->GetRootItem());
546 #endif
547 
548 // mCategories->SetMaxSize({ 790, 600 }); // 790 = 800 - (border * 2)
549  Layout();
550  Fit();
551  wxSize sz = GetSize();
552 
553  // Collapse nodes only after layout so the tree is wide enough
554  if (mCategories)
555  {
556  int iPage = 0;
557  for (auto it = factories.begin(), end = factories.end();
558  it != end; ++it, ++iPage)
559  mCategories->ExpandNode(iPage, it->expanded);
560  }
561 
562  // This ASSERT was originally used to limit us to 800 x 600.
563  // However, the range of screen sizes and dpi of modern (2018) displays
564  // makes pixel dimensions an inadequate measure of usability, so
565  // now we only ASSERT that preferences will fit in the client display
566  // rectangle of the developer / tester's monitor.
567  // Use scrollers when necessary to ensure that preference pages will
568  // be fully visible.
569  wxRect screenRect(wxGetClientDisplayRect());
570  wxASSERT_MSG(sz.x <= screenRect.width && sz.y <= screenRect.height, wxT("Preferences dialog exceeds max size"));
571 
572  sz.DecTo(screenRect.GetSize());
573 
574  if( !mUniquePage ){
575  int prefWidth, prefHeight;
576  gPrefs->Read(wxT("/Prefs/Width"), &prefWidth, sz.x);
577  gPrefs->Read(wxT("/Prefs/Height"), &prefHeight, wxMax(480,sz.y));
578 
579  wxSize prefSize = wxSize(prefWidth, prefHeight);
580  prefSize.DecTo(screenRect.GetSize());
581  SetSize(prefSize);
582  InvalidateBestSize();
583  Layout();
584  }
585  SetMinSize(sz);
586 
587  // Center after all that resizing, but make sure it doesn't end up
588  // off-screen
589  CentreOnParent();
590 }
591 
593 {
594 }
595 
597 {
598  if (mCategories) {
599  /* long is signed, size_t is unsigned. On some platforms they are different
600  * lengths as well. So we must check that the stored category is both > 0
601  * and within the possible range of categories, making the first check on the
602  * _signed_ value to avoid issues when converting an unsigned one.
603  */
604  long selected = GetPreferredPage();
605  if (selected < 0 || size_t(selected) >= mCategories->GetPageCount())
606  selected = 0; // clamp to available range of tabs
607  mCategories->SetSelection(selected);
608  }
609  else {
610  auto Temp = mTitlePrefix;
611  Temp.Join( Verbatim( mUniquePage->GetLabel() ), wxT(" ") );
612  SetTitle(Temp);
613  SetName(Temp);
614  }
615 
616  return wxDialogWrapper::ShowModal();
617 }
618 
619 void PrefsDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
620 {
622 
623  if (mCategories) {
624  for (size_t i = 0; i < mCategories->GetPageCount(); i++) {
625  ((PrefsPanel *)mCategories->GetPage(i))->Cancel();
626  }
627  }
628  else
629  mUniquePage->Cancel();
630 
631  // Remember modified dialog size, even if cancelling.
632  if( !mUniquePage ){
633  wxSize sz = GetSize();
634  gPrefs->Write(wxT("/Prefs/Width"), sz.x);
635  gPrefs->Write(wxT("/Prefs/Height"), sz.y);
636  }
637  gPrefs->Flush();
638 
639  EndModal(false);
640 }
641 
643 {
644  if( mCategories)
645  return static_cast<PrefsPanel*>(mCategories->GetCurrentPage());
646  else
647  {
648  wxASSERT( mUniquePage );
649  return mUniquePage;
650  }
651 }
652 
653 void PrefsDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
654 {
656 }
657 
658 void PrefsDialog::OnHelp(wxCommandEvent & WXUNUSED(event))
659 {
660  const auto &page = GetCurrentPanel()->HelpPageName();
661  HelpSystem::ShowHelp(this, page, true);
662 }
663 
665 {
666  // Validate all pages first
667  if (mCategories) {
668  for (size_t i = 0; i < mCategories->GetPageCount(); i++) {
669  S.ResetId();
670  PrefsPanel *panel = (PrefsPanel *)mCategories->GetPage(i);
671  panel->PopulateOrExchange( S );
672  }
673  }
674  else
675  {
676  S.ResetId();
678  }
679 }
680 
681 void PrefsDialog::OnTreeKeyDown(wxTreeEvent & event)
682 {
683  if(event.GetKeyCode() == WXK_RETURN)
684  OnOK(event);
685  else
686  event.Skip(); // Ensure standard behavior when enter is not pressed
687 }
688 
689 void PrefsDialog::OnOK(wxCommandEvent & WXUNUSED(event))
690 {
692 
693  // Validate all pages first
694  if (mCategories) {
695  for (size_t i = 0; i < mCategories->GetPageCount(); i++) {
696  PrefsPanel *panel = (PrefsPanel *)mCategories->GetPage(i);
697 
698  // The dialog doesn't end until all the input is valid
699  if (!panel->Validate()) {
700  mCategories->SetSelection(i);
701  return;
702  }
703  }
704  }
705  else {
706  if (!mUniquePage->Validate())
707  return;
708  }
709 
710  // flush now so toolbars will know their position.
711  gPrefs->Flush();
712  if (mCategories) {
713  // Now apply the changes
714  // Reverse order - so Track Name is updated before language change
715  // A workaround for Bug 1661
716  for (int i = (int)mCategories->GetPageCount()-1; i>= 0; i--) {
717  PrefsPanel *panel = (PrefsPanel *)mCategories->GetPage(i);
718 
719  panel->Preview();
720  panel->Commit();
721  }
722  }
723  else {
724  mUniquePage->Preview();
725  mUniquePage->Commit();
726  }
727 
728  if( !mUniquePage ){
729  wxSize sz = GetSize();
730  gPrefs->Write(wxT("/Prefs/Width"), sz.x);
731  gPrefs->Write(wxT("/Prefs/Height"), sz.y);
732  }
733  gPrefs->Flush();
734 
736 
737 #if USE_PORTMIXER
738  auto gAudioIO = AudioIOBase::Get();
739  if (gAudioIO) {
740  // We cannot have opened this dialog if gAudioIO->IsAudioTokenActive(),
741  // per the setting of AudioIONotBusyFlag and AudioIOBusyFlag in
742  // AudacityProject::GetUpdateFlags().
743  // However, we can have an invalid audio token (so IsAudioTokenActive()
744  // is false), but be monitoring.
745  // If monitoring, have to stop the stream, so HandleDeviceChange() can work.
746  // We could disable the Preferences command while monitoring, i.e.,
747  // set AudioIONotBusyFlag/AudioIOBusyFlag according to monitoring, as well.
748  // Instead allow it because unlike recording, for example, monitoring
749  // is not clearly something that should prohibit opening prefs.
750  // TODO: We *could* be smarter in this method and call HandleDeviceChange()
751  // only when the device choices actually changed. True of lots of prefs!
752  // As is, we always stop monitoring before handling the device change.
753  if (gAudioIO->IsMonitoring())
754  {
755  gAudioIO->StopStream();
756  while (gAudioIO->IsBusy())
757  wxMilliSleep(100);
758  }
759  gAudioIO->HandleDeviceChange();
760  }
761 #endif
762 
763  // PRL: Is the following concern still valid, now that prefs update is
764  // handled instead by delayed event processing?
765 
766  // LL: wxMac can't handle recreating the menus when this dialog is still active,
767  // so AudacityProject::UpdatePrefs() or any of the routines it calls must
768  // not cause MenuCreator::RebuildMenuBar() to be executed.
769 
771 
772  if( IsModal() )
773  EndModal(true);
774  else
775  Destroy();
776 }
777 
778 void PrefsDialog::SelectPageByName(const wxString &pageName)
779 {
780  if (mCategories) {
781  size_t n = mCategories->GetPageCount();
782 
783  for (size_t i = 0; i < n; i++) {
784  if (mCategories->GetPageText(i) == pageName) {
785  mCategories->SetSelection(i);
786  // This covers the case, when ShowModal is called
787  // after selecting the page.
788  // ShowModal will select the page previously used by
789  // user
791  return;
792  }
793  }
794  }
795 }
796 
798 {
799  if (mCategories)
800  return mCategories->GetSelection();
801  else
802  return 0;
803 }
804 
806  wxWindow * parent, AudacityProject *pProject,
807  PrefsPanel::Factories &factories)
808  : PrefsDialog(parent, pProject, XO("Preferences:"), factories)
809 {
810 }
811 
813 {
814 }
815 
817 {
818  long prefscat = gPrefs->Read(wxT("/Prefs/PrefsCategory"), 0L);
819  return prefscat;
820 }
821 
823 {
824  gPrefs->Write(wxT("/Prefs/PrefsCategory"), (long)GetSelectedPage());
825  gPrefs->Flush();
826 }
827 
829 {
830  // Remember expansion state of the tree control
831  if (mCategories)
832  {
833  int iPage = 0;
834  for (auto it = mFactories.begin(), end = mFactories.end();
835  it != end; ++it, ++iPage)
836  it->expanded = mCategories->IsNodeExpanded(iPage);
837  }
838  else
839  mFactories[0].expanded = true;
840 }
841 
842 #include <wx/frame.h>
843 #include "../Menus.h"
844 #include "Project.h"
845 
847 {
849 
850  {
851  GlobalPrefsDialog dialog(
852  &GetProjectFrame( project ) /* parent */, &project );
853  wxCommandEvent Evt;
854  //dialog.Show();
855  dialog.OnOK(Evt);
856  }
857 
858  // LL: Moved from PrefsDialog since wxWidgets on OSX can't deal with
859  // rebuilding the menus while the PrefsDialog is still in the modal
860  // state.
861  for (auto p : AllProjects{}) {
863 // TODO: The comment below suggests this workaround is obsolete.
864 #if defined(__WXGTK__)
865  // Workaround for:
866  //
867  // http://bugzilla.audacityteam.org/show_bug.cgi?id=458
868  //
869  // This workaround should be removed when Audacity updates to wxWidgets
870  // 3.x which has a fix.
871  auto &window = GetProjectFrame( *p );
872  wxRect r = window.GetRect();
873  window.SetSize(wxSize(1,1));
874  window.SetSize(r.GetSize());
875 #endif
876  }
877 }
PrefsDialog::ShowModal
int ShowModal() override
Definition: PrefsDialog.cpp:596
EVT_BUTTON
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
AudioIOBase.h
DoReloadPreferences
void DoReloadPreferences(AudacityProject &project)
Definition: PrefsDialog.cpp:846
PrefsDialog::OnCancel
void OnCancel(wxCommandEvent &e)
Definition: PrefsDialog.cpp:619
eIsCreating
@ eIsCreating
Definition: ShuttleGui.h:38
ShuttleGuiBase::StartVerticalLay
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:1184
fn
static const auto fn
Definition: WaveformView.cpp:1108
PrefsDialog::GetPreferredPage
virtual long GetPreferredPage()=0
entries
static ProjectFileIORegistry::AttributeReaderEntries entries
Definition: ProjectSettings.cpp:210
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
eHelpButton
@ eHelpButton
Definition: ShuttleGui.h:604
Project.h
ePreviewButton
@ ePreviewButton
Definition: ShuttleGui.h:605
PrefsPanel.h
PrefsPanel::HelpPageName
virtual ManualPageID HelpPageName()
If not empty string, the Help button is added below the panel.
Definition: PrefsPanel.cpp:98
PrefsPanel::PopulateOrExchange
virtual void PopulateOrExchange(ShuttleGui &WXUNUSED(S))
Definition: PrefsPanel.h:116
PrefsDialog.h
GlobalPrefsDialog::~GlobalPrefsDialog
virtual ~GlobalPrefsDialog()
Definition: PrefsDialog.cpp:812
XO
#define XO(s)
Definition: Internat.h:31
PreferenceInitializer::ReinitializeAll
static void ReinitializeAll()
Definition: Prefs.cpp:443
PrefsDialog::GetSelectedPage
int GetSelectedPage() const
Definition: PrefsDialog.cpp:797
PrefsDialog::mCategories
wxTreebook * mCategories
Definition: PrefsDialog.h:70
HelpSystem::ShowHelp
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:237
PrefsListener::Broadcast
static void Broadcast(int id=0)
Call this static function to notify all PrefsListener objects.
Definition: Prefs.cpp:100
PrefsPanel::Preview
virtual void Preview()
Definition: PrefsPanel.h:101
PrefsPanel::Commit
virtual bool Commit()=0
PrefsPanel::ShowsPreviewButton
virtual bool ShowsPreviewButton()
Definition: PrefsPanel.cpp:93
eCancelButton
@ eCancelButton
Definition: ShuttleGui.h:601
ShuttleGuiBase::EndHorizontalLay
void EndHorizontalLay()
Definition: ShuttleGui.cpp:1177
factory
static RegisteredToolbarFactory factory
Definition: ControlToolBar.cpp:817
PrefsDialog::OnOK
void OnOK(wxCommandEvent &e)
Definition: PrefsDialog.cpp:689
ShuttleGuiBase::StartHorizontalLay
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:1167
PrefsDialog::GetCurrentPanel
PrefsPanel * GetCurrentPanel()
Definition: PrefsDialog.cpp:642
ShuttleGuiBase::EndVerticalLay
void EndVerticalLay()
Definition: ShuttleGui.cpp:1203
ShuttleGuiBase::ResetId
void ResetId()
Definition: ShuttleGui.cpp:188
PrefsDialog::SelectPageByName
void SelectPageByName(const wxString &pageName)
Definition: PrefsDialog.cpp:778
name
const TranslatableString name
Definition: Distortion.cpp:98
MenuCreator::RebuildMenuBar
void RebuildMenuBar(AudacityProject &project)
Definition: Menus.cpp:486
PrefsDialog::~PrefsDialog
virtual ~PrefsDialog()
Definition: PrefsDialog.cpp:592
ShuttleGuiBase::GetParent
wxWindow * GetParent()
Definition: ShuttleGui.h:496
AudioIOBase::Get
static AudioIOBase * Get()
Definition: AudioIOBase.cpp:89
ShuttleGuiBase::AddWindow
wxWindow * AddWindow(wxWindow *pWindow, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:299
WindowAccessible
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
PrefsDialog::ShuttleAll
void ShuttleAll(ShuttleGui &S)
Definition: PrefsDialog.cpp:664
ShuttleGui::Prop
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:725
ProjectWindows.h
accessors for certain important windows associated with each project
PrefsDialog::OnHelp
void OnHelp(wxCommandEvent &e)
Definition: PrefsDialog.cpp:658
id
int id
Definition: WaveTrackControls.cpp:577
GlobalPrefsDialog::GlobalPrefsDialog
GlobalPrefsDialog(wxWindow *parent, AudacityProject *pProject, PrefsPanel::Factories &factories=PrefsPanel::DefaultFactories())
Definition: PrefsDialog.cpp:805
anonymous_namespace{Registry.cpp}::VisitItems
void VisitItems(Registry::Visitor &visitor, CollectedItems &collection, Path &path, GroupItem *pGroup, const GroupItem *pToMerge, const OrderingHint &hint, bool &doFlush)
Definition: Registry.cpp:620
wxDialogWrapper
Definition: wxPanelWrapper.h:81
FileConfig::Flush
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
eOkButton
@ eOkButton
Definition: ShuttleGui.h:600
ShuttleGui::Position
ShuttleGui & Position(int flags)
Definition: ShuttleGui.h:712
_
#define _(s)
Definition: Internat.h:75
PrefsPanel::Cancel
virtual void Cancel()
Definition: PrefsPanel.cpp:89
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
PrefsDialog::mTitlePrefix
const TranslatableString mTitlePrefix
Definition: PrefsDialog.h:73
GetProjectFrame
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
Definition: ProjectWindows.cpp:72
MenuManager::Get
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:70
AllProjects
Definition: Project.h:35
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
PrefsDialog
Dialog that shows the current PrefsPanel in a tabbed divider.
Definition: PrefsDialog.h:34
GlobalPrefsDialog
Definition: PrefsDialog.h:81
wxDialogWrapper::SetTitle
void SetTitle(const TranslatableString &title)
Definition: wxPanelWrapper.cpp:66
PrefsDialog::RecordExpansionState
void RecordExpansionState()
Definition: PrefsDialog.cpp:828
ShuttleGui::AddStandardButtons
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxWindow *extra=NULL)
Definition: ShuttleGui.cpp:2444
PrefsPanel
Base class for a panel in the PrefsDialog. Classes derived from this class include BatchPrefs,...
Definition: PrefsPanel.h:51
GlobalPrefsDialog::GetPreferredPage
long GetPreferredPage() override
Definition: PrefsDialog.cpp:816
Prefs.h
PrefsDialog::mFactories
PrefsPanel::Factories & mFactories
Definition: PrefsDialog.h:72
WaveTrackVZoomHandle::Result
unsigned Result
Definition: WaveTrackVZoomHandle.h:24
wxDialogWrapper::SetName
void SetName()
Definition: wxPanelWrapper.cpp:81
TranslatableString::Join
TranslatableString & Join(TranslatableString arg, const wxString &separator={}) &
Append another translatable string.
Definition: TranslatableString.cpp:124
safenew
#define safenew
Definition: MemoryX.h:10
PrefsDialog::OnTreeKeyDown
void OnTreeKeyDown(wxTreeEvent &e)
Definition: PrefsDialog.cpp:681
PrefsDialog::OnPreview
void OnPreview(wxCommandEvent &e)
Definition: PrefsDialog.cpp:653
wxTreebook
A wxTreebook is a class like wxNotebook, but not yet supported by wxWidgets 2.6.3.
END_EVENT_TABLE
END_EVENT_TABLE()
PrefsDialog::SavePreferredPage
virtual void SavePreferredPage()=0
PrefsPanel::Factories
std::vector< PrefsPanel::PrefsNode > Factories
Definition: PrefsPanel.h:69
Identifier::empty
bool empty() const
Definition: Identifier.h:61
GlobalPrefsDialog::SavePreferredPage
void SavePreferredPage() override
Definition: PrefsDialog.cpp:822
PrefsDialog::mUniquePage
PrefsPanel * mUniquePage
Definition: PrefsDialog.h:71
PrefsDialog::PrefsDialog
PrefsDialog(wxWindow *parent, AudacityProject *pProject, const TranslatableString &titlePrefix=XO("Preferences:"), PrefsPanel::Factories &factories=PrefsPanel::DefaultFactories())
Definition: PrefsDialog.cpp:446
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631