fix OSX compilation
[ardour.git] / gtk2_ardour / option_editor.h
index 5fc0dd02b0cd879e2f782cdd8291248bc342f811..53c671287831a4288383490cf2abd5a933715644 100644 (file)
@@ -1,8 +1,5 @@
-#ifndef __gtk_ardour_option_editor_h__
-#define __gtk_ardour_option_editor_h__
-
 /*
-    Copyright (C) 2001 Paul Davis
+    Copyright (C) 2009 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
 */
 
-#include <vector>
+#ifndef __gtk_ardour_option_editor_h__
+#define __gtk_ardour_option_editor_h__
 
 #include <gtkmm/notebook.h>
 #include <gtkmm/checkbutton.h>
-#include <gtkmm/table.h>
-#include <gtkmm/entry.h>
-#include <gtkmm/box.h>
-#include <gtkmm/label.h>
-#include <gtkmm/adjustment.h>
-#include <gtkmm/scale.h>
-#include <gtkmm/spinbutton.h>
-#include <gtkmm/radiobutton.h>
 #include <gtkmm/comboboxtext.h>
+#include <gtkmm/spinbutton.h>
+#include <gtkmm/table.h>
+#include <gtkmm/window.h>
 
-#include "ardour/session.h"
+#include "gtkmm2ext/slider_controller.h"
 
-#include "ardour_dialog.h"
-#include "editing.h"
+#include "ardour_window.h"
 #include "audio_clock.h"
+#include "ardour/types.h"
+
+/** @file option_editor.h
+ *  @brief Base class for option editing dialog boxes.
+ *
+ *  Code to provided the basis for dialogs which allow the user to edit options
+ *  from an ARDOUR::Configuration class.
+ *
+ *  The idea is that we have an OptionEditor class which is the dialog box.
+ *  This is essentially a GTK Notebook.  OptionEditorComponent objects can
+ *  then be added to the OptionEditor, and these components are arranged on
+ *  the pages of the Notebook.  There is also an OptionEditorComponent hierarchy
+ *  here, providing things like boolean and combobox option components.
+ *
+ *  It is intended that OptionEditor be subclassed to implement a particular
+ *  options dialog.
+ */
+
+namespace PBD {
+       class Configuration;
+}
+
+class OptionEditorPage;
+
+/** Base class for components of an OptionEditor dialog */
+class OptionEditorComponent
+{
+public:
+       virtual ~OptionEditorComponent() {}
 
-class ARDOUR_UI;
-class PublicEditor;
-class Mixer_UI;
-class IOSelector;
-class GainMeter;
-class PannerUI;
+       /** Called when a configuration parameter's value has changed.
+        *  @param p parameter name
+        */
+       virtual void parameter_changed (std::string const & p) = 0;
 
-class OptionEditor : public ArdourDialog
+       /** Called to instruct the object to set its UI state from the configuration */
+       virtual void set_state_from_config () = 0;
+
+       /** Called to instruct the object to add itself to an OptionEditorPage */
+       virtual void add_to_page (OptionEditorPage *) = 0;
+
+       void add_widget_to_page (OptionEditorPage*, Gtk::Widget*);
+       void add_widgets_to_page (OptionEditorPage*, Gtk::Widget*, Gtk::Widget*);
+
+       void set_note (std::string const &);
+
+        virtual Gtk::Widget& tip_widget() = 0;
+
+private:
+       void maybe_add_note (OptionEditorPage *, int);
+
+       std::string _note;
+};
+
+/** A component which provides a subheading within the dialog */
+class OptionEditorHeading : public OptionEditorComponent
 {
-  public:
-       OptionEditor (ARDOUR_UI&, PublicEditor&, Mixer_UI&);
-       ~OptionEditor ();
+public:
+       OptionEditorHeading (std::string const &);
 
-       void set_session (ARDOUR::Session *);
-       void save ();
+       void parameter_changed (std::string const &) {}
+       void set_state_from_config () {}
+       void add_to_page (OptionEditorPage *);
+
+        Gtk::Widget& tip_widget() { return *_label; }
+
+private:
+       Gtk::Label* _label; ///< the label used for the heading
+};
+
+/** A component which provides a box into which a subclass can put arbitrary widgets */
+class OptionEditorBox : public OptionEditorComponent
+{
+public:
+
+       /** Construct an OpenEditorBox */
+       OptionEditorBox ()
+       {
+               _box = Gtk::manage (new Gtk::VBox);
+               _box->set_spacing (4);
+       }
+
+       void parameter_changed (std::string const &) = 0;
+       void set_state_from_config () = 0;
+       void add_to_page (OptionEditorPage *);
+
+        Gtk::Widget& tip_widget() { return *_box->children().front().get_widget(); }
+
+protected:
+
+       Gtk::VBox* _box; ///< constituent box for subclasses to add widgets to
+};
+
+class RcConfigDisplay : public OptionEditorComponent
+{
+public:
+       RcConfigDisplay (std::string const &, std::string const &, sigc::slot<std::string>, char s = '\0');
+       void add_to_page (OptionEditorPage *);
+       void parameter_changed (std::string const & p);
+       void set_state_from_config ();
+       Gtk::Widget& tip_widget() { return *_info; }
+protected:
+       sigc::slot<std::string> _get;
+       Gtk::Label* _label;
+       Gtk::Label* _info;
+       std::string _id;
+       char _sep;
+};
+
+class RcActionButton : public OptionEditorComponent
+{
+public:
+       RcActionButton (std::string const & t, const Glib::SignalProxy0< void >::SlotType & slot, std::string const & l = "");
+       void add_to_page (OptionEditorPage *);
+
+       void parameter_changed (std::string const & p) {}
+       void set_state_from_config () {}
+       Gtk::Widget& tip_widget() { return *_button; }
+
+protected:
+       Gtk::Button* _button;
+       Gtk::Label* _label;
+       std::string _name;
+};
+
+/** Base class for components which provide UI to change an option */
+class Option : public OptionEditorComponent
+{
+public:
+       /** Construct an Option.
+        *  @param i Option id (e.g. "plugins-stop-with-transport")
+        *  @param n User-visible name (e.g. "Stop plugins when the transport is stopped")
+        */
+       Option (std::string const & i,
+               std::string const & n
+               )
+               : _id (i),
+                 _name (n)
+       {}
+
+       void parameter_changed (std::string const & p)
+       {
+               if (p == _id) {
+                       set_state_from_config ();
+               }
+       }
+
+       virtual void set_state_from_config () = 0;
+       virtual void add_to_page (OptionEditorPage*) = 0;
+
+       std::string id () const {
+               return _id;
+       }
+
+protected:
+
+       std::string _id;
+       std::string _name;
+};
 
-  private:
-       ARDOUR::Session *session;
-       ARDOUR_UI& ui;
-       PublicEditor& editor;
-       Mixer_UI& mixer;
+/** Component which provides the UI to handle a boolean option using a GTK CheckButton */
+class BoolOption : public Option
+{
+public:
 
-       Gtk::Notebook notebook;
+       BoolOption (std::string const &, std::string const &, sigc::slot<bool>, sigc::slot<bool, bool>);
+       void set_state_from_config ();
+       void add_to_page (OptionEditorPage*);
 
-       /* Generic */
+       void set_sensitive (bool yn) {
+               _button->set_sensitive (yn);
+       }
 
-       gint wm_close (GdkEventAny *);
-       bool focus_out_event_handler (GdkEventFocus*, void (OptionEditor::*pmf)());
-       void parameter_changed (const char* name);
+       Gtk::Widget& tip_widget() { return *_button; }
 
-       /* paths */
+protected:
 
-       Gtk::Table      path_table;
-       Gtk::Entry      session_raid_entry;
+       virtual void toggled ();
 
-       void setup_path_options();
-       void add_session_paths ();
-       void remove_session_paths ();
-       void raid_path_changed ();
+       sigc::slot<bool>       _get; ///< slot to get the configuration variable's value
+       sigc::slot<bool, bool> _set;  ///< slot to set the configuration variable's value
+       Gtk::CheckButton*      _button; ///< UI button
+       Gtk::Label*            _label; ///< label for button, so we can use markup
+};
 
-       /* misc */
+class RouteDisplayBoolOption : public BoolOption
+{
+public:
+       RouteDisplayBoolOption (std::string const &, std::string const &, sigc::slot<bool>, sigc::slot<bool, bool>);
+protected:
+       virtual void toggled ();
+};
 
-       Gtk::VBox        misc_packer;
+/** Component which allows to add any GTK Widget - intended for single buttons and custom stateless objects */
+class FooOption : public OptionEditorComponent
+{
+public:
+       FooOption (Gtk::Widget *w) : _w (w) {}
+
+       void add_to_page (OptionEditorPage* p) {
+               add_widget_to_page (p, _w);
+       }
+
+       Gtk::Widget& tip_widget() { return *_w; }
+       void set_state_from_config () {}
+       void parameter_changed (std::string const &) {}
+private:
+       Gtk::Widget *_w;
+};
 
-       Gtk::Adjustment  short_xfade_adjustment;
-       Gtk::HScale      short_xfade_slider;
-       Gtk::Adjustment  destructo_xfade_adjustment;
-       Gtk::HScale      destructo_xfade_slider;
+/** Component which provides the UI to handle a string option using a GTK Entry */
+class EntryOption : public Option
+{
+public:
 
-       void setup_misc_options();
+       EntryOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
+       void set_state_from_config ();
+       void add_to_page (OptionEditorPage*);
+       void set_sensitive (bool);
+       void set_invalid_chars (std::string i) { _invalid = i; }
 
-       void short_xfade_adjustment_changed ();
-       void destructo_xfade_adjustment_changed ();
+       Gtk::Widget& tip_widget() { return *_entry; }
 
-       Gtk::Adjustment history_depth;
-       Gtk::Adjustment saved_history_depth;
-       Gtk::SpinButton     history_depth_spinner;
-       Gtk::SpinButton     saved_history_depth_spinner;
-       Gtk::CheckButton    limit_history_button;
-       Gtk::CheckButton    save_history_button;
+private:
 
-       void history_depth_changed();
-       void saved_history_depth_changed();
-       void save_history_toggled ();
-       void limit_history_toggled ();
+       void activated ();
+       bool focus_out (GdkEventFocus*);
+       void filter_text (const Glib::ustring&, int*);
 
-       /* Sync */
+       sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
+       sigc::slot<bool, std::string> _set;  ///< slot to set the configuration variable's value
+       Gtk::Label* _label; ///< UI label
+       Gtk::Entry* _entry; ///< UI entry
+       std::string _invalid;
+};
 
-       Gtk::VBox sync_packer;
 
-       Gtk::ComboBoxText slave_type_combo;
-       AudioClock smpte_offset_clock;
-       Gtk::CheckButton smpte_offset_negative_button;
-       Gtk::CheckButton synced_timecode_button;
+/** Component which provides the UI to handle an enumerated option using a GTK ComboBox.
+ *  The template parameter is the enumeration.
+ */
+template <class T>
+class ComboOption : public Option
+{
+public:
+
+       /** Construct an ComboOption.
+        *  @param i id
+        *  @param n User-visible name.
+        *  @param g Slot to get the variable's value.
+        *  @param s Slot to set the variable's value.
+        */
+       ComboOption (
+               std::string const & i,
+               std::string const & n,
+               sigc::slot<T> g,
+               sigc::slot<bool, T> s
+               )
+               : Option (i, n),
+                 _get (g),
+                 _set (s)
+       {
+               _label = Gtk::manage (new Gtk::Label (n + ":"));
+               _label->set_alignment (0, 0.5);
+               _combo = Gtk::manage (new Gtk::ComboBoxText);
+               _combo->signal_changed().connect (sigc::mem_fun (*this, &ComboOption::changed));
+       }
+
+       void set_state_from_config () {
+               uint32_t r = 0;
+               while (r < _options.size() && _get () != _options[r]) {
+                       ++r;
+               }
+
+               if (r < _options.size()) {
+                       _combo->set_active (r);
+               }
+       }
+
+       void add_to_page (OptionEditorPage* p)
+       {
+               add_widgets_to_page (p, _label, _combo);
+       }
+
+       /** Add an allowed value for this option.
+        *  @param e Enumeration.
+        *  @param o User-visible name for this value.
+        */
+       void add (T e, std::string const & o) {
+               _options.push_back (e);
+               _combo->append_text (o);
+       }
+
+       void clear () {
+               _combo->clear_items();
+               _options.clear ();
+       }
+
+       void changed () {
+               uint32_t const r = _combo->get_active_row_number ();
+               if (r < _options.size()) {
+                       _set (_options[r]);
+               }
+       }
+
+       void set_sensitive (bool yn) {
+               _combo->set_sensitive (yn);
+       }
+
+        Gtk::Widget& tip_widget() { return *_combo; }
+
+private:
+
+       sigc::slot<T> _get;
+       sigc::slot<bool, T> _set;
+       Gtk::Label* _label;
+       Gtk::ComboBoxText* _combo;
+       std::vector<T> _options;
+};
 
-       void setup_sync_options ();
 
-       void smpte_offset_chosen ();
-       void smpte_offset_negative_clicked ();
-       void synced_timecode_toggled ();
+/** Component which provides the UI for a GTK HScale.
+ */
+class HSliderOption : public Option
+{
+public:
+
+       /** Construct an ComboOption.
+        *  @param i id
+        *  @param n User-visible name.
+        *  @param g Slot to get the variable's value.
+        *  @param s Slot to set the variable's value.
+        */
+       HSliderOption (
+               std::string const & i,
+               std::string const & n,
+               Gtk::Adjustment &adj
+               )
+               : Option (i, n)
+       {
+               _label = Gtk::manage (new Gtk::Label (n + ":"));
+               _label->set_alignment (0, 0.5);
+               _hscale = Gtk::manage (new Gtk::HScale(adj));
+               _adj = NULL;
+       }
+
+       HSliderOption (
+               std::string const & i,
+               std::string const & n,
+               Gtk::Adjustment *adj,
+               sigc::slot<float> g,
+               sigc::slot<bool, float> s
+               )
+               : Option (i, n)
+               , _get (g)
+               , _set (s)
+               , _adj (adj)
+       {
+               _label = Gtk::manage (new Gtk::Label (n + ":"));
+               _label->set_alignment (0, 0.5);
+               _hscale = Gtk::manage (new Gtk::HScale(*_adj));
+               _adj->signal_value_changed().connect (sigc::mem_fun (*this, &HSliderOption::changed));
+       }
+
+       void set_state_from_config () {
+               if (_adj) _adj->set_value (_get());
+       }
+
+       void changed () {
+               if (_adj) _set (_adj->get_value ());
+       }
+
+       void add_to_page (OptionEditorPage* p)
+       {
+               add_widgets_to_page (p, _label, _hscale);
+       }
+
+       void set_sensitive (bool yn) {
+               _hscale->set_sensitive (yn);
+       }
+
+       Gtk::Widget& tip_widget() { return *_hscale; }
+       Gtk::HScale& scale() { return *_hscale; }
+
+private:
+       sigc::slot<float> _get;
+       sigc::slot<bool, float> _set;
+       Gtk::Label* _label;
+       Gtk::HScale* _hscale;
+       Gtk::Adjustment* _adj;
+};
 
-       /* MIDI */
+/** Component which provides the UI to handle an enumerated option using a GTK ComboBox.
+ *  The template parameter is the enumeration.
+ */
+class ComboStringOption : public Option
+{
+public:
+
+       /** Construct an ComboOption.
+        *  @param i id
+        *  @param n User-visible name.
+        *  @param g Slot to get the variable's value.
+        *  @param s Slot to set the variable's value.
+        */
+       ComboStringOption (
+               std::string const & i,
+               std::string const & n,
+               sigc::slot<std::string> g,
+               sigc::slot<bool, std::string> s
+               )
+               : Option (i, n),
+                 _get (g),
+                 _set (s)
+       {
+               _label = Gtk::manage (new Gtk::Label (n + ":"));
+               _label->set_alignment (0, 0.5);
+               _combo = Gtk::manage (new Gtk::ComboBoxText);
+               _combo->signal_changed().connect (sigc::mem_fun (*this, &ComboStringOption::changed));
+       }
+
+       void set_state_from_config () {
+               _combo->set_active_text (_get());
+       }
+
+       void add_to_page (OptionEditorPage* p)
+       {
+               add_widgets_to_page (p, _label, _combo);
+       }
+
+       /** Set the allowed strings for this option
+        *  @param strings a vector of allowed strings
+        */
+        void set_popdown_strings (const std::vector<std::string>& strings) {
+               _combo->clear_items ();
+               for (std::vector<std::string>::const_iterator i = strings.begin(); i != strings.end(); ++i) {
+                       _combo->append_text (*i);
+               }
+       }
+
+       void clear () {
+               _combo->clear_items();
+       }
+
+       void changed () {
+               _set (_combo->get_active_text ());
+       }
+
+       void set_sensitive (bool yn) {
+               _combo->set_sensitive (yn);
+       }
+
+        Gtk::Widget& tip_widget() { return *_combo; }
+
+private:
+        sigc::slot<std::string> _get;
+        sigc::slot<bool, std::string> _set;
+       Gtk::Label* _label;
+       Gtk::ComboBoxText* _combo;
+};
 
-       Gtk::VBox  midi_packer;
 
-       Gtk::RadioButton::Group mtc_button_group;
-       Gtk::RadioButton::Group mmc_button_group;
-       Gtk::RadioButton::Group midi_button_group;
-       Gtk::RadioButton::Group midi_clock_button_group;
+/** Component which provides the UI to handle a boolean option which needs
+ *  to be represented as a ComboBox to be clear to the user.
+ */
+class BoolComboOption : public Option
+{
+public:
+
+       BoolComboOption (
+               std::string const &,
+               std::string const &,
+               std::string const &,
+               std::string const &,
+               sigc::slot<bool>,
+               sigc::slot<bool, bool>
+               );
+
+       void set_state_from_config ();
+       void add_to_page (OptionEditorPage *);
+       void changed ();
+       void set_sensitive (bool);
+
+        Gtk::Widget& tip_widget() { return *_combo; }
+
+private:
+
+       sigc::slot<bool> _get;
+       sigc::slot<bool, bool> _set;
+       Gtk::Label* _label;
+       Gtk::ComboBoxText* _combo;
+};
 
-       Gtk::Table      midi_port_table;
-       std::vector<Gtk::Widget*> midi_port_table_widgets;
-       Gtk::Adjustment mmc_receive_device_id_adjustment;
-       Gtk::SpinButton mmc_receive_device_id_spinner;
-       Gtk::Adjustment mmc_send_device_id_adjustment;
-       Gtk::SpinButton mmc_send_device_id_spinner;
-       Gtk::Button     add_midi_port_button;
-       Gtk::Adjustment initial_program_change_adjustment;
-       Gtk::SpinButton initial_program_change_spinner;
 
-       void add_midi_port ();
-       void remove_midi_port (MIDI::Port*);
-       void redisplay_midi_ports ();
 
-       void port_online_toggled (MIDI::Port*,Gtk::ToggleButton*);
-       void port_trace_in_toggled (MIDI::Port*,Gtk::ToggleButton*);
-       void port_trace_out_toggled (MIDI::Port*,Gtk::ToggleButton*);
+/** Component which provides the UI to handle an numeric option using a GTK SpinButton */
+template <class T>
+class SpinOption : public Option
+{
+public:
+       /** Construct an SpinOption.
+        *  @param i id
+        *  @param n User-visible name.
+        *  @param g Slot to get the variable's value.
+        *  @param s Slot to set the variable's value.
+        *  @param min Variable minimum value.
+        *  @param max Variable maximum value.
+        *  @param step Step for the spin button.
+        *  @param page Page step for the spin button.
+        *  @param unit Unit name.
+        *  @param scale Scaling factor (such that for a value x in the spinbutton, x * scale is written to the config)
+        *  @param digits Number of decimal digits to show.
+        */
+       SpinOption (
+               std::string const & i,
+               std::string const & n,
+               sigc::slot<T> g,
+               sigc::slot<bool, T> s,
+               T min,
+               T max,
+               T step,
+               T page,
+               std::string const & unit = "",
+               float scale = 1,
+               unsigned digits = 0
+               )
+               : Option (i, n),
+                 _get (g),
+                 _set (s),
+                 _scale (scale)
+       {
+               _label = Gtk::manage (new Gtk::Label (n + ":"));
+               _label->set_alignment (0, 0.5);
+
+               _spin = Gtk::manage (new Gtk::SpinButton);
+               _spin->set_range (min, max);
+               _spin->set_increments (step, page);
+               _spin->set_digits(digits);
+
+               _box = Gtk::manage (new Gtk::HBox);
+               _box->pack_start (*_spin, true, true);
+               _box->set_spacing (4);
+               if (unit.length()) {
+                       _box->pack_start (*Gtk::manage (new Gtk::Label (unit)), false, false);
+               }
+
+               _spin->signal_value_changed().connect (sigc::mem_fun (*this, &SpinOption::changed));
+       }
+
+       void set_state_from_config ()
+       {
+               _spin->set_value (_get () / _scale);
+       }
+
+       void add_to_page (OptionEditorPage* p)
+       {
+               add_widgets_to_page (p, _label, _box);
+       }
+
+       void changed ()
+       {
+               _set (static_cast<T> (_spin->get_value ()) * _scale);
+       }
+
+        Gtk::Widget& tip_widget() { return *_spin; }
+
+private:
+       sigc::slot<T> _get;
+       sigc::slot<bool, T> _set;
+       float _scale;
+       Gtk::Label* _label;
+       Gtk::HBox* _box;
+       Gtk::SpinButton* _spin;
+};
+
+class FaderOption : public Option
+{
+public:
+
+       FaderOption (std::string const &, std::string const &, sigc::slot<ARDOUR::gain_t> g, sigc::slot<bool, ARDOUR::gain_t> s);
+       void set_state_from_config ();
+       void add_to_page (OptionEditorPage *);
+
+        Gtk::Widget& tip_widget() { return *_db_slider; }
+
+private:
+       void db_changed ();
+       void on_activate ();
+       bool on_key_press (GdkEventKey* ev);
+
+       Gtk::Adjustment _db_adjustment;
+       Gtkmm2ext::HSliderController* _db_slider;
+       Gtk::Entry _db_display;
+       Gtk::Label _label;
+       Gtk::HBox _box;
+       Gtk::VBox _fader_centering_box;
+       sigc::slot<ARDOUR::gain_t> _get;
+       sigc::slot<bool, ARDOUR::gain_t> _set;
+};
 
-       void mmc_port_chosen (MIDI::Port*,Gtk::RadioButton*, Gtk::Button*);
-       void mtc_port_chosen (MIDI::Port*,Gtk::RadioButton*, Gtk::Button*);
-       void midi_port_chosen (MIDI::Port*,Gtk::RadioButton*, Gtk::Button*);
-       void midi_clock_port_chosen (MIDI::Port*,Gtk::RadioButton*, Gtk::Button*);
-       bool port_removable (MIDI::Port*);
+class ClockOption : public Option
+{
+public:
+       ClockOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
+       void set_state_from_config ();
+       void add_to_page (OptionEditorPage *);
+       void set_session (ARDOUR::Session *);
 
-       void mmc_receive_device_id_adjusted ();
-       void mmc_send_device_id_adjusted ();
+        Gtk::Widget& tip_widget() { return _clock; }
+        AudioClock& clock() { return _clock; }
 
-       void initial_program_change_adjusted ();
+private:
+       void save_clock_time ();
+       Gtk::Label _label;
+       AudioClock _clock;
+       sigc::slot<std::string> _get;
+       sigc::slot<bool, std::string> _set;
+       ARDOUR::Session *_session;
+};
 
-       void map_port_online (MIDI::Port*, Gtk::ToggleButton*);
+class DirectoryOption : public Option
+{
+public:
+       DirectoryOption (std::string const &, std::string const &, sigc::slot<std::string>, sigc::slot<bool, std::string>);
 
-       void setup_midi_options();
+       void set_state_from_config ();
+       void add_to_page (OptionEditorPage *);
 
-       enum PortIndex {
-               MtcIndex = 0,
-               MmcIndex = 1,
-               MidiIndex = 2,
-               MidiClockIndex = 3
-       };
+        Gtk::Widget& tip_widget() { return _file_chooser; }
 
-       std::map<MIDI::Port*,std::vector<Gtk::RadioButton*> > port_toggle_buttons;
+private:
+       void selection_changed ();
 
-       /* Click */
+       sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
+       sigc::slot<bool, std::string> _set;  ///< slot to set the configuration variable's value
+       Gtk::FileChooserButton _file_chooser;
+};
 
-       IOSelector*   click_io_selector;
-       GainMeter* click_gpm;
-       PannerUI*     click_panner;
-       bool          first_click_setup;
-       Gtk::HBox     click_hpacker;
-       Gtk::VBox     click_packer;
-       Gtk::Table    click_table;
-       Gtk::Entry    click_path_entry;
-       Gtk::Entry    click_emphasis_path_entry;
-       Gtk::Button   click_browse_button;
-       Gtk::Button   click_emphasis_browse_button;
+/** Class to represent a single page in an OptionEditor's notebook.
+ *  Pages are laid out using a 3-column table; the 1st column is used
+ *  to indent non-headings, and the 2nd and 3rd for actual content.
+ */
+class OptionEditorPage
+{
+public:
+       OptionEditorPage (Gtk::Notebook&, std::string const &);
 
-       void setup_click_editor ();
-       void clear_click_editor ();
+       Gtk::VBox box;
+       Gtk::Table table;
+       std::list<OptionEditorComponent*> components;
+};
 
-       void click_chosen (const string & paths);
-       void click_emphasis_chosen (const string & paths);
+/** The OptionEditor dialog base class */
+class OptionEditor : virtual public sigc::trackable
+{
+public:
+       OptionEditor (PBD::Configuration *);
+       virtual ~OptionEditor ();
 
-       void click_browse_clicked ();
-       void click_emphasis_browse_clicked ();
+       void add_option (std::string const &, OptionEditorComponent *);
+       void add_page (std::string const &, Gtk::Widget& page_widget);
 
-       void click_sound_changed ();
-       void click_emphasis_sound_changed ();
+       void set_current_page (std::string const &);
 
-       /* Auditioner */
+protected:
+       virtual void parameter_changed (std::string const &);
 
-       Gtk::VBox     audition_packer;
-       Gtk::HBox     audition_hpacker;
-       Gtk::Label    audition_label;
-       IOSelector*   auditioner_io_selector;
-       GainMeter* auditioner_gpm;
-       PannerUI* auditioner_panner;
+       PBD::Configuration* _config;
+       Gtk::Notebook& notebook() { return _notebook; }
+       Gtk::TreeView& treeview() { return option_treeview; }
 
-       void setup_auditioner_editor ();
-       void clear_auditioner_editor ();
-       void connect_audition_editor ();
+       class OptionColumns : public Gtk::TreeModel::ColumnRecord
+       {
+          public:
+               Gtk::TreeModelColumn<std::string> name;
+               Gtk::TreeModelColumn<Gtk::Widget*> widget;
 
-       /* keyboard/mouse */
+               OptionColumns() {
+                       add (name);
+                       add (widget);
+               }
+       };
 
-       Gtk::Table keyboard_mouse_table;
-       Gtk::ComboBoxText keyboard_layout_selector;
-       Gtk::ComboBoxText edit_modifier_combo;
-       Gtk::ComboBoxText delete_modifier_combo;
-       Gtk::ComboBoxText snap_modifier_combo;
-       Gtk::Adjustment delete_button_adjustment;
-       Gtk::SpinButton delete_button_spin;
-       Gtk::Adjustment edit_button_adjustment;
-       Gtk::SpinButton edit_button_spin;
+       OptionColumns option_columns;
+       Glib::RefPtr<Gtk::TreeStore> option_tree;
 
-       std::map<std::string,std::string> bindings_files;
+private:
+       PBD::ScopedConnection config_connection;
+       Gtk::Notebook _notebook;
+       Gtk::TreeView option_treeview;
+       std::map<std::string, OptionEditorPage*> _pages;
 
-       void setup_keyboard_options ();
-       void delete_modifier_chosen ();
-       void edit_modifier_chosen ();
-       void snap_modifier_chosen ();
-       void edit_button_changed ();
-       void delete_button_changed ();
-       void bindings_changed ();
+       void add_path_to_treeview (std::string const &, Gtk::Widget&);
+       void treeview_row_selected ();
 };
 
-#endif /* __gtk_ardour_option_editor_h__ */
+/** The OptionEditor dialog-as-container base class */
+class OptionEditorContainer : public OptionEditor, public Gtk::VBox
+{
+public:
+       OptionEditorContainer (PBD::Configuration *, std::string const &);
+       ~OptionEditorContainer() {}
+private:
+       Gtk::HBox hpacker;
+};
 
+/** The OptionEditor dialog-as-container base class */
+class OptionEditorWindow : public OptionEditor, public ArdourWindow
+{
+public:
+       OptionEditorWindow (PBD::Configuration *, std::string const &);
+       ~OptionEditorWindow() {}
+private:
+       Gtk::VBox container;
+       Gtk::HBox hpacker;
+};
 
+#endif /* __gtk_ardour_option_editor_h__ */