1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   ShuttleGui.h
6 
7   James Crook
8 
9   Audacity is free software.
10   This file is licensed under the wxWidgets license, see License.txt
11 
12 **********************************************************************/
13 
14 #ifndef SHUTTLE_GUI
15 #define SHUTTLE_GUI
16 
17 
18 #include "Identifier.h"
19 
20 #include <vector>
21 #include <wx/slider.h> // to inherit
22 #include "MemoryX.h"
23 #include <wx/listbase.h> // for wxLIST_FORMAT_LEFT
24 
25 #include "Prefs.h"
26 #include "WrappedType.h"
27 #include "ComponentInterfaceSymbol.h"
28 
29 class ChoiceSetting;
30 
31 class wxArrayStringEx;
32 
33 
34 const int nMaxNestedSizers = 20;
35 
36 enum teShuttleMode
37 {
38    eIsCreating,
39    eIsGettingFromDialog,
40    eIsSettingToDialog,
41    eIsGettingMetadata,
42 
43    // Next two are only ever seen in constructor.
44    // After that they revert to one of the modes above.
45    // They are used to achieve 'two step' operation,
46    // where we transfer between two shuttles in one go.
47    eIsCreatingFromPrefs,
48    eIsSavingToPrefs
49 };
50 
51 class wxListCtrl;
52 class wxCheckBox;
53 class wxChoice;
54 class wxComboBox;
55 class wxScrolledWindow;
56 class wxStaticText;
57 class wxTreeCtrl;
58 class wxTextCtrl;
59 class wxSlider;
60 class wxNotebook;
61 class wxSimplebook;
62 typedef wxWindow wxNotebookPage;  // so far, any window can be a page
63 class wxButton;
64 class wxBitmapButton;
65 class wxRadioButton;
66 class wxBitmap;
67 class wxPanel;
68 class wxSizer;
69 class wxSizerItem;
70 class wxStaticBox;
71 class wxSpinCtrl;
72 class wxListBox;
73 class wxGrid;
74 class Shuttle;
75 class ReadOnlyText;
76 
77 class WrappedType;
78 
79 #ifdef __WXMAC__
80 
81 #include <wx/statbox.h> // to inherit
82 
83 class wxStaticBoxWrapper
84    : public wxStaticBox // inherit to get access to m_container
85 {
86 public:
87    template< typename... Args >
wxStaticBoxWrapper(Args &&...args)88    wxStaticBoxWrapper( Args &&...args )
89       : wxStaticBox( std::forward<Args>(args)... )
90    {
91       m_container.EnableSelfFocus();
92    }
93 };
94 
95 /// Fix a defect in TAB key navigation to sliders, known to happen in wxWidgets
96 /// 3.1.1 and maybe in earlier versions
97 class wxSliderWrapper : public wxSlider
98 {
99 public:
100    using wxSlider::wxSlider;
101    void SetFocus() override;
102 };
103 #else
104 using wxStaticBoxWrapper = wxStaticBox;
105 using wxSliderWrapper = wxSlider;
106 #endif
107 
108 namespace DialogDefinition {
109 
110 struct Item {
111    Item() = default;
112 
113    // Factory is a class that returns a value of some subclass of wxValidator
114    // We must wrap it in another lambda to allow the return type of f to
115    // vary, and avoid the "slicing" problem.
116    // (That is, std::function<wxValidator()> would not work.)
117    template<typename Factory>
ValidatorItem118    Item&& Validator( const Factory &f ) &&
119    {
120       mValidatorSetter = [f](wxWindow *p){ p->SetValidator(f()); };
121       return std::move(*this);
122    }
123 
124    // This allows further abbreviation of the previous:
125    template<typename V, typename... Args>
ValidatorItem126    Item&& Validator( Args&&... args ) &&
127    { return std::move(*this).Validator( [args...]{ return V( args... ); } ); }
128 
ToolTipItem129    Item&& ToolTip( const TranslatableString &tip ) &&
130    {
131       mToolTip = tip;
132       return std::move( *this );
133    }
134 
135    // Menu codes in the translation will be stripped
NameItem136    Item&& Name( const TranslatableString &name ) &&
137    {
138       mName = name;
139       return std::move( *this );
140    }
141 
142    // Append a space, then the translation of the given string, to control name
143    // (not the title or label:  this affects the screen reader behavior)
NameSuffixItem144    Item&& NameSuffix( const TranslatableString &suffix ) &&
145    {
146       mNameSuffix = suffix;
147       return std::move( *this );
148    }
149 
StyleItem150    Item&& Style( long style ) &&
151    {
152       miStyle = style;
153       return std::move( *this );
154    }
155 
156    // Only the last item specified as focused (if more than one) will be
157    Item&& Focus( bool focused = true ) &&
158    {
159       mFocused = focused;
160       return std::move( *this );
161    }
162 
163    Item&& Disable( bool disabled = true ) &&
164    {
165       mDisabled = disabled;
166       return std::move( *this );
167    }
168 
169    // Dispatch events from the control to the dialog
170    // The template type deduction ensures consistency between the argument type
171    // and the event type.  It does not (yet) ensure correctness of the type of
172    // the handler object.
173    template< typename Tag, typename Argument, typename Handler >
174    auto ConnectRoot(
175       wxEventTypeTag<Tag> eventType,
176       void (Handler::*func)(Argument&)
177    ) &&
178         -> typename std::enable_if<
179             std::is_base_of<Argument, Tag>::value,
180             Item&&
181         >::type
182    {
183       mRootConnections.push_back({
184          eventType,
185          (void(wxEvtHandler::*)(wxEvent&)) (
186             static_cast<void(wxEvtHandler::*)(Argument&)>( func )
187          )
188       });
189       return std::move( *this );
190    }
191 
MinSizeItem192    Item&& MinSize() && // set best size as min size
193    {
194       mUseBestSize = true;
195       return std::move ( *this );
196    }
197 
MinSizeItem198    Item&& MinSize( wxSize sz ) &&
199    {
200       mMinSize = sz; mHasMinSize = true;
201       return std::move ( *this );
202    }
203 
PositionItem204    Item&& Position( int flags ) &&
205    {
206       mWindowPositionFlags = flags;
207       return std::move( *this );
208    }
209 
SizeItem210    Item&& Size( wxSize size ) &&
211    {
212       mWindowSize = size;
213       return std::move( *this );
214    }
215 
216    std::function< void(wxWindow*) > mValidatorSetter;
217    TranslatableString mToolTip;
218    TranslatableString mName;
219    TranslatableString mNameSuffix;
220 
221    std::vector<std::pair<wxEventType, wxObjectEventFunction>> mRootConnections;
222 
223    long miStyle{};
224 
225    // Applies to windows, not to subsizers
226    int mWindowPositionFlags{ 0 };
227 
228    wxSize mWindowSize{};
229 
230    wxSize mMinSize{ -1, -1 };
231    bool mHasMinSize{ false };
232    bool mUseBestSize{ false };
233 
234    bool mFocused { false };
235    bool mDisabled { false };
236 
237 };
238 
239 }
240 
241 class AUDACITY_DLL_API ShuttleGuiBase /* not final */
242 {
243 public:
244    ShuttleGuiBase(
245       wxWindow * pParent,
246       teShuttleMode ShuttleMode,
247       bool vertical, // Choose layout direction of topmost level sizer
248       wxSize minSize
249    );
250    virtual ~ShuttleGuiBase();
251    void Init( bool vertical, wxSize minSize );
252    void ResetId();
253 
254 //-- Add functions.  These only add a widget or 2.
255    void HandleOptionality(const TranslatableString &Prompt);
256    void AddPrompt(const TranslatableString &Prompt, int wrapWidth = 0);
257    void AddUnits(const TranslatableString &Prompt, int wrapWidth = 0);
258    void AddTitle(const TranslatableString &Prompt, int wrapWidth = 0);
259    wxWindow * AddWindow(wxWindow* pWindow, int PositionFlags = wxALIGN_CENTRE);
260    wxSlider * AddSlider(
261       const TranslatableString &Prompt, int pos, int Max, int Min = 0);
262    wxSlider * AddVSlider(const TranslatableString &Prompt, int pos, int Max);
263    wxSpinCtrl * AddSpinCtrl(const TranslatableString &Prompt,
264       int Value, int Max, int Min);
265    wxTreeCtrl * AddTree();
266 
267    // Pass the same initValue to the sequence of calls to AddRadioButton and
268    // AddRadioButtonToGroup.
269    // The radio button is filled if selector == initValue
270    // Spoken name of the button defaults to the same as the prompt
271    // (after stripping menu codes):
272    wxRadioButton * AddRadioButton(
273       const TranslatableString & Prompt, int selector = 0, int initValue = 0 );
274    wxRadioButton * AddRadioButtonToGroup(
275       const TranslatableString & Prompt, int selector = 1, int initValue = 0 );
276 
277    // Only the last button specified as default (if more than one) will be
278    // Always ORs the flags with wxALL (which affects borders):
279    wxButton * AddButton(
280       const TranslatableString & Text, int PositionFlags = wxALIGN_CENTRE,
281       bool setDefault = false );
282    // Only the last button specified as default (if more than one) will be
283    // Always ORs the flags with wxALL (which affects borders):
284    wxBitmapButton * AddBitmapButton(
285       const wxBitmap &Bitmap, int PositionFlags = wxALIGN_CENTRE,
286       bool setDefault = false );
287    // When PositionFlags is 0, applies wxALL (which affects borders),
288    // and either wxALIGN_CENTER (if bCenter) or else wxEXPAND
289    wxStaticText * AddVariableText(
290       const TranslatableString &Str, bool bCenter = false,
291       int PositionFlags = 0, int wrapWidth = 0);
292    ReadOnlyText * AddReadOnlyText(
293       const TranslatableString &Caption,
294       const wxString &Value);
295    wxTextCtrl * AddTextBox(
296       const TranslatableString &Caption,
297       const wxString &Value, const int nChars);
298    wxTextCtrl * AddNumericTextBox(
299       const TranslatableString &Caption,
300       const wxString &Value, const int nChars);
301    wxTextCtrl * AddTextWindow(const wxString &Value);
302    wxListBox * AddListBox(const wxArrayStringEx &choices);
303 
304    struct ListControlColumn{
305       ListControlColumn(
306          const TranslatableString &h,
307          int f = wxLIST_FORMAT_LEFT, int w = wxLIST_AUTOSIZE)
headingListControlColumn308          : heading(h), format(f), width(w)
309       {}
310 
311       TranslatableString heading;
312       int format;
313       int width;
314    };
315    wxListCtrl * AddListControl(
316       std::initializer_list<const ListControlColumn> columns = {},
317       long listControlStyles = 0
318    );
319    wxListCtrl * AddListControlReportMode(
320       std::initializer_list<const ListControlColumn> columns = {},
321       long listControlStyles = 0
322    );
323 
324    wxGrid * AddGrid();
325    wxCheckBox * AddCheckBox( const TranslatableString &Prompt, bool Selected);
326    wxCheckBox * AddCheckBoxOnRight( const TranslatableString &Prompt, bool Selected);
327 
328    // These deleted overloads are meant to break compilation of old calls that
329    // passed literal "true" and "false" strings
330    wxCheckBox * AddCheckBox( const TranslatableString &Prompt, const wxChar *) = delete;
331    wxCheckBox * AddCheckBox( const TranslatableString &Prompt, const char *) = delete;
332    wxCheckBox * AddCheckBoxOnRight( const TranslatableString &Prompt, const wxChar *) = delete;
333    wxCheckBox * AddCheckBoxOnRight( const TranslatableString &Prompt, const char *) = delete;
334 
335    wxComboBox * AddCombo( const TranslatableString &Prompt,
336       const wxString &Selected, const wxArrayStringEx & choices );
337    wxChoice   * AddChoice( const TranslatableString &Prompt,
338       const TranslatableStrings &choices, int Selected = -1 );
339    wxChoice   * AddChoice( const TranslatableString &Prompt,
340       const TranslatableStrings &choices, const TranslatableString &selected );
341    void AddIcon( wxBitmap * pBmp);
342    void AddFixedText(
343       const TranslatableString & Str, bool bCenter = false, int wrapWidth = 0 );
344    void AddConstTextBox(
345       const TranslatableString &Caption, const TranslatableString & Value );
346 
347 //-- Start and end functions.  These are used for sizer, or other window containers
348 //   and create the appropriate widget.
349    void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1);
350    void EndHorizontalLay();
351 
352    void StartVerticalLay(int iProp=1);
353    void StartVerticalLay(int PositionFlags, int iProp);
354    void EndVerticalLay();
355 
356    void StartWrapLay(int PositionFlags=wxEXPAND, int iProp = 0);
357    void EndWrapLay();
358 
359    wxScrolledWindow * StartScroller(int iStyle=0);
360    void EndScroller();
361    wxPanel * StartPanel(int iStyle=0);
362    void EndPanel();
363    void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT);
364    void EndMultiColumn();
365 
StartTwoColumn()366    void StartTwoColumn() {StartMultiColumn(2);};
EndTwoColumn()367    void EndTwoColumn() {EndMultiColumn();};
StartThreeColumn()368    void StartThreeColumn(){StartMultiColumn(3);};
EndThreeColumn()369    void EndThreeColumn(){EndMultiColumn();};
370 
371    wxStaticBox * StartStatic( const TranslatableString & Str, int iProp=0 );
372    void EndStatic();
373 
374    wxNotebook * StartNotebook();
375    void EndNotebook();
376 
377    wxSimplebook * StartSimplebook();
378    void EndSimplebook();
379 
380    // Use within any kind of book control:
381    // IDs of notebook pages cannot be chosen by the caller
382    wxNotebookPage * StartNotebookPage( const TranslatableString & Name );
383 
384    void EndNotebookPage();
385 
386    wxPanel * StartInvisiblePanel();
387    void EndInvisiblePanel();
388 
389    // SettingName is a key in Preferences.
390    void StartRadioButtonGroup( const ChoiceSetting &Setting );
391    void EndRadioButtonGroup();
392 
393    bool DoStep( int iStep );
394    int TranslateToIndex( const wxString &Value, const wxArrayStringEx &Choices );
395    wxString TranslateFromIndex( const int nIn, const wxArrayStringEx &Choices );
396 
397 //-- Tie functions both add controls and also read/write to them.
398 
399    wxTextCtrl * TieTextBox(
400       const TranslatableString &Caption, wxString & Value, const int nChars=0);
401    wxTextCtrl * TieTextBox(
402       const TranslatableString &Prompt, int &Selected, const int nChars=0);
403    wxTextCtrl * TieTextBox(
404       const TranslatableString &Prompt, double &Value, const int nChars=0);
405 
406    wxTextCtrl * TieNumericTextBox( const TranslatableString &Prompt, int &Value, const int nChars=0);
407    wxTextCtrl * TieNumericTextBox( const TranslatableString &Prompt, double &Value, const int nChars=0);
408 
409    wxCheckBox * TieCheckBox( const TranslatableString &Prompt, bool & Var );
410    wxCheckBox * TieCheckBoxOnRight( const TranslatableString & Prompt, bool & Var );
411 
412    wxChoice * TieChoice(
413       const TranslatableString &Prompt,
414       TranslatableString &Selected, const TranslatableStrings &choices );
415    wxChoice * TieChoice(
416       const TranslatableString &Prompt, int &Selected, const TranslatableStrings &choices );
417 
418    wxSlider * TieSlider(
419       const TranslatableString &Prompt,
420       int &pos, const int max, const int min = 0);
421    wxSlider * TieSlider(
422       const TranslatableString &Prompt,
423       double &pos, const double max, const double min = 0.0);
424    wxSlider * TieSlider(
425       const TranslatableString &Prompt,
426       float &pos, const float fMin, const float fMax);
427    wxSlider * TieVSlider(
428       const TranslatableString &Prompt,
429       float &pos, const float fMin, const float fMax);
430 
431    // Must be called between a StartRadioButtonGroup / EndRadioButtonGroup pair,
432    // and as many times as there are values in the enumeration.
433    wxRadioButton * TieRadioButton();
434 
435    wxSpinCtrl * TieSpinCtrl( const TranslatableString &Prompt,
436       int &Value, const int max, const int min = 0 );
437 
438 
439 //-- Variants of the standard Tie functions which do two step exchange in one go
440 // Note that unlike the other Tie functions, ALL the arguments are const.
441 // That's because the data is being exchanged between the dialog and mpShuttle
442 // so it doesn't need an argument that is writeable.
443    virtual wxCheckBox * TieCheckBox(
444       const TranslatableString &Prompt,
445       const BoolSetting &Setting);
446    virtual wxCheckBox * TieCheckBoxOnRight(
447       const TranslatableString &Prompt,
448       const BoolSetting &Setting);
449 
450    virtual wxChoice *TieChoice(
451       const TranslatableString &Prompt,
452       const ChoiceSetting &choiceSetting );
453 
454    // This overload presents what is really a numerical setting as a choice among
455    // commonly used values, but the choice is not necessarily exhaustive.
456    // This behaves just like the previous for building dialogs, but the
457    // behavior is different when the call is intercepted for purposes of
458    // emitting scripting information about Preferences.
459    virtual wxChoice * TieNumberAsChoice(
460       const TranslatableString &Prompt,
461       const IntSetting &Setting,
462       const TranslatableStrings & Choices,
463       const std::vector<int> * pInternalChoices = nullptr,
464       int iNoMatchSelector = 0 );
465 
466    virtual wxTextCtrl * TieTextBox(
467       const TranslatableString &Prompt,
468       const StringSetting &Setting,
469       const int nChars);
470    virtual wxTextCtrl * TieIntegerTextBox(
471       const TranslatableString & Prompt,
472       const IntSetting &Setting,
473       const int nChars);
474    virtual wxTextCtrl * TieNumericTextBox(
475       const TranslatableString & Prompt,
476       const DoubleSetting &Setting,
477       const int nChars);
478    virtual wxSlider * TieSlider(
479       const TranslatableString & Prompt,
480       const IntSetting &Setting,
481       const int max,
482       const int min = 0);
483    virtual wxSpinCtrl * TieSpinCtrl(
484       const TranslatableString &Prompt,
485       const IntSetting &Setting,
486       const int max,
487       const int min);
488 //-- End of variants.
SetBorder(int Border)489    void SetBorder( int Border ) {miBorder = Border;};
490    int GetBorder() const noexcept;
SetSizerProportion(int iProp)491    void SetSizerProportion( int iProp ) {miSizerProp = iProp;};
492    void SetStretchyCol( int i );
493    void SetStretchyRow( int i );
494 
495 //--Some Additions since June 2007 that don't fit in elsewhere...
GetParent()496    wxWindow * GetParent()
497    {
498       // This assertion justifies the use of safenew in many places where GetParent()
499       // is used to construct a window
500       wxASSERT(mpParent != NULL);
501       return mpParent;
502    }
503    ShuttleGuiBase & Prop( int iProp );
504    void UseUpId();
505 
GetSizer()506    wxSizer * GetSizer() {return mpSizer;}
507 
508    static void ApplyItem( int step, const DialogDefinition::Item &item,
509       wxWindow *pWind, wxWindow *pDlg );
510 
511 protected:
512    void SetProportions( int Default );
513    void PushSizer();
514    void PopSizer();
515 
516    void UpdateSizersCore( bool bPrepend, int Flags, bool prompt = false );
517    void UpdateSizers();
518    void UpdateSizersC();
519    void UpdateSizersAtStart();
520 
521    long GetStyle( long Style );
522 
523 private:
524    void DoInsertListColumns(
525       wxListCtrl *pListCtrl,
526       long listControlStyles,
527       std::initializer_list<const ListControlColumn> columns );
528 
529 protected:
530    wxWindow *const mpDlg;
531    wxSizer * pSizerStack[ nMaxNestedSizers ];
532 
533    std::unique_ptr<Shuttle> mpShuttle; /*! Controls source/destination of shuttled data.  You can
534    leave this NULL if you are shuttling to variables */
535    int miNoMatchSelector; //! Used in choices to determine which item to use on no match.
536 
537    teShuttleMode mShuttleMode;
538 
539    int miSizerProp;
540    int mSizerDepth;
541    int miBorder;
542    int miProp;
543 
544    // See UseUpId() for explanation of these three.
545    int miId;
546    int miIdNext;
547    int miIdSetByUser;
548    // Proportion set by user rather than default.
549    int miPropSetByUser;
550 
551    bool * mpbOptionalFlag;
552 
553    std::unique_ptr<wxSizer> mpSubSizer;
554    wxSizer * mpSizer;
555    wxWindow * mpParent;
556    wxWindow * mpWind;
557 
558 private:
559    void DoDataShuttle( const wxString &Name, WrappedType & WrappedRef );
560    wxCheckBox * DoTieCheckBoxOnRight( const TranslatableString & Prompt, WrappedType & WrappedRef );
561    wxTextCtrl * DoTieTextBox(
562       const TranslatableString &Prompt,
563       WrappedType &  WrappedRef, const int nChars);
564    wxTextCtrl * DoTieNumericTextBox(
565       const TranslatableString &Prompt, WrappedType &  WrappedRef, const int nChars);
566    wxCheckBox * DoTieCheckBox( const TranslatableString &Prompt, WrappedType & WrappedRef );
567    wxSlider * DoTieSlider(
568       const TranslatableString &Prompt,
569       WrappedType & WrappedRef, const int max, const int min = 0 );
570    wxSpinCtrl * DoTieSpinCtrl( const TranslatableString &Prompt,
571       WrappedType & WrappedRef, const int max, const int min = 0 );
572 
573    std::vector<EnumValueSymbol> mRadioSymbols;
574    wxString mRadioSettingName; /// The setting controlled by a group.
575    Optional<WrappedType> mRadioValue;  /// The wrapped value associated with the active radio button.
576    int mRadioCount;       /// The index of this radio item.  -1 for none.
577    wxString mRadioValueString; /// Unwrapped string value.
578    wxRadioButton * DoAddRadioButton(
579       const TranslatableString &Prompt, int style, int selector, int initValue);
580 
581 protected:
582    DialogDefinition::Item mItem;
583 };
584 
585 // A rarely used helper function that sets a pointer
586 // ONLY if the value it is to be set to is non NULL.
587 extern void SetIfCreated( wxChoice *&Var, wxChoice * Val );
588 extern void SetIfCreated( wxTextCtrl *&Var, wxTextCtrl * Val );
589 extern void SetIfCreated( wxStaticText *&Var, wxStaticText * Val );
590 
591 class GuiWaveTrack;
592 class AttachableScrollBar;
593 class ViewInfo;
594 
595 #include <wx/defs.h>  // to get wxSB_HORIZONTAL
596 
597 // CreateStdButtonSizer defs...should probably move to widgets subdir
598 enum
599 {
600    eOkButton      = 0x0001,
601    eCancelButton  = 0x0002,
602    eYesButton     = 0x0004,
603    eNoButton      = 0x0008,
604    eHelpButton    = 0x0010,
605    ePreviewButton = 0x0020,
606    eDebugButton   = 0x0040,
607    eSettingsButton= 0x0080,
608    ePreviewDryButton  = 0x0100,
609    eApplyButton   = 0x0200,
610    eCloseButton   = 0x0400,
611 };
612 
613 enum
614 {
615    // ePreviewID     = wxID_LOWEST - 1,
616    // But there is a wxID_PREVIEW
617    ePreviewID     = wxID_PREVIEW,
618 
619    eDebugID       = wxID_LOWEST - 2,
620    eSettingsID    = wxID_LOWEST - 3,
621    ePreviewDryID  = wxID_LOWEST - 4,
622    eCloseID       = wxID_CANCEL
623 };
624 
625 AUDACITY_DLL_API std::unique_ptr<wxSizer> CreateStdButtonSizer( wxWindow *parent,
626                                long buttons = eOkButton | eCancelButton,
627                                wxWindow *extra = NULL );
628 
629 // ShuttleGui extends ShuttleGuiBase with Audacity specific extensions.
630 class AUDACITY_DLL_API ShuttleGui /* not final */ : public ShuttleGuiBase
631 {
632 public:
633    ShuttleGui(
634       wxWindow * pParent, teShuttleMode ShuttleMode,
635       bool vertical = true, // Choose layout direction of topmost level sizer
636       wxSize minSize = { 250, 100 }
637    );
638    ~ShuttleGui(void);
639 public:
640    ShuttleGui & Optional( bool & bVar );
641    ShuttleGui & Id(int id );
642 
643    // Only the last item specified as focused (if more than one) will be
644    ShuttleGui & Focus( bool focused = true )
645    {
646       std::move( mItem ).Focus( focused );
647       return *this;
648    }
649 
650    ShuttleGui &Disable( bool disabled = true )
651    {
652       std::move( mItem ).Disable( disabled );
653       return *this;
654    }
655 
ToolTip(const TranslatableString & tip)656    ShuttleGui & ToolTip( const TranslatableString &tip )
657    {
658       std::move( mItem ).ToolTip( tip );
659       return *this;
660    }
661 
662    // Menu codes in the translation will be stripped
Name(const TranslatableString & name)663    ShuttleGui & Name( const TranslatableString &name )
664    {
665       std::move( mItem ).Name( name );
666       return *this;
667    }
668 
669    // Append a space, then the translation of the given string, to control name
670    // (not the title or label:  this affects the screen reader behavior)
NameSuffix(const TranslatableString & suffix)671    ShuttleGui & NameSuffix( const TranslatableString &suffix )
672    {
673       std::move( mItem ).NameSuffix( suffix );
674       return *this;
675    }
676 
677    template<typename Factory>
Validator(const Factory & f)678    ShuttleGui& Validator( const Factory &f )
679    {
680       if ( GetMode() == eIsCreating )
681          std::move( mItem ).Validator( f );
682       return *this;
683    }
684 
685    // This allows further abbreviation of the previous:
686    template<typename V, typename...Args>
Validator(Args &&...args)687    ShuttleGui& Validator( Args&& ...args )
688    {
689       if ( GetMode() == eIsCreating )
690          std::move( mItem ).Validator<V>( std::forward<Args>(args)... );
691       return *this;
692    }
693 
694    // Dispatch events from the control to the dialog
695    // The template type deduction ensures consistency between the argument type
696    // and the event type.  It does not (yet) ensure correctness of the type of
697    // the handler object.
698    template< typename Tag, typename Argument, typename Handler >
699    auto ConnectRoot(
700       wxEventTypeTag<Tag> eventType,
701       void (Handler::*func)(Argument&)
702    )
703         -> typename std::enable_if<
704             std::is_base_of<Argument, Tag>::value,
705             ShuttleGui&
706         >::type
707    {
708       std::move( mItem ).ConnectRoot( eventType, func );
709       return *this;
710    }
711 
Position(int flags)712    ShuttleGui & Position( int flags )
713    {
714       std::move( mItem ).Position( flags );
715       return *this;
716    }
717 
Size(wxSize size)718    ShuttleGui & Size( wxSize size )
719    {
720       std::move( mItem ).Size( size );
721       return *this;
722    }
723 
724    // Prop() sets the proportion value, defined as in wxSizer::Add().
Prop(int iProp)725    ShuttleGui & Prop( int iProp ){ ShuttleGuiBase::Prop(iProp); return *this;}; // Has to be here too, to return a ShuttleGui and not a ShuttleGuiBase.
726 
Style(long iStyle)727    ShuttleGui & Style( long iStyle )
728    {
729       std::move( mItem ).Style( iStyle );
730       return *this;
731    }
732 
MinSize()733    ShuttleGui &MinSize() // set best size as min size
734       { std::move( mItem ).MinSize(); return *this; }
MinSize(wxSize sz)735    ShuttleGui &MinSize( wxSize sz )
736       { std::move( mItem ).MinSize( sz ); return *this; }
737 
738    // The first of these buttons, if any, that is included will be default:
739    // Apply, Yes, OK
740    void AddStandardButtons(
741       long buttons = eOkButton | eCancelButton, wxWindow *extra = NULL );
742 
743    wxSizerItem * AddSpace( int width, int height, int prop = 0 );
AddSpace(int size)744    wxSizerItem * AddSpace( int size ) { return AddSpace( size, size ); };
745 
746    // Calculate width of a choice control adequate for the items, maybe after
747    // the dialog is created but the items change.
748    static void SetMinSize( wxWindow *window, const TranslatableStrings & items );
749    static void SetMinSize( wxWindow *window, const wxArrayStringEx & items );
750   // static void SetMinSize( wxWindow *window, const std::vector<int> & items );
751 
GetMode()752    teShuttleMode GetMode() { return  mShuttleMode; };
753 };
754 
755 //! Convenience function often useful when adding choice controls
756 AUDACITY_DLL_API TranslatableStrings Msgids(
757    const EnumValueSymbol strings[], size_t nStrings);
758 
759 //! Convenience function often useful when adding choice controls
760 AUDACITY_DLL_API TranslatableStrings Msgids( const std::vector<EnumValueSymbol> &strings );
761 
762 #endif
763