Clarify the meaning of the show-region-gain-envelopes option.
[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
20 #ifndef __gtk_ardour_option_editor_h__
21 #define __gtk_ardour_option_editor_h__
22
23 #include <gtkmm/notebook.h>
24 #include <gtkmm/checkbutton.h>
25 #include <gtkmm/comboboxtext.h>
26 #include <gtkmm/spinbutton.h>
27 #include <gtkmm/table.h>
28 #include "gtkmm2ext/slider_controller.h"
29 #include "ardour_window.h"
30 #include "audio_clock.h"
31 #include "ardour/types.h"
32
33 /** @file option_editor.h
34  *  @brief Base class for option editing dialog boxes.
35  *
36  *  Code to provided the basis for dialogs which allow the user to edit options
37  *  from an ARDOUR::Configuration class.
38  *
39  *  The idea is that we have an OptionEditor class which is the dialog box.
40  *  This is essentially a GTK Notebook.  OptionEditorComponent objects can
41  *  then be added to the OptionEditor, and these components are arranged on
42  *  the pages of the Notebook.  There is also an OptionEditorComponent hierarchy
43  *  here, providing things like boolean and combobox option components.
44  *
45  *  It is intended that OptionEditor be subclassed to implement a particular
46  *  options dialog.
47  */
48
49 namespace ARDOUR {
50         class Configuration;
51 }
52
53 class OptionEditorPage;
54
55 /** Base class for components of an OptionEditor dialog */
56 class OptionEditorComponent
57 {
58 public:
59         virtual ~OptionEditorComponent() {}
60
61         /** Called when a configuration parameter's value has changed.
62          *  @param p parameter name
63          */
64         virtual void parameter_changed (std::string const & p) = 0;
65
66         /** Called to instruct the object to set its UI state from the configuration */
67         virtual void set_state_from_config () = 0;
68
69         /** Called to instruct the object to add itself to an OptionEditorPage */
70         virtual void add_to_page (OptionEditorPage *) = 0;
71
72         void add_widget_to_page (OptionEditorPage*, Gtk::Widget*);
73         void add_widgets_to_page (OptionEditorPage*, Gtk::Widget*, Gtk::Widget*);
74
75         void set_note (std::string const &);
76
77 private:
78         void maybe_add_note (OptionEditorPage *, int);
79         
80         std::string _note;
81 };
82
83 /** A component which provides a subheading within the dialog */
84 class OptionEditorHeading : public OptionEditorComponent
85 {
86 public:
87         OptionEditorHeading (std::string const &);
88
89         void parameter_changed (std::string const &) {}
90         void set_state_from_config () {}
91         void add_to_page (OptionEditorPage *);
92
93 private:
94         Gtk::Label* _label; ///< the label used for the heading
95 };
96
97 /** A component which provides a box into which a subclass can put arbitrary widgets */
98 class OptionEditorBox : public OptionEditorComponent
99 {
100 public:
101
102         /** Construct an OpenEditorBox */
103         OptionEditorBox ()
104         {
105                 _box = Gtk::manage (new Gtk::VBox);
106                 _box->set_spacing (4);
107         }
108
109         void parameter_changed (std::string const &) = 0;
110         void set_state_from_config () = 0;
111         void add_to_page (OptionEditorPage *);
112
113 protected:
114
115         Gtk::VBox* _box; ///< constituent box for subclasses to add widgets to
116 };
117
118 /** Base class for components which provide UI to change an option */
119 class Option : public OptionEditorComponent
120 {
121 public:
122         /** Construct an Option.
123          *  @param i Option id (e.g. "plugins-stop-with-transport")
124          *  @param n User-visible name (e.g. "Stop plugins when the transport is stopped")
125          */
126         Option (std::string const & i,
127                 std::string const & n
128                 )
129                 : _id (i),
130                   _name (n)
131         {}
132
133         void parameter_changed (std::string const & p)
134         {
135                 if (p == _id) {
136                         set_state_from_config ();
137                 }
138         }
139
140         virtual void set_state_from_config () = 0;
141         virtual void add_to_page (OptionEditorPage*) = 0;
142
143         std::string id () const {
144                 return _id;
145         }
146
147 protected:
148
149         std::string _id;
150         std::string _name;
151 };
152
153 /** Component which provides the UI to handle a boolean option using a GTK CheckButton */
154 class BoolOption : public Option
155 {
156 public:
157
158         BoolOption (std::string const &, std::string const &, sigc::slot<bool>, sigc::slot<bool, bool>);
159         void set_state_from_config ();
160         void add_to_page (OptionEditorPage*);
161
162         void set_sensitive (bool yn) {
163                 _button->set_sensitive (yn);
164         }
165
166 private:
167
168         void toggled ();
169
170         sigc::slot<bool> _get; ///< slot to get the configuration variable's value
171         sigc::slot<bool, bool> _set;  ///< slot to set the configuration variable's value
172         Gtk::CheckButton* _button; ///< UI button
173 };
174
175 /** Component which provides the UI to handle a string option using a GTK Entry */
176 class EntryOption : public Option
177 {
178 public:
179
180         EntryOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
181         void set_state_from_config ();
182         void add_to_page (OptionEditorPage*);
183
184 private:
185
186         void activated ();
187
188         sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
189         sigc::slot<bool, std::string> _set;  ///< slot to set the configuration variable's value
190         Gtk::Label* _label; ///< UI label
191         Gtk::Entry* _entry; ///< UI entry
192 };
193
194
195 /** Component which provides the UI to handle an enumerated option using a GTK ComboBox.
196  *  The template parameter is the enumeration.
197  */
198 template <class T>
199 class ComboOption : public Option
200 {
201 public:
202
203         /** Construct an ComboOption.
204          *  @param i id
205          *  @param n User-visible name.
206          *  @param g Slot to get the variable's value.
207          *  @param s Slot to set the variable's value.
208          */
209         ComboOption (
210                 std::string const & i,
211                 std::string const & n,
212                 sigc::slot<T> g,
213                 sigc::slot<bool, T> s
214                 )
215                 : Option (i, n),
216                   _get (g),
217                   _set (s)
218         {
219                 _label = manage (new Gtk::Label (n + ":"));
220                 _label->set_alignment (0, 0.5);
221                 _combo = manage (new Gtk::ComboBoxText);
222                 _combo->signal_changed().connect (sigc::mem_fun (*this, &ComboOption::changed));
223         }
224
225         void set_state_from_config () {
226                 uint32_t r = 0;
227                 while (r < _options.size() && _get () != _options[r]) {
228                         ++r;
229                 }
230
231                 if (r < _options.size()) {
232                         _combo->set_active (r);
233                 }
234         }
235
236         void add_to_page (OptionEditorPage* p)
237         {
238                 add_widgets_to_page (p, _label, _combo);
239         }
240
241         /** Add an allowed value for this option.
242          *  @param e Enumeration.
243          *  @param o User-visible name for this value.
244          */
245         void add (T e, std::string const & o) {
246                 _options.push_back (e);
247                 _combo->append_text (o);
248         }
249
250         void clear () {
251                 _combo->clear_items();
252                 _options.clear ();
253         }
254
255         void changed () {
256                 uint32_t const r = _combo->get_active_row_number ();
257                 if (r < _options.size()) {
258                         _set (_options[r]);
259                 }
260         }
261
262         void set_sensitive (bool yn) {
263                 _combo->set_sensitive (yn);
264         }
265
266 private:
267
268         sigc::slot<T> _get;
269         sigc::slot<bool, T> _set;
270         Gtk::Label* _label;
271         Gtk::ComboBoxText* _combo;
272         std::vector<T> _options;
273 };
274
275
276 /** Component which provides the UI to handle a boolean option which needs
277  *  to be represented as a ComboBox to be clear to the user.
278  */
279 class BoolComboOption : public Option
280 {
281 public:
282
283         BoolComboOption (
284                 std::string const &,
285                 std::string const &,
286                 std::string const &,
287                 std::string const &,
288                 sigc::slot<bool>,
289                 sigc::slot<bool, bool>
290                 );
291
292         void set_state_from_config ();
293         void add_to_page (OptionEditorPage *);
294         void changed ();
295         void set_sensitive (bool);
296
297 private:
298
299         sigc::slot<bool> _get;
300         sigc::slot<bool, bool> _set;
301         Gtk::Label* _label;
302         Gtk::ComboBoxText* _combo;
303 };
304
305
306
307 /** Component which provides the UI to handle an numeric option using a GTK SpinButton */
308 template <class T>
309 class SpinOption : public Option
310 {
311 public:
312         /** Construct an SpinOption.
313          *  @param i id
314          *  @param n User-visible name.
315          *  @param g Slot to get the variable's value.
316          *  @param s Slot to set the variable's value.
317          *  @param min Variable minimum value.
318          *  @param max Variable maximum value.
319          *  @param step Step for the spin button.
320          *  @param page Page step for the spin button.
321          *  @param unit Unit name.
322          *  @param scale Scaling factor (such that for a value x in the spinbutton, x * scale is written to the config)
323          */
324         SpinOption (
325                 std::string const & i,
326                 std::string const & n,
327                 sigc::slot<T> g,
328                 sigc::slot<bool, T> s,
329                 T min,
330                 T max,
331                 T step,
332                 T page,
333                 std::string const & unit = "",
334                 float scale = 1
335                 )
336                 : Option (i, n),
337                   _get (g),
338                   _set (s),
339                   _scale (scale)
340         {
341                 _label = manage (new Gtk::Label (n + ":"));
342                 _label->set_alignment (0, 0.5);
343
344                 _spin = manage (new Gtk::SpinButton);
345                 _spin->set_range (min, max);
346                 _spin->set_increments (step, page);
347
348                 _box = manage (new Gtk::HBox);
349                 _box->pack_start (*_spin, true, true);
350                 _box->set_spacing (4);
351                 if (unit.length()) {
352                         _box->pack_start (*manage (new Gtk::Label (unit)), false, false);
353                 }
354
355                 _spin->signal_value_changed().connect (sigc::mem_fun (*this, &SpinOption::changed));
356         }
357
358         void set_state_from_config ()
359         {
360                 _spin->set_value (_get () / _scale);
361         }
362
363         void add_to_page (OptionEditorPage* p)
364         {
365                 add_widgets_to_page (p, _label, _box);
366         }
367
368         void changed ()
369         {
370                 _set (static_cast<T> (_spin->get_value ()) * _scale);
371         }
372
373 private:
374         sigc::slot<T> _get;
375         sigc::slot<bool, T> _set;
376         float _scale;
377         Gtk::Label* _label;
378         Gtk::HBox* _box;
379         Gtk::SpinButton* _spin;
380 };
381
382 class FaderOption : public Option
383 {
384 public:
385
386         FaderOption (std::string const &, std::string const &, sigc::slot<ARDOUR::gain_t> g, sigc::slot<bool, ARDOUR::gain_t> s);
387         void set_state_from_config ();
388         void add_to_page (OptionEditorPage *);
389
390 private:
391         void db_changed ();
392
393         Gtk::Adjustment _db_adjustment;
394         Gtkmm2ext::HSliderController* _db_slider;
395         Glib::RefPtr<Gdk::Pixbuf> _pix;
396         Glib::RefPtr<Gdk::Pixbuf> _pix_desensitised;
397         Gtk::Entry _db_display;
398         Gtk::Label _label;
399         Gtk::HBox _box;
400         Gtk::VBox _fader_centering_box;
401         sigc::slot<ARDOUR::gain_t> _get;
402         sigc::slot<bool, ARDOUR::gain_t> _set;
403 };
404
405 class ClockOption : public Option
406 {
407 public:
408         ClockOption (std::string const &, std::string const &, sigc::slot<ARDOUR::framecnt_t>, sigc::slot<bool, ARDOUR::framecnt_t>);
409         void set_state_from_config ();
410         void add_to_page (OptionEditorPage *);
411         void set_session (ARDOUR::Session *);
412
413 private:
414         Gtk::Label _label;
415         AudioClock _clock;
416         sigc::slot<ARDOUR::framecnt_t> _get;
417         sigc::slot<bool, ARDOUR::framecnt_t> _set;
418 };
419
420 class DirectoryOption : public Option
421 {
422 public:
423         DirectoryOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
424
425         void set_state_from_config ();
426         void add_to_page (OptionEditorPage *);
427
428 private:
429         void file_set ();
430         void current_folder_set ();
431         
432         sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
433         sigc::slot<bool, std::string> _set;  ///< slot to set the configuration variable's value
434         Gtk::FileChooserButton _file_chooser;
435 };
436
437 /** Class to represent a single page in an OptionEditor's notebook.
438  *  Pages are laid out using a 3-column table; the 1st column is used
439  *  to indent non-headings, and the 2nd and 3rd for actual content.
440  */
441 class OptionEditorPage
442 {
443 public:
444         OptionEditorPage (Gtk::Notebook&, std::string const &);
445
446         Gtk::VBox box;
447         Gtk::Table table;
448         std::list<OptionEditorComponent*> components;
449 };
450
451 /** The OptionEditor dialog base class */
452 class OptionEditor : public ArdourWindow
453 {
454 public:
455         OptionEditor (ARDOUR::Configuration *, std::string const &);
456         ~OptionEditor ();
457
458         void add_option (std::string const &, OptionEditorComponent *);
459
460         void set_current_page (std::string const &);
461
462 protected:
463
464         virtual void parameter_changed (std::string const &);
465
466         ARDOUR::Configuration* _config;
467
468 private:
469
470         PBD::ScopedConnection config_connection;
471
472         Gtk::Notebook _notebook;
473         std::map<std::string, OptionEditorPage*> _pages;
474 };
475
476 #endif /* __gtk_ardour_option_editor_h__ */
477
478