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