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