2 Copyright (C) 2009 Paul Davis
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.
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.
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.
19 #ifndef __gtk_ardour_option_editor_h__
20 #define __gtk_ardour_option_editor_h__
22 #include <gtkmm/notebook.h>
23 #include <gtkmm/checkbutton.h>
24 #include <gtkmm/comboboxtext.h>
25 #include <gtkmm/spinbutton.h>
26 #include <gtkmm/table.h>
27 #include <gtkmm/window.h>
29 #include "gtkmm2ext/slider_controller.h"
31 #include "ardour_window.h"
32 #include "audio_clock.h"
33 #include "ardour/types.h"
35 /** @file option_editor.h
36 * @brief Base class for option editing dialog boxes.
38 * Code to provided the basis for dialogs which allow the user to edit options
39 * from an ARDOUR::Configuration class.
41 * The idea is that we have an OptionEditor class which is the dialog box.
42 * This is essentially a GTK Notebook. OptionEditorComponent objects can
43 * then be added to the OptionEditor, and these components are arranged on
44 * the pages of the Notebook. There is also an OptionEditorComponent hierarchy
45 * here, providing things like boolean and combobox option components.
47 * It is intended that OptionEditor be subclassed to implement a particular
55 class OptionEditorPage;
57 /** Base class for components of an OptionEditor dialog */
58 class OptionEditorComponent
61 virtual ~OptionEditorComponent() {}
63 /** Called when a configuration parameter's value has changed.
64 * @param p parameter name
66 virtual void parameter_changed (std::string const & p) = 0;
68 /** Called to instruct the object to set its UI state from the configuration */
69 virtual void set_state_from_config () = 0;
71 /** Called to instruct the object to add itself to an OptionEditorPage */
72 virtual void add_to_page (OptionEditorPage *) = 0;
74 void add_widget_to_page (OptionEditorPage*, Gtk::Widget*);
75 void add_widgets_to_page (OptionEditorPage*, Gtk::Widget*, Gtk::Widget*, bool expand = true);
77 void set_note (std::string const &);
79 virtual Gtk::Widget& tip_widget() = 0;
82 void maybe_add_note (OptionEditorPage *, int);
87 /** A component which provides a subheading within the dialog */
88 class OptionEditorHeading : public OptionEditorComponent
91 OptionEditorHeading (std::string const &);
93 void parameter_changed (std::string const &) {}
94 void set_state_from_config () {}
95 void add_to_page (OptionEditorPage *);
97 Gtk::Widget& tip_widget() { return *_label; }
100 Gtk::Label* _label; ///< the label used for the heading
103 /** Expanding layout helper to push elements to the left on a single column page */
104 class OptionEditorBlank : public OptionEditorComponent
107 OptionEditorBlank () {}
109 void parameter_changed (std::string const &) {}
110 void set_state_from_config () {}
111 void add_to_page (OptionEditorPage *);
113 Gtk::Widget& tip_widget() { return _dummy; }
116 Gtk::EventBox _dummy;
119 class RcConfigDisplay : public OptionEditorComponent
122 RcConfigDisplay (std::string const &, std::string const &, sigc::slot<std::string>, char s = '\0');
123 void add_to_page (OptionEditorPage *);
124 void parameter_changed (std::string const & p);
125 void set_state_from_config ();
126 Gtk::Widget& tip_widget() { return *_info; }
128 sigc::slot<std::string> _get;
135 class RcActionButton : public OptionEditorComponent
138 RcActionButton (std::string const & t, const Glib::SignalProxy0< void >::SlotType & slot, std::string const & l = "");
139 void add_to_page (OptionEditorPage *);
141 void parameter_changed (std::string const & p) {}
142 void set_state_from_config () {}
143 Gtk::Widget& tip_widget() { return *_button; }
146 Gtk::Button* _button;
151 /** Base class for components which provide UI to change an option */
152 class Option : public OptionEditorComponent
155 /** Construct an Option.
156 * @param i Option id (e.g. "plugins-stop-with-transport")
157 * @param n User-visible name (e.g. "Stop plugins when the transport is stopped")
159 Option (std::string const & i,
160 std::string const & n
166 void parameter_changed (std::string const & p)
169 set_state_from_config ();
173 virtual void set_state_from_config () = 0;
174 virtual void add_to_page (OptionEditorPage*) = 0;
176 std::string id () const {
185 /** Component which provides the UI to handle a boolean option using a GTK CheckButton */
186 class BoolOption : public Option
189 BoolOption (std::string const &, std::string const &, sigc::slot<bool>, sigc::slot<bool, bool>);
190 void set_state_from_config ();
191 void add_to_page (OptionEditorPage*);
193 void set_sensitive (bool yn) {
194 _button->set_sensitive (yn);
197 Gtk::Widget& tip_widget() { return *_button; }
200 virtual void toggled ();
202 sigc::slot<bool> _get; ///< slot to get the configuration variable's value
203 sigc::slot<bool, bool> _set; ///< slot to set the configuration variable's value
204 Gtk::CheckButton* _button; ///< UI button
205 Gtk::Label* _label; ///< label for button, so we can use markup
208 class RouteDisplayBoolOption : public BoolOption
211 RouteDisplayBoolOption (std::string const &, std::string const &, sigc::slot<bool>, sigc::slot<bool, bool>);
214 virtual void toggled ();
217 /** Component which allows to add any GTK Widget - intended for single buttons and custom stateless objects */
218 class FooOption : public OptionEditorComponent
221 FooOption (Gtk::Widget *w) : _w (w) {}
223 void add_to_page (OptionEditorPage* p) {
224 add_widget_to_page (p, _w);
227 Gtk::Widget& tip_widget() { return *_w; }
228 void set_state_from_config () {}
229 void parameter_changed (std::string const &) {}
234 /** Component which provides the UI to handle a string option using a GTK Entry */
235 class EntryOption : public Option
238 EntryOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
239 void set_state_from_config ();
240 void add_to_page (OptionEditorPage*);
241 void set_sensitive (bool);
242 void set_invalid_chars (std::string i) { _invalid = i; }
244 Gtk::Widget& tip_widget() { return *_entry; }
248 bool focus_out (GdkEventFocus*);
249 void filter_text (const Glib::ustring&, int*);
251 sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
252 sigc::slot<bool, std::string> _set; ///< slot to set the configuration variable's value
253 Gtk::Label* _label; ///< UI label
254 Gtk::Entry* _entry; ///< UI entry
255 std::string _invalid;
259 /** Component which provides the UI to handle an enumerated option using a GTK ComboBox.
260 * The template parameter is the enumeration.
263 class ComboOption : public Option
266 /** Construct an ComboOption.
268 * @param n User-visible name.
269 * @param g Slot to get the variable's value.
270 * @param s Slot to set the variable's value.
273 std::string const & i,
274 std::string const & n,
276 sigc::slot<bool, T> s
282 _label = Gtk::manage (new Gtk::Label (n + ":"));
283 _label->set_alignment (0, 0.5);
284 _combo = Gtk::manage (new Gtk::ComboBoxText);
285 _combo->signal_changed().connect (sigc::mem_fun (*this, &ComboOption::changed));
288 void set_state_from_config ()
291 while (r < _options.size() && _get () != _options[r]) {
295 if (r < _options.size()) {
296 _combo->set_active (r);
300 void add_to_page (OptionEditorPage* p)
302 add_widgets_to_page (p, _label, _combo);
305 /** Add an allowed value for this option.
306 * @param e Enumeration.
307 * @param o User-visible name for this value.
309 void add (T e, std::string const & o)
311 _options.push_back (e);
312 _combo->append_text (o);
317 _combo->clear_items();
323 uint32_t const r = _combo->get_active_row_number ();
324 if (r < _options.size()) {
328 void set_sensitive (bool yn)
330 _combo->set_sensitive (yn);
333 Gtk::Widget& tip_widget() { return *_combo; }
337 sigc::slot<bool, T> _set;
339 Gtk::ComboBoxText* _combo;
340 std::vector<T> _options;
344 /** Component which provides the UI for a GTK HScale.
346 class HSliderOption : public Option
350 std::string const& i,
351 std::string const& n,
353 sigc::slot<bool, float> s,
354 double lower, double upper,
355 double step_increment = 1,
356 double page_increment = 10,
358 bool logarithmic = false
361 void set_state_from_config ();
362 virtual void changed ();
363 void add_to_page (OptionEditorPage* p);
364 void set_sensitive (bool yn);
366 Gtk::Widget& tip_widget() { return _hscale; }
367 Gtk::HScale& scale() { return _hscale; }
370 sigc::slot<float> _get;
371 sigc::slot<bool, float> _set;
372 Gtk::Adjustment _adj;
380 /** Component which provides the UI to handle an enumerated option using a GTK ComboBox.
381 * The template parameter is the enumeration.
383 class ComboStringOption : public Option
386 /** Construct an ComboOption.
388 * @param n User-visible name.
389 * @param g Slot to get the variable's value.
390 * @param s Slot to set the variable's value.
393 std::string const & i,
394 std::string const & n,
395 sigc::slot<std::string> g,
396 sigc::slot<bool, std::string> s
399 void set_state_from_config ();
400 void add_to_page (OptionEditorPage* p);
402 /** Set the allowed strings for this option
403 * @param strings a vector of allowed strings
405 void set_popdown_strings (const std::vector<std::string>& strings);
409 void set_sensitive (bool yn);
411 Gtk::Widget& tip_widget() { return *_combo; }
414 sigc::slot<std::string> _get;
415 sigc::slot<bool, std::string> _set;
417 Gtk::ComboBoxText* _combo;
421 /** Component which provides the UI to handle a boolean option which needs
422 * to be represented as a ComboBox to be clear to the user.
424 class BoolComboOption : public Option
433 sigc::slot<bool, bool>
436 void set_state_from_config ();
437 void add_to_page (OptionEditorPage *);
439 void set_sensitive (bool);
441 Gtk::Widget& tip_widget() { return *_combo; }
444 sigc::slot<bool> _get;
445 sigc::slot<bool, bool> _set;
447 Gtk::ComboBoxText* _combo;
451 /** Component which provides the UI to handle an numeric option using a GTK SpinButton */
453 class SpinOption : public Option
456 /** Construct an SpinOption.
458 * @param n User-visible name.
459 * @param g Slot to get the variable's value.
460 * @param s Slot to set the variable's value.
461 * @param min Variable minimum value.
462 * @param max Variable maximum value.
463 * @param step Step for the spin button.
464 * @param page Page step for the spin button.
465 * @param unit Unit name.
466 * @param scale Scaling factor (such that for a value x in the spinbutton, x * scale is written to the config)
467 * @param digits Number of decimal digits to show.
470 std::string const & i,
471 std::string const & n,
473 sigc::slot<bool, T> s,
478 std::string const & unit = "",
487 _label = Gtk::manage (new Gtk::Label (n + ":"));
488 _label->set_alignment (0, 0.5);
490 _spin = Gtk::manage (new Gtk::SpinButton);
491 _spin->set_range (min, max);
492 _spin->set_increments (step, page);
493 _spin->set_digits(digits);
495 _box = Gtk::manage (new Gtk::HBox);
496 _box->pack_start (*_spin, true, true);
497 _box->set_spacing (4);
499 _box->pack_start (*Gtk::manage (new Gtk::Label (unit)), false, false);
502 _spin->signal_value_changed().connect (sigc::mem_fun (*this, &SpinOption::changed));
505 void set_state_from_config ()
507 _spin->set_value (_get () / _scale);
510 void add_to_page (OptionEditorPage* p)
512 add_widgets_to_page (p, _label, _box, false);
517 _set (static_cast<T> (_spin->get_value ()) * _scale);
520 Gtk::Widget& tip_widget() { return *_spin; }
524 sigc::slot<bool, T> _set;
528 Gtk::SpinButton* _spin;
531 class FaderOption : public Option
535 FaderOption (std::string const &, std::string const &, sigc::slot<ARDOUR::gain_t> g, sigc::slot<bool, ARDOUR::gain_t> s);
536 void set_state_from_config ();
537 void add_to_page (OptionEditorPage *);
539 Gtk::Widget& tip_widget() { return *_db_slider; }
544 bool on_key_press (GdkEventKey* ev);
546 Gtk::Adjustment _db_adjustment;
547 Gtkmm2ext::HSliderController* _db_slider;
548 Gtk::Entry _db_display;
551 Gtk::VBox _fader_centering_box;
552 sigc::slot<ARDOUR::gain_t> _get;
553 sigc::slot<bool, ARDOUR::gain_t> _set;
556 class ClockOption : public Option
559 ClockOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
560 void set_state_from_config ();
561 void add_to_page (OptionEditorPage *);
562 void set_session (ARDOUR::Session *);
564 Gtk::Widget& tip_widget() { return _clock; }
565 AudioClock& clock() { return _clock; }
568 void save_clock_time ();
571 sigc::slot<std::string> _get;
572 sigc::slot<bool, std::string> _set;
573 ARDOUR::Session *_session;
576 class DirectoryOption : public Option
579 DirectoryOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
581 void set_state_from_config ();
582 void add_to_page (OptionEditorPage *);
584 Gtk::Widget& tip_widget() { return _file_chooser; }
587 void selection_changed ();
589 sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
590 sigc::slot<bool, std::string> _set; ///< slot to set the configuration variable's value
591 Gtk::FileChooserButton _file_chooser;
594 /** Class to represent a single page in an OptionEditor's notebook.
595 * Pages are laid out using a 3-column table; the 1st column is used
596 * to indent non-headings, and the 2nd and 3rd for actual content.
598 class OptionEditorPage
601 OptionEditorPage (Gtk::Notebook&, std::string const &);
606 std::list<OptionEditorComponent*> components;
612 class OptionEditorMiniPage : public OptionEditorComponent, public OptionEditorPage
615 OptionEditorMiniPage ()
617 box.pack_start (table, false, false);
618 box.set_border_width (0);
621 void parameter_changed (std::string const &) = 0;
622 void set_state_from_config () = 0;
623 virtual void add_to_page (OptionEditorPage*);
625 Gtk::Widget& tip_widget() { return *table.children().front().get_widget(); }
628 /** The OptionEditor dialog base class */
629 class OptionEditor : virtual public sigc::trackable
632 OptionEditor (PBD::Configuration *);
633 virtual ~OptionEditor ();
635 void add_option (std::string const &, OptionEditorComponent *);
636 void add_page (std::string const &, Gtk::Widget& page_widget);
638 void set_current_page (std::string const &);
641 virtual void parameter_changed (std::string const &);
643 PBD::Configuration* _config;
644 Gtk::Notebook& notebook() { return _notebook; }
645 Gtk::TreeView& treeview() { return option_treeview; }
647 class OptionColumns : public Gtk::TreeModel::ColumnRecord
650 Gtk::TreeModelColumn<std::string> name;
651 Gtk::TreeModelColumn<Gtk::Widget*> widget;
659 OptionColumns option_columns;
660 Glib::RefPtr<Gtk::TreeStore> option_tree;
663 PBD::ScopedConnection config_connection;
664 Gtk::Notebook _notebook;
665 Gtk::TreeView option_treeview;
666 std::map<std::string, OptionEditorPage*> _pages;
668 void add_path_to_treeview (std::string const &, Gtk::Widget&);
669 Gtk::TreeModel::iterator find_path_in_treemodel (std::string const & pn,
670 bool create_missing = false);
671 void treeview_row_selected ();
674 /** The OptionEditor dialog-as-container base class */
675 class OptionEditorContainer : public OptionEditor, public Gtk::VBox
678 OptionEditorContainer (PBD::Configuration *, std::string const &);
679 ~OptionEditorContainer() {}
684 /** The OptionEditor dialog-as-container base class */
685 class OptionEditorWindow : public OptionEditor, public ArdourWindow
688 OptionEditorWindow (PBD::Configuration *, std::string const &);
689 ~OptionEditorWindow() {}
695 #endif /* __gtk_ardour_option_editor_h__ */