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