Audacity 3.2.0
ShuttleGui.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ShuttleGui.cpp
6
7 James Crook
8
9 Audacity is free software.
10 This file is licensed under the wxWidgets license, see License.txt
11
12**********************************************************************//***************************************************************//***************************************************************//***************************************************************//******************************************************************/
94
95
96#include "ShuttleGui.h"
97
98
99
100#include "MemoryX.h"
101#include "Prefs.h"
102#include "ShuttlePrefs.h"
103#include "Theme.h"
104
105#include <wx/setup.h> // for wxUSE_* macros
106#include <wx/wx.h>
107#include <wx/wxprec.h>
108#include <wx/grid.h>
109#include <wx/listctrl.h>
110#include <wx/notebook.h>
111#include <wx/simplebook.h>
112#include <wx/treectrl.h>
113#include <wx/spinctrl.h>
114#include <wx/stattext.h>
115#include <wx/bmpbuttn.h>
116#include <wx/wrapsizer.h>
117
118#include "ReadOnlyText.h"
119#include "wxPanelWrapper.h"
120#include "wxTextCtrlWrapper.h"
121#include "AllThemeResources.h"
122
123#if wxUSE_ACCESSIBILITY
124#include "WindowAccessible.h"
125#endif
126
128 wxWindow * pParent, teShuttleMode ShuttleMode, bool vertical, wxSize minSize )
129 : mpDlg{ pParent }
130{
131 wxASSERT( (pParent != NULL ) || ( ShuttleMode != eIsCreating));
132 mpbOptionalFlag = nullptr;
133 mpParent = pParent;
134 mShuttleMode = ShuttleMode;
135 Init( vertical, minSize );
136}
137
139{
140}
141
142void ShuttleGuiBase::Init(bool vertical, wxSize minSize)
143{
144 mpShuttle = NULL;
145 mpSizer = NULL;
146 mpWind = NULL;
147 mpSubSizer = NULL;
148
150 mRadioCount = -1;
151
152 miBorder = 5;
153 miProp=0;
155 miSizerProp=0;
156 mSizerDepth=-1;
157
158 ResetId();
159
161
163 return;
164
165 mpSizer = mpParent->GetSizer();
166
167#if 0
168 if( mpSizer == NULL )
169 {
170 wxWindow * pGrandParent = mpParent->GetParent();
171 if( pGrandParent )
172 {
173 mpSizer = pGrandParent->GetSizer();
174 }
175 }
176#endif
177
178 if( !mpSizer )
179 {
180 mpParent->SetSizer(
181 mpSizer = safenew wxBoxSizer(vertical ? wxVERTICAL : wxHORIZONTAL));
182 }
183 PushSizer();
184 mpSizer->SetMinSize(minSize);
185}
186
188{
189 miIdSetByUser = -1;
190 miId = -1;
191 miIdNext = 3000;
192}
193
194
195int ShuttleGuiBase::GetBorder() const noexcept
196{
197 return miBorder;
198}
199
202{
204 return;
205 wxFlexGridSizer *pSizer = wxDynamicCast(mpSizer, wxFlexGridSizer);
206 wxASSERT( pSizer );
207 pSizer->AddGrowableCol( i, 1 );
208}
209
212{
214 return;
215 wxFlexGridSizer *pSizer = wxDynamicCast(mpSizer, wxFlexGridSizer);
216 wxASSERT( pSizer );
217 pSizer->AddGrowableRow( i, 1 );
218}
219
220
221//---- Add Functions.
222
224{
225 // If creating, will be handled by an AddPrompt.
227 return;
228 //wxLogDebug( "Optionality: [%s] Id:%i (%i)", Prompt.c_str(), miId, miIdSetByUser ) ;
229 if( mpbOptionalFlag ){
230 bool * pVar = mpbOptionalFlag;
231 mpbOptionalFlag = nullptr;
232 TieCheckBox( Prompt, *pVar);
233 }
234}
235
237wxStaticText* ShuttleGuiBase::AddPrompt(const TranslatableString &Prompt, int wrapWidth)
238{
240 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxStaticText);
241 //wxLogDebug( "Prompt: [%s] Id:%i (%i)", Prompt.c_str(), miId, miIdSetByUser ) ;
242 if( mpbOptionalFlag ){
243 bool * pVar = mpbOptionalFlag;
244 mpbOptionalFlag = nullptr;
245 TieCheckBox( {}, *pVar);
246 //return;
247 }
248 if( Prompt.empty() )
249 return nullptr;
250 miProp=1;
251 const auto translated = Prompt.Translation();
252 auto text = safenew wxStaticText(GetParent(), -1, translated, wxDefaultPosition, wxDefaultSize,
253 GetStyle( wxALIGN_RIGHT ));
254 mpWind = text;
255 if (wrapWidth > 0)
256 text->Wrap(wrapWidth);
257 mpWind->SetName(wxStripMenuCodes(translated)); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
258 UpdateSizersCore( false, wxALL | wxALIGN_CENTRE_VERTICAL, true );
259
260 return text;
261}
262
264void ShuttleGuiBase::AddUnits(const TranslatableString &Prompt, int wrapWidth)
265{
266 if( Prompt.empty() )
267 return;
269 return;
270 miProp = 1;
271 const auto translated = Prompt.Translation();
272 auto text = safenew wxStaticText(GetParent(), -1, translated, wxDefaultPosition, wxDefaultSize,
273 GetStyle( wxALIGN_LEFT ));
274 mpWind = text;
275 if (wrapWidth > 0)
276 text->Wrap(wrapWidth);
277 mpWind->SetName(translated); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
278 UpdateSizersCore( false, wxALL | wxALIGN_CENTRE_VERTICAL );
279}
280
282void ShuttleGuiBase::AddTitle(const TranslatableString &Prompt, int wrapWidth)
283{
284 if( Prompt.empty() )
285 return;
287 return;
288 const auto translated = Prompt.Translation();
289 auto text = safenew wxStaticText(GetParent(), -1, translated, wxDefaultPosition, wxDefaultSize,
290 GetStyle( wxALIGN_CENTRE ));
291 mpWind = text;
292 if (wrapWidth > 0)
293 text->Wrap(wrapWidth);
294 mpWind->SetName(translated); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
295 UpdateSizers();
296}
297
300wxWindow* ShuttleGuiBase::AddWindow(wxWindow* pWindow, int PositionFlags)
301{
303 return pWindow;
304 mpWind = pWindow;
305 SetProportions( 0 );
306 UpdateSizersCore(false, PositionFlags | wxALL);
307 return pWindow;
308}
309
310wxCheckBox * ShuttleGuiBase::AddCheckBox( const TranslatableString &Prompt, bool Selected)
311{
312 HandleOptionality( Prompt );
313 auto realPrompt = Prompt.Translation();
314 if( mpbOptionalFlag )
315 {
316 AddPrompt( {} );
317 //realPrompt = wxT("");
318 }
319
320 UseUpId();
322 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxCheckBox);
323 wxCheckBox * pCheckBox;
324 miProp=0;
325 mpWind = pCheckBox = safenew wxCheckBox(GetParent(), miId, realPrompt, wxDefaultPosition, wxDefaultSize,
326 GetStyle( 0 ));
327 pCheckBox->SetValue(Selected);
328 if (realPrompt.empty()) {
329 // NVDA 2018.3 does not read controls which are buttons, check boxes or radio buttons which have
330 // an accessibility name which is empty. Bug 1980.
331#if wxUSE_ACCESSIBILITY
332 // so that name can be set on a standard control
333 pCheckBox->SetAccessible(safenew WindowAccessible(pCheckBox));
334#endif
335 pCheckBox->SetName(wxT("\a")); // non-empty string which screen readers do not read
336 }
337 UpdateSizers();
338 return pCheckBox;
339}
340
344wxCheckBox * ShuttleGuiBase::AddCheckBoxOnRight( const TranslatableString &Prompt, bool Selected)
345{
346 HandleOptionality( Prompt );
347 AddPrompt( Prompt );
348 UseUpId();
350 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxCheckBox);
351 wxCheckBox * pCheckBox;
352 miProp=0;
353 mpWind = pCheckBox = safenew wxCheckBox(GetParent(), miId, wxT(""), wxDefaultPosition, wxDefaultSize,
354 GetStyle( 0 ));
355 pCheckBox->SetValue(Selected);
356 pCheckBox->SetName(Prompt.Stripped().Translation());
357 UpdateSizers();
358 return pCheckBox;
359}
360
362 const TranslatableString &Text, int PositionFlags, bool setDefault)
363{
364 UseUpId();
366 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxButton);
367 wxButton * pBtn;
368 const auto translated = Text.Translation();
369 mpWind = pBtn = safenew wxButton(GetParent(), miId,
370 translated, wxDefaultPosition, wxDefaultSize,
371 GetStyle( 0 ) );
372 mpWind->SetName(wxStripMenuCodes(translated));
373 miProp=0;
374 UpdateSizersCore(false, PositionFlags | wxALL);
375 if (setDefault)
376 pBtn->SetDefault();
377 return pBtn;
378}
379
381 const wxBitmap &Bitmap, int PositionFlags, bool setDefault)
382{
383 UseUpId();
385 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxBitmapButton);
386 wxBitmapButton * pBtn;
387 mpWind = pBtn = safenew wxBitmapButton(GetParent(), miId, Bitmap,
388 wxDefaultPosition, wxDefaultSize, GetStyle( wxBU_AUTODRAW ) );
389 pBtn->SetBackgroundColour(
390 wxColour( 246,246,243));
391// wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
392 miProp=0;
393 UpdateSizersCore(false, PositionFlags | wxALL);
394 if (setDefault)
395 pBtn->SetDefault();
396 return pBtn;
397}
398
400 const TranslatableStrings &choices, int Selected )
401{
402 HandleOptionality( Prompt );
403 AddPrompt( Prompt );
404 UseUpId();
406 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxChoice);
407 wxChoice * pChoice;
408 miProp=0;
409
410 mpWind = pChoice = safenew wxChoice(
411 GetParent(),
412 miId,
413 wxDefaultPosition,
414 wxDefaultSize,
415 transform_container<wxArrayString>(
416 choices, std::mem_fn( &TranslatableString::StrippedTranslation ) ),
417 GetStyle( 0 ) );
418
419 pChoice->SetMinSize( { 180, -1 } );// Use -1 for 'default size' - Platform specific.
420#ifdef __WXMAC__
421#if wxUSE_ACCESSIBILITY
422 // so that name can be set on a standard control
423 mpWind->SetAccessible(safenew WindowAccessible(mpWind));
424#endif
425#endif
426 pChoice->SetName(Prompt.Stripped().Translation());
427 if ( Selected >= 0 && Selected < (int)choices.size() )
428 pChoice->SetSelection( Selected );
429
430 UpdateSizers();
431 return pChoice;
432}
433
435 const TranslatableStrings &choices, const TranslatableString &Selected )
436{
437 return AddChoice(
438 Prompt, choices, make_iterator_range( choices ).index( Selected ) );
439}
440
442 const TranslatableString &Str, bool bCenter, int wrapWidth)
443{
444 const auto translated = Str.Translation();
445 UseUpId();
447 return;
448 auto text = safenew wxStaticText(GetParent(),
449 miId, translated, wxDefaultPosition, wxDefaultSize,
450 GetStyle( wxALIGN_LEFT ));
451 mpWind = text;
452 if ( wrapWidth > 0 )
453 text->Wrap( wrapWidth );
454 mpWind->SetName(wxStripMenuCodes(translated)); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
455 if( bCenter )
456 {
457 miProp=1;
459 }
460 else
461 UpdateSizers();
462}
463
465 const TranslatableString &Str,
466 bool bCenter, int PositionFlags, int wrapWidth )
467{
468 const auto translated = Str.Translation();
469 UseUpId();
471 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxStaticText);
472
473 wxStaticText *pStatic;
474 auto text = pStatic = safenew wxStaticText(GetParent(), miId, translated,
475 wxDefaultPosition, wxDefaultSize,
476 GetStyle( wxALIGN_LEFT ));
477 mpWind = text;
478 if ( wrapWidth > 0 )
479 text->Wrap( wrapWidth );
480 mpWind->SetName(wxStripMenuCodes(translated)); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
481 if( bCenter )
482 {
483 miProp=1;
484 if( PositionFlags )
485 UpdateSizersCore( false, PositionFlags );
486 else
488 }
489 else
490 if( PositionFlags )
491 UpdateSizersCore( false, PositionFlags );
492 else
493 UpdateSizers();
494 return pStatic;
495}
496
498 const TranslatableString &Caption, const wxString &Value)
499{
500 const auto translated = Caption.Translation();
501 auto style = GetStyle( wxBORDER_NONE );
502 HandleOptionality( Caption );
503 mItem.miStyle = wxALIGN_CENTER_VERTICAL;
504 AddPrompt( Caption );
505 UseUpId();
507 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), ReadOnlyText);
508 ReadOnlyText * pReadOnlyText;
509 miProp=0;
510
511 mpWind = pReadOnlyText = safenew ReadOnlyText(GetParent(), miId, Value,
512 wxDefaultPosition, wxDefaultSize, GetStyle( style ));
513 mpWind->SetName(wxStripMenuCodes(translated));
514 UpdateSizers();
515 return pReadOnlyText;
516}
517
519 const TranslatableString &Prompt,
520 const wxString &Selected, const wxArrayStringEx & choices )
521{
522 const auto translated = Prompt.Translation();
523 HandleOptionality( Prompt );
524 AddPrompt( Prompt );
525 UseUpId();
527 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxComboBox);
528 wxComboBox * pCombo;
529 miProp=0;
530
531 int n = choices.size();
532 if( n>50 ) n=50;
533 int i;
534 wxString Choices[50];
535 for(i=0;i<n;i++)
536 {
537 Choices[i] = choices[i];
538 }
539
540 mpWind = pCombo = safenew wxComboBox(GetParent(), miId, Selected, wxDefaultPosition, wxDefaultSize,
541 n, Choices, GetStyle( 0 ));
542 mpWind->SetName(wxStripMenuCodes(translated));
543
544 UpdateSizers();
545 return pCombo;
546}
547
548
550 const TranslatableString &Prompt, int style, int selector, int initValue)
551{
552 const auto translated = Prompt.Translation();
555 UseUpId();
557 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxRadioButton);
558 wxRadioButton * pRad;
559 mpWind = pRad = safenew wxRadioButton(GetParent(), miId, translated,
560 wxDefaultPosition, wxDefaultSize, GetStyle( style ) );
561 mpWind->SetName(wxStripMenuCodes(translated));
562 if ( style )
563 pRad->SetValue( true );
564 UpdateSizers();
565 pRad->SetValue( selector == initValue );
566 return pRad;
567}
568
570 const TranslatableString &Prompt, int selector, int initValue)
571{
572 return DoAddRadioButton( Prompt, wxRB_GROUP, selector, initValue );
573}
574
576 const TranslatableString &Prompt, int selector, int initValue)
577{
578 return DoAddRadioButton( Prompt, 0, selector, initValue );
579}
580
581#ifdef __WXMAC__
583{
584 // bypassing the override in wxCompositeWindow<wxSliderBase> which ends up
585 // doing nothing
586 return wxSliderBase::SetFocus();
587}
588#endif
589
591 const TranslatableString &Prompt, int pos, int Max, int Min)
592{
593 HandleOptionality( Prompt );
594 AddPrompt( Prompt );
595 UseUpId();
597 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxSlider);
598 wxSlider * pSlider;
600 pos, Min, Max,
601 wxDefaultPosition,
602 // Bug2289: On Linux at least, sliders like to be constructed with the
603 // proper size, not reassigned size later
604 ( ( mItem.mWindowSize == wxSize{} ) ? wxDefaultSize : mItem.mWindowSize ),
605 GetStyle( wxSL_HORIZONTAL | wxSL_LABELS | wxSL_AUTOTICKS )
606 );
607#if wxUSE_ACCESSIBILITY
608 // so that name can be set on a standard control
609 mpWind->SetAccessible(safenew WindowAccessible(mpWind));
610#endif
611 mpWind->SetName(wxStripMenuCodes(Prompt.Translation()));
612 miProp=1;
613 UpdateSizers();
614 return pSlider;
615}
616
618 const TranslatableString &Prompt, int Value, int Max, int Min)
619{
620 const auto translated = Prompt.Translation();
621 HandleOptionality( Prompt );
622 AddPrompt( Prompt );
623 UseUpId();
625 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxSpinCtrl);
626 wxSpinCtrl * pSpinCtrl;
627 mpWind = pSpinCtrl = safenew wxSpinCtrl(GetParent(), miId,
628 wxEmptyString,
629 wxDefaultPosition, wxDefaultSize,
630 GetStyle( wxSP_VERTICAL | wxSP_ARROW_KEYS ),
631 Min, Max, Value
632 );
633 mpWind->SetName(wxStripMenuCodes(translated));
634 miProp=1;
635 UpdateSizers();
636 return pSpinCtrl;
637}
638
640 const TranslatableString &Caption, const wxString &Value, const int nChars)
641{
642 const auto translated = Caption.Translation();
643 HandleOptionality( Caption );
644 AddPrompt( Caption );
645 UseUpId();
647 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxTextCtrl);
648 wxTextCtrl * pTextCtrl;
649 wxSize Size(wxDefaultSize);
650 if( nChars > 0 )
651 {
652 int width;
653 mpDlg->GetTextExtent( wxT("9"), &width, nullptr );
654 Size.SetWidth( nChars * width );
655 }
656 miProp=0;
657
658#ifdef EXPERIMENTAL_RIGHT_ALIGNED_TEXTBOXES
659 long flags = wxTE_RIGHT;
660#else
661 long flags = wxTE_LEFT;
662#endif
663
664 mpWind = pTextCtrl = safenew wxTextCtrlWrapper(GetParent(), miId, Value,
665 wxDefaultPosition, Size, GetStyle( flags ));
666#if wxUSE_ACCESSIBILITY
667 // so that name can be set on a standard control
668 mpWind->SetAccessible(safenew WindowAccessible(mpWind));
669#endif
670 mpWind->SetName(wxStripMenuCodes(translated));
671 UpdateSizers();
672 return pTextCtrl;
673}
674
676 const TranslatableString& Caption, const wxString& Value, const int nChars,
677 bool acceptEnter)
678{
679 const auto translated = Caption.Translation();
680 HandleOptionality( Caption );
681 AddPrompt( Caption );
682 UseUpId();
684 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxTextCtrl);
685 wxTextCtrl * pTextCtrl;
686 wxSize Size(wxDefaultSize);
687 if( nChars > 0 )
688 {
689 Size.SetWidth( nChars *5 );
690 }
691 miProp=0;
692
693#ifdef EXPERIMENTAL_RIGHT_ALIGNED_TEXTBOXES
694 long flags = wxTE_RIGHT;
695#else
696 long flags = wxTE_LEFT;
697#endif
698
699 if (acceptEnter)
700 flags = wxTE_PROCESS_ENTER;
701
702 wxTextValidator Validator(wxFILTER_NUMERIC);
703 mpWind = pTextCtrl = safenew wxTextCtrl(GetParent(), miId, Value,
704 wxDefaultPosition, Size, GetStyle( flags ),
705 Validator // It's OK to pass this. It will be cloned.
706 );
707#if wxUSE_ACCESSIBILITY
708 // so that name can be set on a standard control
709 mpWind->SetAccessible(safenew WindowAccessible(mpWind));
710#endif
711 mpWind->SetName(wxStripMenuCodes(translated));
712 UpdateSizers();
713 return pTextCtrl;
714}
715
717wxTextCtrl * ShuttleGuiBase::AddTextWindow(const wxString &Value)
718{
719 UseUpId();
721 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxTextCtrl);
722 wxTextCtrl * pTextCtrl;
723 SetProportions( 1 );
724 mpWind = pTextCtrl = safenew wxTextCtrl(GetParent(), miId, Value,
725 wxDefaultPosition, wxDefaultSize, GetStyle( wxTE_MULTILINE ));
726#if wxUSE_ACCESSIBILITY
727 // so that name can be set on a standard control
728 mpWind->SetAccessible(safenew WindowAccessible(mpWind));
729#endif
730 UpdateSizers();
731 // Start off at start of window...
732 pTextCtrl->SetInsertionPoint( 0 );
733 pTextCtrl->ShowPosition( 0 );
734 return pTextCtrl;
735}
736
739 const TranslatableString &Prompt, const TranslatableString &Value)
740{
741 HandleOptionality( Prompt );
742 AddPrompt( Prompt );
743 UseUpId();
745 return;
746// return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wx);
747 miProp=0;
748 UpdateSizers();
749 miProp=0;
750 const auto translatedValue = Value.Translation();
751 mpWind = safenew wxStaticText(GetParent(), miId,
752 translatedValue, wxDefaultPosition, wxDefaultSize,
753 GetStyle( 0 ));
754 mpWind->SetName(translatedValue); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
755 UpdateSizers();
756}
757
759{
760 UseUpId();
762 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxListBox);
763 wxListBox * pListBox;
764 SetProportions( 1 );
765 mpWind = pListBox = safenew wxListBox(GetParent(), miId,
766 wxDefaultPosition, wxDefaultSize, choices, GetStyle(0));
767 pListBox->SetMinSize( wxSize( 120,150 ));
768 UpdateSizers();
769 return pListBox;
770}
771
772
774{
775 UseUpId();
777 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxGrid);
778 wxGrid * pGrid;
779 SetProportions( 1 );
780 mpWind = pGrid = safenew wxGrid(GetParent(), miId, wxDefaultPosition,
781 wxDefaultSize, GetStyle( wxWANTS_CHARS ));
782 pGrid->SetMinSize( wxSize( 120, 150 ));
783 UpdateSizers();
784 return pGrid;
785}
786
788 std::initializer_list<const ListControlColumn> columns,
789 long listControlStyles
790)
791{
792 UseUpId();
794 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxListCtrl);
795 wxListCtrl * pListCtrl;
796 SetProportions( 1 );
797 mpWind = pListCtrl = safenew wxListCtrl(GetParent(), miId,
798 wxDefaultPosition, wxDefaultSize, GetStyle( wxLC_ICON ));
799 pListCtrl->SetMinSize( wxSize( 120,150 ));
800 UpdateSizers();
801
802 DoInsertListColumns( pListCtrl, listControlStyles, columns );
803
804 return pListCtrl;
805}
806
808 std::initializer_list<const ListControlColumn> columns,
809 long listControlStyles
810)
811{
812 UseUpId();
814 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxListCtrl);
815 wxListCtrl * pListCtrl;
816 SetProportions( 1 );
817 mpWind = pListCtrl = safenew wxListCtrl(GetParent(), miId,
818 wxDefaultPosition, wxSize(230,120),//wxDefaultSize,
819 GetStyle( wxLC_REPORT | wxLC_HRULES | wxLC_VRULES | wxSUNKEN_BORDER ));
820// pListCtrl->SetMinSize( wxSize( 120,150 ));
821 UpdateSizers();
822
823 DoInsertListColumns( pListCtrl, listControlStyles, columns );
824
825 return pListCtrl;
826}
827
829 wxListCtrl *pListCtrl,
830 long listControlStyles,
831 std::initializer_list<const ListControlColumn> columns )
832{
833 // Old comment from HistoryWindow.cpp follows
834 // -- is it still correct for wxWidgets 3?
835
836 // Do this BEFORE inserting the columns. On the Mac at least, the
837 // columns are deleted and later InsertItem()s will cause Audacity to crash.
838 for ( auto style = 1l; style <= listControlStyles; style <<= 1 )
839 if ( (style & listControlStyles) )
840 pListCtrl->SetSingleStyle(style, true);
841
842 long iCol = 0;
843 bool dummyColumn =
844 columns.size() > 0 && begin(columns)->format == wxLIST_FORMAT_RIGHT;
845
846 //A dummy first column, which is then deleted, is a workaround -
847 // under Windows the first column can't be right aligned.
848 if (dummyColumn)
849 pListCtrl->InsertColumn( iCol++, wxString{} );
850
851 for (auto &column : columns)
852 pListCtrl->InsertColumn(
853 iCol++, column.heading.Translation(), column.format, column.width );
854
855 if (dummyColumn)
856 pListCtrl->DeleteColumn( 0 );
857}
858
860{
861 UseUpId();
863 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxTreeCtrl);
864 wxTreeCtrl * pTreeCtrl;
865 SetProportions( 1 );
866 mpWind = pTreeCtrl = safenew wxTreeCtrl(GetParent(), miId, wxDefaultPosition, wxDefaultSize,
867 GetStyle( wxTR_HAS_BUTTONS ));
868 pTreeCtrl->SetMinSize( wxSize( 120,650 ));
869 UpdateSizers();
870 return pTreeCtrl;
871}
872
873void ShuttleGuiBase::AddIcon(wxBitmap *pBmp)
874{
875 UseUpId();
877// return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wx);
878 return;
879 wxBitmapButton * pBtn;
880 mpWind = pBtn = safenew wxBitmapButton(GetParent(), miId, *pBmp,
881 wxDefaultPosition, wxDefaultSize, GetStyle( wxBU_AUTODRAW ) );
882 pBtn->SetWindowStyle( wxBORDER_NONE );
883 pBtn->SetCanFocus(false);
885}
886
888{
889 miPropSetByUser = iProp;
890 return *this;
891}
892
898wxStaticBox * ShuttleGuiBase::StartStatic(const TranslatableString &Str, int iProp)
899{
900 UseUpId();
902 return NULL;
903 auto translated = Str.Translation();
904 wxStaticBox * pBox = safenew wxStaticBoxWrapper(
905 GetParent(), miId, translated );
906 pBox->SetLabel( translated );
907 if (Str.empty()) {
908 // NVDA 2018.3 or later does not read the controls in a group box which has
909 // an accessibility name which is empty. Bug 2169.
910#if wxUSE_ACCESSIBILITY
911 // so that name can be set on a standard control
912 pBox->SetAccessible(safenew WindowAccessible(pBox));
913#endif
914 pBox->SetName(wxT("\a")); // non-empty string which screen readers do not read
915 }
916 else
917 pBox->SetName( wxStripMenuCodes( translated ) );
918 mpSubSizer = std::make_unique<wxStaticBoxSizer>(
919 pBox,
920 wxVERTICAL );
921 miSizerProp = iProp;
922 UpdateSizers();
923 mpParent = pBox;
924 return pBox;
925}
926
928{
930 return;
931 PopSizer();
932 mpParent = mpParent->GetParent();
933}
934
943wxScrolledWindow * ShuttleGuiBase::StartScroller(int iStyle)
944{
945 UseUpId();
947 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxScrolledWindow);
948
949 wxScrolledWindow * pScroller;
950 mpWind = pScroller = safenew wxScrolledWindow(GetParent(), miId, wxDefaultPosition, wxDefaultSize,
951 GetStyle( wxSUNKEN_BORDER ) );
952 pScroller->SetScrollRate( 20,20 );
953
954 // This fools NVDA into not saying "Panel" when the dialog gets focus
955 pScroller->SetName(wxT("\a"));
956 pScroller->SetLabel(wxT("\a"));
957
958 SetProportions( 1 );
959 if( iStyle==2 )
960 {
962 }
963 else
964 {
965 // mpWind->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR));
966 UpdateSizers(); // adds window in to current sizer.
967 }
968
969 // create a sizer within the window...
970 mpParent = pScroller;
971 pScroller->SetSizer(mpSizer = safenew wxBoxSizer(wxVERTICAL));
972 PushSizer();
973 return pScroller;
974}
975
977{
979 return;
980 wxSize ScrollSize = mpSizer->GetMinSize();
981 int yMin = ScrollSize.y+4;
982 int xMin = ScrollSize.x+4;
983 if( yMin > 400)
984 {
985 yMin = 400;
986 xMin+=50;// extra space for vertical scrollbar.
987 }
988
989 mpParent->SetMinSize( wxSize(xMin, yMin) );
990
991 PopSizer();
992 mpParent = mpParent->GetParent();
993}
994
995wxPanel * ShuttleGuiBase::StartPanel(int iStyle)
996{
997 UseUpId();
999 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxPanel);
1000 wxPanel * pPanel;
1001 mpWind = pPanel = safenew wxPanelWrapper( GetParent(), miId, wxDefaultPosition, wxDefaultSize,
1002 GetStyle( wxNO_BORDER ));
1003
1004 if( iStyle != 0 )
1005 {
1006 mpWind->SetBackgroundColour(
1007 iStyle==1
1008 ? wxColour( 190,200,230) :
1009 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)
1010 );
1011 }
1012 SetProportions(0);
1013 miBorder=2;
1014 UpdateSizers(); // adds window in to current sizer.
1015
1016 // create a sizer within the window...
1017 mpParent = pPanel;
1018 pPanel->SetSizer(mpSizer = safenew wxBoxSizer(wxVERTICAL));
1019 PushSizer();
1020 return pPanel;
1021}
1022
1024{
1025 if( mShuttleMode != eIsCreating )
1026 return;
1027 PopSizer();
1028 mpParent = mpParent->GetParent();
1029}
1030
1032{
1033 UseUpId();
1034 if( mShuttleMode != eIsCreating )
1035 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxNotebook);
1036 wxNotebook * pNotebook;
1037 mpWind = pNotebook = safenew wxNotebook(GetParent(),
1038 miId, wxDefaultPosition, wxDefaultSize, GetStyle( 0 ));
1039 SetProportions( 1 );
1040 UpdateSizers();
1041 mpParent = pNotebook;
1042 return pNotebook;
1043}
1044
1046{
1047 //PopSizer();
1048 mpParent = mpParent->GetParent();
1049}
1050
1051
1053{
1054 UseUpId();
1055 if( mShuttleMode != eIsCreating )
1056 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxSimplebook);
1057 wxSimplebook * pNotebook;
1058 mpWind = pNotebook = safenew wxSimplebook(GetParent(),
1059 miId, wxDefaultPosition, wxDefaultSize, GetStyle( 0 ));
1060 SetProportions( 1 );
1061 UpdateSizers();
1062 mpParent = pNotebook;
1063 return pNotebook;
1064}
1065
1067{
1068 //PopSizer();
1069 mpParent = mpParent->GetParent();
1070}
1071
1072
1074 const TranslatableString & Name )
1075{
1076 if( mShuttleMode != eIsCreating )
1077 return NULL;
1078// return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wx);
1079 auto pNotebook = static_cast< wxBookCtrlBase* >( mpParent );
1081 const auto translated = Name.Translation();
1082 pPage->SetName(translated);
1083
1084 pNotebook->AddPage(
1085 pPage,
1086 translated);
1087
1088 SetProportions( 1 );
1089 mpParent = pPage;
1090 pPage->SetSizer(mpSizer = safenew wxBoxSizer(wxVERTICAL));
1091 PushSizer();
1092 // UpdateSizers();
1093 return pPage;
1094}
1095
1097{
1098 if( mShuttleMode != eIsCreating )
1099 return;
1100 PopSizer();
1101 mpParent = mpParent->GetParent();
1102}
1103
1104// Doxygen description is at the start of the file
1105// this is a wxPanel with erase background disabled.
1106class InvisiblePanel final : public wxPanelWrapper
1107{
1108public:
1110 wxWindow* parent,
1111 wxWindowID id = -1,
1112 const wxPoint& pos = wxDefaultPosition,
1113 const wxSize& size = wxDefaultSize,
1114 long style = wxTAB_TRAVERSAL ) :
1115 wxPanelWrapper( parent, id, pos, size, style )
1116 {
1117 };
1119 void OnPaint( wxPaintEvent &event );
1120 void OnErase(wxEraseEvent &/*evt*/){;};
1121 DECLARE_EVENT_TABLE()
1122};
1123
1124
1125BEGIN_EVENT_TABLE(InvisiblePanel, wxPanelWrapper)
1126// EVT_PAINT(InvisiblePanel::OnPaint)
1127 EVT_ERASE_BACKGROUND( InvisiblePanel::OnErase)
1129
1130void InvisiblePanel::OnPaint( wxPaintEvent & WXUNUSED(event))
1131{
1132 // Don't repaint my background.
1133 wxPaintDC dc(this);
1134 // event.Skip(); // swallow the paint event.
1135}
1136
1138{
1139 UseUpId();
1140 if( mShuttleMode != eIsCreating )
1141 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxPanel);
1142 wxPanel * pPanel;
1143 mpWind = pPanel = safenew wxPanelWrapper(GetParent(), miId, wxDefaultPosition, wxDefaultSize,
1144 wxNO_BORDER);
1145
1146 mpWind->SetBackgroundColour(
1147 wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)
1148 );
1149 SetProportions( 1 );
1150 miBorder = border;
1151 UpdateSizers(); // adds window in to current sizer.
1152
1153 // create a sizer within the window...
1154 mpParent = pPanel;
1155 pPanel->SetSizer(mpSizer = safenew wxBoxSizer(wxVERTICAL));
1156 PushSizer();
1157 return pPanel;
1158}
1159
1161{
1162 EndPanel();
1163}
1164
1165
1172void ShuttleGuiBase::StartHorizontalLay( int PositionFlags, int iProp)
1173{
1174 if( mShuttleMode != eIsCreating )
1175 return;
1176 miSizerProp=iProp;
1177 mpSubSizer = std::make_unique<wxBoxSizer>( wxHORIZONTAL );
1178 // PRL: wxALL has no effect because UpdateSizersCore ignores border
1179 UpdateSizersCore( false, PositionFlags | wxALL );
1180}
1181
1183{
1184 if( mShuttleMode != eIsCreating )
1185 return;
1186 PopSizer();
1187}
1188
1190{
1191 if( mShuttleMode != eIsCreating )
1192 return;
1193 miSizerProp=iProp;
1194 mpSubSizer = std::make_unique<wxBoxSizer>( wxVERTICAL );
1195 UpdateSizers();
1196}
1197
1198void ShuttleGuiBase::StartVerticalLay(int PositionFlags, int iProp)
1199{
1200 if( mShuttleMode != eIsCreating )
1201 return;
1202 miSizerProp=iProp;
1203 mpSubSizer = std::make_unique<wxBoxSizer>( wxVERTICAL );
1204 // PRL: wxALL has no effect because UpdateSizersCore ignores border
1205 UpdateSizersCore( false, PositionFlags | wxALL );
1206}
1207
1209{
1210 if( mShuttleMode != eIsCreating )
1211 return;
1212 PopSizer();
1213}
1214
1215void ShuttleGuiBase::StartWrapLay(int PositionFlags, int iProp)
1216{
1218 return;
1219
1220 miSizerProp = iProp;
1221 mpSubSizer = std::make_unique<wxWrapSizer>(wxHORIZONTAL, 0);
1222
1223 UpdateSizersCore(false, PositionFlags | wxALL);
1224}
1225
1227{
1229 return;
1230
1231 PopSizer();
1232}
1233
1234void ShuttleGuiBase::StartMultiColumn(int nCols, int PositionFlags)
1235{
1236 if( mShuttleMode != eIsCreating )
1237 return;
1238 mpSubSizer = std::make_unique<wxFlexGridSizer>( nCols );
1239 // PRL: wxALL has no effect because UpdateSizersCore ignores border
1240 UpdateSizersCore( false, PositionFlags | wxALL );
1241}
1242
1244{
1245 if( mShuttleMode != eIsCreating )
1246 return;
1247 PopSizer();
1248}
1249
1252void ShuttleGuiBase::DoDataShuttle( const wxString &Name, WrappedType & WrappedRef )
1253{
1254 wxASSERT( mpShuttle );
1255 mpShuttle->TransferWrappedType( Name, WrappedRef );
1256}
1257
1258//-----------------------------------------------------------------------//
1259
1260// We now have a group of tie functions which are generic in the type
1261// they bind to (i.e. WrappedType).
1262// The type specific versions are much shorter and are later
1263// in this file.
1264wxCheckBox * ShuttleGuiBase::DoTieCheckBox(const TranslatableString &Prompt, WrappedType & WrappedRef)
1265{
1266 HandleOptionality( Prompt );
1267 // The Add function does a UseUpId(), so don't do it here in that case.
1268 if( mShuttleMode == eIsCreating )
1269 return AddCheckBox( Prompt, WrappedRef.ReadAsString() == wxT("true"));
1270
1271 UseUpId();
1272
1273 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1274 wxCheckBox * pCheckBox = wxDynamicCast(pWnd, wxCheckBox);
1275
1276 switch( mShuttleMode )
1277 {
1278 // IF setting internal storage from the controls.
1279 case eIsGettingMetadata:
1280 break;
1282 {
1283 wxASSERT( pCheckBox );
1284 WrappedRef.WriteToAsBool( pCheckBox->GetValue() );
1285 }
1286 break;
1287 case eIsSettingToDialog:
1288 {
1289 wxASSERT( pCheckBox );
1290 pCheckBox->SetValue( WrappedRef.ReadAsBool() );
1291 }
1292 break;
1293 default:
1294 wxASSERT( false );
1295 break;
1296 }
1297 return pCheckBox;
1298}
1299
1301{
1302 HandleOptionality( Prompt );
1303 // The Add function does a UseUpId(), so don't do it here in that case.
1304 if( mShuttleMode == eIsCreating )
1305 return AddCheckBoxOnRight( Prompt, WrappedRef.ReadAsString() == wxT("true"));
1306
1307 UseUpId();
1308
1309 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1310 wxCheckBox * pCheckBox = wxDynamicCast(pWnd, wxCheckBox);
1311
1312 switch( mShuttleMode )
1313 {
1314 // IF setting internal storage from the controls.
1315 case eIsGettingMetadata:
1316 break;
1318 {
1319 wxASSERT( pCheckBox );
1320 WrappedRef.WriteToAsBool( pCheckBox->GetValue() );
1321 }
1322 break;
1323 case eIsSettingToDialog:
1324 {
1325 wxASSERT( pCheckBox );
1326 pCheckBox->SetValue( WrappedRef.ReadAsBool() );
1327 }
1328 break;
1329 default:
1330 wxASSERT( false );
1331 break;
1332 }
1333 return pCheckBox;
1334}
1335
1337 const TranslatableString &Prompt,
1338 WrappedType & WrappedRef, const int max, const int min )
1339{
1340 HandleOptionality( Prompt );
1341 // The Add function does a UseUpId(), so don't do it here in that case.
1342 if( mShuttleMode == eIsCreating )
1343 return AddSpinCtrl( Prompt, WrappedRef.ReadAsInt(), max, min );
1344
1345 UseUpId();
1346 wxSpinCtrl * pSpinCtrl=NULL;
1347
1348 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1349 pSpinCtrl = wxDynamicCast(pWnd, wxSpinCtrl);
1350
1351 switch( mShuttleMode )
1352 {
1353 // IF setting internal storage from the controls.
1354 case eIsGettingMetadata:
1355 break;
1357 {
1358 wxASSERT( pSpinCtrl );
1359 WrappedRef.WriteToAsInt( pSpinCtrl->GetValue() );
1360 }
1361 break;
1362 case eIsSettingToDialog:
1363 {
1364 wxASSERT( pSpinCtrl );
1365 pSpinCtrl->SetValue( WrappedRef.ReadAsInt() );
1366 }
1367 break;
1368 default:
1369 wxASSERT( false );
1370 break;
1371 }
1372 return pSpinCtrl;
1373}
1374
1376 const TranslatableString &Prompt, WrappedType & WrappedRef, const int nChars)
1377{
1378 HandleOptionality( Prompt );
1379 // The Add function does a UseUpId(), so don't do it here in that case.
1380 if( mShuttleMode == eIsCreating )
1381 return AddTextBox( Prompt, WrappedRef.ReadAsString(), nChars );
1382
1383 UseUpId();
1384 wxTextCtrl * pTextBox=NULL;
1385
1386 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1387 pTextBox = wxDynamicCast(pWnd, wxTextCtrl);
1388
1389 switch( mShuttleMode )
1390 {
1391 // IF setting internal storage from the controls.
1392 case eIsGettingMetadata:
1393 break;
1395 {
1396 wxASSERT( pTextBox );
1397 WrappedRef.WriteToAsString( pTextBox->GetValue() );
1398 }
1399 break;
1400 case eIsSettingToDialog:
1401 {
1402 wxASSERT( pTextBox );
1403 pTextBox->SetValue( WrappedRef.ReadAsString() );
1404 }
1405 break;
1406 default:
1407 wxASSERT( false );
1408 break;
1409 }
1410 return pTextBox;
1411}
1412
1414 const TranslatableString& Prompt, WrappedType& WrappedRef, const int nChars,
1415 bool acceptEnter)
1416{
1417 HandleOptionality( Prompt );
1418 // The Add function does a UseUpId(), so don't do it here in that case.
1419 if( mShuttleMode == eIsCreating )
1420 return AddNumericTextBox( Prompt, WrappedRef.ReadAsString(), nChars, acceptEnter );
1421
1422 UseUpId();
1423 wxTextCtrl * pTextBox=NULL;
1424
1425 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1426 pTextBox = wxDynamicCast(pWnd, wxTextCtrl);
1427
1428 switch( mShuttleMode )
1429 {
1430 // IF setting internal storage from the controls.
1431 case eIsGettingMetadata:
1432 break;
1434 {
1435 wxASSERT( pTextBox );
1436 WrappedRef.WriteToAsString( pTextBox->GetValue() );
1437 }
1438 break;
1439 case eIsSettingToDialog:
1440 {
1441 wxASSERT( pTextBox );
1442 pTextBox->SetValue( WrappedRef.ReadAsString() );
1443 }
1444 break;
1445 default:
1446 wxASSERT( false );
1447 break;
1448 }
1449 return pTextBox;
1450}
1451
1453 const TranslatableString &Prompt,
1454 WrappedType & WrappedRef, const int max, int min )
1455{
1456 HandleOptionality( Prompt );
1457 // The Add function does a UseUpId(), so don't do it here in that case.
1458 if( mShuttleMode != eIsCreating )
1459 UseUpId();
1460 wxSlider * pSlider=NULL;
1461 switch( mShuttleMode )
1462 {
1463 case eIsCreating:
1464 {
1465 pSlider = AddSlider( Prompt, WrappedRef.ReadAsInt(), max, min );
1466 }
1467 break;
1468 // IF setting internal storage from the controls.
1469 case eIsGettingMetadata:
1470 break;
1472 {
1473 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1474 pSlider = wxDynamicCast(pWnd, wxSlider);
1475 wxASSERT( pSlider );
1476 WrappedRef.WriteToAsInt( pSlider->GetValue() );
1477 }
1478 break;
1479 case eIsSettingToDialog:
1480 {
1481 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1482 pSlider = wxDynamicCast(pWnd, wxSlider);
1483 wxASSERT( pSlider );
1484 pSlider->SetValue( WrappedRef.ReadAsInt() );
1485 }
1486 break;
1487 default:
1488 wxASSERT( false );
1489 break;
1490 }
1491 return pSlider;
1492}
1493
1494
1496 const TranslatableString &Prompt,
1497 int &Selected,
1498 const TranslatableStrings &choices )
1499{
1500 HandleOptionality( Prompt );
1501
1502 // The Add function does a UseUpId(), so don't do it here in that case.
1503 if( mShuttleMode != eIsCreating )
1504 UseUpId();
1505
1506 wxChoice * pChoice=NULL;
1507 switch( mShuttleMode )
1508 {
1509 case eIsCreating:
1510 {
1511 pChoice = AddChoice( Prompt, choices, Selected );
1512 ShuttleGui::SetMinSize(pChoice, choices);
1513 }
1514 break;
1515 // IF setting internal storage from the controls.
1516 case eIsGettingMetadata:
1517 break;
1519 {
1520 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1521 pChoice = wxDynamicCast(pWnd, wxChoice);
1522 wxASSERT( pChoice );
1523 Selected = pChoice->GetSelection();
1524 }
1525 break;
1526 case eIsSettingToDialog:
1527 {
1528 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1529 pChoice = wxDynamicCast(pWnd, wxChoice);
1530 wxASSERT( pChoice );
1531 pChoice->SetSelection( Selected );
1532 }
1533 break;
1534 default:
1535 wxASSERT( false );
1536 break;
1537 }
1538 return pChoice;
1539}
1540
1543{
1544 wxASSERT( mRadioCount >= 0); // Did you remember to use StartRadioButtonGroup() ?
1545
1546 EnumValueSymbol symbol;
1547 if (mRadioCount >= 0 && mRadioCount < (int)mRadioSymbols.size() )
1548 symbol = mRadioSymbols[ mRadioCount ];
1549
1550 // In what follows, WrappedRef is used in read only mode, but we
1551 // don't have a 'read-only' version, so we copy to deal with the constness.
1552 auto Temp = symbol.Internal();
1553 wxASSERT( !Temp.empty() ); // More buttons than values?
1554
1555 WrappedType WrappedRef( Temp );
1556
1557 mRadioCount++;
1558
1559 UseUpId();
1560 wxRadioButton * pRadioButton = NULL;
1561
1562 switch( mShuttleMode )
1563 {
1564 case eIsCreating:
1565 {
1566 const auto &Prompt = symbol.Translation();
1567
1568 mpWind = pRadioButton = safenew wxRadioButton(GetParent(), miId, Prompt,
1569 wxDefaultPosition, wxDefaultSize,
1570 (mRadioCount==1)?wxRB_GROUP:0);
1571
1572 wxASSERT( WrappedRef.IsString() );
1573 wxASSERT( mRadioValue->IsString() );
1574 const bool value =
1575 (WrappedRef.ReadAsString() == mRadioValue->ReadAsString() );
1576 pRadioButton->SetValue( value );
1577
1578 pRadioButton->SetName(wxStripMenuCodes(Prompt));
1579 UpdateSizers();
1580 }
1581 break;
1582 case eIsGettingMetadata:
1583 break;
1585 {
1586 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1587 pRadioButton = wxDynamicCast(pWnd, wxRadioButton);
1588 wxASSERT( pRadioButton );
1589 if( pRadioButton->GetValue() )
1590 mRadioValue->WriteToAsString( WrappedRef.ReadAsString() );
1591 }
1592 break;
1593 default:
1594 wxASSERT( false );
1595 break;
1596 }
1597 return pRadioButton;
1598}
1599
1602{
1603 mRadioSymbols = Setting.GetSymbols();
1604
1605 // Configure the generic type mechanism to use OUR string.
1606 mRadioValueString = Setting.Default().Internal();
1607 mRadioValue.emplace( mRadioValueString );
1608
1609 // Now actually start the radio button group.
1610 mRadioSettingName = Setting.Key();
1611 mRadioCount = 0;
1612 if( mShuttleMode == eIsCreating )
1614}
1615
1619{
1620 // too few buttons?
1621 wxASSERT( mRadioCount == mRadioSymbols.size() );
1622
1625 mRadioValue.reset();// Clear it out...
1626 mRadioSettingName = wxT("");
1627 mRadioCount = -1; // So we detect a problem.
1628 mRadioSymbols = {};
1629}
1630
1631//-----------------------------------------------------------------------//
1632//-- Now we are into type specific Tie() functions.
1633//-- These are all 'one-step' tie functions.
1634
1635wxCheckBox * ShuttleGuiBase::TieCheckBox(const TranslatableString &Prompt, bool &Var)
1636{
1637 WrappedType WrappedRef( Var );
1638 return DoTieCheckBox( Prompt, WrappedRef );
1639}
1640
1641// See comment in AddCheckBoxOnRight() for why we have this variant.
1642wxCheckBox * ShuttleGuiBase::TieCheckBoxOnRight(const TranslatableString &Prompt, bool &Var)
1643{
1644 // Only does anything different if it's creating.
1645 WrappedType WrappedRef( Var );
1646 if( mShuttleMode == eIsCreating )
1647 return AddCheckBoxOnRight( Prompt, WrappedRef.ReadAsString() == wxT("true") );
1648 return DoTieCheckBox( Prompt, WrappedRef );
1649}
1650
1652 const TranslatableString &Prompt, int &Value, const int max, const int min )
1653{
1654 WrappedType WrappedRef(Value);
1655 return DoTieSpinCtrl( Prompt, WrappedRef, max, min );
1656}
1657
1659 const TranslatableString &Prompt, wxString &Selected, const int nChars)
1660{
1661 WrappedType WrappedRef(Selected);
1662 return DoTieTextBox( Prompt, WrappedRef, nChars );
1663}
1664
1666 const TranslatableString &Prompt, int &Selected, const int nChars)
1667{
1668 WrappedType WrappedRef( Selected );
1669 return DoTieTextBox( Prompt, WrappedRef, nChars );
1670}
1671
1673 const TranslatableString &Prompt, double &Value, const int nChars)
1674{
1675 WrappedType WrappedRef( Value );
1676 return DoTieTextBox( Prompt, WrappedRef, nChars );
1677}
1678
1680 const TranslatableString& Prompt, int& Value, const int nChars,
1681 bool acceptEnter)
1682{
1683 WrappedType WrappedRef(Value);
1684 return DoTieNumericTextBox(Prompt, WrappedRef, nChars, acceptEnter);
1685}
1686
1688 const TranslatableString& Prompt, double& Value, const int nChars,
1689 bool acceptEnter)
1690{
1691 WrappedType WrappedRef( Value );
1692 return DoTieNumericTextBox( Prompt, WrappedRef, nChars, acceptEnter );
1693}
1694
1696 const TranslatableString &Prompt, int &pos, const int max, const int min )
1697{
1698 WrappedType WrappedRef( pos );
1699 return DoTieSlider( Prompt, WrappedRef, max, min );
1700}
1701
1703 const TranslatableString &Prompt,
1704 double &pos, const double max, const double min )
1705{
1706 WrappedType WrappedRef( pos );
1707 return DoTieSlider( Prompt, WrappedRef, max, min );
1708}
1709
1711 const TranslatableString &Prompt,
1712 float &pos, const float fMin, const float fMax)
1713{
1714 const float RoundFix=0.0000001f;
1715 int iVal=(pos-fMin+RoundFix)*100.0/(fMax-fMin);
1716 wxSlider * pWnd = TieSlider( Prompt, iVal, 100 );
1717 pos = iVal*(fMax-fMin)*0.01+fMin;
1718 return pWnd;
1719}
1720
1722 const TranslatableString &Prompt,
1723 float &pos, const float fMin, const float fMax)
1724{
1725 int iVal=(pos-fMin)*100.0/(fMax-fMin);
1726// if( mShuttleMode == eIsCreating )
1727// {
1728// return AddVSlider( Prompt, iVal, 100 );
1729// }
1730 wxSlider * pWnd = TieSlider( Prompt, iVal, 100 );
1731 pos = iVal*(fMax-fMin)*0.01+fMin;
1732 return pWnd;
1733}
1734
1736 const TranslatableString &Prompt,
1737 TranslatableString &Selected,
1738 const TranslatableStrings &choices )
1739{
1740 int Index = make_iterator_range( choices ).index( Selected );
1741 auto result = TieChoice( Prompt, Index, choices );
1742 if ( Index >= 0 && Index < choices.size() )
1743 Selected = choices[ Index ];
1744 else
1745 Selected = {};
1746 return result;
1747}
1748
1749//-----------------------------------------------------------------------//
1750
1751// ShuttleGui utility functions to look things up in a list.
1752// If not present, we use the configured default index value.
1753
1754//-----------------------------------------------------------------------//
1755
1757int ShuttleGuiBase::TranslateToIndex( const wxString &Value, const wxArrayStringEx &Choices )
1758{
1759 int n = make_iterator_range( Choices ).index( Value );
1760 if( n == wxNOT_FOUND )
1763 return n;
1764}
1765
1767wxString ShuttleGuiBase::TranslateFromIndex( const int nIn, const wxArrayStringEx &Choices )
1768{
1769 int n = nIn;
1770 if( n== wxNOT_FOUND )
1773 if( n < (int)Choices.size() )
1774 {
1775 return Choices[n];
1776 }
1777 return wxT("");
1778}
1779
1780//-----------------------------------------------------------------------//
1781
1782
1783// ShuttleGui code uses the model that you read into program variables
1784// and write out from program variables.
1785
1786// In programs like Audacity which don't use internal program variables
1787// you have to do both steps in one go, using variants of the standard
1788// 'Tie' functions which call the underlying Tie functions twice.
1789
1790//----------------------------------------------------------------------//
1791
1792
1825bool ShuttleGuiBase::DoStep( int iStep )
1826{
1827 // Get value and create
1828 if( mShuttleMode == eIsCreating )
1829 {
1830 return (iStep==1) || (iStep==2);
1831 }
1832 // Like creating, get the value and set.
1834 {
1835 return (iStep==1) || (iStep==2);
1836 }
1838 {
1839 return (iStep==2) || (iStep==3);
1840 }
1842 return iStep ==2;
1843 wxASSERT( false );
1844 return false;
1845}
1846
1847
1851 const TranslatableString &Prompt,
1852 const BoolSetting &Setting)
1853{
1854 wxCheckBox * pCheck=NULL;
1855
1856 auto Value = Setting.GetDefault();
1857 WrappedType WrappedRef( Value );
1858 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1859 if( DoStep(2) ) pCheck = DoTieCheckBox( Prompt, WrappedRef );
1860 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1861
1862 return pCheck;
1863}
1864
1868 const TranslatableString &Prompt,
1869 const BoolSetting & Setting)
1870{
1871 wxCheckBox * pCheck=NULL;
1872
1873 auto Value = Setting.GetDefault();
1874 WrappedType WrappedRef( Value );
1875 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1876 if( DoStep(2) ) pCheck = DoTieCheckBoxOnRight( Prompt, WrappedRef );
1877 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1878
1879 return pCheck;
1880}
1881
1885 const TranslatableString &Prompt,
1886 const IntSetting & Setting,
1887 const int max,
1888 const int min)
1889{
1890 wxSlider * pSlider=NULL;
1891
1892 auto Value = Setting.GetDefault();
1893 WrappedType WrappedRef( Value );
1894 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1895 if( DoStep(2) ) pSlider = DoTieSlider( Prompt, WrappedRef, max, min );
1896 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1897
1898 return pSlider;
1899}
1900
1904 const TranslatableString &Prompt,
1905 const IntSetting &Setting,
1906 const int max,
1907 const int min)
1908{
1909 wxSpinCtrl * pSpinCtrl=NULL;
1910
1911 auto Value = Setting.GetDefault();
1912 WrappedType WrappedRef( Value );
1913 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1914 if( DoStep(2) ) pSpinCtrl = DoTieSpinCtrl( Prompt, WrappedRef, max, min );
1915 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1916
1917 return pSpinCtrl;
1918}
1919
1923 const TranslatableString & Prompt,
1924 const StringSetting & Setting,
1925 const int nChars)
1926{
1927 wxTextCtrl * pText=(wxTextCtrl*)NULL;
1928
1929 auto Value = Setting.GetDefault();
1930 WrappedType WrappedRef( Value );
1931 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1932 if( DoStep(2) ) pText = DoTieTextBox( Prompt, WrappedRef, nChars );
1933 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1934 return pText;
1935}
1936
1941 const TranslatableString & Prompt,
1942 const IntSetting &Setting,
1943 const int nChars)
1944{
1945 wxTextCtrl * pText=(wxTextCtrl*)NULL;
1946
1947 auto Value = Setting.GetDefault();
1948 WrappedType WrappedRef( Value );
1949 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1950 if( DoStep(2) ) pText = DoTieNumericTextBox( Prompt, WrappedRef, nChars );
1951 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1952 return pText;
1953}
1954
1959 const TranslatableString & Prompt,
1960 const DoubleSetting & Setting,
1961 const int nChars, bool acceptEnter)
1962{
1963 wxTextCtrl * pText=(wxTextCtrl*)NULL;
1964
1965 auto Value = Setting.GetDefault();
1966 WrappedType WrappedRef( Value );
1967 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1968 if( DoStep(2) ) pText = DoTieNumericTextBox( Prompt, WrappedRef, nChars, acceptEnter );
1969 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1970 return pText;
1971}
1972
1980 ChoiceSetting &choiceSetting)
1981{
1982 // Do this to force any needed migrations first
1983 choiceSetting.Read();
1984
1985 const auto &symbols = choiceSetting.GetSymbols();
1986 const auto &SettingName = choiceSetting.Key();
1987 const auto &Default = choiceSetting.Default().Internal();
1988 const auto &Choices = symbols.GetMsgids();
1989 const auto &InternalChoices = symbols.GetInternals();
1990
1991 wxChoice * pChoice=(wxChoice*)NULL;
1992
1993 int TempIndex=0;
1994// int TempIndex = TranslateToIndex( Default, InternalChoices );
1995 wxString TempStr = Default;
1996 WrappedType WrappedRef( TempStr );
1997 // Get from prefs does 1 and 2.
1998 // Put to prefs does 2 and 3.
1999 if( DoStep(1) ) DoDataShuttle( SettingName, WrappedRef ); // Get Index from Prefs.
2000 if( DoStep(1) ) TempIndex = TranslateToIndex( TempStr, InternalChoices ); // To an index
2001 if( DoStep(2) ) pChoice = TieChoice( Prompt, TempIndex, Choices );
2002 if( DoStep(3) ) TempStr = TranslateFromIndex( TempIndex, InternalChoices ); // To a string
2003 if( DoStep(3) ) choiceSetting.Write(TempStr); // Put into Prefs.
2004 return pChoice;
2005}
2006
2020 const TranslatableStrings & Choices,
2021 const std::vector<int> * pInternalChoices,
2022 int iNoMatchSelector)
2023{
2024 auto fn = [](int arg){ return wxString::Format( "%d", arg ); };
2025
2026 wxArrayStringEx InternalChoices;
2027 if ( pInternalChoices )
2028 InternalChoices =
2029 transform_container<wxArrayStringEx>(*pInternalChoices, fn);
2030 else
2031 for ( int ii = 0; ii < (int)Choices.size(); ++ii )
2032 InternalChoices.push_back( fn( ii ) );
2033
2034 const auto Default = Setting.GetDefault();
2035
2036 miNoMatchSelector = iNoMatchSelector;
2037
2038 long defaultIndex;
2039 if ( pInternalChoices )
2040 defaultIndex = make_iterator_range( *pInternalChoices ).index( Default );
2041 else
2042 defaultIndex = Default;
2043 if ( defaultIndex < 0 || defaultIndex >= (int)Choices.size() )
2044 defaultIndex = -1;
2045
2046 ChoiceSetting choiceSetting{
2047 Setting,
2048 {
2049 ByColumns,
2050 Choices,
2051 InternalChoices,
2052 },
2053 defaultIndex
2054 };
2055
2056 return ShuttleGuiBase::TieChoice(Prompt, choiceSetting);
2057}
2058
2059//------------------------------------------------------------------//
2060
2061// We're now into ShuttleGuiBase sizer and misc functions.
2062
2070{
2071 if( miIdSetByUser > 0)
2072 {
2074 miIdSetByUser = -1;
2075 return;
2076 }
2077 miId = miIdNext++;
2078}
2079
2081{
2082 if( miPropSetByUser >=0 )
2083 {
2085 miPropSetByUser =-1;
2086 return;
2087 }
2088 miProp = Default;
2089}
2090
2091
2093 wxWindow *pWind, wxWindow *pDlg )
2094{
2095 if ( step == 0 ) {
2096 // Do these steps before adding the window to the sizer
2097 if( item.mUseBestSize )
2098 pWind->SetMinSize( pWind->GetBestSize() );
2099 else if( item.mHasMinSize )
2100 pWind->SetMinSize( item.mMinSize );
2101
2102 if ( item.mWindowSize != wxSize{} )
2103 pWind->SetSize( item.mWindowSize );
2104 }
2105 else if ( step == 1) {
2106 // Apply certain other optional window attributes here
2107
2108 if ( item.mValidatorSetter )
2109 item.mValidatorSetter( pWind );
2110
2111 if ( !item.mToolTip.empty() )
2112 pWind->SetToolTip( item.mToolTip.Translation() );
2113
2114 if ( !item.mName.empty() ) {
2115 pWind->SetName( item.mName.Stripped().Translation() );
2116#ifndef __WXMAC__
2117 if (auto pButton = dynamic_cast< wxBitmapButton* >( pWind ))
2118 pButton->SetLabel( item.mName.Translation() );
2119#endif
2120 }
2121
2122 if ( !item.mNameSuffix.empty() )
2123 pWind->SetName(
2124 pWind->GetName() + " " + item.mNameSuffix.Translation() );
2125
2126 if (item.mFocused)
2127 pWind->SetFocus();
2128
2129 if (item.mDisabled)
2130 pWind->Enable( false );
2131
2132 for (auto &pair : item.mRootConnections)
2133 pWind->Connect( pair.first, pair.second, nullptr, pDlg );
2134 }
2135}
2136
2137
2138void ShuttleGuiBase::UpdateSizersCore(bool bPrepend, int Flags, bool prompt)
2139{
2140 if( mpWind && mpParent )
2141 {
2142 int useFlags = Flags;
2143
2144 if ( !prompt && mItem.mWindowPositionFlags )
2145 // override the given Flags
2146 useFlags = mItem.mWindowPositionFlags;
2147
2148 if (!prompt)
2149 ApplyItem( 0, mItem, mpWind, mpDlg );
2150
2151 if( mpSizer){
2152 if( bPrepend )
2153 {
2154 mpSizer->Prepend(mpWind, miProp, useFlags, miBorder);
2155 }
2156 else
2157 {
2158 mpSizer->Add(mpWind, miProp, useFlags, miBorder);
2159 }
2160 }
2161
2162 if (!prompt) {
2163 ApplyItem( 1, mItem, mpWind, mpDlg );
2164 // Reset to defaults
2165 mItem = {};
2166 }
2167 }
2168
2169 if( mpSubSizer && mpSizer )
2170 {
2171 // When adding sizers into sizers, don't add a border.
2172 // unless it's a static box sizer.
2173 wxSizer *const pSubSizer = mpSubSizer.get();
2174 if (wxDynamicCast(pSubSizer, wxStaticBoxSizer))
2175 {
2176 mpSizer->Add( mpSubSizer.release(), miSizerProp, Flags , miBorder);
2177 }
2178 else
2179 {
2180 mpSizer->Add( mpSubSizer.release(), miSizerProp, Flags ,0);//miBorder);
2181 }
2182 mpSizer = pSubSizer;
2183 PushSizer();
2184 }
2185
2186 mpWind = NULL;
2187 miProp = 0;
2188 miSizerProp =0;
2189}
2190
2191// Sizer is added into parent sizer, and will expand/shrink.
2193{ UpdateSizersCore( false, wxEXPAND | wxALL );}
2194
2195// Sizer is added into parent sizer, centred
2197{ UpdateSizersCore( false, wxALIGN_CENTRE | wxALL );}
2198
2199// Sizer is added into parent sizer, and will expand/shrink.
2200// added to start of sizer list.
2202{ UpdateSizersCore( true, wxEXPAND | wxALL );}
2203
2205{
2206 mSizerDepth--;
2207 wxASSERT( mSizerDepth >=0 );
2209}
2210
2212{
2213 mSizerDepth++;
2214 wxASSERT( mSizerDepth < nMaxNestedSizers );
2216}
2217
2219{
2220 if( mItem.miStyle )
2221 style = mItem.miStyle;
2222 mItem.miStyle = 0;
2223 return style;
2224}
2225
2226// A rarely used helper function that sets a pointer
2227// ONLY if the value it is to be set to is non NULL.
2228void SetIfCreated( wxChoice * &Var, wxChoice * Val )
2229{
2230 if( Val != NULL )
2231 Var = Val;
2232};
2233void SetIfCreated( wxTextCtrl * &Var, wxTextCtrl * Val )
2234{
2235 if( Val != NULL )
2236 Var = Val;
2237};
2238void SetIfCreated( wxStaticText *&Var, wxStaticText * Val )
2239{
2240 if( Val != NULL )
2241 Var = Val;
2242};
2243
2245 wxWindow * pParent, teShuttleMode ShuttleMode, bool vertical, wxSize minSize)
2246 : ShuttleGuiBase( pParent, ShuttleMode, vertical, minSize )
2247{
2248 if( ShuttleMode == eIsCreatingFromPrefs )
2249 {
2251 Init( vertical, minSize ); // Wasn't fully done in base constructor because it is only done when eIsCreating is set.
2252 }
2253 else if( ShuttleMode == eIsSavingToPrefs )
2254 {
2256 }
2257 else
2258 {
2259 return;
2260 }
2261
2262 mpShuttle = std::make_unique<ShuttlePrefs>();
2263 // In this case the client is the GUI, so if creating we do want to
2264 // store in the client.
2265 mpShuttle->mbStoreInClient = (mShuttleMode == eIsCreating );
2266};
2267
2269{
2270}
2271
2272// Now we have Audacity specific shuttle functions.
2274{
2275 miIdSetByUser = id;
2276 return *this;
2277}
2278
2280 mpbOptionalFlag = &bVar;
2281 return *this;
2282};
2283
2284
2285std::unique_ptr<wxSizer> CreateStdButtonSizer(wxWindow *parent, long buttons, wxWindow *extra)
2286{
2287 wxASSERT(parent != NULL); // To justify safenew
2288
2289 int margin;
2290 {
2291#if defined(__WXMAC__)
2292 margin = 12;
2293#elif defined(__WXGTK20__)
2294 margin = 12;
2295#elif defined(__WXMSW__)
2296 wxButton b(parent, 0, wxEmptyString);
2297 margin = b.ConvertDialogToPixels(wxSize(2, 0)).x;
2298#else
2299 wxButton b(parent, 0, wxEmptyString);
2300 margin = b->ConvertDialogToPixels(wxSize(4, 0)).x;
2301#endif
2302 }
2303
2304 wxButton *b = NULL;
2305 auto bs = std::make_unique<wxStdDialogButtonSizer>();
2306
2307 const auto makeButton =
2308 [parent]( wxWindowID id, const wxString label = {} ) {
2309 auto result = safenew wxButton( parent, id, label );
2310 result->SetName( result->GetLabel() );
2311 return result;
2312 };
2313
2314 if( buttons & eOkButton )
2315 {
2316 b = makeButton( wxID_OK );
2317 b->SetDefault();
2318 bs->AddButton( b );
2319 }
2320
2321 if( buttons & eCancelButton )
2322 {
2323 bs->AddButton( makeButton( wxID_CANCEL ) );
2324 }
2325
2326 if( buttons & eYesButton )
2327 {
2328 b = makeButton( wxID_YES );
2329 b->SetDefault();
2330 bs->AddButton( b );
2331 }
2332
2333 if( buttons & eNoButton )
2334 {
2335 bs->AddButton( makeButton( wxID_NO ) );
2336 }
2337
2338 if( buttons & eApplyButton )
2339 {
2340 b = makeButton( wxID_APPLY );
2341 b->SetDefault();
2342 bs->AddButton( b );
2343 }
2344
2345 if( buttons & eCloseButton )
2346 {
2347 bs->AddButton( makeButton( wxID_CANCEL, XO("&Close").Translation() ) );
2348 }
2349
2350#if defined(__WXMSW__)
2351 // See below for explanation
2352 if( buttons & eHelpButton )
2353 {
2354 // Replace standard Help button with smaller icon button.
2355 // bs->AddButton(safenew wxButton(parent, wxID_HELP));
2356 b = safenew wxBitmapButton(parent, wxID_HELP, theTheme.Bitmap( bmpHelpIcon ));
2357 b->SetToolTip( XO("Help").Translation() );
2358 b->SetLabel(XO("Help").Translation()); // for screen readers
2359 b->SetName( b->GetLabel() );
2360 bs->AddButton( b );
2361 }
2362#endif
2363
2364 if (buttons & ePreviewButton)
2365 {
2366 bs->Add( makeButton( ePreviewID, XO("&Preview").Translation() ),
2367 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin);
2368 }
2369 if (buttons & ePreviewDryButton)
2370 {
2371 bs->Add( makeButton( ePreviewDryID, XO("Dry Previe&w").Translation() ),
2372 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin);
2373 bs->Add( 20, 0 );
2374 }
2375
2376 if( buttons & eSettingsButton )
2377 {
2378 bs->Add( makeButton( eSettingsID, XO("&Settings").Translation() ),
2379 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin);
2380 bs->Add( 20, 0 );
2381 }
2382
2383 if( extra )
2384 {
2385 bs->Add( extra, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin );
2386 bs->Add( 40, 0 );
2387 }
2388
2389 bs->AddStretchSpacer();
2390 bs->Realize();
2391
2392 size_t lastLastSpacer = 0;
2393 size_t lastSpacer = 0;
2394 wxSizerItemList & list = bs->GetChildren();
2395 for( size_t i = 0, cnt = list.size(); i < cnt; i++ )
2396 {
2397 if( list[i]->IsSpacer() )
2398 {
2399 lastSpacer = i;
2400 }
2401 else
2402 {
2403 lastLastSpacer = lastSpacer;
2404 }
2405 }
2406
2407 // Add any buttons that need to cuddle up to the right hand cluster
2408 if( buttons & eDebugButton )
2409 {
2410 b = makeButton( eDebugID, XO("Debu&g").Translation() );
2411 bs->Insert( ++lastLastSpacer, b, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin );
2412 }
2413
2414#if !defined(__WXMSW__)
2415 // Bug #2432: Couldn't find GTK guidelines, but Mac HIGs state:
2416 //
2417 // View style Help button position
2418 // Dialog with dismissal buttons (like OK and Cancel). Lower-left corner, vertically aligned with the dismissal buttons.
2419 // Dialog without dismissal buttons. Lower-left or lower-right corner.
2420 // Preference window or pane. Lower-left or lower-right corner.
2421 //
2422 // So, we're gonna cheat a little and use the lower-right corner.
2423 if( buttons & eHelpButton )
2424 {
2425 // Replace standard Help button with smaller icon button.
2426 // bs->AddButton(safenew wxButton(parent, wxID_HELP));
2427 b = safenew wxBitmapButton(parent, wxID_HELP, theTheme.Bitmap( bmpHelpIcon ));
2428 b->SetToolTip( XO("Help").Translation() );
2429 b->SetLabel(XO("Help").Translation()); // for screen readers
2430 b->SetName( b->GetLabel() );
2431 bs->Add( b, 0, wxALIGN_CENTER );
2432 }
2433#endif
2434
2435
2436 auto s = std::make_unique<wxBoxSizer>( wxVERTICAL );
2437 s->Add( bs.release(), 1, wxEXPAND | wxALL, 7 );
2438 s->Add( 0, 3 ); // a little extra space
2439
2440 return std::unique_ptr<wxSizer>{ s.release() };
2441}
2442
2443void ShuttleGui::AddStandardButtons(long buttons, wxWindow *extra)
2444{
2445 if( mShuttleMode != eIsCreating )
2446 return;
2447
2448 StartVerticalLay( false );
2449
2450 miSizerProp = false;
2451 mpSubSizer = CreateStdButtonSizer( mpParent, buttons, extra );
2452 UpdateSizers();
2453 PopSizer();
2454
2456}
2457
2458wxSizerItem * ShuttleGui::AddSpace( int width, int height, int prop )
2459{
2460 if( mShuttleMode != eIsCreating )
2461 return NULL;
2462
2463// SetProportions(0);
2464 // return mpSizer->Add( width, height, miProp);
2465
2466 return mpSizer->Add( width, height, prop );
2467}
2468
2469void ShuttleGui::SetMinSize( wxWindow *window, const TranslatableStrings & items )
2470{
2471 SetMinSize( window,
2472 transform_container<wxArrayStringEx>(
2473 items, std::mem_fn( &TranslatableString::StrippedTranslation ) ) );
2474}
2475
2476void ShuttleGui::SetMinSize( wxWindow *window, const wxArrayStringEx & items )
2477{
2478 int maxw = 0;
2479
2480 for( size_t i = 0; i < items.size(); i++ )
2481 {
2482 int x;
2483 int y;
2484
2485 window->GetTextExtent(items[i], &x, &y );
2486 if( x > maxw )
2487 {
2488 maxw = x;
2489 }
2490 }
2491
2492 // Would be nice to know the sizes of the button and borders, but this is
2493 // the best we can do for now.
2494#if defined(__WXMAC__)
2495 maxw += 50;
2496#elif defined(__WXMSW__)
2497 maxw += 50;
2498#elif defined(__WXGTK__)
2499 maxw += 50;
2500#else
2501 maxw += 50;
2502#endif
2503
2504 window->SetMinSize( { maxw, -1 } );
2505}
2506
2507/*
2508void ShuttleGui::SetMinSize( wxWindow *window, const std::vector<int> & items )
2509{
2510 wxArrayStringEx strs;
2511
2512 for( size_t i = 0; i < items.size(); i++ )
2513 {
2514 strs.Add( wxString::Format( wxT("%d"), items[i] ) );
2515 }
2516
2517 SetMinSize( window, strs );
2518}
2519*/
2520
2522 const EnumValueSymbol strings[], size_t nStrings)
2523{
2524 return transform_range<TranslatableStrings>(
2525 strings, strings + nStrings,
2526 std::mem_fn( &EnumValueSymbol::Msgid )
2527 );
2528}
2529
2530TranslatableStrings Msgids( const std::vector<EnumValueSymbol> &strings )
2531{
2532 return Msgids( strings.data(), strings.size() );
2533}
wxT("CloseDown"))
END_EVENT_TABLE()
int min(int a, int b)
XO("Cut/Copy/Paste")
#define safenew
Definition: MemoryX.h:10
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:448
ByColumns_t ByColumns
Definition: Prefs.cpp:489
std::unique_ptr< wxSizer > CreateStdButtonSizer(wxWindow *parent, long buttons, wxWindow *extra)
TranslatableStrings Msgids(const EnumValueSymbol strings[], size_t nStrings)
Convenience function often useful when adding choice controls.
void SetIfCreated(wxChoice *&Var, wxChoice *Val)
teShuttleMode
Definition: ShuttleGui.h:36
@ eIsSettingToDialog
Definition: ShuttleGui.h:39
@ eIsCreating
Definition: ShuttleGui.h:37
@ eIsCreatingFromPrefs
Definition: ShuttleGui.h:46
@ eIsSavingToPrefs
Definition: ShuttleGui.h:47
@ eIsGettingFromDialog
Definition: ShuttleGui.h:38
@ eIsGettingMetadata
Definition: ShuttleGui.h:40
const int nMaxNestedSizers
Definition: ShuttleGui.h:33
@ ePreviewID
Definition: ShuttleGui.h:616
@ eDebugID
Definition: ShuttleGui.h:618
@ eSettingsID
Definition: ShuttleGui.h:619
@ ePreviewDryID
Definition: ShuttleGui.h:620
wxWindow wxNotebookPage
Definition: ShuttleGui.h:60
@ eOkButton
Definition: ShuttleGui.h:599
@ eApplyButton
Definition: ShuttleGui.h:608
@ eYesButton
Definition: ShuttleGui.h:601
@ eCancelButton
Definition: ShuttleGui.h:600
@ ePreviewDryButton
Definition: ShuttleGui.h:607
@ eCloseButton
Definition: ShuttleGui.h:609
@ eHelpButton
Definition: ShuttleGui.h:603
@ eNoButton
Definition: ShuttleGui.h:602
@ ePreviewButton
Definition: ShuttleGui.h:604
@ eDebugButton
Definition: ShuttleGui.h:605
@ eSettingsButton
Definition: ShuttleGui.h:606
TranslatableString label
Definition: TagsEditor.cpp:165
THEME_API Theme theTheme
Definition: Theme.cpp:82
std::vector< TranslatableString > TranslatableStrings
int id
static const auto fn
This specialization of Setting for bool adds a Toggle method to negate the saved value.
Definition: Prefs.h:344
bool Write(const wxString &value)
Definition: Prefs.cpp:405
const wxString & Key() const
Definition: Prefs.h:437
wxString Read() const
Definition: Prefs.cpp:369
const EnumValueSymbols & GetSymbols() const
Definition: Prefs.h:439
const EnumValueSymbol & Default() const
Definition: Prefs.cpp:361
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
const wxString & Internal() const
const TranslatableString & Msgid() const
const wxString Translation() const
Specialization of Setting for double.
Definition: Prefs.h:361
Specialization of Setting for int.
Definition: Prefs.h:354
An InvisiblePanel is a panel which does not repaint its own background.
InvisiblePanel(wxWindow *parent, wxWindowID id=-1, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL)
void OnPaint(wxPaintEvent &event)
void OnErase(wxEraseEvent &)
const SettingPath & GetPath() const
Definition: Prefs.h:88
Definition: Prefs.h:178
const T & GetDefault() const
Definition: Prefs.h:197
Base class for shuttling data to and from a GUI.
Definition: ShuttleGui.h:240
wxSimplebook * StartSimplebook()
void EndVerticalLay()
wxStaticText * AddPrompt(const TranslatableString &Prompt, int wrapWidth=0)
Right aligned text string.
Definition: ShuttleGui.cpp:237
wxStaticBox * StartStatic(const TranslatableString &Str, int iProp=0)
Definition: ShuttleGui.cpp:898
wxTextCtrl * DoTieNumericTextBox(const TranslatableString &Prompt, WrappedType &WrappedRef, const int nChars, bool acceptEnter=false)
int GetBorder() const noexcept
Definition: ShuttleGui.cpp:195
wxNotebookPage * StartNotebookPage(const TranslatableString &Name)
long GetStyle(long Style)
wxCheckBox * AddCheckBoxOnRight(const TranslatableString &Prompt, bool Selected)
Definition: ShuttleGui.cpp:344
wxWindow *const mpDlg
Definition: ShuttleGui.h:529
void EndMultiColumn()
wxComboBox * AddCombo(const TranslatableString &Prompt, const wxString &Selected, const wxArrayStringEx &choices)
Definition: ShuttleGui.cpp:518
virtual wxTextCtrl * TieIntegerTextBox(const TranslatableString &Prompt, const IntSetting &Setting, const int nChars)
ShuttleGuiBase(wxWindow *pParent, teShuttleMode ShuttleMode, bool vertical, wxSize minSize)
Definition: ShuttleGui.cpp:127
void DoDataShuttle(const wxString &Name, WrappedType &WrappedRef)
void StartRadioButtonGroup(ChoiceSetting &Setting)
Call this before any TieRadioButton calls.
wxPanel * StartPanel(int iStyle=0)
Definition: ShuttleGui.cpp:995
void EndInvisiblePanel()
wxNotebook * StartNotebook()
wxString mRadioValueString
The index of this radio item. -1 for none.
Definition: ShuttleGui.h:577
wxSlider * TieVSlider(const TranslatableString &Prompt, float &pos, const float fMin, const float fMax)
wxCheckBox * AddCheckBox(const TranslatableString &Prompt, bool Selected)
Definition: ShuttleGui.cpp:310
wxChoice * TieChoice(const TranslatableString &Prompt, TranslatableString &Selected, const TranslatableStrings &choices)
wxPanel * StartInvisiblePanel(int border=0)
wxWindow * GetParent()
Definition: ShuttleGui.h:495
wxCheckBox * TieCheckBox(const TranslatableString &Prompt, bool &Var)
DialogDefinition::Item mItem
Definition: ShuttleGui.h:582
std::unique_ptr< ShuttlePrefs > mpShuttle
Definition: ShuttleGui.h:532
void UpdateSizersC()
void UpdateSizersAtStart()
void EndNotebookPage()
wxTextCtrl * AddTextBox(const TranslatableString &Caption, const wxString &Value, const int nChars)
Definition: ShuttleGui.cpp:639
wxTextCtrl * AddNumericTextBox(const TranslatableString &Caption, const wxString &Value, const int nChars, bool acceptEnter=false)
Definition: ShuttleGui.cpp:675
static void ApplyItem(int step, const DialogDefinition::Item &item, wxWindow *pWind, wxWindow *pDlg)
void AddUnits(const TranslatableString &Prompt, int wrapWidth=0)
Left aligned text string.
Definition: ShuttleGui.cpp:264
int TranslateToIndex(const wxString &Value, const wxArrayStringEx &Choices)
String-to-Index.
virtual wxChoice * TieNumberAsChoice(const TranslatableString &Prompt, IntSetting &Setting, const TranslatableStrings &Choices, const std::vector< int > *pInternalChoices=nullptr, int iNoMatchSelector=0)
wxSpinCtrl * AddSpinCtrl(const TranslatableString &Prompt, int Value, int Max, int Min)
Definition: ShuttleGui.cpp:617
void EndSimplebook()
void SetStretchyRow(int i)
Used to modify an already placed FlexGridSizer to make a row stretchy.
Definition: ShuttleGui.cpp:211
void StartVerticalLay(int iProp=1)
std::vector< EnumValueSymbol > mRadioSymbols
Definition: ShuttleGui.h:573
ReadOnlyText * AddReadOnlyText(const TranslatableString &Caption, const wxString &Value)
Definition: ShuttleGui.cpp:497
wxButton * AddButton(const TranslatableString &Text, int PositionFlags=wxALIGN_CENTRE, bool setDefault=false)
Definition: ShuttleGui.cpp:361
void HandleOptionality(const TranslatableString &Prompt)
Definition: ShuttleGui.cpp:223
wxSlider * DoTieSlider(const TranslatableString &Prompt, WrappedType &WrappedRef, const int max, const int min=0)
virtual ~ShuttleGuiBase()
Definition: ShuttleGui.cpp:138
wxBitmapButton * AddBitmapButton(const wxBitmap &Bitmap, int PositionFlags=wxALIGN_CENTRE, bool setDefault=false)
Definition: ShuttleGui.cpp:380
wxListBox * AddListBox(const wxArrayStringEx &choices)
Definition: ShuttleGui.cpp:758
void EndHorizontalLay()
wxTextCtrl * AddTextWindow(const wxString &Value)
Multiline text box that grows.
Definition: ShuttleGui.cpp:717
void StartWrapLay(int PositionFlags=wxEXPAND, int iProp=0)
void Init(bool vertical, wxSize minSize)
Definition: ShuttleGui.cpp:142
wxSizer * mpSizer
Definition: ShuttleGui.h:553
void AddIcon(wxBitmap *pBmp)
Definition: ShuttleGui.cpp:873
wxTreeCtrl * AddTree()
Definition: ShuttleGui.cpp:859
wxCheckBox * DoTieCheckBoxOnRight(const TranslatableString &Prompt, WrappedType &WrappedRef)
wxCheckBox * TieCheckBoxOnRight(const TranslatableString &Prompt, bool &Var)
void EndRadioButtonGroup()
wxScrolledWindow * StartScroller(int iStyle=0)
Definition: ShuttleGui.cpp:943
wxRadioButton * AddRadioButton(const TranslatableString &Prompt, int selector=0, int initValue=0)
Definition: ShuttleGui.cpp:569
wxString TranslateFromIndex(const int nIn, const wxArrayStringEx &Choices)
Index-to-String.
wxGrid * AddGrid()
Definition: ShuttleGui.cpp:773
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
wxTextCtrl * TieNumericTextBox(const TranslatableString &Prompt, int &Value, const int nChars=0, bool acceptEnter=false)
std::optional< WrappedType > mRadioValue
The setting controlled by a group.
Definition: ShuttleGui.h:575
wxSpinCtrl * TieSpinCtrl(const TranslatableString &Prompt, int &Value, const int max, const int min=0)
bool DoStep(int iStep)
wxString mRadioSettingName
Definition: ShuttleGui.h:574
ShuttleGuiBase & Prop(int iProp)
Definition: ShuttleGui.cpp:887
wxWindow * AddWindow(wxWindow *pWindow, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:300
wxCheckBox * DoTieCheckBox(const TranslatableString &Prompt, WrappedType &WrappedRef)
bool * mpbOptionalFlag
Definition: ShuttleGui.h:550
wxWindow * mpParent
Definition: ShuttleGui.h:554
wxRadioButton * AddRadioButtonToGroup(const TranslatableString &Prompt, int selector=1, int initValue=0)
Definition: ShuttleGui.cpp:575
wxSpinCtrl * DoTieSpinCtrl(const TranslatableString &Prompt, WrappedType &WrappedRef, const int max, const int min=0)
wxSlider * AddSlider(const TranslatableString &Prompt, int pos, int Max, int Min=0)
Definition: ShuttleGui.cpp:590
void SetStretchyCol(int i)
Used to modify an already placed FlexGridSizer to make a column stretchy.
Definition: ShuttleGui.cpp:201
wxTextCtrl * TieTextBox(const TranslatableString &Caption, wxString &Value, const int nChars=0)
int mRadioCount
The wrapped value associated with the active radio button.
Definition: ShuttleGui.h:576
void UpdateSizersCore(bool bPrepend, int Flags, bool prompt=false)
void EndScroller()
Definition: ShuttleGui.cpp:976
wxChoice * AddChoice(const TranslatableString &Prompt, const TranslatableStrings &choices, int Selected=-1)
Definition: ShuttleGui.cpp:399
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
wxListCtrl * AddListControlReportMode(std::initializer_list< const ListControlColumn > columns={}, long listControlStyles=0)
Definition: ShuttleGui.cpp:807
wxSizer * pSizerStack[nMaxNestedSizers]
Definition: ShuttleGui.h:530
void AddConstTextBox(const TranslatableString &Caption, const TranslatableString &Value)
Single line text box of fixed size.
Definition: ShuttleGui.cpp:738
wxTextCtrl * DoTieTextBox(const TranslatableString &Prompt, WrappedType &WrappedRef, const int nChars)
wxListCtrl * AddListControl(std::initializer_list< const ListControlColumn > columns={}, long listControlStyles=0)
Definition: ShuttleGui.cpp:787
teShuttleMode mShuttleMode
Used in choices to determine which item to use on no match.
Definition: ShuttleGui.h:536
void AddFixedText(const TranslatableString &Str, bool bCenter=false, int wrapWidth=0)
Definition: ShuttleGui.cpp:441
void SetProportions(int Default)
wxSlider * TieSlider(const TranslatableString &Prompt, int &pos, const int max, const int min=0)
wxStaticText * AddVariableText(const TranslatableString &Str, bool bCenter=false, int PositionFlags=0, int wrapWidth=0)
Definition: ShuttleGui.cpp:464
void AddTitle(const TranslatableString &Prompt, int wrapWidth=0)
Centred text string.
Definition: ShuttleGui.cpp:282
wxRadioButton * TieRadioButton()
This function must be within a StartRadioButtonGroup - EndRadioButtonGroup pair.
wxWindow * mpWind
Definition: ShuttleGui.h:555
void DoInsertListColumns(wxListCtrl *pListCtrl, long listControlStyles, std::initializer_list< const ListControlColumn > columns)
Definition: ShuttleGui.cpp:828
wxRadioButton * DoAddRadioButton(const TranslatableString &Prompt, int style, int selector, int initValue)
Unwrapped string value.
Definition: ShuttleGui.cpp:549
int miNoMatchSelector
Definition: ShuttleGui.h:534
std::unique_ptr< wxSizer > mpSubSizer
Definition: ShuttleGui.h:552
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:630
ShuttleGui & Id(int id)
wxSizerItem * AddSpace(int width, int height, int prop=0)
ShuttleGui & Optional(bool &bVar)
~ShuttleGui(void)
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxWindow *extra=NULL)
ShuttleGui(wxWindow *pParent, teShuttleMode ShuttleMode, bool vertical=true, wxSize minSize={ 250, 100 })
static void SetMinSize(wxWindow *window, const TranslatableStrings &items)
Specialization of Setting for strings.
Definition: Prefs.h:368
wxBitmap & Bitmap(int iIndex)
Holds a msgid for the translation catalog; may also bind format arguments.
wxString StrippedTranslation() const
wxString Translation() const
TranslatableString Stripped(unsigned options=MenuCodes) const
non-mutating, constructs another TranslatableString object
A Validator is an object which checks whether a wxVariant satisfies a certain criterion....
Definition: Validators.h:53
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
Used in type conversions, this wrapper for ints, strings, doubles and enums provides conversions betw...
Definition: WrappedType.h:28
bool ReadAsBool()
bool IsString()
Definition: WrappedType.cpp:34
void WriteToAsInt(const int InInt)
int ReadAsInt()
Definition: WrappedType.cpp:67
void WriteToAsBool(const bool InBool)
void WriteToAsString(const wxString &InStr)
wxString ReadAsString()
Definition: WrappedType.cpp:41
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
void SetFocus() override
Definition: ShuttleGui.cpp:582
void SetFocus(const WindowPlacement &focus)
Set the window that accepts keyboard input.
Definition: BasicUI.h:382
NumericFormatSymbol Default(const NumericConverterType &type)
Returns the default format for the type or empty symbol, if no default symbol is registered.
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
std::function< void(wxWindow *) > mValidatorSetter
Definition: ShuttleGui.h:214
std::vector< std::pair< wxEventType, wxObjectEventFunction > > mRootConnections
Definition: ShuttleGui.h:219
TranslatableString mToolTip
Definition: ShuttleGui.h:215
TranslatableString mName
Definition: ShuttleGui.h:216
TranslatableString mNameSuffix
Definition: ShuttleGui.h:217