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 | wxSUNKEN_BORDER ));
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 GetStyle( wxSUNKEN_BORDER ) );
972 pScroller->SetScrollRate( 20,20 );
973
974 // This fools NVDA into not saying "Panel" when the dialog gets focus
975 pScroller->SetName(wxT("\a"));
976 pScroller->SetLabel(wxT("\a"));
977
978 SetProportions( 1 );
979 if( iStyle==2 )
980 {
982 }
983 else
984 {
985 // mpWind->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR));
986 UpdateSizers(); // adds window in to current sizer.
987 }
988
989 // create a sizer within the window...
990 mpParent = pScroller;
991 pScroller->SetSizer(mpSizer = safenew wxBoxSizer(wxVERTICAL));
992 PushSizer();
993 return pScroller;
994}
995
997{
999 return;
1000 wxSize ScrollSize = mpSizer->GetMinSize();
1001 int yMin = ScrollSize.y+4;
1002 int xMin = ScrollSize.x+4;
1003 if( yMin > 400)
1004 {
1005 yMin = 400;
1006 xMin+=50;// extra space for vertical scrollbar.
1007 }
1008
1009 mpParent->SetMinSize( wxSize(xMin, yMin) );
1010
1011 PopSizer();
1012 mpParent = mpParent->GetParent();
1013}
1014
1015wxPanel * ShuttleGuiBase::StartPanel(int iStyle)
1016{
1017 UseUpId();
1018 if( mShuttleMode != eIsCreating )
1019 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxPanel);
1020 wxPanel * pPanel;
1021 mpWind = pPanel = safenew wxPanelWrapper( GetParent(), miId, wxDefaultPosition, wxDefaultSize,
1022 GetStyle( wxNO_BORDER ));
1023
1024 if( iStyle != 0 )
1025 {
1026 mpWind->SetBackgroundColour(
1027 iStyle==1
1028 ? wxColour( 190,200,230) :
1029 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)
1030 );
1031 }
1032 SetProportions(0);
1033 miBorder=2;
1034 UpdateSizers(); // adds window in to current sizer.
1035
1036 // create a sizer within the window...
1037 mpParent = pPanel;
1038 pPanel->SetSizer(mpSizer = safenew wxBoxSizer(wxVERTICAL));
1039 PushSizer();
1040 return pPanel;
1041}
1042
1044{
1045 if( mShuttleMode != eIsCreating )
1046 return;
1047 PopSizer();
1048 mpParent = mpParent->GetParent();
1049}
1050
1052{
1053 UseUpId();
1054 if( mShuttleMode != eIsCreating )
1055 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxNotebook);
1056 wxNotebook * pNotebook;
1057 mpWind = pNotebook = safenew wxNotebook(GetParent(),
1058 miId, wxDefaultPosition, wxDefaultSize, GetStyle( 0 ));
1059 SetProportions( 1 );
1060 UpdateSizers();
1061 mpParent = pNotebook;
1062 return pNotebook;
1063}
1064
1066{
1067 //PopSizer();
1068 mpParent = mpParent->GetParent();
1069}
1070
1071
1073{
1074 UseUpId();
1075 if( mShuttleMode != eIsCreating )
1076 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxSimplebook);
1077 wxSimplebook * pNotebook;
1078 mpWind = pNotebook = safenew wxSimplebook(GetParent(),
1079 miId, wxDefaultPosition, wxDefaultSize, GetStyle( 0 ));
1080 SetProportions( 1 );
1081 UpdateSizers();
1082 mpParent = pNotebook;
1083 return pNotebook;
1084}
1085
1087{
1088 //PopSizer();
1089 mpParent = mpParent->GetParent();
1090}
1091
1092
1094 const TranslatableString & Name )
1095{
1096 if( mShuttleMode != eIsCreating )
1097 return NULL;
1098// return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wx);
1099 auto pNotebook = static_cast< wxBookCtrlBase* >( mpParent );
1101 const auto translated = Name.Translation();
1102 pPage->SetName(translated);
1103
1104 pNotebook->AddPage(
1105 pPage,
1106 translated);
1107
1108 SetProportions( 1 );
1109 mpParent = pPage;
1110 pPage->SetSizer(mpSizer = safenew wxBoxSizer(wxVERTICAL));
1111 PushSizer();
1112 // UpdateSizers();
1113 return pPage;
1114}
1115
1117{
1118 if( mShuttleMode != eIsCreating )
1119 return;
1120 PopSizer();
1121 mpParent = mpParent->GetParent();
1122}
1123
1124// Doxygen description is at the start of the file
1125// this is a wxPanel with erase background disabled.
1126class InvisiblePanel final : public wxPanelWrapper
1127{
1128public:
1130 wxWindow* parent,
1131 wxWindowID id = -1,
1132 const wxPoint& pos = wxDefaultPosition,
1133 const wxSize& size = wxDefaultSize,
1134 long style = wxTAB_TRAVERSAL ) :
1135 wxPanelWrapper( parent, id, pos, size, style )
1136 {
1137 };
1139 void OnPaint( wxPaintEvent &event );
1140 void OnErase(wxEraseEvent &/*evt*/){;};
1141 DECLARE_EVENT_TABLE()
1142};
1143
1144
1145BEGIN_EVENT_TABLE(InvisiblePanel, wxPanelWrapper)
1146// EVT_PAINT(InvisiblePanel::OnPaint)
1147 EVT_ERASE_BACKGROUND( InvisiblePanel::OnErase)
1149
1150void InvisiblePanel::OnPaint( wxPaintEvent & WXUNUSED(event))
1151{
1152 // Don't repaint my background.
1153 wxPaintDC dc(this);
1154 // event.Skip(); // swallow the paint event.
1155}
1156
1158{
1159 UseUpId();
1160 if( mShuttleMode != eIsCreating )
1161 return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxPanel);
1162 wxPanel * pPanel;
1163 mpWind = pPanel = safenew wxPanelWrapper(GetParent(), miId, wxDefaultPosition, wxDefaultSize,
1164 wxNO_BORDER);
1165
1166 mpWind->SetBackgroundColour(
1167 wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)
1168 );
1169 SetProportions( 1 );
1170 miBorder = border;
1171 UpdateSizers(); // adds window in to current sizer.
1172
1173 // create a sizer within the window...
1174 mpParent = pPanel;
1175 pPanel->SetSizer(mpSizer = safenew wxBoxSizer(wxVERTICAL));
1176 PushSizer();
1177 return pPanel;
1178}
1179
1181{
1182 EndPanel();
1183}
1184
1185
1192void ShuttleGuiBase::StartHorizontalLay( int PositionFlags, int iProp)
1193{
1194 if( mShuttleMode != eIsCreating )
1195 return;
1196 miSizerProp=iProp;
1197 mpSubSizer = std::make_unique<wxBoxSizer>( wxHORIZONTAL );
1198 // PRL: wxALL has no effect because UpdateSizersCore ignores border
1199 UpdateSizersCore( false, PositionFlags | wxALL );
1200}
1201
1203{
1204 if( mShuttleMode != eIsCreating )
1205 return;
1206 PopSizer();
1207}
1208
1210{
1211 if( mShuttleMode != eIsCreating )
1212 return;
1213 miSizerProp=iProp;
1214 mpSubSizer = std::make_unique<wxBoxSizer>( wxVERTICAL );
1215 UpdateSizers();
1216}
1217
1218void ShuttleGuiBase::StartVerticalLay(int PositionFlags, int iProp)
1219{
1220 if( mShuttleMode != eIsCreating )
1221 return;
1222 miSizerProp=iProp;
1223 mpSubSizer = std::make_unique<wxBoxSizer>( wxVERTICAL );
1224 // PRL: wxALL has no effect because UpdateSizersCore ignores border
1225 UpdateSizersCore( false, PositionFlags | wxALL );
1226}
1227
1229{
1230 if( mShuttleMode != eIsCreating )
1231 return;
1232 PopSizer();
1233}
1234
1235void ShuttleGuiBase::StartWrapLay(int PositionFlags, int iProp)
1236{
1238 return;
1239
1240 miSizerProp = iProp;
1241 mpSubSizer = std::make_unique<wxWrapSizer>(wxHORIZONTAL, 0);
1242
1243 UpdateSizersCore(false, PositionFlags | wxALL);
1244}
1245
1247{
1249 return;
1250
1251 PopSizer();
1252}
1253
1254void ShuttleGuiBase::StartMultiColumn(int nCols, int PositionFlags)
1255{
1256 if( mShuttleMode != eIsCreating )
1257 return;
1258 mpSubSizer = std::make_unique<wxFlexGridSizer>( nCols );
1259 // PRL: wxALL has no effect because UpdateSizersCore ignores border
1260 UpdateSizersCore( false, PositionFlags | wxALL );
1261}
1262
1264{
1265 if( mShuttleMode != eIsCreating )
1266 return;
1267 PopSizer();
1268}
1269
1272void ShuttleGuiBase::DoDataShuttle( const wxString &Name, WrappedType & WrappedRef )
1273{
1274 wxASSERT( mpShuttle );
1275 mpShuttle->TransferWrappedType( Name, WrappedRef );
1276}
1277
1278//-----------------------------------------------------------------------//
1279
1280// We now have a group of tie functions which are generic in the type
1281// they bind to (i.e. WrappedType).
1282// The type specific versions are much shorter and are later
1283// in this file.
1284wxCheckBox * ShuttleGuiBase::DoTieCheckBox(const TranslatableString &Prompt, WrappedType & WrappedRef)
1285{
1286 HandleOptionality( Prompt );
1287 // The Add function does a UseUpId(), so don't do it here in that case.
1288 if( mShuttleMode == eIsCreating )
1289 return AddCheckBox( Prompt, WrappedRef.ReadAsString() == wxT("true"));
1290
1291 UseUpId();
1292
1293 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1294 wxCheckBox * pCheckBox = wxDynamicCast(pWnd, wxCheckBox);
1295
1296 switch( mShuttleMode )
1297 {
1298 // IF setting internal storage from the controls.
1299 case eIsGettingMetadata:
1300 break;
1302 {
1303 wxASSERT( pCheckBox );
1304 WrappedRef.WriteToAsBool( pCheckBox->GetValue() );
1305 }
1306 break;
1307 case eIsSettingToDialog:
1308 {
1309 wxASSERT( pCheckBox );
1310 pCheckBox->SetValue( WrappedRef.ReadAsBool() );
1311 }
1312 break;
1313 default:
1314 wxASSERT( false );
1315 break;
1316 }
1317 return pCheckBox;
1318}
1319
1321{
1322 HandleOptionality( Prompt );
1323 // The Add function does a UseUpId(), so don't do it here in that case.
1324 if( mShuttleMode == eIsCreating )
1325 return AddCheckBoxOnRight( Prompt, WrappedRef.ReadAsString() == wxT("true"));
1326
1327 UseUpId();
1328
1329 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1330 wxCheckBox * pCheckBox = wxDynamicCast(pWnd, wxCheckBox);
1331
1332 switch( mShuttleMode )
1333 {
1334 // IF setting internal storage from the controls.
1335 case eIsGettingMetadata:
1336 break;
1338 {
1339 wxASSERT( pCheckBox );
1340 WrappedRef.WriteToAsBool( pCheckBox->GetValue() );
1341 }
1342 break;
1343 case eIsSettingToDialog:
1344 {
1345 wxASSERT( pCheckBox );
1346 pCheckBox->SetValue( WrappedRef.ReadAsBool() );
1347 }
1348 break;
1349 default:
1350 wxASSERT( false );
1351 break;
1352 }
1353 return pCheckBox;
1354}
1355
1357 const TranslatableString &Prompt,
1358 WrappedType & WrappedRef, const int max, const int min )
1359{
1360 HandleOptionality( Prompt );
1361 // The Add function does a UseUpId(), so don't do it here in that case.
1362 if( mShuttleMode == eIsCreating )
1363 return AddSpinCtrl( Prompt, WrappedRef.ReadAsInt(), max, min );
1364
1365 UseUpId();
1366 wxSpinCtrl * pSpinCtrl=NULL;
1367
1368 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1369 pSpinCtrl = wxDynamicCast(pWnd, wxSpinCtrl);
1370
1371 switch( mShuttleMode )
1372 {
1373 // IF setting internal storage from the controls.
1374 case eIsGettingMetadata:
1375 break;
1377 {
1378 wxASSERT( pSpinCtrl );
1379 WrappedRef.WriteToAsInt( pSpinCtrl->GetValue() );
1380 }
1381 break;
1382 case eIsSettingToDialog:
1383 {
1384 wxASSERT( pSpinCtrl );
1385 pSpinCtrl->SetValue( WrappedRef.ReadAsInt() );
1386 }
1387 break;
1388 default:
1389 wxASSERT( false );
1390 break;
1391 }
1392 return pSpinCtrl;
1393}
1394
1396 const wxSize& size, const TranslatableString& Prompt,
1397 WrappedType& WrappedRef, const double max, const double min)
1398{
1399 HandleOptionality( Prompt );
1400 // The Add function does a UseUpId(), so don't do it here in that case.
1401 if( mShuttleMode == eIsCreating )
1402 return AddSpinControl(size, Prompt, WrappedRef.ReadAsDouble(), max, min);
1403
1404 UseUpId();
1405 SpinControl * pSpinCtrl=NULL;
1406
1407 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1408 pSpinCtrl = dynamic_cast<SpinControl*>(pWnd);
1409
1410 switch( mShuttleMode )
1411 {
1412 // IF setting internal storage from the controls.
1413 case eIsGettingMetadata:
1414 break;
1416 {
1417 wxASSERT( pSpinCtrl );
1418 WrappedRef.WriteToAsDouble( pSpinCtrl->GetValue() );
1419 }
1420 break;
1421 case eIsSettingToDialog:
1422 {
1423 wxASSERT( pSpinCtrl );
1424 pSpinCtrl->SetValue( WrappedRef.ReadAsDouble() );
1425 }
1426 break;
1427 default:
1428 wxASSERT( false );
1429 break;
1430 }
1431 return pSpinCtrl;
1432}
1433
1435 const TranslatableString &Prompt, WrappedType & WrappedRef, const int nChars)
1436{
1437 HandleOptionality( Prompt );
1438 // The Add function does a UseUpId(), so don't do it here in that case.
1439 if( mShuttleMode == eIsCreating )
1440 return AddTextBox( Prompt, WrappedRef.ReadAsString(), nChars );
1441
1442 UseUpId();
1443 wxTextCtrl * pTextBox=NULL;
1444
1445 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1446 pTextBox = wxDynamicCast(pWnd, wxTextCtrl);
1447
1448 switch( mShuttleMode )
1449 {
1450 // IF setting internal storage from the controls.
1451 case eIsGettingMetadata:
1452 break;
1454 {
1455 wxASSERT( pTextBox );
1456 WrappedRef.WriteToAsString( pTextBox->GetValue() );
1457 }
1458 break;
1459 case eIsSettingToDialog:
1460 {
1461 wxASSERT( pTextBox );
1462 pTextBox->SetValue( WrappedRef.ReadAsString() );
1463 }
1464 break;
1465 default:
1466 wxASSERT( false );
1467 break;
1468 }
1469 return pTextBox;
1470}
1471
1473 const TranslatableString& Prompt, WrappedType& WrappedRef, const int nChars,
1474 bool acceptEnter)
1475{
1476 HandleOptionality( Prompt );
1477 // The Add function does a UseUpId(), so don't do it here in that case.
1478 if( mShuttleMode == eIsCreating )
1479 return AddNumericTextBox( Prompt, WrappedRef.ReadAsString(), nChars, acceptEnter );
1480
1481 UseUpId();
1482 wxTextCtrl * pTextBox=NULL;
1483
1484 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1485 pTextBox = wxDynamicCast(pWnd, wxTextCtrl);
1486
1487 switch( mShuttleMode )
1488 {
1489 // IF setting internal storage from the controls.
1490 case eIsGettingMetadata:
1491 break;
1493 {
1494 wxASSERT( pTextBox );
1495 WrappedRef.WriteToAsString( pTextBox->GetValue() );
1496 }
1497 break;
1498 case eIsSettingToDialog:
1499 {
1500 wxASSERT( pTextBox );
1501 pTextBox->SetValue( WrappedRef.ReadAsString() );
1502 }
1503 break;
1504 default:
1505 wxASSERT( false );
1506 break;
1507 }
1508 return pTextBox;
1509}
1510
1512 const TranslatableString &Prompt,
1513 WrappedType & WrappedRef, const int max, int min )
1514{
1515 HandleOptionality( Prompt );
1516 // The Add function does a UseUpId(), so don't do it here in that case.
1517 if( mShuttleMode != eIsCreating )
1518 UseUpId();
1519 wxSlider * pSlider=NULL;
1520 switch( mShuttleMode )
1521 {
1522 case eIsCreating:
1523 {
1524 pSlider = AddSlider( Prompt, WrappedRef.ReadAsInt(), max, min );
1525 }
1526 break;
1527 // IF setting internal storage from the controls.
1528 case eIsGettingMetadata:
1529 break;
1531 {
1532 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1533 pSlider = wxDynamicCast(pWnd, wxSlider);
1534 wxASSERT( pSlider );
1535 WrappedRef.WriteToAsInt( pSlider->GetValue() );
1536 }
1537 break;
1538 case eIsSettingToDialog:
1539 {
1540 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1541 pSlider = wxDynamicCast(pWnd, wxSlider);
1542 wxASSERT( pSlider );
1543 pSlider->SetValue( WrappedRef.ReadAsInt() );
1544 }
1545 break;
1546 default:
1547 wxASSERT( false );
1548 break;
1549 }
1550 return pSlider;
1551}
1552
1553
1555 const TranslatableString &Prompt,
1556 int &Selected,
1557 const TranslatableStrings &choices )
1558{
1559 HandleOptionality( Prompt );
1560
1561 // The Add function does a UseUpId(), so don't do it here in that case.
1562 if( mShuttleMode != eIsCreating )
1563 UseUpId();
1564
1565 wxChoice * pChoice=NULL;
1566 switch( mShuttleMode )
1567 {
1568 case eIsCreating:
1569 {
1570 pChoice = AddChoice( Prompt, choices, Selected );
1571 ShuttleGui::SetMinSize(pChoice, choices);
1572 }
1573 break;
1574 // IF setting internal storage from the controls.
1575 case eIsGettingMetadata:
1576 break;
1578 {
1579 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1580 pChoice = wxDynamicCast(pWnd, wxChoice);
1581 wxASSERT( pChoice );
1582 Selected = pChoice->GetSelection();
1583 }
1584 break;
1585 case eIsSettingToDialog:
1586 {
1587 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1588 pChoice = wxDynamicCast(pWnd, wxChoice);
1589 wxASSERT( pChoice );
1590 pChoice->SetSelection( Selected );
1591 }
1592 break;
1593 default:
1594 wxASSERT( false );
1595 break;
1596 }
1597 return pChoice;
1598}
1599
1602{
1603 wxASSERT( mRadioCount >= 0); // Did you remember to use StartRadioButtonGroup() ?
1604
1605 EnumValueSymbol symbol;
1606 if (mRadioCount >= 0 && mRadioCount < (int)mRadioSymbols.size() )
1607 symbol = mRadioSymbols[ mRadioCount ];
1608
1609 // In what follows, WrappedRef is used in read only mode, but we
1610 // don't have a 'read-only' version, so we copy to deal with the constness.
1611 auto Temp = symbol.Internal();
1612 wxASSERT( !Temp.empty() ); // More buttons than values?
1613
1614 WrappedType WrappedRef( Temp );
1615
1616 mRadioCount++;
1617
1618 UseUpId();
1619 wxRadioButton * pRadioButton = NULL;
1620
1621 switch( mShuttleMode )
1622 {
1623 case eIsCreating:
1624 {
1625 const auto &Prompt = symbol.Translation();
1626
1627 mpWind = pRadioButton = safenew wxRadioButton(GetParent(), miId, Prompt,
1628 wxDefaultPosition, wxDefaultSize,
1629 (mRadioCount==1)?wxRB_GROUP:0);
1630
1631 wxASSERT( WrappedRef.IsString() );
1632 wxASSERT( mRadioValue->IsString() );
1633 const bool value =
1634 (WrappedRef.ReadAsString() == mRadioValue->ReadAsString() );
1635 pRadioButton->SetValue( value );
1636
1637 pRadioButton->SetName(wxStripMenuCodes(Prompt));
1638 UpdateSizers();
1639 }
1640 break;
1641 case eIsGettingMetadata:
1642 break;
1644 {
1645 wxWindow * pWnd = wxWindow::FindWindowById( miId, mpDlg);
1646 pRadioButton = wxDynamicCast(pWnd, wxRadioButton);
1647 wxASSERT( pRadioButton );
1648 if( pRadioButton->GetValue() )
1649 mRadioValue->WriteToAsString( WrappedRef.ReadAsString() );
1650 }
1651 break;
1652 default:
1653 wxASSERT( false );
1654 break;
1655 }
1656 return pRadioButton;
1657}
1658
1661{
1662 mRadioSymbols = Setting.GetSymbols();
1663
1664 // Configure the generic type mechanism to use OUR string.
1665 mRadioValueString = Setting.Default().Internal();
1666 mRadioValue.emplace( mRadioValueString );
1667
1668 // Now actually start the radio button group.
1669 mRadioSettingName = Setting.Key();
1670 mRadioCount = 0;
1671 if( mShuttleMode == eIsCreating )
1673}
1674
1678{
1679 // too few buttons?
1680 wxASSERT( mRadioCount == mRadioSymbols.size() );
1681
1684 mRadioValue.reset();// Clear it out...
1685 mRadioSettingName = wxT("");
1686 mRadioCount = -1; // So we detect a problem.
1687 mRadioSymbols = {};
1688}
1689
1690//-----------------------------------------------------------------------//
1691//-- Now we are into type specific Tie() functions.
1692//-- These are all 'one-step' tie functions.
1693
1694wxCheckBox * ShuttleGuiBase::TieCheckBox(const TranslatableString &Prompt, bool &Var)
1695{
1696 WrappedType WrappedRef( Var );
1697 return DoTieCheckBox( Prompt, WrappedRef );
1698}
1699
1700// See comment in AddCheckBoxOnRight() for why we have this variant.
1701wxCheckBox * ShuttleGuiBase::TieCheckBoxOnRight(const TranslatableString &Prompt, bool &Var)
1702{
1703 // Only does anything different if it's creating.
1704 WrappedType WrappedRef( Var );
1705 if( mShuttleMode == eIsCreating )
1706 return AddCheckBoxOnRight( Prompt, WrappedRef.ReadAsString() == wxT("true") );
1707 return DoTieCheckBox( Prompt, WrappedRef );
1708}
1709
1711 const TranslatableString &Prompt, int &Value, const int max, const int min )
1712{
1713 WrappedType WrappedRef(Value);
1714 return DoTieSpinCtrl( Prompt, WrappedRef, max, min );
1715}
1716
1718 const wxSize& size, const TranslatableString& Prompt, double& Value,
1719 const double max, const double min)
1720{
1721 WrappedType WrappedRef(Value);
1722 return DoTieSpinControl(size, Prompt, WrappedRef, max, min);
1723}
1724
1726 const TranslatableString &Prompt, wxString &Selected, const int nChars)
1727{
1728 WrappedType WrappedRef(Selected);
1729 return DoTieTextBox( Prompt, WrappedRef, nChars );
1730}
1731
1733 const TranslatableString &Prompt, int &Selected, const int nChars)
1734{
1735 WrappedType WrappedRef( Selected );
1736 return DoTieTextBox( Prompt, WrappedRef, nChars );
1737}
1738
1740 const TranslatableString &Prompt, double &Value, const int nChars)
1741{
1742 WrappedType WrappedRef( Value );
1743 return DoTieTextBox( Prompt, WrappedRef, nChars );
1744}
1745
1747 const TranslatableString& Prompt, int& Value, const int nChars,
1748 bool acceptEnter)
1749{
1750 WrappedType WrappedRef(Value);
1751 return DoTieNumericTextBox(Prompt, WrappedRef, nChars, acceptEnter);
1752}
1753
1755 const TranslatableString& Prompt, double& Value, const int nChars,
1756 bool acceptEnter)
1757{
1758 WrappedType WrappedRef( Value );
1759 return DoTieNumericTextBox( Prompt, WrappedRef, nChars, acceptEnter );
1760}
1761
1763 const TranslatableString &Prompt, int &pos, const int max, const int min )
1764{
1765 WrappedType WrappedRef( pos );
1766 return DoTieSlider( Prompt, WrappedRef, max, min );
1767}
1768
1770 const TranslatableString &Prompt,
1771 double &pos, const double max, const double min )
1772{
1773 WrappedType WrappedRef( pos );
1774 return DoTieSlider( Prompt, WrappedRef, max, min );
1775}
1776
1778 const TranslatableString &Prompt,
1779 float &pos, const float fMin, const float fMax)
1780{
1781 const float RoundFix=0.0000001f;
1782 int iVal=(pos-fMin+RoundFix)*100.0/(fMax-fMin);
1783 wxSlider * pWnd = TieSlider( Prompt, iVal, 100 );
1784 pos = iVal*(fMax-fMin)*0.01+fMin;
1785 return pWnd;
1786}
1787
1789 const TranslatableString &Prompt,
1790 float &pos, const float fMin, const float fMax)
1791{
1792 int iVal=(pos-fMin)*100.0/(fMax-fMin);
1793// if( mShuttleMode == eIsCreating )
1794// {
1795// return AddVSlider( Prompt, iVal, 100 );
1796// }
1797 wxSlider * pWnd = TieSlider( Prompt, iVal, 100 );
1798 pos = iVal*(fMax-fMin)*0.01+fMin;
1799 return pWnd;
1800}
1801
1803 const TranslatableString &Prompt,
1804 TranslatableString &Selected,
1805 const TranslatableStrings &choices )
1806{
1807 int Index = make_iterator_range( choices ).index( Selected );
1808 auto result = TieChoice( Prompt, Index, choices );
1809 if ( Index >= 0 && Index < choices.size() )
1810 Selected = choices[ Index ];
1811 else
1812 Selected = {};
1813 return result;
1814}
1815
1816//-----------------------------------------------------------------------//
1817
1818// ShuttleGui utility functions to look things up in a list.
1819// If not present, we use the configured default index value.
1820
1821//-----------------------------------------------------------------------//
1822
1824int ShuttleGuiBase::TranslateToIndex( const wxString &Value, const wxArrayStringEx &Choices )
1825{
1826 int n = make_iterator_range( Choices ).index( Value );
1827 if( n == wxNOT_FOUND )
1830 return n;
1831}
1832
1834wxString ShuttleGuiBase::TranslateFromIndex( const int nIn, const wxArrayStringEx &Choices )
1835{
1836 int n = nIn;
1837 if( n== wxNOT_FOUND )
1840 if( n < (int)Choices.size() )
1841 {
1842 return Choices[n];
1843 }
1844 return wxT("");
1845}
1846
1847//-----------------------------------------------------------------------//
1848
1849
1850// ShuttleGui code uses the model that you read into program variables
1851// and write out from program variables.
1852
1853// In programs like Audacity which don't use internal program variables
1854// you have to do both steps in one go, using variants of the standard
1855// 'Tie' functions which call the underlying Tie functions twice.
1856
1857//----------------------------------------------------------------------//
1858
1859
1892bool ShuttleGuiBase::DoStep( int iStep )
1893{
1894 // Get value and create
1895 if( mShuttleMode == eIsCreating )
1896 {
1897 return (iStep==1) || (iStep==2);
1898 }
1899 // Like creating, get the value and set.
1901 {
1902 return (iStep==1) || (iStep==2);
1903 }
1905 {
1906 return (iStep==2) || (iStep==3);
1907 }
1909 return iStep ==2;
1910 wxASSERT( false );
1911 return false;
1912}
1913
1914
1918 const TranslatableString &Prompt,
1919 const BoolSetting &Setting)
1920{
1921 wxCheckBox * pCheck=NULL;
1922
1923 auto Value = Setting.GetDefault();
1924 WrappedType WrappedRef( Value );
1925 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1926 if( DoStep(2) ) pCheck = DoTieCheckBox( Prompt, WrappedRef );
1927 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1928
1929 return pCheck;
1930}
1931
1935 const TranslatableString &Prompt,
1936 const BoolSetting & Setting)
1937{
1938 wxCheckBox * pCheck=NULL;
1939
1940 auto Value = Setting.GetDefault();
1941 WrappedType WrappedRef( Value );
1942 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1943 if( DoStep(2) ) pCheck = DoTieCheckBoxOnRight( Prompt, WrappedRef );
1944 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1945
1946 return pCheck;
1947}
1948
1952 const TranslatableString &Prompt,
1953 const IntSetting & Setting,
1954 const int max,
1955 const int min)
1956{
1957 wxSlider * pSlider=NULL;
1958
1959 auto Value = Setting.GetDefault();
1960 WrappedType WrappedRef( Value );
1961 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1962 if( DoStep(2) ) pSlider = DoTieSlider( Prompt, WrappedRef, max, min );
1963 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1964
1965 return pSlider;
1966}
1967
1971 const TranslatableString &Prompt,
1972 const IntSetting &Setting,
1973 const int max,
1974 const int min)
1975{
1976 wxSpinCtrl * pSpinCtrl=NULL;
1977
1978 auto Value = Setting.GetDefault();
1979 WrappedType WrappedRef( Value );
1980 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1981 if( DoStep(2) ) pSpinCtrl = DoTieSpinCtrl( Prompt, WrappedRef, max, min );
1982 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1983
1984 return pSpinCtrl;
1985}
1986
1990 const TranslatableString & Prompt,
1991 const StringSetting & Setting,
1992 const int nChars)
1993{
1994 wxTextCtrl * pText=(wxTextCtrl*)NULL;
1995
1996 auto Value = Setting.GetDefault();
1997 WrappedType WrappedRef( Value );
1998 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
1999 if( DoStep(2) ) pText = DoTieTextBox( Prompt, WrappedRef, nChars );
2000 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
2001 return pText;
2002}
2003
2008 const TranslatableString & Prompt,
2009 const IntSetting &Setting,
2010 const int nChars)
2011{
2012 wxTextCtrl * pText=(wxTextCtrl*)NULL;
2013
2014 auto Value = Setting.GetDefault();
2015 WrappedType WrappedRef( Value );
2016 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
2017 if( DoStep(2) ) pText = DoTieNumericTextBox( Prompt, WrappedRef, nChars );
2018 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
2019 return pText;
2020}
2021
2026 const TranslatableString & Prompt,
2027 const DoubleSetting & Setting,
2028 const int nChars, bool acceptEnter)
2029{
2030 wxTextCtrl * pText=(wxTextCtrl*)NULL;
2031
2032 auto Value = Setting.GetDefault();
2033 WrappedType WrappedRef( Value );
2034 if( DoStep(1) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
2035 if( DoStep(2) ) pText = DoTieNumericTextBox( Prompt, WrappedRef, nChars, acceptEnter );
2036 if( DoStep(3) ) DoDataShuttle( Setting.GetPath(), WrappedRef );
2037 return pText;
2038}
2039
2047 ChoiceSetting &choiceSetting)
2048{
2049 // Do this to force any needed migrations first
2050 choiceSetting.Read();
2051
2052 const auto &symbols = choiceSetting.GetSymbols();
2053 const auto &SettingName = choiceSetting.Key();
2054 const auto &Default = choiceSetting.Default().Internal();
2055 const auto &Choices = symbols.GetMsgids();
2056 const auto &InternalChoices = symbols.GetInternals();
2057
2058 wxChoice * pChoice=(wxChoice*)NULL;
2059
2060 int TempIndex=0;
2061// int TempIndex = TranslateToIndex( Default, InternalChoices );
2062 wxString TempStr = Default;
2063 WrappedType WrappedRef( TempStr );
2064 // Get from prefs does 1 and 2.
2065 // Put to prefs does 2 and 3.
2066 if( DoStep(1) ) DoDataShuttle( SettingName, WrappedRef ); // Get Index from Prefs.
2067 if( DoStep(1) ) TempIndex = TranslateToIndex( TempStr, InternalChoices ); // To an index
2068 if( DoStep(2) ) pChoice = TieChoice( Prompt, TempIndex, Choices );
2069 if( DoStep(3) ) TempStr = TranslateFromIndex( TempIndex, InternalChoices ); // To a string
2070 if( DoStep(3) ) choiceSetting.Write(TempStr); // Put into Prefs.
2071 return pChoice;
2072}
2073
2087 const TranslatableStrings & Choices,
2088 const std::vector<int> * pInternalChoices,
2089 int iNoMatchSelector)
2090{
2091 auto fn = [](int arg){ return wxString::Format( "%d", arg ); };
2092
2093 wxArrayStringEx InternalChoices;
2094 if ( pInternalChoices )
2095 InternalChoices =
2096 transform_container<wxArrayStringEx>(*pInternalChoices, fn);
2097 else
2098 for ( int ii = 0; ii < (int)Choices.size(); ++ii )
2099 InternalChoices.push_back( fn( ii ) );
2100
2101 const auto Default = Setting.GetDefault();
2102
2103 miNoMatchSelector = iNoMatchSelector;
2104
2105 long defaultIndex;
2106 if ( pInternalChoices )
2107 defaultIndex = make_iterator_range( *pInternalChoices ).index( Default );
2108 else
2109 defaultIndex = Default;
2110 if ( defaultIndex < 0 || defaultIndex >= (int)Choices.size() )
2111 defaultIndex = -1;
2112
2113 ChoiceSetting choiceSetting{
2114 Setting,
2115 {
2116 ByColumns,
2117 Choices,
2118 InternalChoices,
2119 },
2120 defaultIndex
2121 };
2122
2123 return ShuttleGuiBase::TieChoice(Prompt, choiceSetting);
2124}
2125
2126//------------------------------------------------------------------//
2127
2128// We're now into ShuttleGuiBase sizer and misc functions.
2129
2137{
2138 if( miIdSetByUser > 0)
2139 {
2141 miIdSetByUser = -1;
2142 return;
2143 }
2144 miId = miIdNext++;
2145}
2146
2148{
2149 if( miPropSetByUser >=0 )
2150 {
2152 miPropSetByUser =-1;
2153 return;
2154 }
2155 miProp = Default;
2156}
2157
2158
2160 wxWindow *pWind, wxWindow *pDlg )
2161{
2162 if ( step == 0 ) {
2163 // Do these steps before adding the window to the sizer
2164 if( item.mUseBestSize )
2165 pWind->SetMinSize( pWind->GetBestSize() );
2166 else if( item.mHasMinSize )
2167 pWind->SetMinSize( item.mMinSize );
2168
2169 if ( item.mWindowSize != wxSize{} )
2170 pWind->SetSize( item.mWindowSize );
2171 }
2172 else if ( step == 1) {
2173 // Apply certain other optional window attributes here
2174
2175 if ( item.mValidatorSetter )
2176 item.mValidatorSetter( pWind );
2177
2178 if ( !item.mToolTip.empty() )
2179 pWind->SetToolTip( item.mToolTip.Translation() );
2180
2181 if ( !item.mName.empty() ) {
2182 pWind->SetName( item.mName.Stripped().Translation() );
2183#ifndef __WXMAC__
2184 if (auto pButton = dynamic_cast< wxBitmapButton* >( pWind ))
2185 pButton->SetLabel( item.mName.Translation() );
2186#endif
2187 }
2188
2189 if ( !item.mNameSuffix.empty() )
2190 pWind->SetName(
2191 pWind->GetName() + " " + item.mNameSuffix.Translation() );
2192
2193 if (item.mFocused)
2194 pWind->SetFocus();
2195
2196 if (item.mDisabled)
2197 pWind->Enable( false );
2198
2199 for (auto &pair : item.mRootConnections)
2200 pWind->Connect( pair.first, pair.second, nullptr, pDlg );
2201 }
2202}
2203
2204
2205void ShuttleGuiBase::UpdateSizersCore(bool bPrepend, int Flags, bool prompt)
2206{
2207 if( mpWind && mpParent )
2208 {
2209 int useFlags = Flags;
2210
2211 if ( !prompt && mItem.mWindowPositionFlags )
2212 // override the given Flags
2213 useFlags = mItem.mWindowPositionFlags;
2214
2215 if (!prompt)
2216 ApplyItem( 0, mItem, mpWind, mpDlg );
2217
2218 if( mpSizer){
2219 if( bPrepend )
2220 {
2221 mpSizer->Prepend(mpWind, miProp, useFlags, miBorder);
2222 }
2223 else
2224 {
2225 mpSizer->Add(mpWind, miProp, useFlags, miBorder);
2226 }
2227 }
2228
2229 if (!prompt) {
2230 ApplyItem( 1, mItem, mpWind, mpDlg );
2231 // Reset to defaults
2232 mItem = {};
2233 }
2234 }
2235
2236 if( mpSubSizer && mpSizer )
2237 {
2238 // When adding sizers into sizers, don't add a border.
2239 // unless it's a static box sizer.
2240 wxSizer *const pSubSizer = mpSubSizer.get();
2241 if (wxDynamicCast(pSubSizer, wxStaticBoxSizer))
2242 {
2243 mpSizer->Add( mpSubSizer.release(), miSizerProp, Flags , miBorder);
2244 }
2245 else
2246 {
2247 mpSizer->Add( mpSubSizer.release(), miSizerProp, Flags ,0);//miBorder);
2248 }
2249 mpSizer = pSubSizer;
2250 PushSizer();
2251 }
2252
2253 mpWind = NULL;
2254 miProp = 0;
2255 miSizerProp =0;
2256}
2257
2258// Sizer is added into parent sizer, and will expand/shrink.
2260{ UpdateSizersCore( false, wxEXPAND | wxALL );}
2261
2262// Sizer is added into parent sizer, centred
2264{ UpdateSizersCore( false, wxALIGN_CENTRE | wxALL );}
2265
2266// Sizer is added into parent sizer, and will expand/shrink.
2267// added to start of sizer list.
2269{ UpdateSizersCore( true, wxEXPAND | wxALL );}
2270
2272{
2273 mSizerDepth--;
2274 wxASSERT( mSizerDepth >=0 );
2276}
2277
2279{
2280 mSizerDepth++;
2281 wxASSERT( mSizerDepth < nMaxNestedSizers );
2283}
2284
2286{
2287 if( mItem.miStyle )
2289 mItem.miStyle = 0;
2290 return style;
2291}
2292
2293// A rarely used helper function that sets a pointer
2294// ONLY if the value it is to be set to is non NULL.
2295void SetIfCreated( wxChoice * &Var, wxChoice * Val )
2296{
2297 if( Val != NULL )
2298 Var = Val;
2299};
2300void SetIfCreated( wxTextCtrl * &Var, wxTextCtrl * Val )
2301{
2302 if( Val != NULL )
2303 Var = Val;
2304};
2305void SetIfCreated( wxStaticText *&Var, wxStaticText * Val )
2306{
2307 if( Val != NULL )
2308 Var = Val;
2309};
2310
2312 wxWindow * pParent, teShuttleMode ShuttleMode, bool vertical, wxSize minSize)
2313 : ShuttleGuiBase( pParent, ShuttleMode, vertical, minSize )
2314{
2315 if( ShuttleMode == eIsCreatingFromPrefs )
2316 {
2318 Init( vertical, minSize ); // Wasn't fully done in base constructor because it is only done when eIsCreating is set.
2319 }
2320 else if( ShuttleMode == eIsSavingToPrefs )
2321 {
2323 }
2324 else
2325 {
2326 return;
2327 }
2328
2329 mpShuttle = std::make_unique<ShuttlePrefs>();
2330 // In this case the client is the GUI, so if creating we do want to
2331 // store in the client.
2332 mpShuttle->mbStoreInClient = (mShuttleMode == eIsCreating );
2333};
2334
2336{
2337}
2338
2339// Now we have Audacity specific shuttle functions.
2341{
2342 miIdSetByUser = id;
2343 return *this;
2344}
2345
2347 mpbOptionalFlag = &bVar;
2348 return *this;
2349};
2350
2351
2352std::unique_ptr<wxSizer> CreateStdButtonSizer(wxWindow *parent, long buttons, wxWindow *extra)
2353{
2354 wxASSERT(parent != NULL); // To justify safenew
2355
2356 int margin;
2357 {
2358#if defined(__WXMAC__)
2359 margin = 12;
2360#elif defined(__WXGTK20__)
2361 margin = 12;
2362#elif defined(__WXMSW__)
2363 wxButton b(parent, 0, wxEmptyString);
2364 margin = b.ConvertDialogToPixels(wxSize(2, 0)).x;
2365#else
2366 wxButton b(parent, 0, wxEmptyString);
2367 margin = b->ConvertDialogToPixels(wxSize(4, 0)).x;
2368#endif
2369 }
2370
2371 wxButton *b = NULL;
2372 auto bs = std::make_unique<wxStdDialogButtonSizer>();
2373
2374 const auto makeButton =
2375 [parent]( wxWindowID id, const wxString label = {} ) {
2376 auto result = safenew wxButton( parent, id, label );
2377 result->SetName( result->GetLabel() );
2378 return result;
2379 };
2380
2381 if( buttons & eOkButton )
2382 {
2383 b = makeButton( wxID_OK );
2384 b->SetDefault();
2385 bs->AddButton( b );
2386 }
2387
2388 if( buttons & eCancelButton )
2389 {
2390 bs->AddButton( makeButton( wxID_CANCEL ) );
2391 }
2392
2393 if( buttons & eYesButton )
2394 {
2395 b = makeButton( wxID_YES );
2396 b->SetDefault();
2397 bs->AddButton( b );
2398 }
2399
2400 if( buttons & eNoButton )
2401 {
2402 bs->AddButton( makeButton( wxID_NO ) );
2403 }
2404
2405 if( buttons & eApplyButton )
2406 {
2407 b = makeButton( wxID_APPLY );
2408 b->SetDefault();
2409 bs->AddButton( b );
2410 }
2411
2412 if( buttons & eCloseButton )
2413 {
2414 bs->AddButton( makeButton( wxID_CANCEL, XO("&Close").Translation() ) );
2415 }
2416
2417#if defined(__WXMSW__)
2418 // See below for explanation
2419 if( buttons & eHelpButton )
2420 {
2421 // Replace standard Help button with smaller icon button.
2422 // bs->AddButton(safenew wxButton(parent, wxID_HELP));
2423 b = safenew wxBitmapButton(parent, wxID_HELP, theTheme.Bitmap( bmpHelpIcon ));
2424 b->SetToolTip( XO("Help").Translation() );
2425 b->SetLabel(XO("Help").Translation()); // for screen readers
2426 b->SetName( b->GetLabel() );
2427 bs->AddButton( b );
2428 }
2429#endif
2430
2431 if (buttons & ePreviewButton)
2432 {
2433 bs->Add( makeButton( ePreviewID, XO("&Preview").Translation() ),
2434 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin);
2435 }
2436 if (buttons & ePreviewDryButton)
2437 {
2438 bs->Add( makeButton( ePreviewDryID, XO("Dry Previe&w").Translation() ),
2439 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin);
2440 bs->Add( 20, 0 );
2441 }
2442
2443 if( buttons & eSettingsButton )
2444 {
2445 bs->Add( makeButton( eSettingsID, XO("&Settings").Translation() ),
2446 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin);
2447 bs->Add( 20, 0 );
2448 }
2449
2450 if( extra )
2451 {
2452 bs->Add( extra, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin );
2453 bs->Add( 40, 0 );
2454 }
2455
2456 bs->AddStretchSpacer();
2457 bs->Realize();
2458
2459 size_t lastLastSpacer = 0;
2460 size_t lastSpacer = 0;
2461 wxSizerItemList & list = bs->GetChildren();
2462 for( size_t i = 0, cnt = list.size(); i < cnt; i++ )
2463 {
2464 if( list[i]->IsSpacer() )
2465 {
2466 lastSpacer = i;
2467 }
2468 else
2469 {
2470 lastLastSpacer = lastSpacer;
2471 }
2472 }
2473
2474 // Add any buttons that need to cuddle up to the right hand cluster
2475 if( buttons & eDebugButton )
2476 {
2477 b = makeButton( eDebugID, XO("Debu&g").Translation() );
2478 bs->Insert( ++lastLastSpacer, b, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin );
2479 }
2480
2481#if !defined(__WXMSW__)
2482 // Bug #2432: Couldn't find GTK guidelines, but Mac HIGs state:
2483 //
2484 // View style Help button position
2485 // Dialog with dismissal buttons (like OK and Cancel). Lower-left corner, vertically aligned with the dismissal buttons.
2486 // Dialog without dismissal buttons. Lower-left or lower-right corner.
2487 // Preference window or pane. Lower-left or lower-right corner.
2488 //
2489 // So, we're gonna cheat a little and use the lower-right corner.
2490 if( buttons & eHelpButton )
2491 {
2492 // Replace standard Help button with smaller icon button.
2493 // bs->AddButton(safenew wxButton(parent, wxID_HELP));
2494 b = safenew wxBitmapButton(parent, wxID_HELP, theTheme.Bitmap( bmpHelpIcon ));
2495 b->SetToolTip( XO("Help").Translation() );
2496 b->SetLabel(XO("Help").Translation()); // for screen readers
2497 b->SetName( b->GetLabel() );
2498 bs->Add( b, 0, wxALIGN_CENTER );
2499 }
2500#endif
2501
2502
2503 auto s = std::make_unique<wxBoxSizer>( wxVERTICAL );
2504 s->Add( bs.release(), 1, wxEXPAND | wxALL, 7 );
2505 s->Add( 0, 3 ); // a little extra space
2506
2507 return std::unique_ptr<wxSizer>{ s.release() };
2508}
2509
2510void ShuttleGui::AddStandardButtons(long buttons, wxWindow *extra)
2511{
2512 if( mShuttleMode != eIsCreating )
2513 return;
2514
2515 StartVerticalLay( false );
2516
2517 miSizerProp = false;
2518 mpSubSizer = CreateStdButtonSizer( mpParent, buttons, extra );
2519 UpdateSizers();
2520 PopSizer();
2521
2523}
2524
2525wxSizerItem * ShuttleGui::AddSpace( int width, int height, int prop )
2526{
2527 if( mShuttleMode != eIsCreating )
2528 return NULL;
2529
2530// SetProportions(0);
2531 // return mpSizer->Add( width, height, miProp);
2532
2533 return mpSizer->Add( width, height, prop );
2534}
2535
2536void ShuttleGui::SetMinSize( wxWindow *window, const TranslatableStrings & items )
2537{
2538 SetMinSize( window,
2539 transform_container<wxArrayStringEx>(
2540 items, std::mem_fn( &TranslatableString::StrippedTranslation ) ) );
2541}
2542
2543void ShuttleGui::SetMinSize( wxWindow *window, const wxArrayStringEx & items )
2544{
2545 int maxw = 0;
2546
2547 for( size_t i = 0; i < items.size(); i++ )
2548 {
2549 int x;
2550 int y;
2551
2552 window->GetTextExtent(items[i], &x, &y );
2553 if( x > maxw )
2554 {
2555 maxw = x;
2556 }
2557 }
2558
2559 // Would be nice to know the sizes of the button and borders, but this is
2560 // the best we can do for now.
2561#if defined(__WXMAC__)
2562 maxw += 50;
2563#elif defined(__WXMSW__)
2564 maxw += 50;
2565#elif defined(__WXGTK__)
2566 maxw += 50;
2567#else
2568 maxw += 50;
2569#endif
2570
2571 window->SetMinSize( { maxw, -1 } );
2572}
2573
2574/*
2575void ShuttleGui::SetMinSize( wxWindow *window, const std::vector<int> & items )
2576{
2577 wxArrayStringEx strs;
2578
2579 for( size_t i = 0; i < items.size(); i++ )
2580 {
2581 strs.Add( wxString::Format( wxT("%d"), items[i] ) );
2582 }
2583
2584 SetMinSize( window, strs );
2585}
2586*/
2587
2589 const EnumValueSymbol strings[], size_t nStrings)
2590{
2591 return transform_range<TranslatableStrings>(
2592 strings, strings + nStrings,
2593 std::mem_fn( &EnumValueSymbol::Msgid )
2594 );
2595}
2596
2597TranslatableStrings Msgids( const std::vector<EnumValueSymbol> &strings )
2598{
2599 return Msgids( strings.data(), strings.size() );
2600}
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
@ ePreviewID
Definition: ShuttleGui.h:626
@ eDebugID
Definition: ShuttleGui.h:628
@ eSettingsID
Definition: ShuttleGui.h:629
@ ePreviewDryID
Definition: ShuttleGui.h:630
wxWindow wxNotebookPage
Definition: ShuttleGui.h:60
@ 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
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:996
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:384
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