partial patch/partial by-hand merge of 2.X commits 3169&3170 to 3.X codebase
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 8 Dec 2008 16:07:28 +0000 (16:07 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 8 Dec 2008 16:07:28 +0000 (16:07 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@4300 d708f5d6-7413-0410-9779-e7cbd77b26cf

35 files changed:
gtk2_ardour/SConscript
gtk2_ardour/ardour_ui.cc
gtk2_ardour/audio_region_view.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_mixer.cc
gtk2_ardour/gain_meter.cc
gtk2_ardour/gain_meter.h
gtk2_ardour/level_meter.cc
gtk2_ardour/level_meter.h
gtk2_ardour/main.cc
gtk2_ardour/matrix.cc [new file with mode: 0644]
gtk2_ardour/matrix.h [new file with mode: 0644]
gtk2_ardour/mixer_strip.cc
gtk2_ardour/mixer_strip.h
gtk2_ardour/option_editor.cc
gtk2_ardour/panner_ui.cc
gtk2_ardour/panner_ui.h
gtk2_ardour/port_group.h [new file with mode: 0644]
gtk2_ardour/port_matrix.cc
gtk2_ardour/port_matrix.h
gtk2_ardour/processor_box.cc
gtk2_ardour/processor_box.h
gtk2_ardour/route_params_ui.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/route_ui.cc
gtk2_ardour/route_ui.h
gtk2_ardour/send_ui.cc
gtk2_ardour/sfdb_ui.cc
libs/ardour/plugin_manager.cc
libs/gtkmm2ext/binding_proxy.cc
libs/gtkmm2ext/gtkmm2ext/barcontroller.h
libs/gtkmm2ext/gtkmm2ext/bindable_button.h
libs/gtkmm2ext/gtkmm2ext/binding_proxy.h
libs/gtkmm2ext/gtkmm2ext/slider_controller.h
libs/gtkmm2ext/slider_controller.cc

index fef196e5ba046371c9b0f5ca42b38306fe7b23ac..8bfccae2b4e3b263699c2f231e9cc2c523e3e682 100644 (file)
@@ -194,6 +194,7 @@ lineset.cc
 location_ui.cc
 main.cc
 marker.cc
+matrix.cc
 midi_channel_selector.cc
 midi_port_dialog.cc
 midi_region_view.cc
index b3ac2e3db827afb9c396cc850819a6194f54066a..44280a3109806ad7a480183ca943a996e7bab9c5 100644 (file)
@@ -1736,8 +1736,8 @@ ARDOUR_UI::engine_halted ()
                           _("\
 JACK has either been shutdown or it\n\
 disconnected Ardour because Ardour\n\
-was not fast enough. You can save the\n\
-session and/or try to reconnect to JACK ."));
+was not fast enough. Try to restart\n\
+JACK, reconnect and save the session."));
        pop_back_splash ();
        msg.run ();
 }
index 40046cd9a1a8f0f6f81e6812af55159ca526a464..e3dd980eee93f8b3d4e4b94aa8c3de086eeaa3bc 100644 (file)
@@ -196,6 +196,10 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
 
        setup_fade_handle_positions ();
 
+       if (!Config->get_show_region_fades()) {
+               set_fade_visibility (false);
+       }
+
        string line_name = _region->name();
        line_name += ':';
        line_name += "gain";
@@ -410,8 +414,10 @@ AudioRegionView::reset_width_dependent_items (double pixel_width)
                                fade_in_handle->hide();
                                fade_out_handle->hide();
                        } else {
-                               fade_in_handle->show();
-                               fade_out_handle->show();
+                               if (Config->get_show_region_fades()) {
+                                       fade_in_handle->show();
+                                       fade_out_handle->show();
+                               }
                        }
                }
        }
index 279de992986721dcdb361b076fcb5cf8b1167fc1..394c1ad121e91fc64e00a4ecc9d22cab6abec894 100644 (file)
@@ -294,6 +294,7 @@ class Editor : public PublicEditor
        Width editor_mixer_strip_width;
        void maybe_add_mixer_strip_width (XMLNode&);
        void show_editor_mixer (bool yn);
+       void create_editor_mixer ();
        void show_editor_list (bool yn);
        void set_selected_mixer_strip (TimeAxisView&);
        void hide_track_in_display (TimeAxisView& tv, bool temporary = false);
index 6bfc325f6de62426c3c7a4548bcb5ef023e032f0..cb10b2f55173ccfd7554cddbf0802c59dbfcc4ab 100644 (file)
@@ -57,13 +57,6 @@ Editor::editor_list_button_toggled ()
        }
 }
 
-void
-Editor::cms_new (boost::shared_ptr<ARDOUR::Route> r)
-{
-       current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(), *session, r);
-       current_mixer_strip->GoingAway.connect (mem_fun (*this, &Editor::cms_deleted));
-}
-
 void
 Editor::cms_deleted ()
 {
@@ -73,76 +66,108 @@ Editor::cms_deleted ()
 void
 Editor::show_editor_mixer (bool yn)
 {
+       boost::shared_ptr<ARDOUR::Route> r;
+
        show_editor_mixer_when_tracks_arrive = false;
 
+       if (!session) {
+               show_editor_mixer_when_tracks_arrive = yn;
+               return;
+       }
+
        if (yn) {
 
-               if (current_mixer_strip == 0) {
+               if (selection->tracks.empty()) {
+                       
+                       if (track_views.empty()) {      
+                               show_editor_mixer_when_tracks_arrive = true;
+                               return;
+                       } 
 
-                       if (selection->tracks.empty()) {
-                               
-                               if (track_views.empty()) {      
-                                       show_editor_mixer_when_tracks_arrive = true;
-                                       return;
-                               } 
+                       for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+                               AudioTimeAxisView* atv;
                                
-                               for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-                                       AudioTimeAxisView* atv;
-
-                                       if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
-                                               cms_new (atv->route ());
-                                               break;
-                                       }
+                               if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
+                                       r = atv->route();
+                                       break;
                                }
+                       }
 
-                       } else {
-
-                               sort_track_selection ();
-
-                               for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
-                                       AudioTimeAxisView* atv;
+               } else {
 
-                                       if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
-                                               cms_new (atv->route ());
-                                               break;
-                                       }
+                       sort_track_selection ();
+                       
+                       for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+                               AudioTimeAxisView* atv;
+                               
+                               if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
+                                       r = atv->route();
+                                       break;
                                }
-
                        }
+               }
+
+               if (r) {
+                       bool created;
 
                        if (current_mixer_strip == 0) {
-                               return;
-                       }               
+                               create_editor_mixer ();
+                               created = true;
+                       } else {
+                               created = false;
+                       }
+
+                       current_mixer_strip->set_route (r);
+
+                       if (created) {
+                               current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this);
+                       }
                }
                
                if (current_mixer_strip->get_parent() == 0) {
-                       current_mixer_strip->set_embedded (true);
-                       current_mixer_strip->Hiding.connect (mem_fun(*this, &Editor::current_mixer_strip_hidden));
-                       current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::current_mixer_strip_removed));
-                       current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this);
-
                        global_hpacker.pack_start (*current_mixer_strip, Gtk::PACK_SHRINK );
                        global_hpacker.reorder_child (*current_mixer_strip, 0);
-
                        current_mixer_strip->show_all ();
                }
 
        } else {
 
                if (current_mixer_strip) {
-                       editor_mixer_strip_width = current_mixer_strip->get_width ();
                        if (current_mixer_strip->get_parent() != 0) {
                                global_hpacker.remove (*current_mixer_strip);
                        }
                }
        }
+
 #ifdef GTKOSX
        /* XXX gtk problem here */
+       ensure_all_elements_drawn();
+#endif
+}
+
+#ifdef GTKOSX
+void
+Editor::ensure_all_elements_drawn ()
+{
+       controls_layout.queue_draw ();
        ruler_label_event_box.queue_draw ();
        time_button_event_box.queue_draw ();
-       controls_layout.queue_draw ();
-#endif
 }
+#endif
+
+void
+Editor::create_editor_mixer ()
+{
+       current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
+                                             *session,
+                                             false);
+       current_mixer_strip->Hiding.connect (mem_fun(*this, &Editor::current_mixer_strip_hidden));
+       current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::current_mixer_strip_removed));
+#ifdef GTKOSX
+       current_mixer_strip->WidthChanged.connect (mem_fun(*this, &Editor::ensure_all_elements_drawn));
+#endif
+       current_mixer_strip->set_embedded (true);
+}      
 
 void
 Editor::show_editor_list (bool yn)
@@ -157,38 +182,52 @@ Editor::show_editor_list (bool yn)
 void
 Editor::set_selected_mixer_strip (TimeAxisView& view)
 {
-       RouteTimeAxisView* rt;
+       AudioTimeAxisView* at;
        bool show = false;
+       bool created;
 
-       if (!session || (rt = dynamic_cast<RouteTimeAxisView*>(&view)) == 0) {
+       if (!session || (at = dynamic_cast<AudioTimeAxisView*>(&view)) == 0) {
                return;
        }
-       
-       if (current_mixer_strip) {
 
-               /* might be nothing to do */
-
-               if (current_mixer_strip->route() == rt->route()) {
+       Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
+       if (act) {
+               Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(act);
+               if (!tact || !tact->get_active()) {
+                       /* not showing mixer strip presently */
                        return;
                }
+       }
 
-               if (current_mixer_strip->get_parent()) {
-                       show = true;
-               }
-               delete current_mixer_strip;
-               current_mixer_strip = 0;
+       if (current_mixer_strip == 0) {
+               create_editor_mixer ();
+               created = true;
+       } else {
+               created = false;
        }
 
-       current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
-                                             *session,
-                                             rt->route(), false);
-       current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::cms_deleted));
+       /* might be nothing to do */
        
+       if (current_mixer_strip->route() == at->route()) {
+               return;
+       }
+       
+       if (current_mixer_strip->get_parent()) {
+               show = true;
+       }
+
+       current_mixer_strip->set_route (at->route());
+
+       if (created) {
+               current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this);
+       }
+
        if (show) {
                show_editor_mixer (true);
        }
 }
 
+
 double current = 0.0;
 bool currentInitialized = 0;
 
@@ -276,7 +315,7 @@ void
 Editor::current_mixer_strip_removed ()
 {
        if (current_mixer_strip) {
-               /* it is being deleted */
+               /* it is being deleted elsewhere */
                current_mixer_strip = 0;
        }
 }
index a580ec6b3876726bf0293a6c03608477cac79338..b34c0b8d28b5f76dde5327e3fd1677834c4e9ea9 100644 (file)
@@ -72,17 +72,18 @@ GainMeter::setup_slider_pix ()
        }
 }
 
-GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s, 
+GainMeterBase::GainMeterBase (Session& s, 
                              const Glib::RefPtr<Gdk::Pixbuf>& pix,
                              bool horizontal)
-       : _io (io),
-         _session (s),
+       : _session (s),
          // 0.781787 is the value needed for gain to be set to 0.
          gain_adjustment (0.781787, 0.0, 1.0, 0.01, 0.1),
          gain_automation_style_button (""),
          gain_automation_state_button ("")
        
 {
+       using namespace Menu_Helpers;
+
        ignore_toggle = false;
        meter_menu = 0;
        next_release_selects = false;
@@ -92,16 +93,14 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
        if (horizontal) {
                gain_slider = manage (new HSliderController (pix,
                                                             &gain_adjustment,
-                                                            _io->gain_control(),
                                                             false));
        } else {
                gain_slider = manage (new VSliderController (pix,
                                                             &gain_adjustment,
-                                                            _io->gain_control(),
                                                             false));
        }
 
-       level_meter = new LevelMeter(_io, _session);
+       level_meter = new LevelMeter(_session);
 
        gain_slider->signal_button_press_event().connect (mem_fun(*this, &GainMeter::start_gain_touch));
        gain_slider->signal_button_release_event().connect (mem_fun(*this, &GainMeter::end_gain_touch));
@@ -133,10 +132,40 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
 
        gain_automation_state_button.set_size_request(15, 15);
        gain_automation_style_button.set_size_request(15, 15);
+  
+       gain_astyle_menu.items().push_back (MenuElem (_("Trim")));
+       gain_astyle_menu.items().push_back (MenuElem (_("Abs")));
+       
+       gain_astate_menu.set_name ("ArdourContextMenu");
+       gain_astyle_menu.set_name ("ArdourContextMenu");
 
+       gain_adjustment.signal_value_changed().connect (mem_fun(*this, &GainMeterBase::gain_adjusted));
+       peak_display.signal_button_release_event().connect (mem_fun(*this, &GainMeterBase::peak_button_release), false);
+       gain_display.signal_key_press_event().connect (mem_fun(*this, &GainMeterBase::gain_key_press), false);
 
+       ResetAllPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_peak_display));
+       ResetGroupPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_group_peak_display));
 
+       UI::instance()->theme_changed.connect (mem_fun(*this, &GainMeterBase::on_theme_changed));
+       ColorsChanged.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), false));
+       DPIReset.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), true));
+}
+
+GainMeterBase::~GainMeterBase ()
+{
+       delete meter_menu;
+       delete level_meter;
+}
 
+void
+GainMeterBase::set_io (boost::shared_ptr<IO> io)
+{
+       connections.clear ();
+       
+       _io = io;
+       
+       level_meter->set_io (_io);
+       gain_slider->set_controllable (_io->gain_control());
 
        boost::shared_ptr<Route> r;
 
@@ -146,6 +175,8 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
 
                        using namespace Menu_Helpers;
        
+                       gain_astate_menu.items().clear ();
+
                        gain_astate_menu.items().push_back (MenuElem (_("Manual"), 
                                                                      bind (mem_fun (*_io, &IO::set_parameter_automation_state),
                                                                            Evoral::Parameter(GainAutomation), (AutoState) Off)));
@@ -159,50 +190,21 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
                                                                      bind (mem_fun (*_io, &IO::set_parameter_automation_state),
                                                                            Evoral::Parameter(GainAutomation), (AutoState) Touch)));
                        
-                       gain_astyle_menu.items().push_back (MenuElem (_("Trim")));
-                       gain_astyle_menu.items().push_back (MenuElem (_("Abs")));
-                       
-                       gain_astate_menu.set_name ("ArdourContextMenu");
-                       gain_astyle_menu.set_name ("ArdourContextMenu");
+                       connections.push_back (gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false));
+                       connections.push_back (gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false));
                        
-                       gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false);
-                       gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false);
-                       
-                       r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed));
-                       r->gain_control()->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed));
+                       connections.push_back (r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed)));
+                       connections.push_back (r->gain_control()->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed)));
 
                        gain_automation_state_changed ();
                }
        }
 
-       _io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed));
-
-       gain_adjustment.signal_value_changed().connect (mem_fun(*this, &GainMeterBase::gain_adjusted));
-       peak_display.signal_button_release_event().connect (mem_fun(*this, &GainMeterBase::peak_button_release), false);
-       gain_display.signal_key_press_event().connect (mem_fun(*this, &GainMeterBase::gain_key_press), false);
+       connections.push_back (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed)));
 
        gain_changed ();
        show_gain ();
-
        update_gain_sensitive ();
-       
-       ResetAllPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_peak_display));
-       ResetGroupPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_group_peak_display));
-
-       UI::instance()->theme_changed.connect (mem_fun(*this, &GainMeterBase::on_theme_changed));
-       ColorsChanged.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), false));
-       DPIReset.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), true));
-}
-
-GainMeterBase::~GainMeterBase ()
-{
-       if (meter_menu) {
-               delete meter_menu;
-       }
-
-       if (level_meter) {
-               delete level_meter;
-       }
 }
 
 void
@@ -752,10 +754,9 @@ GainMeterBase::on_theme_changed()
        style_changed = true;
 }
 
-GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
-       : GainMeterBase (io, s, slider, false)
+GainMeter::GainMeter (Session& s)
+       : GainMeterBase (s, slider, false)
 {
-
        gain_display_box.set_homogeneous (true);
        gain_display_box.set_spacing (2);
        gain_display_box.pack_start (gain_display, true, true);
@@ -785,6 +786,31 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
        hbox.set_spacing (2);
        hbox.pack_start (*fader_vbox, true, true);
 
+       set_spacing (2);
+
+       pack_start (gain_display_box, Gtk::PACK_SHRINK);
+       pack_start (hbox, Gtk::PACK_SHRINK);
+
+       meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose));
+}
+
+void
+GainMeter::set_io (boost::shared_ptr<IO> io)
+{
+       if (level_meter->get_parent()) {
+               hbox.remove (*level_meter);
+       }
+
+       if (peak_display.get_parent()) {
+               gain_display_box.remove (peak_display);
+       }
+
+       if (gain_automation_state_button.get_parent()) {
+               fader_vbox->remove (gain_automation_state_button);
+       }
+
+       GainMeterBase::set_io (io);
+
        boost::shared_ptr<Route> r;
 
        if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
@@ -801,16 +827,8 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
                        fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
                }
        }
-
-       set_spacing (2);
-
-       pack_start (gain_display_box, Gtk::PACK_SHRINK);
-       pack_start (hbox, Gtk::PACK_SHRINK);
-
-       meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose));
 }
 
-
 int
 GainMeter::get_gm_width ()
 {
index d493edf0fb3f059e3ca89ece9d9ce1cfc22309f9..820e9ef0e76f5d0474e318073a63edac37fabf94 100644 (file)
@@ -58,10 +58,12 @@ namespace Gtk {
 class GainMeterBase : virtual public sigc::trackable
 {
   public:
-       GainMeterBase (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&, const Glib::RefPtr<Gdk::Pixbuf>& pix,
+       GainMeterBase ( ARDOUR::Session&, const Glib::RefPtr<Gdk::Pixbuf>& pix,
                       bool horizontal);
        virtual ~GainMeterBase ();
 
+       virtual void set_io (boost::shared_ptr<ARDOUR::IO>);
+
        void update_gain_sensitive ();
        void update_meters ();
 
@@ -82,6 +84,7 @@ class GainMeterBase : virtual public sigc::trackable
        friend class MixerStrip;
        boost::shared_ptr<ARDOUR::IO> _io;
        ARDOUR::Session& _session;
+       std::vector<sigc::connection> connections;
 
        bool ignore_toggle;
        bool next_release_selects;
@@ -169,9 +172,11 @@ class GainMeterBase : virtual public sigc::trackable
 class GainMeter : public GainMeterBase, public Gtk::VBox
 {
   public:
-       GainMeter (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&);
+       GainMeter (ARDOUR::Session&);
        ~GainMeter () {}
 
+       void set_io (boost::shared_ptr<ARDOUR::IO>);
+
        int get_gm_width ();
        void setup_meters (int len=0);
 
index f6e3731aac1130546759fcf9a59ce038cd1c13db..cd7308cfa26111205f4bbdf39167dacc3ef1e9b8 100644 (file)
@@ -58,9 +58,8 @@ using namespace std;
 //sigc::signal<void,RouteGroup*> LevelMeter::ResetGroupPeakDisplays;
 
 
-LevelMeter::LevelMeter (boost::shared_ptr<IO> io, Session& s)
-       : _io (io),
-         _session (s)
+LevelMeter::LevelMeter (Session& s)
+       : _session (s)
        
 {
        set_spacing (1);
@@ -85,6 +84,12 @@ LevelMeter::~LevelMeter ()
        }
 }
 
+void
+LevelMeter::set_io (boost::shared_ptr<IO> io)
+{
+       _io = io;
+}
+
 float
 LevelMeter::update_meters ()
 {
@@ -144,6 +149,10 @@ LevelMeter::hide_all_meters ()
 void
 LevelMeter::setup_meters (int len, int initial_width)
 {
+       if (!_io) {
+               return; /* do it later */
+       }
        uint32_t nmeters = _io->n_outputs().n_total();
        regular_meter_width = initial_width;
 
index ce0aa125cbbd668185fce9433cca4fdc74d00ea7..521b9d1d8f10e5c766d65486f72a371b20d68374 100644 (file)
@@ -56,9 +56,11 @@ namespace Gtk {
 class LevelMeter : public Gtk::HBox
 {
   public:
-       LevelMeter (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&);
+       LevelMeter (ARDOUR::Session&);
        ~LevelMeter ();
 
+       virtual void set_io (boost::shared_ptr<ARDOUR::IO> io);
+
        void update_gain_sensitive ();
 
        float update_meters ();
index edbdcd58cb747911140ffb4a3299127721b8a7a3..aecbc1f634bdf8ca25fe58d35e70f8c7a02ce76e 100644 (file)
@@ -117,7 +117,10 @@ fixup_bundle_environment ()
        Glib::ustring path;
        const char *cstr = getenv ("PATH");
 
-       /* ensure that we find any bundled executables (e.g. JACK) */
+       /* ensure that we find any bundled executables (e.g. JACK),
+          and find them before any instances of the same name
+          elsewhere in PATH
+       */
 
        path = dir_path;
        if (cstr) {
@@ -152,8 +155,10 @@ fixup_bundle_environment ()
        if (cstr) {
                path = cstr;
                path += ':';
+       } else {
+               path = "";
        }
-       path = dir_path;
+       path += dir_path;
        path += "/../Plugins";
        
        setenv ("LADSPA_PATH", path.c_str(), 1);
@@ -162,8 +167,10 @@ fixup_bundle_environment ()
        if (cstr) {
                path = cstr;
                path += ':';
+       } else {
+               path = "";
        }
-       path = dir_path;
+       path += dir_path;
        path += "/../Frameworks";
        
        setenv ("VAMP_PATH", path.c_str(), 1);
@@ -172,8 +179,10 @@ fixup_bundle_environment ()
        if (cstr) {
                path = cstr;
                path += ':';
+       } else {
+               path = "";
        }
-       path = dir_path;
+       path += dir_path;
        path += "/../Surfaces";
        
        setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
@@ -182,8 +191,10 @@ fixup_bundle_environment ()
        if (cstr) {
                path = cstr;
                path += ':';
+       } else {
+               path = "";
        }
-       path = dir_path;
+       path += dir_path;
        path += "/../Plugins";
        
        setenv ("LV2_PATH", path.c_str(), 1);
diff --git a/gtk2_ardour/matrix.cc b/gtk2_ardour/matrix.cc
new file mode 100644 (file)
index 0000000..db16362
--- /dev/null
@@ -0,0 +1,427 @@
+#include <gtkmm.h>
+#include <cairo/cairo.h>
+#include <stdlib.h>
+#include <iostream>
+#include <algorithm>
+#include <stdint.h>
+#include <cmath>
+#include <map>
+#include <vector>
+
+#include "matrix.h"
+
+using namespace std;
+using namespace Gtk;
+using namespace ARDOUR;
+
+Matrix::Matrix ()
+{
+       alloc_width = 0;
+       alloc_height = 0;
+       line_width = 0;
+       line_height = 0;
+       labels_y_shift = 0;
+       labels_x_shift = 0;
+       arc_radius = 0;
+       xstep = 0;
+       ystep = 0;
+       pixmap = 0;
+       drawn = false;
+       angle_radians = M_PI/4.0;
+       motion_x = -1;
+       motion_y = -1;
+
+       add_events (Gdk::POINTER_MOTION_MASK|Gdk::LEAVE_NOTIFY_MASK);
+}
+
+void 
+Matrix::set_ports (const list<string>& ports)
+{
+       ours = ports;
+       reset_size ();
+}
+
+void 
+Matrix::add_group (PortGroup& pg)
+{
+       for (vector<string>::const_iterator s = pg.ports.begin(); s != pg.ports.end(); ++s) {
+               others.push_back (OtherPort (*s, pg));
+       }
+       reset_size ();
+}
+
+void
+Matrix::remove_group (PortGroup& pg)
+{
+       for (list<OtherPort>::iterator o = others.begin(); o != others.end(); ) {
+               if (&(*o).group() == &pg) {
+                       o = others.erase (o);
+               } else {
+                       ++o;
+               }
+       }
+       reset_size ();
+}
+
+void
+Matrix::hide_group (PortGroup& pg)
+{
+       reset_size();
+}
+
+void
+Matrix::show_group (PortGroup& pg)
+{
+       reset_size ();
+}
+
+void
+Matrix::setup_nodes ()
+{
+       int n, x, y;
+       list<string>::iterator m;
+       list<OtherPort>::iterator s;
+
+       for (vector<MatrixNode*>::iterator p = nodes.begin(); p != nodes.end(); ++p) {
+               delete *p;
+       }
+       nodes.clear ();
+
+       list<OtherPort>::size_type visible_others = 0;
+       
+       for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
+               if ((*s).visible()) {
+                       ++visible_others;
+               }
+       }
+       
+       nodes.assign (ours.size() * visible_others, 0);
+
+       for (n = 0, y = 0, m = ours.begin(); m != ours.end(); ++m, ++y) {
+               for (x = 0, s = others.begin(); s != others.end(); ++s) {
+                       if ((*s).visible()) {
+                               nodes[n] = new MatrixNode (*m, *s, x, y);
+                               n++;
+                               x++;
+                       }
+               }
+       }
+}
+
+void
+Matrix::reset_size ()
+{
+       list<OtherPort>::size_type visible_others = 0;
+       
+       for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
+               if ((*s).visible()) {
+                       ++visible_others;
+               }
+       }
+       
+       border = 10;
+
+       if (alloc_width > line_width) {
+
+               xstep = (alloc_width - labels_x_shift - (2 * border) - (2 * arc_radius)) / visible_others;
+               line_width = xstep * (others.size() - 1);
+
+               ystep = (alloc_height - labels_y_shift - (2 * border) - (2 * arc_radius)) / (ours.size() - 1);
+               line_height = ystep * (ours.size() - 1);
+
+       } else {
+
+               xstep = 20;
+               ystep = 20;
+               
+               line_height = (ours.size() - 1) * ystep;
+               line_width = visible_others * xstep;
+       }
+
+       int half_step = min (ystep/2,xstep/2);
+       if (half_step > 3) {
+               arc_radius = half_step - 5;
+       } else {
+               arc_radius = 3;
+       }
+
+       arc_radius = min (arc_radius, 10);
+
+       /* scan all the port names that will be rotated, and compute
+          how much space we need for them
+       */
+       
+       float w = 0;
+       float w1;
+       float h = 0;
+       cairo_text_extents_t extents;
+       cairo_t* cr;
+       GdkPixmap* pm;
+
+       pm = gdk_pixmap_new (NULL, 1, 1, 24);
+       gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
+
+       cr = gdk_cairo_create (pm);
+
+       for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
+               if ((*s).visible()) {
+                       cairo_text_extents (cr, (*s).name().c_str(), &extents);
+                       w = max ((float) extents.width, w);
+                       h = max ((float) extents.height, h);
+               }
+       }
+
+       cairo_destroy (cr);
+       gdk_pixmap_unref (pm);
+
+       /* transform */
+
+       w = fabs (w * cos (angle_radians) + h * sin (angle_radians));
+       h = fabs (w * sin (angle_radians) + h * cos (angle_radians));
+
+       labels_y_shift = (int) ceil (h) + 10;
+       labels_x_shift = (int) ceil (w);
+
+       setup_nodes ();
+}
+
+bool
+Matrix::on_motion_notify_event (GdkEventMotion* ev)
+{
+       motion_x = ev->x;
+       motion_y = ev->y;
+       queue_draw ();
+       return false;
+}
+
+bool
+Matrix::on_leave_notify_event (GdkEventCrossing *ev)
+{
+       motion_x = -1;
+       motion_y = -1;
+       queue_draw ();
+       return false;
+}
+
+void
+Matrix::on_size_request (Requisition* req)
+{
+       req->width = labels_x_shift + line_width + (2*border) + (2*arc_radius);
+       req->height = labels_y_shift + line_height + (2*border) + (2*arc_radius);
+}
+
+MatrixNode*
+Matrix::get_node (int32_t x, int32_t y)
+{
+       int half_xstep = xstep / 2;
+       int half_ystep = ystep / 2;
+
+       x -= labels_x_shift - border;
+       if (x < half_xstep) {
+               return 0;
+       }
+
+       y -= labels_y_shift - border;
+       if (y < half_ystep) {
+               return 0;
+       }
+
+       x = (x - half_xstep) / xstep;
+       y = (y - half_ystep) / ystep;
+
+       x = y*ours.size() + x;
+
+       if (x >= nodes.size()) {
+               return 0;
+       }
+
+       return nodes[x];
+}
+
+bool
+Matrix::on_button_press_event (GdkEventButton* ev)
+{
+       MatrixNode* node;
+       
+       if ((node = get_node (ev->x, ev->y)) != 0) {
+               cerr << "Event in node " << node->our_name() << " x " << node->their_name () << endl;
+               node->set_connected (!node->connected());
+               drawn = false;
+               queue_draw();
+       } 
+}
+
+void
+Matrix::alloc_pixmap ()
+{
+       if (pixmap) {
+               gdk_pixmap_unref (pixmap);
+       }
+
+       pixmap = gdk_pixmap_new (get_window()->gobj(),
+                                alloc_width,
+                                alloc_height,
+                                -1);
+
+       drawn = false;
+}
+
+void
+Matrix::on_size_allocate (Allocation& alloc)
+{
+       EventBox::on_size_allocate (alloc);
+
+       alloc_width = alloc.get_width();
+       alloc_height = alloc.get_height();
+
+       if (is_realized()) {
+               alloc_pixmap ();
+               reset_size ();
+#ifdef MATRIX_USE_BACKING_PIXMAP
+               redraw (pixmap, 0, 0, alloc_width, alloc_height);
+#endif
+       }
+}
+
+void
+Matrix::on_realize ()
+{
+       EventBox::on_realize ();
+       alloc_pixmap ();
+}
+
+void
+Matrix::redraw (GdkDrawable* drawable, GdkRectangle* rect)
+{
+       list<string>::iterator o;
+       list<OtherPort>::iterator t;
+       int x, y;
+       uint32_t top_shift, bottom_shift, left_shift, right_shift;
+       cairo_t* cr;
+
+       cr = gdk_cairo_create (drawable);
+
+       cairo_set_source_rgb (cr, 0.83, 0.83, 0.83);
+       cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
+       cairo_fill (cr);
+
+       cairo_set_line_width (cr, 0.5);
+       
+       top_shift = labels_y_shift + border;
+       left_shift = labels_x_shift + border;
+       bottom_shift = 0;
+       right_shift = 0;
+
+       /* horizontal grid lines and side labels */
+
+       for (y = top_shift, o = ours.begin(); o != ours.end(); ++o, y += ystep) {
+               
+               cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+               cairo_move_to (cr, left_shift, y);
+               cairo_line_to (cr, left_shift+line_width, y);
+               cairo_stroke (cr);
+#if 0
+               
+               cairo_text_extents_t extents;
+               cairo_text_extents (cr, (*o).c_str(),&extents);
+               cairo_move_to (cr, border, y+extents.height/2);
+               cairo_show_text (cr, (*o).c_str());
+#endif
+
+       }
+
+       /* vertical grid lines and rotated labels*/
+
+       for (x = left_shift, t = others.begin(); t != others.end(); ++t, x += xstep) {
+
+               cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+               cairo_move_to (cr, x, top_shift);
+               cairo_line_to (cr, x, top_shift+line_height);
+               cairo_stroke (cr);
+
+               cairo_move_to (cr, x-left_shift+12, border);
+               cairo_set_source_rgb (cr, 0, 0, 1.0);
+               
+               cairo_save (cr);
+               cairo_rotate (cr, angle_radians);
+               cairo_show_text (cr, (*t).name().c_str());
+               cairo_restore (cr);
+
+       }
+
+       /* nodes */
+
+       for (vector<MatrixNode*>::iterator n = nodes.begin(); n != nodes.end(); ++n) {
+
+               x = (*n)->x() * xstep;
+               y = (*n)->y() * ystep;
+
+               cairo_new_path (cr);
+
+               if (arc_radius) {
+                       cairo_arc (cr, left_shift+x, top_shift+y, arc_radius, 0, 2.0 * M_PI);
+                       if ((*n)->connected()) {
+                               cairo_set_source_rgba (cr, 1.0, 0, 0, 1.0);
+                               cairo_stroke (cr);
+                       } else {
+                               cairo_set_source_rgba (cr, 1.0, 0, 0, 0.7);
+                               cairo_fill (cr);
+                       }
+               }
+       }
+
+       /* motion indicators */
+
+       if (motion_x >= left_shift && motion_y >= top_shift) {
+               
+               int col_left = left_shift + ((motion_x - left_shift) / xstep) * xstep;
+               int row_top = top_shift + ((motion_y - top_shift) / ystep) * ystep;
+
+               cairo_set_line_width (cr, 5);
+               cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.3);
+               
+               /* horizontal (row) */
+
+               cairo_line_to (cr, left_shift, row_top);
+               cairo_line_to (cr, left_shift + line_width, row_top);
+               cairo_stroke (cr);
+
+               /* vertical (col) */
+               
+               cairo_move_to (cr, col_left, top_shift);
+               cairo_line_to (cr, col_left, top_shift + line_height);
+               cairo_stroke (cr);
+       }
+
+       cairo_destroy (cr);
+
+#ifdef MATRIX_USE_BACKING_PIXMAP
+       drawn = true;
+#endif
+}
+
+bool
+Matrix::on_expose_event (GdkEventExpose* event)
+{
+#ifdef MATRIX_USE_BACKING_PIXMAP
+       if (!drawn) {
+               redraw (pixmap, 0, 0, alloc_width, alloc_height);
+       }
+
+       gdk_draw_drawable (get_window()->gobj(),
+                          get_style()->get_fg_gc (STATE_NORMAL)->gobj(),
+                          pixmap,
+                          event->area.x,
+                          event->area.y,
+                          event->area.x,
+                          event->area.y,
+                          event->area.width,
+                          event->area.height);
+#else
+       redraw (get_window()->gobj(), &event->area);
+#endif
+       
+
+
+       return true;
+}
diff --git a/gtk2_ardour/matrix.h b/gtk2_ardour/matrix.h
new file mode 100644 (file)
index 0000000..f859a88
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef __gtk_ardour_matrix_h__
+#define __gtk_ardour_matrix_h__
+
+#include <list>
+#include <vector>
+#include <string>
+#include <stdint.h>
+
+#include <gtkmm/eventbox.h>
+#include <gtkmm/widget.h>
+
+#include "port_group.h"
+
+class OtherPort {
+public:
+    OtherPort (const std::string& n, PortGroup& g)
+           : _name (n), _group (g) {}
+
+    std::string name() const { return _name; }
+    PortGroup& group() const { return _group; }
+    bool visible() const { return _group.visible; }
+
+public:
+    std::string _name;
+    PortGroup& _group;
+};
+
+class MatrixNode {
+  public:
+    MatrixNode (std::string a, OtherPort o, int32_t x, int32_t y)
+           : _name (a), them (o), _connected (random()%3), _x(x), _y(y) {}
+    ~MatrixNode() {}
+
+    PortGroup& get_group() const { return them.group(); }
+
+    std::string our_name() const { return _name; }
+    std::string their_name() const { return them.name(); }
+
+    bool connected() const { return _connected; }
+    void set_connected (bool yn) { _connected = yn; }
+    int32_t x() const { return _x; }
+    int32_t y() const { return _y; }
+
+  private:
+    std::string _name;
+    OtherPort them;
+    bool _connected;
+    int32_t _x;
+    int32_t _y;
+};
+
+class Matrix : public Gtk::EventBox
+{
+  public: 
+    Matrix();
+
+    void set_ports (const std::list<std::string>&);
+    void add_group (PortGroup&);
+    void remove_group (PortGroup&);
+    void hide_group (PortGroup&);
+    void show_group (PortGroup&);
+
+    int row_spacing () const { return xstep; }
+
+  protected:
+    bool on_button_press_event (GdkEventButton* ev);
+    bool on_expose_event (GdkEventExpose* ev);
+    void on_size_allocate (Gtk::Allocation&);
+    void on_size_request (Gtk::Requisition*);
+    void on_realize ();
+    bool on_motion_notify_event (GdkEventMotion*);
+    bool on_leave_notify_event (GdkEventCrossing*);
+
+    MatrixNode* get_node (int32_t x, int32_t y);
+
+private: 
+    int height;
+    int width;
+    int alloc_width;
+    int alloc_height;
+    bool drawn;
+    int labels_y_shift;
+    int labels_x_shift;
+    float angle_radians;
+    int border;
+    int ystep;
+    int xstep;
+    uint32_t line_height;
+    uint32_t line_width;
+    int arc_radius;
+    int32_t motion_x;
+    int32_t motion_y;
+
+    std::list<std::string> ours;
+    std::list<OtherPort> others;
+    std::vector<MatrixNode*> nodes;
+
+    void reset_size ();
+    void redraw (GdkDrawable*, GdkRectangle*);
+    void alloc_pixmap ();
+    void setup_nodes ();
+
+    GdkPixmap* pixmap;
+};
+
+#endif /* __gtk_ardour_matrix_h__ */
index 373babf417d47a4cc0701b73c13a96851e032d31..1a357dc0024d20073d48b0dc70d33506ebced82e 100644 (file)
@@ -82,34 +82,56 @@ speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg)
 }
 #endif 
 
-MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer)
-       : AxisView(sess),
-         RouteUI (rt, sess, _("Mute"), _("Solo"), _("Record")),
-         _mixer(mx),
-         _mixer_owned (in_mixer),
-         pre_processor_box (PreFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer),
-         post_processor_box (PostFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer),
-         gpm (_route, sess),
-         panners (_route, sess),
-         button_table (3, 2),
-         middle_button_table (1, 2),
-         bottom_button_table (1, 2),
-         meter_point_label (_("pre")),
-         comment_button (_("Comments")),
-         speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1),
-         speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
+MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer)
+       : AxisView(sess)
+       , RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
+       ,_mixer(mx)
+       , _mixer_owned (in_mixer)
+       , pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
+       , post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
+       , gpm (sess)
+       , panners (sess)
+       , button_table (3, 2)
+       , middle_button_table (1, 2)
+       , bottom_button_table (1, 2)
+       , meter_point_label (_("pre"))
+       , comment_button (_("Comments"))
+       , speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
+       , speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
+                        
+{
+       init ();
+}
 
+MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer)
+       : AxisView(sess)
+       , RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
+       ,_mixer(mx)
+       , _mixer_owned (in_mixer)
+       , pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
+       , post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
+       , gpm (sess)
+       , panners (sess)
+       , button_table (3, 2)
+       , middle_button_table (1, 2)
+       , bottom_button_table (1, 2)
+       , meter_point_label (_("pre"))
+       , comment_button (_("Comments"))
+       , speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
+       , speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
+                        
 {
-       if (set_color_from_route()) {
-               set_color (unique_random_color());
-       }
+       init ();
+       set_route (rt);
+}
 
+void
+MixerStrip::init ()
+{
        input_selector = 0;
        output_selector = 0;
        group_menu = 0;
-       if (!_route->is_hidden()) {
-               _marked_for_display = true;
-       }
+       _marked_for_display = false;
        route_ops_menu = 0;
        ignore_comment_edit = false;
        ignore_toggle = false;
@@ -118,40 +140,26 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
        comment_area = 0;
        _width_owner = 0;
 
-       Gtk::Image *width_icon = manage (new Gtk::Image (::get_icon("strip_width")));
-       Gtk::Image *hide_icon = manage (new Gtk::Image (::get_icon("hide")));
-       width_button.add (*width_icon);
-       hide_button.add (*hide_icon);
+       width_button.add (*(manage (new Gtk::Image (::get_icon("strip_width")))));
+       hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
 
        input_label.set_text (_("Input"));
+       ARDOUR_UI::instance()->set_tip (&input_button, _("Click to choose inputs"), "");
        input_button.add (input_label);
        input_button.set_name ("MixerIOButton");
        input_label.set_name ("MixerIOButtonLabel");
 
        output_label.set_text (_("Output"));
+       ARDOUR_UI::instance()->set_tip (&output_button, _("Click to choose outputs"), "");
        output_button.add (output_label);
        output_button.set_name ("MixerIOButton");
        output_label.set_name ("MixerIOButtonLabel");
 
-       _route->meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed));
+       ARDOUR_UI::instance()->set_tip (&meter_point_button, _("Select metering point"), "");
        meter_point_button.add (meter_point_label);
        meter_point_button.set_name ("MixerStripMeterPreButton");
        meter_point_label.set_name ("MixerStripMeterPreButton");
        
-       switch (_route->meter_point()) {
-       case MeterInput:
-               meter_point_label.set_text (_("input"));
-               break;
-               
-       case MeterPreFader:
-               meter_point_label.set_text (_("pre"));
-               break;
-               
-       case MeterPostFader:
-               meter_point_label.set_text (_("post"));
-               break;
-       }
-       
        /* TRANSLATORS: this string should be longest of the strings
           used to describe meter points. In english, it's "input".
        */
@@ -183,56 +191,18 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
        bottom_button_table.set_homogeneous (true);
        bottom_button_table.attach (group_button, 0, 1, 0, 1);
        
-       if (is_audio_track()) {
-               boost::shared_ptr<AudioTrack> at = audio_track();
-
-               at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen));
-
-#ifdef VARISPEED_IN_MIXER_STRIP
-               speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
-               
-               speed_frame.set_name ("BaseFrame");
-               speed_frame.set_shadow_type (Gtk::SHADOW_IN);
-               speed_frame.add (speed_spinner);
-               
-               speed_spinner.set_print_func (speed_printer, 0);
-
-               ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
-
-               button_table.attach (speed_frame, 0, 2, 5, 6);
-#endif /* VARISPEED_IN_MIXER_STRIP */
-
-       }
-       
-       if(rec_enable_button) {
-               rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
-               rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
-       
-               rec_enable_button->set_name ("MixerRecordEnableButton");
-               button_table.attach (*rec_enable_button, 0, 2, 2, 3);
-       }
-       
        name_button.add (name_label);
        name_button.set_name ("MixerNameButton");
        Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
 
        name_label.set_name ("MixerNameButtonLabel");
-       if (_route->phase_invert()) {
-               name_label.set_text (X_("Ø ") + name_label.get_text());
-       } else {
-               name_label.set_text (_route->name());
-       }
-
+       ARDOUR_UI::instance()->set_tip (&group_button, _("Mix group"), "");
        group_button.add (group_label);
        group_button.set_name ("MixerGroupButton");
        group_label.set_name ("MixerGroupButtonLabel");
 
        comment_button.set_name ("MixerCommentButton");
 
-       ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment()==""        ?
-                                                       _("Click to Add/Edit Comments"):
-                                                       _route->comment());
-
        comment_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::comment_button_clicked));
        
        global_vpacker.set_border_width (0);
@@ -269,19 +239,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
        global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
        global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK);
 
-       if (route()->is_master() || route()->is_control()) {
-               
-               if (scrollbar_height == 0) {
-                       HScrollbar scrollbar;
-                       Gtk::Requisition requisition(scrollbar.size_request ());
-                       scrollbar_height = requisition.height;
-               }
-
-               EventBox* spacer = manage (new EventBox);
-               spacer->set_size_request (-1, scrollbar_height);
-               global_vpacker.pack_start (*spacer, false, false);
-       }
-
        global_frame.add (global_vpacker);
        global_frame.set_shadow_type (Gtk::SHADOW_IN);
        global_frame.set_name ("BaseFrame");
@@ -298,22 +255,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
 
        _session.engine().Stopped.connect (mem_fun(*this, &MixerStrip::engine_stopped));
        _session.engine().Running.connect (mem_fun(*this, &MixerStrip::engine_running));
-       _route->input_changed.connect (mem_fun(*this, &MixerStrip::input_changed));
-       _route->output_changed.connect (mem_fun(*this, &MixerStrip::output_changed));
-       _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
-       _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
-       _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
-       _route->mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed));
-       _route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan));
-
-       if (is_audio_track()) {
-               audio_track()->DiskstreamChanged.connect (mem_fun(*this, &MixerStrip::diskstream_changed));
-               get_diskstream()->SpeedChanged.connect (mem_fun(*this, &MixerStrip::speed_changed));
-       }
-
-       _route->NameChanged.connect (mem_fun(*this, &RouteUI::name_changed));
-       _route->comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed));
-       _route->gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed));
 
        input_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::input_press), false);
        output_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::output_press), false);
@@ -323,11 +264,22 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
        mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
        mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false);
 
+       /* we don't need this if its not an audio track, but we don't know that yet and it doesn't
+          hurt (much).
+       */
+
+       rec_enable_button->set_name ("MixerRecordEnableButton");
+       rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
+       rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
+
        name_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::name_button_button_press), false);
        group_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::select_mix_group), false);
 
        _width = (Width) -1;
-       set_stuff_from_route ();
+
+       /* start off as a passthru strip. we'll correct this, if necessary,
+          in update_diskstream_display().
+       */
 
        /* start off as a passthru strip. we'll correct this, if necessary,
           in update_diskstream_display().
@@ -338,6 +290,126 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
        else
                set_name ("AudioTrackStripBase");
 
+       add_events (Gdk::BUTTON_RELEASE_MASK);
+}
+
+MixerStrip::~MixerStrip ()
+{
+       GoingAway(); /* EMIT_SIGNAL */
+
+       if (input_selector) {
+               delete input_selector;
+       }
+
+       if (output_selector) {
+               delete output_selector;
+       }
+}
+
+void
+MixerStrip::set_route (boost::shared_ptr<Route> rt)
+{
+       if (rec_enable_button->get_parent()) {
+               button_table.remove (*rec_enable_button);
+       }
+
+#ifdef VARISPEED_IN_MIXER_STRIP
+       if (speed_frame->get_parent()) {
+               button_table.remove (*speed_frame);
+       }
+#endif
+
+       RouteUI::set_route (rt);
+
+       panners.set_io (rt);
+       gpm.set_io (rt);
+       pre_processor_box.set_route (rt);
+       post_processor_box.set_route (rt);
+
+       if (set_color_from_route()) {
+               set_color (unique_random_color());
+       }
+
+       if (_mixer_owned && (route()->is_master() || route()->is_control())) {
+               
+               if (scrollbar_height == 0) {
+                       HScrollbar scrollbar;
+                       Gtk::Requisition requisition(scrollbar.size_request ());
+                       scrollbar_height = requisition.height;
+               }
+
+               EventBox* spacer = manage (new EventBox);
+               spacer->set_size_request (-1, scrollbar_height);
+               global_vpacker.pack_start (*spacer, false, false);
+       }
+
+       if (is_audio_track()) {
+
+               boost::shared_ptr<AudioTrack> at = audio_track();
+
+               connections.push_back (at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen)));
+
+#ifdef VARISPEED_IN_MIXER_STRIP
+               speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
+               
+               speed_frame.set_name ("BaseFrame");
+               speed_frame.set_shadow_type (Gtk::SHADOW_IN);
+               speed_frame.add (speed_spinner);
+               
+               speed_spinner.set_print_func (speed_printer, 0);
+
+               ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
+
+               button_table.attach (speed_frame, 0, 2, 5, 6);
+#endif /* VARISPEED_IN_MIXER_STRIP */
+
+               button_table.attach (*rec_enable_button, 0, 2, 2, 3);
+       }
+
+       if (_route->phase_invert()) {
+               name_label.set_text (X_("Ø ") + name_label.get_text());
+       } else {
+               name_label.set_text (_route->name());
+       }
+
+       switch (_route->meter_point()) {
+       case MeterInput:
+               meter_point_label.set_text (_("input"));
+               break;
+               
+       case MeterPreFader:
+               meter_point_label.set_text (_("pre"));
+               break;
+               
+       case MeterPostFader:
+               meter_point_label.set_text (_("post"));
+               break;
+       }
+       
+       ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment().empty() ?
+                                                  _("Click to Add/Edit Comments"):
+                                                  _route->comment());
+
+       connections.push_back (_route->meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed)));
+       connections.push_back (_route->input_changed.connect (mem_fun(*this, &MixerStrip::input_changed)));
+       connections.push_back (_route->output_changed.connect (mem_fun(*this, &MixerStrip::output_changed)));
+       connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
+       connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
+       connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
+       connections.push_back (_route->mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed)));
+       connections.push_back (_route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan)));
+
+       if (is_audio_track()) {
+               connections.push_back (audio_track()->DiskstreamChanged.connect (mem_fun(*this, &MixerStrip::diskstream_changed)));
+               connections.push_back (get_diskstream()->SpeedChanged.connect (mem_fun(*this, &MixerStrip::speed_changed)));
+       }
+
+       connections.push_back (_route->NameChanged.connect (mem_fun(*this, &RouteUI::name_changed)));
+       connections.push_back (_route->comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed)));
+       connections.push_back (_route->gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed)));
+
+       set_stuff_from_route ();
+
        /* now force an update of all the various elements */
 
        pre_processor_box.update();
@@ -362,11 +434,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
 
        add_events (Gdk::BUTTON_RELEASE_MASK);
 
-       whvbox->show();
-       hide_icon->show();
-       width_icon->show();
-       gain_meter_alignment->show_all();
-
        pre_processor_box.show();
 
        if (!route()->is_master() && !route()->is_control()) {
@@ -402,19 +469,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
        show();
 }
 
-MixerStrip::~MixerStrip ()
-{
-       GoingAway(); /* EMIT_SIGNAL */
-
-       if (input_selector) {
-               delete input_selector;
-       }
-
-       if (output_selector) {
-               delete output_selector;
-       }
-}
-
 void
 MixerStrip::set_stuff_from_route ()
 {
@@ -796,6 +850,7 @@ MixerStrip::update_output_display ()
                        break;
                }
        }
+
        gpm.setup_meters ();
        panners.setup_pan ();
 }
@@ -1292,22 +1347,22 @@ MixerStrip::meter_changed (void *src)
        ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src));
 
        switch (_route->meter_point()) {
-               case MeterInput:
-                       meter_point_label.set_text (_("input"));
-                       break;
-
-               case MeterPreFader:
-                       meter_point_label.set_text (_("pre"));
-                       break;
+       case MeterInput:
+               meter_point_label.set_text (_("input"));
+               break;
 
-               case MeterPostFader:
-                       meter_point_label.set_text (_("post"));
-                       break;
+       case MeterPreFader:
+               meter_point_label.set_text (_("pre"));
+               break;
+               
+       case MeterPostFader:
+               meter_point_label.set_text (_("post"));
+               break;
        }
 
        gpm.setup_meters ();
-               // reset peak when meter point changes
-               gpm.reset_peak_display();
-               set_width(_width, this);
+       // reset peak when meter point changes
+       gpm.reset_peak_display();
+       set_width(_width, this);
 }
 
index 63a47974ccd3d6a2d43d3cdba283c0d8a628419f..c4c28a06e9eab20d665baeb230529e484ffaa903 100644 (file)
@@ -83,6 +83,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
 {
   public:
        MixerStrip (Mixer_UI&, ARDOUR::Session&, boost::shared_ptr<ARDOUR::Route>, bool in_mixer = true);
+       MixerStrip (Mixer_UI&, ARDOUR::Session&, bool in_mixer = true);
        ~MixerStrip ();
 
        void set_width (Width, void* owner);
@@ -93,6 +94,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
        void set_embedded (bool);
        
        ARDOUR::RouteGroup* mix_group() const;
+       void set_route (boost::shared_ptr<ARDOUR::Route>);
 
   protected:
        friend class Mixer_UI;
@@ -105,6 +107,8 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
   private:
        Mixer_UI& _mixer;
 
+       void init ();
+
        bool  _embedded;
        bool  _packed;
        bool  _mixer_owned;
index ca598a363f76720b200ad000af23201d5d1c45c5..c261aba6498b1057ece02726a7d898216847dff4 100644 (file)
@@ -1117,7 +1117,8 @@ OptionEditor::setup_click_editor ()
        click_emphasis_path_entry.set_sensitive (true);
 
        click_io_selector = new IOSelector (*session, session->click_io(), false);
-       click_gpm = new GainMeter (session->click_io(), *session);
+       click_gpm = new GainMeter (*session);
+       click_gpm->set_io (session->click_io());
 
        click_hpacker.pack_start (*click_io_selector, false, false);
        click_hpacker.pack_start (*click_gpm, false, false);
@@ -1173,7 +1174,8 @@ void
 OptionEditor::connect_audition_editor ()
 {
        auditioner_io_selector = new IOSelector (*session, session->the_auditioner(), false);
-       auditioner_gpm = new GainMeter (session->the_auditioner(), *session);
+       auditioner_gpm = new GainMeter (*session);
+       auditioner_gpm->set_io (session->the_auditioner());
 
        audition_hpacker.pack_start (*auditioner_io_selector, false, false);
        audition_hpacker.pack_start (*auditioner_gpm, false, false);
index 2be7be73ed43398c0fe38449d21bf05858837939..b1273aa460cb1c64195280e743f9ef9d02805168 100644 (file)
@@ -47,9 +47,8 @@ using namespace sigc;
 
 const int PannerUI::pan_bar_height = 30;
 
-PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
-       : _io (io),
-         _session (s),
+PannerUI::PannerUI (Session& s)
+       : _session (s),
          hAdjustment(0.0, 0.0, 0.0),
          vAdjustment(0.0, 0.0, 0.0),
          panning_viewport(hAdjustment, vAdjustment),
@@ -61,6 +60,8 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
 {
        ignore_toggle = false;
        pan_menu = 0;
+       pan_astate_menu = 0;
+       pan_astyle_menu = 0;
        in_pan_update = false;
 
        pan_automation_style_button.set_name ("MixerAutomationModeButton");
@@ -84,22 +85,6 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
        pan_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
        pan_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
 
-       using namespace Menu_Helpers;
-       pan_astate_menu.items().push_back (MenuElem (_("Manual"), 
-                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Off)));
-       pan_astate_menu.items().push_back (MenuElem (_("Play"),
-                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Play)));
-       pan_astate_menu.items().push_back (MenuElem (_("Write"),
-                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Write)));
-       pan_astate_menu.items().push_back (MenuElem (_("Touch"),
-                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Touch)));
-
-       pan_astyle_menu.items().push_back (MenuElem (_("Trim")));
-       pan_astyle_menu.items().push_back (MenuElem (_("Abs")));
-
-       pan_astate_menu.set_name ("ArdourContextMenu");
-       pan_astyle_menu.set_name ("ArdourContextMenu");
-
        pan_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &PannerUI::pan_automation_style_button_event), false);
        pan_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &PannerUI::pan_automation_state_button_event), false);
 
@@ -141,16 +126,41 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
        panner = 0;
 
        set_width(Narrow);
-
-       _io->panner().Changed.connect (mem_fun(*this, &PannerUI::panner_changed));
-       _io->panner().LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage));
-       _io->panner().StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state));
+}
+  
+void
+PannerUI::set_io (boost::shared_ptr<IO> io)
+{
+       connections.clear ();
+       
+       if (pan_astyle_menu) {
+               delete pan_astyle_menu;
+               pan_astyle_menu = 0;
+       }
+       if (pan_astate_menu) {
+               delete pan_astate_menu;
+               pan_astate_menu = 0;
+       }
+                       
+       _io = io;
+       connections.push_back (_io->panner().Changed.connect (mem_fun(*this, &PannerUI::panner_changed)));
+       connections.push_back (_io->panner().LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)));
+       connections.push_back (_io->panner().StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)));
+       if (panner) {
+               delete panner;
+               panner = 0;
+       }
 
        pan_changed (0);
        update_pan_sensitive ();
        update_pan_linkage ();
        pan_automation_state_changed ();
 
+#if WHERE_DOES_THIS_LIVE       
        pan_bar_packer.show();
        panning_viewport.show();
        panning_up.show();
@@ -164,6 +174,46 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
        pan_automation_style_button.show();
        pan_automation_state_button.show();
        show();
+#endif
+}
+
+void
+PannerUI::build_astate_menu ()
+{
+       using namespace Menu_Helpers;
+
+       if (pan_astate_menu == 0) {
+               pan_astate_menu = new Menu;
+               pan_astate_menu->set_name ("ArdourContextMenu");
+       } else {
+               pan_astate_menu->items().clear ();
+       }
+
+       pan_astate_menu->items().push_back (MenuElem (_("Manual"), 
+                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Off)));
+       pan_astate_menu->items().push_back (MenuElem (_("Play"),
+                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Play)));
+       pan_astate_menu->items().push_back (MenuElem (_("Write"),
+                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Write)));
+       pan_astate_menu->items().push_back (MenuElem (_("Touch"),
+                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Touch)));
+
+}
+
+void
+PannerUI::build_astyle_menu ()
+{
+       using namespace Menu_Helpers;
+
+       if (pan_astyle_menu == 0) {
+               pan_astyle_menu = new Menu;
+               pan_astyle_menu->set_name ("ArdourContextMenu");
+       } else {
+               pan_astyle_menu->items().clear();
+       }
+
+       pan_astyle_menu->items().push_back (MenuElem (_("Trim")));
+       pan_astyle_menu->items().push_back (MenuElem (_("Abs")));
 }
 
 boost::shared_ptr<PBD::Controllable>
@@ -262,7 +312,14 @@ PannerUI::~PannerUI ()
        if (pan_menu) {
                delete pan_menu;
        }
-
+       
+       if (pan_astyle_menu) {
+               delete pan_astyle_menu;
+       }
+       
+       if (pan_astate_menu) {
+               delete pan_astate_menu;
+       }
 }
 
 
@@ -662,7 +719,10 @@ PannerUI::pan_automation_state_button_event (GdkEventButton *ev)
 
        switch (ev->button) {
        case 1:
-               pan_astate_menu.popup (1, ev->time);
+               if (pan_astate_menu == 0) {
+                       build_astate_menu ();
+               }
+               pan_astate_menu->popup (1, ev->time);
                break;
        default:
                break;
@@ -680,7 +740,10 @@ PannerUI::pan_automation_style_button_event (GdkEventButton *ev)
 
        switch (ev->button) {
        case 1:
-               pan_astyle_menu.popup (1, ev->time);
+               if (pan_astyle_menu == 0) {
+                       build_astyle_menu ();
+               }
+               pan_astyle_menu->popup (1, ev->time);
                break;
        default:
                break;
index e10080a3176c313a84b46edbec5e44e796b6b2c7..45016597503cbc4074055e09fb21f543d5f611b7 100644 (file)
@@ -54,9 +54,11 @@ namespace Gtk {
 class PannerUI : public Gtk::HBox
 {
   public:
-       PannerUI (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&);
+       PannerUI (ARDOUR::Session&);
        ~PannerUI ();
 
+       virtual void set_io (boost::shared_ptr<ARDOUR::IO>);
+
        void pan_changed (void *);
 
        void update_pan_sensitive ();
@@ -75,6 +77,7 @@ class PannerUI : public Gtk::HBox
 
        boost::shared_ptr<ARDOUR::IO> _io;
        ARDOUR::Session& _session;
+       std::vector<sigc::connection> connections;
 
        bool ignore_toggle;
        bool in_pan_update;
@@ -101,8 +104,8 @@ class PannerUI : public Gtk::HBox
        bool panning_link_button_press (GdkEventButton*);
        bool panning_link_button_release (GdkEventButton*);
 
-       Gtk::Menu pan_astate_menu;
-       Gtk::Menu pan_astyle_menu;
+       Gtk::Menu* pan_astate_menu;
+       Gtk::Menu* pan_astyle_menu;
 
        Gtk::Button pan_automation_style_button;
        Gtk::ToggleButton pan_automation_state_button;
@@ -118,6 +121,8 @@ class PannerUI : public Gtk::HBox
        void update_pan_bars (bool only_if_aplay);
        void update_pan_linkage ();
        void update_pan_state ();
+       void build_astate_menu ();
+       void build_astyle_menu ();
 
        void panner_changed ();
        
diff --git a/gtk2_ardour/port_group.h b/gtk2_ardour/port_group.h
new file mode 100644 (file)
index 0000000..d533464
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef  __gtk_ardour_port_group_h__ 
+#define  __gtk_ardour_port_group_h__ 
+
+#include <vector>
+#include <string>
+
+#include <gtkmm/widget.h>
+#include <gtkmm/checkbutton.h>
+
+#include <ardour/data_type.h>
+
+namespace ARDOUR {
+       class Session;
+       class IO;
+       class PortInsert;
+}
+
+class PortMatrix;
+
+/// A list of port names, grouped by some aspect of their type e.g. busses, tracks, system
+class PortGroup
+{
+  public:
+       /** PortGroup constructor.
+        * @param n Name.
+        * @param p Port name prefix.
+        * @param v true if group should be visible in the UI, otherwise false.
+        */
+       PortGroup (std::string const & n, std::string const & p, bool v) : name (n), prefix (p), visible (v) {}
+
+       void add (std::string const & p);
+
+       std::string name; ///< name for the group
+       std::string prefix; ///< prefix (before colon) e.g. "ardour:"
+       std::vector<std::string> ports; ///< port names
+       bool visible; ///< true if the group is visible in the UI
+};
+
+/// The UI for a PortGroup
+class PortGroupUI
+{
+  public:
+       PortGroupUI (PortMatrix&, PortGroup&);
+
+       Gtk::Widget& get_visibility_checkbutton ();
+       PortGroup& port_group () { return _port_group; }
+       void setup_visibility ();
+
+  private:
+       void port_checkbutton_toggled (Gtk::CheckButton*, int, int);
+       bool port_checkbutton_release (GdkEventButton* ev, Gtk::CheckButton* b, int r, int c);
+       void visibility_checkbutton_toggled ();
+
+       PortMatrix& _port_matrix; ///< the PortMatrix that we are working for
+       PortGroup& _port_group; ///< the PortGroup that we are representing
+       bool _ignore_check_button_toggle;
+       Gtk::CheckButton _visibility_checkbutton;
+};
+
+/// A list of PortGroups
+class PortGroupList : public std::list<PortGroup*>
+{
+  public:
+       enum Mask {
+               BUSS = 0x1,
+               TRACK = 0x2,
+               SYSTEM = 0x4,
+               OTHER = 0x8
+       };
+
+       PortGroupList (ARDOUR::Session &, ARDOUR::DataType, bool, Mask);
+
+       void refresh ();
+       int n_visible_ports () const;
+       std::string get_port_by_index (int, bool with_prefix = true) const;
+       void set_type (ARDOUR::DataType);
+       void set_offer_inputs (bool);
+       
+  private:
+       ARDOUR::Session& _session;
+       ARDOUR::DataType _type;
+       bool _offer_inputs;
+
+       PortGroup buss;
+       PortGroup track;
+       PortGroup system;
+       PortGroup other;
+};
+
+#endif /* __gtk_ardour_port_group_h__ */
index cff4a3328ee328c6f9802c74241e0ce14757b324..b1dd2a17ac5949e218e9a1c6cde062cca77bd791 100644 (file)
@@ -69,59 +69,8 @@ PortGroupUI::PortGroupUI (PortMatrix& m, PortGroup& g)
        , _ignore_check_button_toggle (false)
        , _visibility_checkbutton (g.name)
 {
-       int const ports = _port_group.ports.size();
-       int const rows = _port_matrix.n_rows ();
-
-       if (rows == 0 || ports == 0) {
-               return;
-       }
-
-       /* Sort out the table and the checkbuttons inside it */
-       
-       _table.resize (rows, ports);
-       _port_checkbuttons.resize (rows);
-       for (int i = 0; i < rows; ++i) {
-               _port_checkbuttons[i].resize (ports);
-       }
-
-
-       for (int i = 0; i < rows; ++i) {
-               for (uint32_t j = 0; j < _port_group.ports.size(); ++j) {
-                       CheckButton* b = new CheckButton;
-                       
-                       b->signal_toggled().connect (
-                               sigc::bind (sigc::mem_fun (*this, &PortGroupUI::port_checkbutton_toggled), b, i, j));
-                       
-                       b->signal_button_release_event().connect (
-                               sigc::bind (sigc::mem_fun (*this, &PortGroupUI::port_checkbutton_release), b, i, j), false);
-
-                       _port_checkbuttons[i][j] = b;
-
-                       cerr << this << " bind to " << &_port_checkbuttons << " via " << b 
-                            << endl;
-
-                       _table.attach (*b, j, j + 1, i, i + 1);
-               }
-       }
-       
-       _table_box.add (_table);
-
-       _ignore_check_button_toggle = true;
-
-       /* Set the state of the check boxes according to current connections */
-       for (int i = 0; i < rows; ++i) {
-               for (uint32_t j = 0; j < _port_group.ports.size(); ++j) {
-                       std::string const t = _port_group.prefix + _port_group.ports[j];
-                       bool const s = _port_matrix.get_state (i, t);
-                       _port_checkbuttons[i][j]->set_active (s);
-                       if (s) {
-                               _port_group.visible = true;
-                       }
-               }
-       }
-
+       _port_group.visible = true;
        _ignore_check_button_toggle = false;
-
        _visibility_checkbutton.signal_toggled().connect (sigc::mem_fun (*this, &PortGroupUI::visibility_checkbutton_toggled));
 }
 
@@ -132,34 +81,6 @@ PortGroupUI::visibility_checkbutton_toggled ()
        _port_group.visible = _visibility_checkbutton.get_active ();
 }
 
-/** @return Width and height of a single checkbutton in a port group table */
-std::pair<int, int>
-PortGroupUI::unit_size () const
-{
-       if (_port_checkbuttons.empty() || _port_checkbuttons[0].empty())
-       {
-               return std::pair<int, int> (0, 0);
-       }
-
-       int r = 0;
-       /* We can't ask for row spacing unless there >1 rows, otherwise we get a warning */
-       if (_table.property_n_rows() > 1) {
-               r = _table.get_row_spacing (0);
-       }
-
-       return std::make_pair (
-               _port_checkbuttons[0][0]->get_width() + _table.get_col_spacing (0),
-               _port_checkbuttons[0][0]->get_height() + r
-               );
-}
-
-/** @return Table widget containing the port checkbuttons */
-Widget&
-PortGroupUI::get_table ()
-{
-       return _table_box;
-}
-
 /** @return Checkbutton used to toggle visibility */
 Widget&
 PortGroupUI::get_visibility_checkbutton ()
@@ -173,324 +94,37 @@ void
 PortGroupUI::port_checkbutton_toggled (CheckButton* b, int r, int c)
 {
        if (_ignore_check_button_toggle == false) {
-               _port_matrix.set_state (r, _port_group.prefix + _port_group.ports[c], b->get_active(), 0);
+               // _port_matrix.hide_group (_port_group);
        }
 }
 
-bool
-PortGroupUI::port_checkbutton_release (GdkEventButton* ev, CheckButton* b, int r, int c)
-{
-       cerr << this << " RELEASE on " << b << " state = " << ev->state << endl;
-
-       if (ev->state == 0) {
-               /* let usual toggle handler take care of it */
-               return false;
-       }
-
-       /* The fun starts here 
-        */
-
-       const size_t ports = _port_group.ports.size();
-       const size_t rows = _port_matrix.n_rows ();
-
-       if (rows == 0 || ports == 0) {
-               return true;
-       }
-
-       /* For each port in the group, change the state of
-          the connection for the corresponding "connector" port.
-       */
-       
-       for (size_t j = c; j < ports; ++j) {
-
-               /* we've got a port to connect, now lets find the thing to 
-                  connect it too ... (search "down" the rows)
-               */
-
-               cerr << "we're going to connect port " << j << " of " << ports << endl;
-
-               for (size_t i = r; i < rows; ++i) {
-
-                       cerr << this << " going to connect to row " << i << " of " << rows << endl;
-                       cerr << "access [" << i << "][" << j << "]\n";
-                       cerr << " @ " << &_port_checkbuttons << endl;
-
-                       _port_checkbuttons[i][j]->set_active (!_port_checkbuttons[i][j]->get_active());
-
-                       /* next time, get at least as far as this port before looking
-                          for more.
-                       */
-
-                       r = i + 1;
-
-                       /* changed connection state, stop looking for more */
-
-                       break;
-               }
-       }
-
-       return true;
-}
-
 /** Set up visibility of the port group according to PortGroup::visible */
 void
 PortGroupUI::setup_visibility ()
 {
-       if (!_port_group.ports.empty() && _port_group.visible) {
-               _table_box.show ();
-       } else {
-               _table_box.hide ();
-       }
-
        if (_visibility_checkbutton.get_active () != _port_group.visible) {
-
                _visibility_checkbutton.set_active (_port_group.visible);
        }
 }
 
-RotatedLabelSet::RotatedLabelSet (PortGroupList& g)
-       : Glib::ObjectBase ("RotatedLabelSet"), Widget (), _port_group_list (g), _base_width (128)
-{
-       set_flags (NO_WINDOW);
-       if (getenv ("AD_ANGLE") != 0) {
-               set_angle (atoi (getenv ("AD_ANGLE")));
-       } else {
-               set_angle (45);
-       }
-}
-
-RotatedLabelSet::~RotatedLabelSet ()
-{
-       
-}
-
-
-/** Set the angle that the labels are drawn at.
- * @param degrees New angle in degrees.
- */
-
-void
-RotatedLabelSet::set_angle (int degrees)
-{
-       _angle_degrees = degrees;
-       _angle_radians = M_PI * _angle_degrees / 180;
-
-       queue_resize ();
-}
-
-void
-RotatedLabelSet::on_size_request (Requisition* requisition)
-{
-       *requisition = Requisition ();
-
-       if (_pango_layout == 0) {
-               return;
-       }
-
-       /* Our height is the highest label */
-       requisition->height = 0;
-       for (PortGroupList::const_iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
-               for (std::vector<std::string>::const_iterator j = (*i)->ports.begin(); j != (*i)->ports.end(); ++j) {
-                       std::pair<int, int> const d = setup_layout (*j);
-                       if (d.second > requisition->height) {
-                               requisition->height = d.second;
-                       }
-               }
-       }
-
-       /* And our width is the base plus the width of the last label */
-       requisition->width = _base_width;
-       int const n = _port_group_list.n_visible_ports ();
-       if (n > 0) {
-               std::pair<int, int> const d = setup_layout (_port_group_list.get_port_by_index (n - 1, false));
-               requisition->width += d.first;
-       }
-
-       cerr << "Labels will be " << requisition->width << " x " << requisition->height << endl;
-}
-
-void
-RotatedLabelSet::on_size_allocate (Allocation& allocation)
-{
-       set_allocation (allocation);
-
-       if (_gdk_window) {
-               _gdk_window->move_resize (allocation.get_x(), allocation.get_y(), allocation.get_width(), allocation.get_height());
-       }
-}
-
-void
-RotatedLabelSet::on_realize ()
-{
-       Widget::on_realize ();
-
-       Glib::RefPtr<Style> style = get_style ();
-
-       if (!_gdk_window) {
-               GdkWindowAttr attributes;
-               memset (&attributes, 0, sizeof (attributes));
-
-               Allocation allocation = get_allocation ();
-               attributes.x = allocation.get_x ();
-               attributes.y = allocation.get_y ();
-               attributes.width = allocation.get_width ();
-               attributes.height = allocation.get_height ();
-
-               attributes.event_mask = get_events () | Gdk::EXPOSURE_MASK; 
-               attributes.window_type = GDK_WINDOW_CHILD;
-               attributes.wclass = GDK_INPUT_OUTPUT;
-
-               _gdk_window = Gdk::Window::create (get_window (), &attributes, GDK_WA_X | GDK_WA_Y);
-               unset_flags (NO_WINDOW);
-               set_window (_gdk_window);
-
-               _bg_colour = style->get_bg (STATE_NORMAL );
-               modify_bg (STATE_NORMAL, _bg_colour);
-               _fg_colour = style->get_fg (STATE_NORMAL);
-
-               _gdk_window->set_user_data (gobj ());
-
-               /* Set up Pango stuff */
-               _pango_context = create_pango_context ();
-
-               Pango::Matrix matrix = PANGO_MATRIX_INIT;
-               pango_matrix_rotate (&matrix, _angle_degrees);
-               _pango_context->set_matrix (matrix);
-
-               _pango_layout = Pango::Layout::create (_pango_context);
-               _gc = Gdk::GC::create (get_window ());
-       }
-}
-
-void
-RotatedLabelSet::on_unrealize()
-{
-       _gdk_window.clear ();
-
-       Widget::on_unrealize ();
-}
-
-
-/** Set up our Pango layout to plot a given string, and compute its dimensions once
- *  it has been rotated.
- *  @param s String to use.
- *  @return width and height of the rotated string, in pixels.
- */
-
-std::pair<int, int>
-RotatedLabelSet::setup_layout (std::string const & s)
-{
-       _pango_layout->set_text (s);
-
-       /* Here's the unrotated size */
-       int w;
-       int h;
-       _pango_layout->get_pixel_size (w, h);
-
-       /* Rotate the width and height as appropriate.  I thought Pango might be able
-          to do this for us, but I can't find out how... 
-       */
-
-       std::pair<int, int> d;
-
-       // cerr << "\"" << s << "\" was " << w << " x " << h << endl;
-
-       d.first = int (fabs (w * cos (_angle_radians) + h * sin (_angle_radians)));
-       d.second = int (fabs (w * sin (_angle_radians) + h * cos (_angle_radians)));
-
-       // cerr << "\trotated by " << _angle_degrees << " = " << d.first << " x " << d.second << endl;
-
-       return d;
-}
-
-bool
-RotatedLabelSet::on_expose_event (GdkEventExpose* event)
-{
-       if (!_gdk_window) {
-               return true;
-       }
-
-       int const height = get_allocation().get_height ();
-       double const spacing = double (_base_width) / _port_group_list.n_visible_ports();
-
-       /* Plot all the visible labels; really we should clip for efficiency */
-       int n = 0;
-       for (PortGroupList::const_iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
-               if ((*i)->visible) {
-                       for (uint32_t j = 0; j < (*i)->ports.size(); ++j) {
-                               std::pair<int, int> const d = setup_layout ((*i)->ports[j]);
-                               int x, y;
-                               if (getenv ("AD_X_SHIFT") != 0) {
-                                       x = atoi (getenv ("AD_X_SHIFT"));
-                               } else {
-                                       x = 0;
-                               }
-                               if (getenv ("AD_Y_SHIFT") != 0) {
-                                       y = atoi (getenv ("AD_Y_SHIFT"));
-                               } else {
-                                       y = 0;
-                               }
-                               get_window()->draw_layout (_gc, int ((n + 0.25) * spacing) + x, height - d.second + y, _pango_layout, _fg_colour, _bg_colour);
-                               ++n;
-                       }
-               }
-       }
-
-       return true;
-}
-
-/** Set the `base width'.  This is the width of the base of the label set, ie:
- *
- *     L L L L
- *    E E E E
- *   B B B B
- *  A A A A
- * L L L L
- * <--w-->
- */
-    
-void
-RotatedLabelSet::set_base_width (int w)
-{
-       _base_width = w;
-       queue_resize ();
-}
-
-
 PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type, bool offer_inputs, PortGroupList::Mask mask)
-       : _offer_inputs (offer_inputs), _port_group_list (session, type, offer_inputs, mask), _type (type),
-         _column_labels (_port_group_list)
+       : _offer_inputs (offer_inputs), _port_group_list (session, type, offer_inputs, mask), _type (type)
 {
        _row_labels_vbox = 0;
        _side_vbox_pad = 0;
 
        _visibility_checkbutton_box.pack_start (*(manage (new Label (_("Connections displayed: ")))), false, false, 10);
        pack_start (_visibility_checkbutton_box, false, false);
-       
+
        _scrolled_window.set_policy (POLICY_ALWAYS, POLICY_AUTOMATIC);
        _scrolled_window.set_shadow_type (SHADOW_NONE);
 
        VBox* b = manage (new VBox);
 
-       if (offer_inputs) {
-               b->pack_start (_port_group_hbox, false, false);
-               b->pack_start (_column_labels, false, false);
-       } else {
-               b->pack_start (_column_labels, false, false);
-               b->pack_start (_port_group_hbox, false, false);
-       }
+       b->pack_start (_port_group_hbox, false, false);
+       b->pack_start (_port_group_hbox, false, false);
 
-       Alignment* a; 
-
-       if (offer_inputs) {
-               a = manage (new Alignment (1, 0, 0, 0));
-       } else {
-               a = manage (new Alignment (0, 1, 0, 0));
-       }
-
-       a->add (*b);
-
-       _scrolled_window.add (*a);
+       _scrolled_window.add (matrix);
 
        if (offer_inputs) {
                _overall_hbox.pack_start (_side_vbox, false, false, 6);
@@ -535,7 +169,6 @@ PortMatrix::clear ()
        }
 
        for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
-               _port_group_hbox.remove ((*i)->get_table());
                _visibility_checkbutton_box.remove ((*i)->get_visibility_checkbutton());
                delete *i;
        }
@@ -550,46 +183,16 @@ PortMatrix::clear ()
 void
 PortMatrix::setup_dimensions ()
 {
-       /* Get some dimensions from various places */
-       int const scrollbar_height = _scrolled_window.get_hscrollbar()->get_height();
-
-       std::pair<int, int> unit_size (0, 0);
-       int port_group_tables_height = 0;
-       for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
-               std::pair<int, int> const u = (*i)->unit_size ();
-               unit_size.first = std::max (unit_size.first, u.first);
-               unit_size.second = std::max (unit_size.second, u.second);
-               port_group_tables_height = std::max (
-                       port_group_tables_height, (*i)->get_table().get_height()
-                       );
-       }
-
-       /* Column labels */
-       _column_labels.set_base_width (_port_group_list.n_visible_ports () * unit_size.first);
-
-       /* Scrolled window */
-       /* XXX: really shouldn't set a minimum horizontal size here, but if we don't
-          the window starts up very small.
-          The constant value in the set_size_request() computation will control
-          how big the scrolled window will be if we fill the port matrix will a gajillion
-          ports.
-       */
-
-       _scrolled_window.set_size_request (
-               std::min (_column_labels.get_width(), 400),
-               _column_labels.get_height() + port_group_tables_height + scrollbar_height + 16
-               );
-       
        /* Row labels */
        for (std::vector<EventBox*>::iterator j = _row_labels.begin(); j != _row_labels.end(); ++j) {
-               (*j)->get_child()->set_size_request (-1, unit_size.second);
+               (*j)->get_child()->set_size_request (-1, matrix.row_spacing());
        }
        
        if (_side_vbox_pad) {
                if (_offer_inputs) {
-                       _side_vbox_pad->set_size_request (-1, unit_size.second / 4);
+                       _side_vbox_pad->set_size_request (-1, matrix.row_spacing() / 4);
                } else {
-                       _side_vbox_pad->set_size_request (-1, scrollbar_height + unit_size.second / 4);
+                       _side_vbox_pad->set_size_request (-1, matrix.row_spacing() / 4);
                }
        } 
 }
@@ -647,7 +250,6 @@ PortMatrix::setup ()
                PortGroupUI* t = new PortGroupUI (*this, **i);
                
                _port_group_ui.push_back (t);
-               _port_group_hbox.pack_start (t->get_table(), false, false);
                
                _visibility_checkbutton_box.pack_start (t->get_visibility_checkbutton(), false, false);
 
@@ -666,23 +268,14 @@ PortMatrix::setup ()
 void
 PortMatrix::reset_visibility ()
 {
-       /* now adjust visibility and coloring */
-
-       bool even = true;
-       Gdk::Color odd_bg (color_from_style ("OddPortGroups", STATE_NORMAL, "fg"));
-       Gdk::Color even_bg (color_from_style ("EvenPortGroups", STATE_NORMAL, "fg"));
-
        for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
 
                (*i)->setup_visibility ();
                
                if ((*i)->port_group().visible) {
-                       if (even) {
-                               (*i)->get_table().modify_bg (STATE_NORMAL, even_bg);
-                       } else {
-                               (*i)->get_table().modify_bg (STATE_NORMAL, odd_bg);
-                       }
-                       even = !even;
+                       matrix.show_group ((*i)->port_group());
+               } else {
+                       matrix.hide_group ((*i)->port_group());
                }
        }
 }
index 89208f357a071bffd55ee36ea44d3f6925e696c6..b9a5f7e4c69759ec20560ede31115defcb980a58 100644 (file)
@@ -28,6 +28,8 @@
 #include <gtkmm/scrolledwindow.h>
 
 #include "ardour_dialog.h"
+#include "port_group.h"
+#include "matrix.h"
 
 namespace ARDOUR {
        class Session;
@@ -35,118 +37,6 @@ namespace ARDOUR {
        class PortInsert;
 }
 
-class PortMatrix;
-
-/// A list of port names, grouped by some aspect of their type e.g. busses, tracks, system
-class PortGroup
-{
-  public:
-       /** PortGroup constructor.
-        * @param n Name.
-        * @param p Port name prefix.
-        * @param v true if group should be visible in the UI, otherwise false.
-        */
-       PortGroup (std::string const & n, std::string const & p, bool v) : name (n), prefix (p), visible (v) {}
-
-       void add (std::string const & p);
-
-       std::string name; ///< name for the group
-       std::string prefix; ///< prefix (before colon) e.g. "ardour:"
-       std::vector<std::string> ports; ///< port names
-       bool visible; ///< true if the group is visible in the UI
-};
-
-/// The UI for a PortGroup
-class PortGroupUI
-{
-  public:
-       PortGroupUI (PortMatrix&, PortGroup&);
-
-       Gtk::Widget& get_table ();
-       Gtk::Widget& get_visibility_checkbutton ();
-       std::pair<int, int> unit_size () const;
-       PortGroup& port_group () { return _port_group; }
-       void setup_visibility ();
-
-  private:
-       void port_checkbutton_toggled (Gtk::CheckButton*, int, int);
-       bool port_checkbutton_release (GdkEventButton* ev, Gtk::CheckButton* b, int r, int c);
-       void visibility_checkbutton_toggled ();
-
-       PortMatrix& _port_matrix; ///< the PortMatrix that we are working for
-       PortGroup& _port_group; ///< the PortGroup that we are representing
-       bool _ignore_check_button_toggle;
-       Gtk::Table _table;
-       Gtk::EventBox _table_box;
-       std::vector<std::vector<Gtk::CheckButton* > > _port_checkbuttons;
-       Gtk::CheckButton _visibility_checkbutton;
-};
-
-/// A list of PortGroups
-class PortGroupList : public std::list<PortGroup*>
-{
-  public:
-       enum Mask {
-               BUSS = 0x1,
-               TRACK = 0x2,
-               SYSTEM = 0x4,
-               OTHER = 0x8
-       };
-
-       PortGroupList (ARDOUR::Session &, ARDOUR::DataType, bool, Mask);
-
-       void refresh ();
-       int n_visible_ports () const;
-       std::string get_port_by_index (int, bool with_prefix = true) const;
-       void set_type (ARDOUR::DataType);
-       void set_offer_inputs (bool);
-       
-  private:
-       ARDOUR::Session& _session;
-       ARDOUR::DataType _type;
-       bool _offer_inputs;
-
-       PortGroup buss;
-       PortGroup track;
-       PortGroup system;
-       PortGroup other;
-};
-
-
-/// A widget which provides a set of rotated text labels
-class RotatedLabelSet : public Gtk::Widget {
-  public:
-       RotatedLabelSet (PortGroupList&);
-       virtual ~RotatedLabelSet ();
-
-       void set_angle (int);
-       void set_base_width (int);
-       void update_visibility ();
-       
-  protected:
-       virtual void on_size_request (Gtk::Requisition*);
-       virtual void on_size_allocate (Gtk::Allocation&);
-       virtual void on_realize ();
-       virtual void on_unrealize ();
-       virtual bool on_expose_event (GdkEventExpose*);
-
-       Glib::RefPtr<Gdk::Window> _gdk_window;
-
-  private:
-       std::pair<int, int> setup_layout (std::string const &);
-
-       PortGroupList& _port_group_list; ///< list of ports to display
-       int _angle_degrees; ///< label rotation angle in degrees
-       double _angle_radians; ///< label rotation angle in radians
-       int _base_width; ///< width of labels; see set_base_width() for more details
-       Glib::RefPtr<Pango::Context> _pango_context;
-       Glib::RefPtr<Pango::Layout> _pango_layout;
-       Glib::RefPtr<Gdk::GC> _gc;
-       Gdk::Color _fg_colour;
-       Gdk::Color _bg_colour;
-};
-
-
 class PortMatrix : public Gtk::VBox {
   public:
        PortMatrix (ARDOUR::Session&, ARDOUR::DataType, bool, PortGroupList::Mask);
@@ -184,10 +74,10 @@ class PortMatrix : public Gtk::VBox {
   private:
        PortGroupList _port_group_list;
        ARDOUR::DataType _type;
+       Matrix matrix;
        std::vector<PortGroupUI*> _port_group_ui;
        std::vector<Gtk::EventBox*> _row_labels;
        Gtk::VBox* _row_labels_vbox;
-       RotatedLabelSet _column_labels;
        Gtk::HBox _overall_hbox;
        Gtk::VBox _side_vbox;
        Gtk::HBox _port_group_hbox;
index 370bb7548be683e6145293bc23cc84c54d4adf8a..88bd7d0b1524f3bfc9d1421a444abb745bba1279 100644 (file)
@@ -82,10 +82,9 @@ bool ProcessorBox::get_colors = true;
 Gdk::Color* ProcessorBox::active_processor_color;
 Gdk::Color* ProcessorBox::inactive_processor_color;
 
-ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, boost::shared_ptr<Route> rt, PluginSelector &plugsel, 
-                         RouteRedirectSelection & rsel, bool owner_is_mixer)
-       : _route(rt), 
-         _session(sess), 
+ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plugsel, 
+                           RouteRedirectSelection & rsel, bool owner_is_mixer)
+       : _session(sess), 
          _owner_is_mixer (owner_is_mixer), 
          _placement(pcmnt), 
          _plugin_selector(plugsel),
@@ -138,27 +137,29 @@ ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, boost::shared_ptr<Ro
 
        pack_start (processor_eventbox, true, true);
 
-       _route->processors_changed.connect (mem_fun(*this, &ProcessorBox::redisplay_processors));
-       _route->GoingAway.connect (mem_fun (*this, &ProcessorBox::route_going_away));
-
        processor_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (ProcessorBox::enter_box), this));
 
        processor_display.signal_button_press_event().connect (mem_fun(*this, &ProcessorBox::processor_button_press_event), false);
        processor_display.signal_button_release_event().connect (mem_fun(*this, &ProcessorBox::processor_button_release_event));
-
-       /* start off as a passthru strip. we'll correct this, if necessary,
-          in update_diskstream_display().
-       */
-
-       /* now force an update of all the various elements */
-
-       redisplay_processors ();
 }
 
 ProcessorBox::~ProcessorBox ()
 {
 }
 
+void
+ProcessorBox::set_route (boost::shared_ptr<Route> r)
+{
+       connections.clear ();
+
+       _route = r;
+
+       connections.push_back (_route->processors_changed.connect (mem_fun(*this, &ProcessorBox::redisplay_processors)));
+       connections.push_back (_route->GoingAway.connect (mem_fun (*this, &ProcessorBox::route_going_away)));
+
+       redisplay_processors ();
+}
+
 void
 ProcessorBox::route_going_away ()
 {
index 5d3eb731cafdbd4183cade3939adcd478512a065..74d781a0d44092071a736c9ab647206274b5169d 100644 (file)
@@ -68,10 +68,10 @@ namespace ARDOUR {
 class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
 {
   public:
-       ProcessorBox (ARDOUR::Placement, ARDOUR::Session&, 
-                    boost::shared_ptr<ARDOUR::Route>, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false);
+       ProcessorBox (ARDOUR::Placement, ARDOUR::Session&, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false);
        ~ProcessorBox ();
 
+       void set_route (boost::shared_ptr<ARDOUR::Route>);
        void set_width (Width);
 
        void update();
@@ -87,14 +87,12 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
        
        static void register_actions();
 
-  protected:
-       void set_stuff_from_route ();
-
   private:
        boost::shared_ptr<ARDOUR::Route>  _route;
        ARDOUR::Session &   _session;
        bool                _owner_is_mixer;
        bool                 ab_direction;
+       std::vector<sigc::connection> connections;
 
        ARDOUR::Placement   _placement;
 
index f39d41def5a3be7826419089769035c9b2666286..00a4858c422e2fadc51f16b1537b38c259fc8932 100644 (file)
@@ -229,8 +229,11 @@ RouteParams_UI::setup_processor_boxes()
                cleanup_processor_boxes();
                
                // construct new redirect boxes
-               pre_insert_box = new ProcessorBox(PreFader, *session, _route, *_plugin_selector, _rr_selection);
-               post_insert_box = new ProcessorBox(PostFader, *session, _route, *_plugin_selector, _rr_selection);
+               pre_insert_box = new ProcessorBox(PreFader, *session, *_plugin_selector, _rr_selection);
+               post_insert_box = new ProcessorBox(PostFader, *session, *_plugin_selector, _rr_selection);
+  
+               pre_insert_box->set_route (_route);
+               post_insert_box->set_route (_route);
 
                pre_redir_hpane.pack1 (*pre_insert_box);
                post_redir_hpane.pack1 (*post_insert_box);
index 71ad6e73bdd728b8d3c423e2917ec2f7eda60dce..8985e85071130a1a6e15bb561d57c0ba7e4443a3 100644 (file)
@@ -106,9 +106,9 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
          size_button (_("h")), // height
          automation_button (_("a")),
          visual_button (_("v")),
-         gm (rt, sess, slider, true)
-
+         gm (sess, slider, true)
 {
+       gm.set_io (rt);
        gm.get_level_meter().set_no_show_all();
        gm.get_level_meter().setup_meters(50);
 
index 44032a4ea5cbf11eaa7afa299aea02297c0cce37..3019d954fc2a2e7995d39fd5b77ba3c22fa952c4 100644 (file)
@@ -54,13 +54,33 @@ using namespace Gtkmm2ext;
 using namespace ARDOUR;
 using namespace PBD;
 
-RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, const char* m_name,
-                 const char* s_name, const char* r_name)
-       : AxisView(sess),
-         _route(rt),
-         mute_button(0),
-         solo_button(0),
-         rec_enable_button(0)
+RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
+       : AxisView(sess)
+{
+       init ();
+       set_button_names (mute_name, solo_name, rec_name);
+}
+
+RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, 
+                 ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
+       : AxisView(sess)
+{
+       init ();
+       set_button_names (mute_name, solo_name, rec_name);
+       set_route (rt);
+}
+
+RouteUI::~RouteUI()
+{
+       GoingAway (); /* EMIT SIGNAL */
+
+       delete solo_menu;
+       delete mute_menu;
+       delete remote_control_menu;
+}
+
+void
+RouteUI::init ()
 {
        xml_node = 0;
        mute_menu = 0;
@@ -73,27 +93,87 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
        polarity_menu_item = 0;
        denormal_menu_item = 0;
 
-       if (set_color_from_route()) {
-               set_color (unique_random_color());
+       mute_button = manage (new BindableToggleButton (""));
+       mute_button->set_self_managed (true);
+       mute_button->set_name ("MuteButton");
+
+       solo_button = manage (new BindableToggleButton (""));
+       solo_button->set_self_managed (true);
+       solo_button->set_name ("SoloButton");
+
+       rec_enable_button = manage (new BindableToggleButton (""));
+       rec_enable_button->set_name ("RecordEnableButton");
+       rec_enable_button->set_self_managed (true);
+       
+       _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
+}
+
+void
+RouteUI::reset ()
+{
+       connections.clear ();
+
+       if (solo_menu) {
+               delete solo_menu;
+               solo_menu = 0;
        }
 
-       new PairedShiva<Route,RouteUI> (*_route, *this);
+       if (mute_menu) {
+               delete mute_menu;
+               mute_menu = 0;
+       }
+       
+       if (remote_control_menu) {
+               delete remote_control_menu;
+               remote_control_menu = 0;
+       }
 
-       _route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed));
+       if (xml_node) {
+               /* do not delete the node - its owned by the route */
+               xml_node = 0;
+       }
 
-       mute_button = manage (new BindableToggleButton (_route->mute_control(), m_name ));
-       mute_button->set_self_managed (true);
+       route_active_menu_item = 0;
+       polarity_menu_item = 0;
+       denormal_menu_item = 0;
+}
 
-       solo_button = manage (new BindableToggleButton (_route->solo_control(), s_name ));
-       solo_button->set_self_managed (true);
+void
+RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
+{
+       m_name = mute;
+       s_name = solo;
+       r_name = rec;
+}
 
-       mute_button->set_name ("MuteButton");
-       solo_button->set_name ("SoloButton");
+void
+RouteUI::set_route (boost::shared_ptr<Route> rp)
+{
+       reset ();
+
+       _route = rp;
+
+       if (set_color_from_route()) {
+               set_color (unique_random_color());
+       }
 
-       _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
-       _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
-       _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
+       /* no, there is no memory leak here. This object cleans itself (and other stuff)
+          up when the route is destroyed.
+       */
 
+       new PairedShiva<Route,RouteUI> (*_route, *this);
+  
+       mute_button->set_controllable (_route->mute_control());
+       mute_button->set_label (m_name);
+       
+       solo_button->set_controllable (_route->solo_control());
+       solo_button->set_label (s_name);
+  
+       connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
+       connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
+       connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
+       connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
+  
        /* when solo changes, update mute state too, in case the user wants us to display it */
 
        _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
@@ -101,15 +181,13 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
        if (is_track()) {
                boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
 
-               t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed));
-
-               _session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed));
+               connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
+               connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
 
-               rec_enable_button = manage (new BindableToggleButton (t->rec_enable_control(), r_name ));
-               rec_enable_button->set_name ("RecordEnableButton");
-               rec_enable_button->set_self_managed (true);
-               
                rec_enable_button->show();
+               rec_enable_button->set_controllable (t->rec_enable_control());
+               rec_enable_button->set_label (r_name);
+
                update_rec_display ();
        } 
 
@@ -119,19 +197,13 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
        mute_button->show();
        solo_button->show();
 
-       _route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu));
+       connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
 
        /* map the current state */
 
        map_frozen ();
 }
 
-RouteUI::~RouteUI()
-{
-       GoingAway (); /* EMIT SIGNAL */
-       delete mute_menu;
-}
-
 bool
 RouteUI::mute_press(GdkEventButton* ev)
 {
index e18eda687175b39fc6b523f7372529d5bbe1bed9..67aa409dda01729c8e8dce42c2b6f84d3666565c 100644 (file)
@@ -45,9 +45,14 @@ class BindableToggleButton;
 class RouteUI : public virtual AxisView
 {
   public:
+       RouteUI(ARDOUR::Session&, const char*, const char*, const char*);
        RouteUI(boost::shared_ptr<ARDOUR::Route>, ARDOUR::Session&, const char*, const char*, const char*);
+
        virtual ~RouteUI();
 
+       virtual void set_route (boost::shared_ptr<ARDOUR::Route>);
+       void set_button_names (const char*, const char*, const char*);
+
        bool is_track() const;
        bool is_audio_track() const;
        bool is_midi_track() const;
@@ -161,6 +166,15 @@ class RouteUI : public virtual AxisView
        void reversibly_apply_track_boolean (string name, void (ARDOUR::Track::*func)(bool, void*), bool, void *);
 
        void adjust_latency ();
+   protected:
+       std::vector<sigc::connection> connections;
+       std::string s_name;
+       std::string m_name;
+       std::string r_name;
+       void init ();
+       void reset ();
 };
 
 #endif /* __ardour_route_ui__ */
index 90ff3de717637378aa6e3260020c05a7158aa2e1..6ce6edd303903c3f5eecdf9cf1664d5a23752056 100644 (file)
@@ -30,11 +30,14 @@ using namespace ARDOUR;
 using namespace PBD;
 
 SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
-       : _send (s),
-         _session (se),
-         gpm (s->io(), se),
-         panners (s->io(), se)
+       : _send (s)
+       , _session (se)
+       , gpm (se)
+       , panners (se)
 {
+       panners.set_io (s->io());
+       gpm.set_io (s->io());
+
        hbox.pack_start (gpm, true, true);
        set_name ("SendUIFrame");
        
index 601b83f0c0dffbdf2f949d6492964a7f71d60318..915c3c6d3c208d4a75ccb5eeb5d69179f02c1370 100644 (file)
@@ -596,7 +596,8 @@ SoundFileBrowser::add_gain_meter ()
                delete gm;
        }
 
-       gm = new GainMeter (session->the_auditioner(), *session);
+       gm = new GainMeter (*session);
+       gm->set_io (session->the_auditioner());
 
        meter_packer.set_border_width (12);
        meter_packer.pack_start (*gm, false, true);
index d4e995f0bf0651e41593214d01c3be7531247973..0b5a14bf565622b5e0c4fea6ef6d81b484f8515c 100644 (file)
@@ -153,12 +153,45 @@ PluginManager::refresh ()
 void
 PluginManager::ladspa_refresh ()
 {
-       _ladspa_plugin_info.clear ();
-
-       if (ladspa_path.length() == 0) {
-               ladspa_path = "/usr/local/lib64/ladspa:/usr/local/lib/ladspa:/usr/lib64/ladspa:/usr/lib/ladspa:/Library/Audio/Plug-Ins/LADSPA";
-       }
-
+       _ladspa_plugin_info.clear ();
+       
+       static const char *standard_paths[] = {
+               "/usr/local/lib64/ladspa",
+               "/usr/local/lib/ladspa",
+               "/usr/lib64/ladspa",
+               "/usr/lib/ladspa",
+               "/Library/Audio/Plug-Ins/LADSPA",
+               ""
+       };
+       
+       /* allow LADSPA_PATH to augment, not override standard locations */
+       /* Only add standard locations to ladspa_path if it doesn't
+        * already contain them. Check for trailing '/'s too.
+        */
+        
+       int i;
+       for (i = 0; standard_paths[i][0]; i++) {
+               size_t found = ladspa_path.find(standard_paths[i]);
+               if (found != ladspa_path.npos) {
+                       switch (ladspa_path[found + strlen(standard_paths[i])]) {
+                               case ':' :
+                               case '\0':
+                                       continue;
+                               case '/' :
+                                       if (ladspa_path[found + strlen(standard_paths[i]) + 1] == ':' ||
+                                           ladspa_path[found + strlen(standard_paths[i]) + 1] == '\0') {
+                                               continue;
+                                       }
+                       }
+               }
+               if (!ladspa_path.empty())
+                       ladspa_path += ":";
+               ladspa_path += standard_paths[i]; 
+               
+       }
+  
        ladspa_discover_from_path (ladspa_path);
 }
 
index 6c60deaa8ffbd71c22ea7eeff054a46386b584b5..845146239dc4ae56a08301a6166f5c113bf02948 100644 (file)
@@ -40,6 +40,14 @@ BindingProxy::BindingProxy (boost::shared_ptr<Controllable> c)
 {                        
 }
 
+BindingProxy::BindingProxy ()
+       : prompter (0),
+         bind_button (2),
+         bind_statemask (Gdk::CONTROL_MASK)
+
+{                        
+}
+
 BindingProxy::~BindingProxy ()
 {
        if (prompter) {
@@ -47,6 +55,13 @@ BindingProxy::~BindingProxy ()
        }
 }
 
+void
+BindingProxy::set_controllable (boost::shared_ptr<Controllable> c)
+{
+       learning_finished ();
+       controllable = c;
+}
+
 void
 BindingProxy::set_bind_button_state (guint button, guint statemask)
 {
@@ -64,7 +79,7 @@ BindingProxy::get_bind_button_state (guint &button, guint &statemask)
 bool
 BindingProxy::button_press_handler (GdkEventButton *ev)
 {
-       if ((ev->state & bind_statemask) && ev->button == bind_button) { 
+       if (controllable && (ev->state & bind_statemask) && ev->button == bind_button) { 
                if (Controllable::StartLearning (controllable.get())) {
                        string prompt = _("operate controller now");
                        if (prompter == 0) {
@@ -95,7 +110,9 @@ bool
 BindingProxy::prompter_hiding (GdkEventAny *ev)
 {
        learning_connection.disconnect ();
-       Controllable::StopLearning (controllable.get());
+       if (controllable) {
+               Controllable::StopLearning (controllable.get());
+       }
        return false;
 }
 
index 5e9a6fed906501886fc79766f74a71f894a00982..2c0ca948d995b50a949ae251c3dce5013074032f 100644 (file)
@@ -63,7 +63,9 @@ class BarController : public Gtk::Frame
        /* export this to allow direct connection to button events */
 
        Gtk::Widget& event_widget() { return darea; }
+
        boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
+       void set_controllable(boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable(c); }
 
   protected:
        Gtk::Adjustment&    adjustment;
index 844dc27d086ae6167a3d70a1b3de79dca1d17a83..3fad7d1faaf9ba09d39be2dc8ddda09ce21650a6 100644 (file)
@@ -32,10 +32,8 @@ namespace PBD {
 class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton
 {
    public:
-       BindableToggleButton (boost::shared_ptr<PBD::Controllable> c) : binding_proxy (c) {}
-
-       explicit BindableToggleButton (boost::shared_ptr<PBD::Controllable> c, const std::string &label)
-               : Gtkmm2ext::StatefulToggleButton (label), binding_proxy (c) {}
+       BindableToggleButton (const std::string &label)
+               : Gtkmm2ext::StatefulToggleButton (label) {}
 
        virtual ~BindableToggleButton() {}
        
@@ -49,7 +47,8 @@ class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton
        }
        
        boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
-
+       void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
   private:
        BindingProxy binding_proxy;
 };
@@ -58,10 +57,6 @@ class BindableButton : public Gtkmm2ext::StatefulButton
 {
    public:
        BindableButton (boost::shared_ptr<PBD::Controllable> c) : binding_proxy (c) {}
-
-       explicit BindableButton (boost::shared_ptr<PBD::Controllable> c, const std::string &label)
-               : Gtkmm2ext::StatefulButton (label), binding_proxy (c) {}
-
        ~BindableButton() {}
        
        bool on_button_press_event (GdkEventButton *ev) {
@@ -74,6 +69,7 @@ class BindableButton : public Gtkmm2ext::StatefulButton
        }
 
        boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
+       void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
 
   private:
        BindingProxy binding_proxy;
index ecb95bf8156feabb68af0c968845a2698873ef3b..f684cce5c3e76e1e0d201cd237ac052c596ad2de 100644 (file)
@@ -34,6 +34,7 @@ class BindingProxy : public sigc::trackable
 {
    public:
        BindingProxy (boost::shared_ptr<PBD::Controllable>);
+       BindingProxy ();
        virtual ~BindingProxy();
        
        void set_bind_button_state (guint button, guint statemask);
@@ -42,6 +43,7 @@ class BindingProxy : public sigc::trackable
        bool button_press_handler (GdkEventButton *);
 
        boost::shared_ptr<PBD::Controllable> get_controllable() { return controllable; }
+       void set_controllable (boost::shared_ptr<PBD::Controllable>);
 
   protected:
        Gtkmm2ext::PopUp*  prompter;
index 46f70dacd8d3b22d772b9ecc3d98c5faffa252df..7fea4a40d7257653f4ac0f1c5a2a9175112e4c47 100644 (file)
@@ -41,7 +41,6 @@ class SliderController : public Gtkmm2ext::PixFader
   public:
        SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
                          Gtk::Adjustment* adj, int orientation,
-                         boost::shared_ptr<PBD::Controllable>,
                          bool with_numeric = true);
        
         virtual ~SliderController () {}
@@ -52,6 +51,8 @@ class SliderController : public Gtkmm2ext::PixFader
        
        bool on_button_press_event (GdkEventButton *ev);
 
+       void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
+
   protected:
        BindingProxy binding_proxy;
        Glib::RefPtr<Gdk::Pixbuf> slider;
@@ -59,6 +60,8 @@ class SliderController : public Gtkmm2ext::PixFader
        Gtk::SpinButton     spin;
        Gtk::Frame          spin_frame;
        Gtk::HBox           spin_hbox;
+
+       void init ();
 };
 
 class VSliderController : public SliderController
@@ -66,7 +69,6 @@ class VSliderController : public SliderController
   public:
        VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
                           Gtk::Adjustment *adj,
-                          boost::shared_ptr<PBD::Controllable>,
                           bool with_numeric = true);
 };
 
@@ -75,7 +77,6 @@ class HSliderController : public SliderController
   public:
        HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
                           Gtk::Adjustment *adj,
-                          boost::shared_ptr<PBD::Controllable>,
                           bool with_numeric = true);
 };
 
index 92fd9d078b7ee5d442debdc817a139d21e8f4660..4eee6a6f36df944a088dfa2403bb91186ae78b2c 100644 (file)
@@ -30,11 +30,9 @@ using namespace PBD;
 
 SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
                                    Gtk::Adjustment *adj,  int orientation,
-                                   boost::shared_ptr<Controllable> c,
                                    bool with_numeric)
 
        : PixFader (image, *adj, orientation),
-         binding_proxy (c),
          spin (*adj, 0, 2)
 {                        
        spin.set_name ("SliderControllerValue");
@@ -55,15 +53,15 @@ SliderController::on_button_press_event (GdkEventButton *ev)
        if (binding_proxy.button_press_handler (ev)) {
                return true;
        }
+
        return PixFader::on_button_press_event (ev);
 }
 
 VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
                                      Gtk::Adjustment *adj,
-                                     boost::shared_ptr<Controllable> control,
                                      bool with_numeric)
 
-       : SliderController (image, adj, VERT, control, with_numeric)
+       : SliderController (image, adj, VERT, with_numeric)
 {
        if (with_numeric) {
                spin_frame.add (spin);
@@ -76,10 +74,9 @@ VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
 
 HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
                                      Gtk::Adjustment *adj,
-                                     boost::shared_ptr<Controllable> control,
                                      bool with_numeric)
        
-       : SliderController (image, adj, HORIZ, control, with_numeric)
+       : SliderController (image, adj, HORIZ, with_numeric)
 {
        if (with_numeric) {
                spin_frame.add (spin);