90% done with external sync design changes (GUI now has toggle switch for ext/int...
[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 "ardour_dialog.h"
29
30 /** @file option_editor.h
31  *  @brief Base class for option editing dialog boxes.
32  *
33  *  Code to provided the basis for dialogs which allow the user to edit options
34  *  from an ARDOUR::Configuration class.
35  *
36  *  The idea is that we have an OptionEditor class which is the dialog box.
37  *  This is essentially a GTK Notebook.  OptionEditorComponent objects can
38  *  then be added to the OptionEditor, and these components are arranged on
39  *  the pages of the Notebook.  There is also an OptionEditorComponent hierarchy
40  *  here, providing things like boolean and combobox option components.
41  *
42  *  It is intended that OptionEditor be subclassed to implement a particular
43  *  options dialog.
44  */
45
46 namespace ARDOUR {
47         class Configuration;
48 }
49
50 class OptionEditorPage;
51
52 /** Base class for components of an OptionEditor dialog */
53 class OptionEditorComponent
54 {
55 public:
56         /** Called when a configuration parameter's value has changed.
57          *  @param p parameter name
58          */
59         virtual void parameter_changed (std::string const & p) = 0;
60
61         /** Called to instruct the object to set its UI state from the configuration */
62         virtual void set_state_from_config () = 0;
63
64         /** Called to instruct the object to add itself to an OptionEditorPage */
65         virtual void add_to_page (OptionEditorPage *) = 0;
66
67         void add_widget_to_page (OptionEditorPage*, Gtk::Widget*);
68         void add_widgets_to_page (OptionEditorPage*, Gtk::Widget*, Gtk::Widget*);
69 };
70
71 /** A component which provides a subheading within the dialog */
72 class OptionEditorHeading : public OptionEditorComponent
73 {
74 public:
75         OptionEditorHeading (std::string const &);
76
77         void parameter_changed (std::string const &) {}
78         void set_state_from_config () {}
79         void add_to_page (OptionEditorPage *);
80
81 private:
82         Gtk::Label* _label; ///< the label used for the heading
83 };
84
85 /** A component which provides a box into which a subclass can put arbitrary widgets */
86 class OptionEditorBox : public OptionEditorComponent
87 {
88 public:
89
90         /** Construct an OpenEditorBox */
91         OptionEditorBox ()
92         {
93                 _box = Gtk::manage (new Gtk::VBox);
94                 _box->set_spacing (4);
95         }
96
97         void parameter_changed (std::string const &) = 0;
98         void set_state_from_config () = 0;
99         void add_to_page (OptionEditorPage *);
100
101 protected:
102
103         Gtk::VBox* _box; ///< constituent box for subclasses to add widgets to
104 };
105
106 /** Base class for components which provide UI to change an option */
107 class Option : public OptionEditorComponent {
108
109 public:
110         /** Construct an Option.
111          *  @param i Option id (e.g. "plugins-stop-with-transport")
112          *  @param n User-visible name (e.g. "Stop plugins when the transport is stopped")
113          */
114         Option (std::string const & i,
115                 std::string const & n
116                 )
117                 : _id (i),
118                   _name (n)
119         {}
120
121         void parameter_changed (std::string const & p)
122         {
123                 if (p == _id) {
124                         set_state_from_config ();
125                 }
126         }
127
128         virtual void set_state_from_config () = 0;
129         virtual void add_to_page (OptionEditorPage*) = 0;
130
131         std::string id () const {
132                 return _id;
133         }
134
135 private:
136
137         std::string _id;
138         std::string _name;
139 };
140
141 /** Component which provides the UI to handle a boolean option using a GTK CheckButton */
142 class BoolOption : public Option {
143
144 public:
145
146         BoolOption (std::string const &, std::string const &, sigc::slot<bool>, sigc::slot<bool, bool>);
147         void set_state_from_config ();
148         void add_to_page (OptionEditorPage*);
149
150 private:
151
152         void toggled ();
153
154         sigc::slot<bool> _get; ///< slot to get the configuration variable's value
155         sigc::slot<bool, bool> _set;  ///< slot to set the configuration variable's value
156         Gtk::CheckButton* _button; ///< UI button
157 };
158
159 /** Component which provides the UI to handle a string option using a GTK Entry */
160 class EntryOption : public Option {
161
162 public:
163
164         EntryOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
165         void set_state_from_config ();
166         void add_to_page (OptionEditorPage*);
167
168 private:
169
170         void activated ();
171
172         sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
173         sigc::slot<bool, std::string> _set;  ///< slot to set the configuration variable's value
174         Gtk::Label* _label; ///< UI label
175         Gtk::Entry* _entry; ///< UI entry
176 };
177
178
179 /** Component which provides the UI to handle an enumerated option using a GTK CheckButton.
180  *  The template parameter is the enumeration.
181  */
182 template <class T>
183 class ComboOption : public Option {
184
185 public:
186
187         /** Construct an ComboOption.
188          *  @param i id
189          *  @param n User-visible name.
190          *  @param g Slot to get the variable's value.
191          *  @param s Slot to set the variable's value.
192          */
193         ComboOption (
194                 std::string const & i,
195                 std::string const & n,
196                 sigc::slot<T> g,
197                 sigc::slot<bool, T> s
198                 )
199                 : Option (i, n),
200                   _get (g),
201                   _set (s)
202         {
203                 _label = manage (new Gtk::Label (n + ":"));
204                 _label->set_alignment (1, 0.5);
205                 _combo = manage (new Gtk::ComboBoxText);
206                 _combo->signal_changed().connect (sigc::mem_fun (*this, &ComboOption::changed));
207         }
208
209         void set_state_from_config () {
210                 uint32_t r = 0;
211                 while (r < _options.size() && _get () != _options[r]) {
212                         ++r;
213                 }
214
215                 if (r < _options.size()) {
216                         _combo->set_active (r);
217                 }
218         }
219
220         void add_to_page (OptionEditorPage* p)
221         {
222                 add_widgets_to_page (p, _label, _combo);
223         }
224
225         /** Add an allowed value for this option.
226          *  @param e Enumeration.
227          *  @param o User-visible name for this value.
228          */
229         void add (T e, std::string const & o) {
230                 _options.push_back (e);
231                 _combo->append_text (o);
232         }
233
234         void clear () {
235                 _combo->clear_items();
236                 _options.clear ();
237         }
238
239         void changed () {
240                 uint32_t const r = _combo->get_active_row_number ();
241                 if (r < _options.size()) {
242                         _set (_options[r]);
243                 }
244         }
245
246 private:
247
248         sigc::slot<T> _get;
249         sigc::slot<bool, T> _set;
250         Gtk::Label* _label;
251         Gtk::ComboBoxText* _combo;
252         std::vector<T> _options;
253 };
254
255
256 /** Component which provides the UI to handle an numeric option using a GTK SpinButton */
257 template <class T>
258 class SpinOption : public Option
259 {
260 public:
261         /** Construct an SpinOption.
262          *  @param i id
263          *  @param n User-visible name.
264          *  @param g Slot to get the variable's value.
265          *  @param s Slot to set the variable's value.
266          *  @param min Variable minimum value.
267          *  @param max Variable maximum value.
268          *  @param step Step for the spin button.
269          *  @param page Page step for the spin button.
270          *  @param unit Unit name.
271          *  @param scale Scaling factor (such that for a value x in the spinbutton, x * scale is written to the config)
272          */
273         SpinOption (
274                 std::string const & i,
275                 std::string const & n,
276                 sigc::slot<T> g,
277                 sigc::slot<bool, T> s,
278                 T min,
279                 T max,
280                 T step,
281                 T page,
282                 std::string const & unit = "",
283                 float scale = 1
284                 )
285                 : Option (i, n),
286                   _get (g),
287                   _set (s),
288                   _scale (scale)
289         {
290                 _label = manage (new Gtk::Label (n + ":"));
291                 _label->set_alignment (1, 0.5);
292
293                 _spin = manage (new Gtk::SpinButton);
294                 _spin->set_range (min, max);
295                 _spin->set_increments (step, page);
296
297                 _box = manage (new Gtk::HBox);
298                 _box->pack_start (*_spin, true, true);
299                 _box->set_spacing (4);
300                 if (unit.length()) {
301                         _box->pack_start (*manage (new Gtk::Label (unit)), false, false);
302                 }
303
304                 _spin->signal_value_changed().connect (sigc::mem_fun (*this, &SpinOption::changed));
305         }
306
307         void set_state_from_config ()
308         {
309                 _spin->set_value (_get () / _scale);
310         }
311
312         void add_to_page (OptionEditorPage* p)
313         {
314                 add_widgets_to_page (p, _label, _box);
315         }
316
317         void changed ()
318         {
319                 _set (static_cast<T> (_spin->get_value ()) * _scale);
320         }
321
322 private:
323         sigc::slot<T> _get;
324         sigc::slot<bool, T> _set;
325         float _scale;
326         Gtk::Label* _label;
327         Gtk::HBox* _box;
328         Gtk::SpinButton* _spin;
329 };
330
331 /** Class to represent a single page in an OptionEditor's notebook.
332  *  Pages are laid out using a 3-column table; the 1st column is used
333  *  to indent non-headings, and the 2nd and 3rd for actual content.
334  */
335 class OptionEditorPage
336 {
337 public:
338         OptionEditorPage (Gtk::Notebook&, std::string const &);
339
340         Gtk::VBox box;
341         Gtk::Table table;
342         std::list<OptionEditorComponent*> components;
343 };
344
345 /** The OptionEditor dialog base class */
346 class OptionEditor : public ArdourDialog
347 {
348 public:
349         OptionEditor (ARDOUR::Configuration *, std::string const &);
350         ~OptionEditor ();
351
352         void add_option (std::string const &, OptionEditorComponent *);
353
354 protected:
355
356         ARDOUR::Configuration* _config;
357
358 private:
359
360         void parameter_changed (std::string const &);
361
362         Gtk::Notebook _notebook;
363         std::map<std::string, OptionEditorPage*> _pages;
364 };
365
366 #endif /* __gtk_ardour_option_editor_h__ */
367
368