Neaten up option editor layouts a bit.
[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 (0, 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         void set_sensitive (bool yn) {
247                 _combo->set_sensitive (yn);
248         }
249
250 private:
251
252         sigc::slot<T> _get;
253         sigc::slot<bool, T> _set;
254         Gtk::Label* _label;
255         Gtk::ComboBoxText* _combo;
256         std::vector<T> _options;
257 };
258
259
260 /** Component which provides the UI to handle an numeric option using a GTK SpinButton */
261 template <class T>
262 class SpinOption : public Option
263 {
264 public:
265         /** Construct an SpinOption.
266          *  @param i id
267          *  @param n User-visible name.
268          *  @param g Slot to get the variable's value.
269          *  @param s Slot to set the variable's value.
270          *  @param min Variable minimum value.
271          *  @param max Variable maximum value.
272          *  @param step Step for the spin button.
273          *  @param page Page step for the spin button.
274          *  @param unit Unit name.
275          *  @param scale Scaling factor (such that for a value x in the spinbutton, x * scale is written to the config)
276          */
277         SpinOption (
278                 std::string const & i,
279                 std::string const & n,
280                 sigc::slot<T> g,
281                 sigc::slot<bool, T> s,
282                 T min,
283                 T max,
284                 T step,
285                 T page,
286                 std::string const & unit = "",
287                 float scale = 1
288                 )
289                 : Option (i, n),
290                   _get (g),
291                   _set (s),
292                   _scale (scale)
293         {
294                 _label = manage (new Gtk::Label (n + ":"));
295                 _label->set_alignment (0, 0.5);
296
297                 _spin = manage (new Gtk::SpinButton);
298                 _spin->set_range (min, max);
299                 _spin->set_increments (step, page);
300
301                 _box = manage (new Gtk::HBox);
302                 _box->pack_start (*_spin, true, true);
303                 _box->set_spacing (4);
304                 if (unit.length()) {
305                         _box->pack_start (*manage (new Gtk::Label (unit)), false, false);
306                 }
307
308                 _spin->signal_value_changed().connect (sigc::mem_fun (*this, &SpinOption::changed));
309         }
310
311         void set_state_from_config ()
312         {
313                 _spin->set_value (_get () / _scale);
314         }
315
316         void add_to_page (OptionEditorPage* p)
317         {
318                 add_widgets_to_page (p, _label, _box);
319         }
320
321         void changed ()
322         {
323                 _set (static_cast<T> (_spin->get_value ()) * _scale);
324         }
325
326 private:
327         sigc::slot<T> _get;
328         sigc::slot<bool, T> _set;
329         float _scale;
330         Gtk::Label* _label;
331         Gtk::HBox* _box;
332         Gtk::SpinButton* _spin;
333 };
334
335 /** Class to represent a single page in an OptionEditor's notebook.
336  *  Pages are laid out using a 3-column table; the 1st column is used
337  *  to indent non-headings, and the 2nd and 3rd for actual content.
338  */
339 class OptionEditorPage
340 {
341 public:
342         OptionEditorPage (Gtk::Notebook&, std::string const &);
343
344         Gtk::VBox box;
345         Gtk::Table table;
346         std::list<OptionEditorComponent*> components;
347 };
348
349 /** The OptionEditor dialog base class */
350 class OptionEditor : public ArdourDialog
351 {
352 public:
353         OptionEditor (ARDOUR::Configuration *, std::string const &);
354         ~OptionEditor ();
355
356         void add_option (std::string const &, OptionEditorComponent *);
357
358 protected:
359
360         ARDOUR::Configuration* _config;
361
362 private:
363
364         void parameter_changed (std::string const &);
365
366         Gtk::Notebook _notebook;
367         std::map<std::string, OptionEditorPage*> _pages;
368 };
369
370 #endif /* __gtk_ardour_option_editor_h__ */
371
372