Skip silent sources on session-archive -- fixes #7699
[ardour.git] / gtk2_ardour / option_editor.h
1 /*
2     Copyright (C) 2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifndef __gtk_ardour_option_editor_h__
20 #define __gtk_ardour_option_editor_h__
21
22 #include <gtkmm/checkbutton.h>
23 #include <gtkmm/comboboxtext.h>
24 #include <gtkmm/filechooserbutton.h>
25 #include <gtkmm/label.h>
26 #include <gtkmm/notebook.h>
27 #include <gtkmm/scale.h>
28 #include <gtkmm/spinbutton.h>
29 #include <gtkmm/table.h>
30 #include <gtkmm/treestore.h>
31 #include <gtkmm/treeview.h>
32 #include <gtkmm/window.h>
33
34 #include "widgets/slider_controller.h"
35
36 #include "ardour_window.h"
37 #include "audio_clock.h"
38 #include "ardour/types.h"
39
40 /** @file option_editor.h
41  *  @brief Base class for option editing dialog boxes.
42  *
43  *  Code to provided the basis for dialogs which allow the user to edit options
44  *  from an ARDOUR::Configuration class.
45  *
46  *  The idea is that we have an OptionEditor class which is the dialog box.
47  *  This is essentially a GTK Notebook.  OptionEditorComponent objects can
48  *  then be added to the OptionEditor, and these components are arranged on
49  *  the pages of the Notebook.  There is also an OptionEditorComponent hierarchy
50  *  here, providing things like boolean and combobox option components.
51  *
52  *  It is intended that OptionEditor be subclassed to implement a particular
53  *  options dialog.
54  */
55
56 namespace PBD {
57         class Configuration;
58 }
59
60 class OptionEditorPage;
61
62 /** Base class for components of an OptionEditor dialog */
63 class OptionEditorComponent
64 {
65 public:
66         virtual ~OptionEditorComponent() {}
67
68         /** Called when a configuration parameter's value has changed.
69          *  @param p parameter name
70          */
71         virtual void parameter_changed (std::string const & p) = 0;
72
73         /** Called to instruct the object to set its UI state from the configuration */
74         virtual void set_state_from_config () = 0;
75
76         /** Called to instruct the object to add itself to an OptionEditorPage */
77         virtual void add_to_page (OptionEditorPage *) = 0;
78
79         void add_widget_to_page (OptionEditorPage*, Gtk::Widget*);
80         void add_widgets_to_page (OptionEditorPage*, Gtk::Widget*, Gtk::Widget*, bool expand = true);
81
82         void set_note (std::string const &);
83
84         virtual Gtk::Widget& tip_widget() = 0;
85
86 protected:
87         void maybe_add_note (OptionEditorPage *, int);
88
89         std::string _note;
90 };
91
92 /** A component which provides a subheading within the dialog */
93 class OptionEditorHeading : public OptionEditorComponent
94 {
95 public:
96         OptionEditorHeading (std::string const &);
97
98         void parameter_changed (std::string const &) {}
99         void set_state_from_config () {}
100         void add_to_page (OptionEditorPage *);
101
102         Gtk::Widget& tip_widget() { return *_label; }
103
104 private:
105         Gtk::Label* _label; ///< the label used for the heading
106 };
107
108 /** Expanding layout helper to push elements to the left on a single column page  */
109 class OptionEditorBlank : public OptionEditorComponent
110 {
111 public:
112         OptionEditorBlank () {}
113
114         void parameter_changed (std::string const &) {}
115         void set_state_from_config () {}
116         void add_to_page (OptionEditorPage *);
117
118         Gtk::Widget& tip_widget() { return _dummy; }
119
120 private:
121         Gtk::EventBox _dummy;
122 };
123
124 class RcConfigDisplay : public OptionEditorComponent
125 {
126 public:
127         RcConfigDisplay (std::string const &, std::string const &, sigc::slot<std::string>, char s = '\0');
128         void add_to_page (OptionEditorPage *);
129         void parameter_changed (std::string const & p);
130         void set_state_from_config ();
131         Gtk::Widget& tip_widget() { return *_info; }
132 protected:
133         sigc::slot<std::string> _get;
134         Gtk::Label* _label;
135         Gtk::Label* _info;
136         std::string _id;
137         char _sep;
138 };
139
140 class RcActionButton : public OptionEditorComponent
141 {
142 public:
143         RcActionButton (std::string const & t, const Glib::SignalProxy0< void >::SlotType & slot, std::string const & l = "");
144         void add_to_page (OptionEditorPage *);
145
146         void parameter_changed (std::string const & p) {}
147         void set_state_from_config () {}
148         Gtk::Widget& tip_widget() { return *_button; }
149
150 protected:
151         Gtk::Button* _button;
152         Gtk::Label* _label;
153         std::string _name;
154 };
155
156 /** Base class for components which provide UI to change an option */
157 class Option : public OptionEditorComponent
158 {
159 public:
160         /** Construct an Option.
161          *  @param i Option id (e.g. "plugins-stop-with-transport")
162          *  @param n User-visible name (e.g. "Stop plugins when the transport is stopped")
163          */
164         Option (std::string const & i,
165                 std::string const & n
166                 )
167                 : _id (i),
168                   _name (n)
169         {}
170
171         void parameter_changed (std::string const & p)
172         {
173                 if (p == _id) {
174                         set_state_from_config ();
175                 }
176         }
177
178         virtual void set_state_from_config () = 0;
179         virtual void add_to_page (OptionEditorPage*) = 0;
180
181         std::string id () const {
182                 return _id;
183         }
184
185 protected:
186         std::string _id;
187         std::string _name;
188 };
189
190 /** Component which provides the UI to handle a boolean option using a GTK CheckButton */
191 class BoolOption : public Option
192 {
193 public:
194         BoolOption (std::string const &, std::string const &, sigc::slot<bool>, sigc::slot<bool, bool>);
195         void set_state_from_config ();
196         void add_to_page (OptionEditorPage*);
197
198         void set_sensitive (bool yn) {
199                 _button->set_sensitive (yn);
200         }
201
202         Gtk::Widget& tip_widget() { return *_button; }
203
204 protected:
205         virtual void toggled ();
206
207         sigc::slot<bool>       _get; ///< slot to get the configuration variable's value
208         sigc::slot<bool, bool> _set;  ///< slot to set the configuration variable's value
209         Gtk::CheckButton*      _button; ///< UI button
210         Gtk::Label*            _label; ///< label for button, so we can use markup
211 };
212
213 class RouteDisplayBoolOption : public BoolOption
214 {
215 public:
216         RouteDisplayBoolOption (std::string const &, std::string const &, sigc::slot<bool>, sigc::slot<bool, bool>);
217
218 protected:
219         virtual void toggled ();
220 };
221
222 /** Component which allows to add any GTK Widget - intended for single buttons and custom stateless objects */
223 class FooOption : public OptionEditorComponent
224 {
225 public:
226         FooOption (Gtk::Widget *w) : _w (w) {}
227
228         void add_to_page (OptionEditorPage* p) {
229                 add_widget_to_page (p, _w);
230         }
231
232         Gtk::Widget& tip_widget() { return *_w; }
233         void set_state_from_config () {}
234         void parameter_changed (std::string const &) {}
235 private:
236         Gtk::Widget *_w;
237 };
238
239 /** Component which provides the UI to handle a string option using a GTK Entry */
240 class EntryOption : public Option
241 {
242 public:
243         EntryOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
244         void set_state_from_config ();
245         void add_to_page (OptionEditorPage*);
246         void set_sensitive (bool);
247         void set_invalid_chars (std::string i) { _invalid = i; }
248
249         Gtk::Widget& tip_widget() { return *_entry; }
250
251 private:
252         void activated ();
253         bool focus_out (GdkEventFocus*);
254         void filter_text (const Glib::ustring&, int*);
255
256         sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
257         sigc::slot<bool, std::string> _set;  ///< slot to set the configuration variable's value
258         Gtk::Label* _label; ///< UI label
259         Gtk::Entry* _entry; ///< UI entry
260         std::string _invalid;
261 };
262
263
264 /** Component which provides the UI to handle an enumerated option using a GTK ComboBox.
265  *  The template parameter is the enumeration.
266  */
267 template <class T>
268 class ComboOption : public Option
269 {
270 public:
271         /** Construct an ComboOption.
272          *  @param i id
273          *  @param n User-visible name.
274          *  @param g Slot to get the variable's value.
275          *  @param s Slot to set the variable's value.
276          */
277         ComboOption (
278                 std::string const & i,
279                 std::string const & n,
280                 sigc::slot<T> g,
281                 sigc::slot<bool, T> s
282                 )
283                 : Option (i, n)
284                 , _get (g)
285                 , _set (s)
286         {
287                 _label = Gtk::manage (new Gtk::Label (n + ":"));
288                 _label->set_alignment (0, 0.5);
289                 _combo = Gtk::manage (new Gtk::ComboBoxText);
290                 _combo->signal_changed().connect (sigc::mem_fun (*this, &ComboOption::changed));
291         }
292
293         void set_state_from_config ()
294         {
295                 uint32_t r = 0;
296                 while (r < _options.size() && _get () != _options[r]) {
297                         ++r;
298                 }
299
300                 if (r < _options.size()) {
301                         _combo->set_active (r);
302                 }
303         }
304
305         void add_to_page (OptionEditorPage* p)
306         {
307                 add_widgets_to_page (p, _label, _combo);
308         }
309
310         /** Add an allowed value for this option.
311          *  @param e Enumeration.
312          *  @param o User-visible name for this value.
313          */
314         void add (T e, std::string const & o)
315         {
316                 _options.push_back (e);
317                 _combo->append_text (o);
318         }
319
320         void clear ()
321         {
322                 _combo->clear_items();
323                 _options.clear ();
324         }
325
326         void changed ()
327         {
328                 uint32_t const r = _combo->get_active_row_number ();
329                 if (r < _options.size()) {
330                         _set (_options[r]);
331                 }
332         }
333         void set_sensitive (bool yn)
334         {
335                 _combo->set_sensitive (yn);
336         }
337
338         Gtk::Widget& tip_widget() { return *_combo; }
339
340 private:
341         sigc::slot<T> _get;
342         sigc::slot<bool, T> _set;
343         Gtk::Label* _label;
344         Gtk::ComboBoxText* _combo;
345         std::vector<T> _options;
346 };
347
348
349 /** Component which provides the UI for a GTK HScale.
350  */
351 class HSliderOption : public Option
352 {
353 public:
354         HSliderOption (
355                         std::string const& i,
356                         std::string const& n,
357                         sigc::slot<float> g,
358                         sigc::slot<bool, float> s,
359                         double lower, double upper,
360                         double step_increment = 1,
361                         double page_increment = 10,
362                         double mult = 1.0,
363                         bool logarithmic = false
364                 );
365
366         void set_state_from_config ();
367         virtual void changed ();
368         void add_to_page (OptionEditorPage* p);
369         void set_sensitive (bool yn);
370
371         Gtk::Widget& tip_widget() { return _hscale; }
372         Gtk::HScale& scale() { return _hscale; }
373
374 protected:
375         sigc::slot<float> _get;
376         sigc::slot<bool, float> _set;
377         Gtk::Adjustment _adj;
378         Gtk::HScale _hscale;
379         Gtk::Label _label;
380         double _mult;
381         bool _log;
382 };
383
384
385 /** Component which provides the UI to handle an enumerated option using a GTK ComboBox.
386  *  The template parameter is the enumeration.
387  */
388 class ComboStringOption : public Option
389 {
390 public:
391         /** Construct an ComboOption.
392          *  @param i id
393          *  @param n User-visible name.
394          *  @param g Slot to get the variable's value.
395          *  @param s Slot to set the variable's value.
396          */
397         ComboStringOption (
398                 std::string const & i,
399                 std::string const & n,
400                 sigc::slot<std::string> g,
401                 sigc::slot<bool, std::string> s
402                 );
403
404         void set_state_from_config ();
405         void add_to_page (OptionEditorPage* p);
406
407         /** Set the allowed strings for this option
408          *  @param strings a vector of allowed strings
409          */
410         void set_popdown_strings (const std::vector<std::string>& strings);
411
412         void clear ();
413         void changed ();
414         void set_sensitive (bool yn);
415
416         Gtk::Widget& tip_widget() { return *_combo; }
417
418 private:
419         sigc::slot<std::string> _get;
420         sigc::slot<bool, std::string> _set;
421         Gtk::Label* _label;
422         Gtk::ComboBoxText* _combo;
423 };
424
425
426 /** Component which provides the UI to handle a boolean option which needs
427  *  to be represented as a ComboBox to be clear to the user.
428  */
429 class BoolComboOption : public Option
430 {
431 public:
432         BoolComboOption (
433                 std::string const &,
434                 std::string const &,
435                 std::string const &,
436                 std::string const &,
437                 sigc::slot<bool>,
438                 sigc::slot<bool, bool>
439                 );
440
441         void set_state_from_config ();
442         void add_to_page (OptionEditorPage *);
443         void changed ();
444         void set_sensitive (bool);
445
446         Gtk::Widget& tip_widget() { return *_combo; }
447
448 private:
449         sigc::slot<bool> _get;
450         sigc::slot<bool, bool> _set;
451         Gtk::Label* _label;
452         Gtk::ComboBoxText* _combo;
453 };
454
455
456 /** Component which provides the UI to handle an numeric option using a GTK SpinButton */
457 template <class T>
458 class SpinOption : public Option
459 {
460 public:
461         /** Construct an SpinOption.
462          *  @param i id
463          *  @param n User-visible name.
464          *  @param g Slot to get the variable's value.
465          *  @param s Slot to set the variable's value.
466          *  @param min Variable minimum value.
467          *  @param max Variable maximum value.
468          *  @param step Step for the spin button.
469          *  @param page Page step for the spin button.
470          *  @param unit Unit name.
471          *  @param scale Scaling factor (such that for a value x in the spinbutton, x * scale is written to the config)
472          *  @param digits Number of decimal digits to show.
473          */
474         SpinOption (
475                 std::string const & i,
476                 std::string const & n,
477                 sigc::slot<T> g,
478                 sigc::slot<bool, T> s,
479                 T min,
480                 T max,
481                 T step,
482                 T page,
483                 std::string const & unit = "",
484                 float scale = 1,
485                 unsigned digits = 0
486                 )
487                 : Option (i, n)
488                 , _get (g)
489                 , _set (s)
490                 , _scale (scale)
491         {
492                 _label = Gtk::manage (new Gtk::Label (n + ":"));
493                 _label->set_alignment (0, 0.5);
494
495                 _spin = Gtk::manage (new Gtk::SpinButton);
496                 _spin->set_range (min, max);
497                 _spin->set_increments (step, page);
498                 _spin->set_digits(digits);
499
500                 _box = Gtk::manage (new Gtk::HBox);
501                 _box->pack_start (*_spin, true, true);
502                 _box->set_spacing (4);
503                 if (unit.length()) {
504                         _box->pack_start (*Gtk::manage (new Gtk::Label (unit)), false, false);
505                 }
506
507                 _spin->signal_value_changed().connect (sigc::mem_fun (*this, &SpinOption::changed));
508         }
509
510         void set_state_from_config ()
511         {
512                 _spin->set_value (_get () / _scale);
513         }
514
515         void add_to_page (OptionEditorPage* p)
516         {
517                 add_widgets_to_page (p, _label, _box, false);
518         }
519
520         void changed ()
521         {
522                 _set (static_cast<T> (_spin->get_value ()) * _scale);
523         }
524
525         Gtk::Widget& tip_widget() { return *_spin; }
526
527 private:
528         sigc::slot<T> _get;
529         sigc::slot<bool, T> _set;
530         float _scale;
531         Gtk::Label* _label;
532         Gtk::HBox* _box;
533         Gtk::SpinButton* _spin;
534 };
535
536 class FaderOption : public Option
537 {
538 public:
539
540         FaderOption (std::string const &, std::string const &, sigc::slot<ARDOUR::gain_t> g, sigc::slot<bool, ARDOUR::gain_t> s);
541         void set_state_from_config ();
542         void add_to_page (OptionEditorPage *);
543
544         Gtk::Widget& tip_widget() { return *_db_slider; }
545
546 private:
547         void db_changed ();
548         void on_activate ();
549         bool on_key_press (GdkEventKey* ev);
550
551         Gtk::Adjustment _db_adjustment;
552         ArdourWidgets::HSliderController* _db_slider;
553         Gtk::Entry _db_display;
554         Gtk::Label _label;
555         Gtk::HBox _box;
556         Gtk::VBox _fader_centering_box;
557         sigc::slot<ARDOUR::gain_t> _get;
558         sigc::slot<bool, ARDOUR::gain_t> _set;
559 };
560
561 class WidgetOption : public Option
562 {
563   public:
564         WidgetOption (std::string const & i, std::string const & n, Gtk::Widget& w);
565
566         void add_to_page (OptionEditorPage*);
567         void parameter_changed (std::string const &) {}
568         void set_state_from_config () {}
569
570         Gtk::Widget& tip_widget() { return *_widget; }
571
572   private:
573         Gtk::Widget* _widget;
574 };
575
576 class ClockOption : public Option
577 {
578 public:
579         ClockOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
580         void set_state_from_config ();
581         void add_to_page (OptionEditorPage *);
582         void set_session (ARDOUR::Session *);
583
584         Gtk::Widget& tip_widget() { return _clock; }
585         AudioClock& clock() { return _clock; }
586
587 private:
588         void save_clock_time ();
589         Gtk::Label _label;
590         AudioClock _clock;
591         sigc::slot<std::string> _get;
592         sigc::slot<bool, std::string> _set;
593         ARDOUR::Session *_session;
594 };
595
596 class DirectoryOption : public Option
597 {
598 public:
599         DirectoryOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
600
601         void set_state_from_config ();
602         void add_to_page (OptionEditorPage *);
603
604         Gtk::Widget& tip_widget() { return _file_chooser; }
605
606 private:
607         void selection_changed ();
608
609         sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
610         sigc::slot<bool, std::string> _set;  ///< slot to set the configuration variable's value
611         Gtk::FileChooserButton _file_chooser;
612 };
613
614 /** Class to represent a single page in an OptionEditor's notebook.
615  *  Pages are laid out using a 3-column table; the 1st column is used
616  *  to indent non-headings, and the 2nd and 3rd for actual content.
617  */
618 class OptionEditorPage
619 {
620 public:
621         OptionEditorPage (Gtk::Notebook&, std::string const &);
622         OptionEditorPage ();
623
624         Gtk::VBox box;
625         Gtk::Table table;
626         std::list<OptionEditorComponent*> components;
627
628 private:
629         void init ();
630 };
631
632 class OptionEditorMiniPage : public OptionEditorComponent, public OptionEditorPage
633 {
634 public:
635         OptionEditorMiniPage ()
636         {
637                 box.pack_start (table, false, false);
638                 box.set_border_width (0);
639         }
640
641         void parameter_changed (std::string const &) = 0;
642         void set_state_from_config () = 0;
643         virtual void add_to_page (OptionEditorPage*);
644
645         Gtk::Widget& tip_widget() { return *table.children().front().get_widget(); }
646 };
647
648 /** The OptionEditor dialog base class */
649 class OptionEditor : virtual public sigc::trackable
650 {
651 public:
652         OptionEditor (PBD::Configuration *);
653         virtual ~OptionEditor ();
654
655         void add_option (std::string const &, OptionEditorComponent *);
656         void add_page (std::string const &, Gtk::Widget& page_widget);
657
658         void set_current_page (std::string const &);
659
660 protected:
661         virtual void parameter_changed (std::string const &);
662
663         PBD::Configuration* _config;
664         Gtk::Notebook& notebook() { return _notebook; }
665         Gtk::TreeView& treeview() { return option_treeview; }
666
667         class OptionColumns : public Gtk::TreeModel::ColumnRecord
668         {
669                 public:
670                         Gtk::TreeModelColumn<std::string> name;
671                         Gtk::TreeModelColumn<Gtk::Widget*> widget;
672
673                         OptionColumns() {
674                                 add (name);
675                                 add (widget);
676                         }
677         };
678
679         OptionColumns option_columns;
680         Glib::RefPtr<Gtk::TreeStore> option_tree;
681
682 private:
683         PBD::ScopedConnection config_connection;
684         Gtk::Notebook _notebook;
685         Gtk::TreeView option_treeview;
686         std::map<std::string, OptionEditorPage*> _pages;
687
688         void add_path_to_treeview (std::string const &, Gtk::Widget&);
689         Gtk::TreeModel::iterator find_path_in_treemodel (std::string const & pn,
690                                                          bool create_missing = false);
691         void treeview_row_selected ();
692 };
693
694 /** The OptionEditor dialog-as-container base class */
695 class OptionEditorContainer : public OptionEditor, public Gtk::VBox
696 {
697 public:
698         OptionEditorContainer (PBD::Configuration *, std::string const &);
699         ~OptionEditorContainer() {}
700 private:
701         Gtk::HBox hpacker;
702 };
703
704 /** The OptionEditor dialog-as-container base class */
705 class OptionEditorWindow : public OptionEditor, public ArdourWindow
706 {
707 public:
708         OptionEditorWindow (PBD::Configuration *, std::string const &);
709         ~OptionEditorWindow() {}
710 private:
711         Gtk::VBox container;
712         Gtk::HBox hpacker;
713 };
714
715 #endif /* __gtk_ardour_option_editor_h__ */