New matrix-based editor for connections and bundles, based on thorwil's design.
authorCarl Hetherington <carl@carlh.net>
Tue, 20 Jan 2009 14:46:00 +0000 (14:46 +0000)
committerCarl Hetherington <carl@carlh.net>
Tue, 20 Jan 2009 14:46:00 +0000 (14:46 +0000)
Add Bundle Manager dialog.

git-svn-id: svn://localhost/ardour2/branches/3.0@4415 d708f5d6-7413-0410-9779-e7cbd77b26cf

32 files changed:
gtk2_ardour/SConscript
gtk2_ardour/ardour.menus.in
gtk2_ardour/bundle_manager.cc
gtk2_ardour/bundle_manager.h
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_actions.cc
gtk2_ardour/io_selector.cc
gtk2_ardour/io_selector.h
gtk2_ardour/matrix.cc [deleted file]
gtk2_ardour/matrix.h [deleted file]
gtk2_ardour/option_editor.cc
gtk2_ardour/port_group.cc
gtk2_ardour/port_group.h
gtk2_ardour/port_matrix.cc
gtk2_ardour/port_matrix.h
gtk2_ardour/port_matrix_body.cc [new file with mode: 0644]
gtk2_ardour/port_matrix_body.h [new file with mode: 0644]
gtk2_ardour/port_matrix_column_labels.cc [new file with mode: 0644]
gtk2_ardour/port_matrix_column_labels.h [new file with mode: 0644]
gtk2_ardour/port_matrix_component.cc [new file with mode: 0644]
gtk2_ardour/port_matrix_component.h [new file with mode: 0644]
gtk2_ardour/port_matrix_grid.cc [new file with mode: 0644]
gtk2_ardour/port_matrix_grid.h [new file with mode: 0644]
gtk2_ardour/port_matrix_row_labels.cc [new file with mode: 0644]
gtk2_ardour/port_matrix_row_labels.h [new file with mode: 0644]
gtk2_ardour/route_params_ui.cc
libs/ardour/ardour/bundle.h
libs/ardour/bundle.cc
libs/ardour/io.cc
libs/ardour/session.cc
libs/ardour/user_bundle.cc

index c6fb356cd90eb1a36e485b12a902c4cf081eec05..d42edb1919b0710c80b19ac27e67168bcb4662c1 100644 (file)
@@ -196,7 +196,6 @@ lineset.cc
 location_ui.cc
 main.cc
 marker.cc
-matrix.cc
 midi_channel_selector.cc
 midi_port_dialog.cc
 midi_region_view.cc
@@ -216,8 +215,13 @@ piano_roll_header.cc
 playlist_selector.cc
 plugin_selector.cc
 plugin_ui.cc
-port_matrix.cc
 port_group.cc
+port_matrix.cc
+port_matrix_body.cc
+port_matrix_column_labels.cc
+port_matrix_component.cc
+port_matrix_grid.cc
+port_matrix_row_labels.cc
 processor_box.cc
 prompter.cc
 public_editor.cc
index c6688e92a2acf2d6beb316748103e038c662bfe7..dbddc2d93c96df6d86d90c45724eaa2d41465336 100644 (file)
                <menuitem action='ToggleThemeManager'/>
                <menuitem action='ToggleBigClock'/>
                <menuitem action='toggle-rhythm-ferret'/>
+               <menuitem action='toggle-bundle-manager'/>
               <separator/>
         </menu>
         <menu name='Options' action='Options'>
index e4e848557e1b45ea7dcde8c897d16dfc3c0bb182..1b493348ae692f536469154b8425934e2fb60076 100644 (file)
@@ -38,71 +38,79 @@ BundleEditorMatrix::BundleEditorMatrix (
                PortGroupList::Mask (PortGroupList::SYSTEM | PortGroupList::OTHER)
                )
 {
-       _bundle = boost::dynamic_pointer_cast<ARDOUR::UserBundle> (bundle);
-       assert (_bundle != 0);
+       _our_bundle = bundle;
 }
 
 void
-BundleEditorMatrix::set_state (int r, std::string const & p, bool s, uint32_t keymod)
+BundleEditorMatrix::set_state (
+       boost::shared_ptr<ARDOUR::Bundle> ab,
+       uint32_t ac,
+       boost::shared_ptr<ARDOUR::Bundle> bb,
+       uint32_t bc,
+       bool s,
+       uint32_t k
+       )
 {
-       if (s) {
-               _bundle->add_port_to_channel (r, p);
-       } else {
-               _bundle->remove_port_from_channel (r, p);
+       ARDOUR::Bundle::PortList const& pl = bb->channel_ports (bc);
+       for (ARDOUR::Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
+               if (s) {
+                       ab->add_port_to_channel (ac, *i);
+               } else {
+                       ab->remove_port_from_channel (ac, *i);
+               }
        }
 }
 
 bool
-BundleEditorMatrix::get_state (int r, std::string const & p) const
+BundleEditorMatrix::get_state (
+       boost::shared_ptr<ARDOUR::Bundle> ab,
+       uint32_t ac,
+       boost::shared_ptr<ARDOUR::Bundle> bb,
+       uint32_t bc
+       ) const
 {
-       return _bundle->port_attached_to_channel (r, p);
-}
+       ARDOUR::Bundle::PortList const& pl = bb->channel_ports (bc);
+       for (ARDOUR::Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
+               if (!ab->port_attached_to_channel (ac, *i)) {
+                       return false;
+               }
+       }
 
-uint32_t
-BundleEditorMatrix::n_rows () const
-{
-       return _bundle->nchannels ();
+       return true;
 }
 
-uint32_t
-BundleEditorMatrix::maximum_rows () const
+void
+BundleEditorMatrix::add_channel (boost::shared_ptr<ARDOUR::Bundle> b)
 {
-       /* 65536 channels in a bundle ought to be enough for anyone (TM) */
-       return 65536;
-}
+       NameChannelDialog d;
+       d.set_position (Gtk::WIN_POS_MOUSE);
 
-uint32_t
-BundleEditorMatrix::minimum_rows () const
-{
-       return 0;
-}
+       if (d.run () != Gtk::RESPONSE_ACCEPT) {
+               return;
+       }
 
-std::string
-BundleEditorMatrix::row_name (int r) const
-{
-       std::stringstream s;
-       s << r + 1; // 1-based counting
-       return s.str();
+       _our_bundle->add_channel (d.get_name());
+       setup ();
 }
 
 void
-BundleEditorMatrix::add_row ()
+BundleEditorMatrix::remove_channel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c)
 {
-       _bundle->add_channel ();
+       _our_bundle->remove_channel (c);
        setup ();
 }
 
 void
-BundleEditorMatrix::remove_row (int r)
+BundleEditorMatrix::rename_channel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c)
 {
-       _bundle->remove_channel (r);
-       setup ();
-}
+       NameChannelDialog d (b, c);
+       d.set_position (Gtk::WIN_POS_MOUSE);
 
-std::string
-BundleEditorMatrix::row_descriptor () const
-{
-       return _("channel");
+       if (d.run () != Gtk::RESPONSE_ACCEPT) {
+               return;
+       }
+
+       b->set_channel_name (c, d.get_name ());
 }
 
 BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::UserBundle> bundle, bool add)
@@ -111,21 +119,21 @@ BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::
        Gtk::Table* t = new Gtk::Table (3, 2);
        t->set_spacings (4);
 
+       /* Bundle name */
        Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
        a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
        t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
        t->attach (_name, 1, 2, 0, 1);
-       
        _name.set_text (_bundle->name ());
        _name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
 
+       /* Direction (input or output) */
        a = new Gtk::Alignment (1, 0.5, 0, 1);
        a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
        t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
        a = new Gtk::Alignment (0, 0.5, 0, 1);
        a->add (_input_or_output);
        t->attach (*Gtk::manage (a), 1, 2, 1, 2);
-       
        _input_or_output.append_text (_("Input"));
        _input_or_output.append_text (_("Output"));
        
@@ -137,6 +145,7 @@ BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::
 
        _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
 
+       /* Type (audio or MIDI) */
        a = new Gtk::Alignment (1, 0.5, 0, 1);
        a->add (*Gtk::manage (new Gtk::Label (_("Type:"))));
        t->attach (*Gtk::manage (a), 0, 1, 2, 3, Gtk::FILL, Gtk::FILL);
@@ -159,11 +168,16 @@ BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::
        _type.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::type_changed));
                                        
        get_vbox()->pack_start (*Gtk::manage (t), false, false);
-       
        get_vbox()->pack_start (_matrix);
-
        get_vbox()->set_spacing (4);
 
+       /* Add Channel button */
+       Gtk::Button* add_channel_button = Gtk::manage (new Gtk::Button (_("Add Channel")));
+       add_channel_button->set_name ("IOSelectorButton");
+       add_channel_button->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::ADD, Gtk::ICON_SIZE_BUTTON)));
+       get_action_area()->pack_start (*add_channel_button, false, false);
+       add_channel_button->signal_clicked().connect (sigc::bind (sigc::mem_fun (_matrix, &BundleEditorMatrix::add_channel), boost::shared_ptr<ARDOUR::Bundle> ()));
+
        if (add) {
                add_button (Gtk::Stock::CANCEL, 1);
                add_button (Gtk::Stock::ADD, 0);
@@ -269,7 +283,7 @@ BundleManager::new_clicked ()
        boost::shared_ptr<ARDOUR::UserBundle> b (new ARDOUR::UserBundle (""));
 
        /* Start off with a single channel */
-       b->add_channel ();
+       b->add_channel ("");
 
        BundleEditor e (_session, b, true);
        if (e.run () == 0) {
@@ -333,3 +347,47 @@ BundleManager::bundle_name_changed (boost::shared_ptr<ARDOUR::UserBundle> b)
        }
 }
 
+
+NameChannelDialog::NameChannelDialog ()
+       : ArdourDialog (_("Add channel")),
+         _adding (true)
+{
+       setup ();
+}
+
+NameChannelDialog::NameChannelDialog (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c)
+       : ArdourDialog (_("Rename channel")),
+         _bundle (b),
+         _channel (c),
+         _adding (false)
+{
+       _name.set_text (b->channel_name (c));
+
+       setup ();
+}
+
+void
+NameChannelDialog::setup ()
+{      
+       Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
+
+       box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
+       box->pack_start (_name);
+
+       get_vbox ()->pack_end (*box);
+       box->show_all ();
+
+       add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+       if (_adding) {
+               add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
+       } else {
+               add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
+       }
+       set_default_response (Gtk::RESPONSE_ACCEPT);
+}
+
+std::string
+NameChannelDialog::get_name () const
+{
+       return _name.get_text ();
+}
index 097328b602d83dd8c7372366fb0346e88c8d3c3e..18b0b29e92ec601dadf0ca505eeffc102131d606 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <gtkmm/treeview.h>
 #include <gtkmm/liststore.h>
+#include <gtkmm/entry.h>
 #include "ardour_dialog.h"
 #include "port_matrix.h"
 
@@ -35,19 +36,28 @@ class BundleEditorMatrix : public PortMatrix
   public:
        BundleEditorMatrix (ARDOUR::Session &, boost::shared_ptr<ARDOUR::Bundle>);
 
-       void set_state (int, std::string const &, bool, uint32_t);
-       bool get_state (int, std::string const &) const;
-       uint32_t n_rows () const;
-       uint32_t maximum_rows () const;
-       uint32_t minimum_rows () const;
-       std::string row_name (int) const;
-       void add_row ();
-       void remove_row (int);
-       std::string row_descriptor () const;
-
-  private:
-
-       boost::shared_ptr<ARDOUR::UserBundle> _bundle;
+       void set_state (
+               boost::shared_ptr<ARDOUR::Bundle> ab,
+               uint32_t ac,
+               boost::shared_ptr<ARDOUR::Bundle> bb,
+               uint32_t bc,
+               bool s,
+               uint32_t k
+               );
+       
+       bool get_state (
+               boost::shared_ptr<ARDOUR::Bundle> ab,
+               uint32_t ac,
+               boost::shared_ptr<ARDOUR::Bundle> bb,
+               uint32_t bc
+               ) const;
+
+       void add_channel (boost::shared_ptr<ARDOUR::Bundle>);
+       void remove_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t);
+       bool can_rename_channels () const {
+               return true;
+       }
+       void rename_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t);
 };
 
 class BundleEditor : public ArdourDialog
@@ -104,4 +114,22 @@ class BundleManager : public ArdourDialog
        Gtk::Button delete_button;
 };
 
+class NameChannelDialog : public ArdourDialog
+{
+public:
+       NameChannelDialog ();
+       NameChannelDialog (boost::shared_ptr<ARDOUR::Bundle>, uint32_t);
+
+       std::string get_name () const;
+
+private:
+
+       void setup ();
+       
+       boost::shared_ptr<ARDOUR::Bundle> _bundle;
+       uint32_t _channel;
+       Gtk::Entry _name;
+       bool _adding;
+};
+
 #endif
index 3eba17a06ec1208989a36bdbe7bcbf16485062c7..08be372b148125193dc91d81bafc531acce56bdf 100644 (file)
@@ -87,6 +87,7 @@
 #include "actions.h"
 #include "tempo_lines.h"
 #include "analysis_window.h"
+#include "bundle_manager.h"
 
 #include "i18n.h"
 
@@ -347,6 +348,7 @@ Editor::Editor ()
        select_new_marker = false;
        zoomed_to_region = false;
        rhythm_ferret = 0;
+       _bundle_manager = 0;
        allow_vertical_scroll = false;
        no_save_visual = false;
        need_resize_line = false;
@@ -5127,6 +5129,16 @@ Editor::show_rhythm_ferret ()
        rhythm_ferret->present ();
 }
 
+void
+Editor::show_bundle_manager ()
+{
+       if (_bundle_manager == 0) {
+               _bundle_manager = new BundleManager (*session);
+       }
+
+       _bundle_manager->show ();
+}
+
 void
 Editor::first_idle ()
 {
index 622d288213d565262ff2d04bdba48fc396fd6b06..87c2a1deb953912190aaf2dd58d40593aedcbbdc 100644 (file)
@@ -110,6 +110,7 @@ class ControlPoint;
 class SoundFileOmega;
 class RhythmFerret;
 class AnalysisWindow;
+class BundleManager;
 
 /* <CMT Additions> */
 class ImageFrameView;
@@ -394,6 +395,7 @@ class Editor : public PublicEditor
        void toggle_meter_updating();
 
        void show_rhythm_ferret();
+       void show_bundle_manager ();
 
        void goto_visual_state (uint32_t);
        void save_visual_state (uint32_t);
@@ -2347,6 +2349,7 @@ public:
        void snap_to_internal (nframes64_t& first, int32_t direction = 0, bool for_mark = false);
 
        RhythmFerret* rhythm_ferret;
+       BundleManager* _bundle_manager;
 
        void fit_tracks ();
        void set_track_height (uint32_t h);
index 0e27aabaef396c99e955da2a147ddc14428ce112..5c973034c48cd5bd05e1b561ad671a735a11473a 100644 (file)
@@ -563,6 +563,7 @@ Editor::register_actions ()
        ActionManager::region_selection_sensitive_actions.push_back (act);
        act = ActionManager::register_action (editor_actions, "toggle-rhythm-ferret", _("Rhythm Ferret"), mem_fun(*this, &Editor::show_rhythm_ferret));
        ActionManager::session_sensitive_actions.push_back (act);
+       act = ActionManager::register_action (editor_actions, "toggle-bundle-manager", _("Bundle Manager"), mem_fun (*this, &Editor::show_bundle_manager));
 
        act = ActionManager::register_action (editor_actions, "tab-to-transient-forwards", _("Move Forward to Transient"), bind (mem_fun(*this, &Editor::tab_to_transient), true));
        ActionManager::session_sensitive_actions.push_back (act);
index 0e40aa6ad306ddaaf4d22d0b4c62bfd1b4a82d77..06274df95effc45ba8838687c3d9246f1ff3a008 100644 (file)
@@ -30,6 +30,7 @@
 #include "ardour/audio_track.h"
 #include "ardour/midi_track.h"
 #include "ardour/data_type.h"
+#include "ardour/bundle.h"
 
 #include "io_selector.h"
 #include "utils.h"
@@ -44,80 +45,130 @@ IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO>
                      PortGroupList::Mask (PortGroupList::BUSS | 
                                           PortGroupList::SYSTEM | 
                                           PortGroupList::OTHER))
+       , _session (session)
        , _io (io)
 {
-       list<string> our_ports;
-
        /* Listen for ports changing on the IO */
-       if (_offer_inputs) {
-               _io->output_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
+       _io->PortCountChanged.connect (sigc::hide (mem_fun (*this, &IOSelector::ports_changed)));
+       
+       setup ();
+}
 
+void
+IOSelector::setup ()
+{
+       _our_bundle = boost::shared_ptr<ARDOUR::Bundle> (new ARDOUR::Bundle);
+       _our_bundle->set_name (_io->name());
+
+       if (offering_input ()) {
                const PortSet& ps (_io->outputs());
 
+               int j = 0;
                for (PortSet::const_iterator i = ps.begin(); i != ps.end(); ++i) {
-                       our_ports.push_back (i->name());
+                       char buf[32];
+                       snprintf (buf, sizeof(buf), _("out %d"), j + 1);
+                       _our_bundle->add_channel (buf);
+                       _our_bundle->add_port_to_channel (j, i->name());
+                       ++j;
                }
-
+               
        } else {
-               _io->input_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
-
+               
                const PortSet& ps (_io->inputs());
 
+               int j = 0;
                for (PortSet::const_iterator i = ps.begin(); i != ps.end(); ++i) {
-                       our_ports.push_back (i->name());
+                       char buf[32];
+                       snprintf (buf, sizeof(buf), _("in %d"), j + 1);
+                       _our_bundle->add_channel (buf);
+                       _our_bundle->add_port_to_channel (j, i->name());
+                       ++j;
                }
 
        }
-       
-       set_ports (our_ports);
 
-       setup ();
+       PortMatrix::setup ();
 }
 
 void
-IOSelector::ports_changed (ARDOUR::IOChange change, void *src)
+IOSelector::ports_changed ()
 {
-       ENSURE_GUI_THREAD (bind (mem_fun (*this, &IOSelector::ports_changed), change, src));
+       ENSURE_GUI_THREAD (mem_fun (*this, &IOSelector::ports_changed));
 
        setup ();
 }
 
 void
-IOSelector::set_state (int r, std::string const & p, bool s, uint32_t keymod)
+IOSelector::set_state (
+       boost::shared_ptr<ARDOUR::Bundle> ab,
+       uint32_t ac,
+       boost::shared_ptr<ARDOUR::Bundle> bb,
+       uint32_t bc,
+       bool s,
+       uint32_t k
+       )
 {
-       if (s) {
-               if (!_offer_inputs) {
-                       _io->connect_input (_io->input(r), p, 0);
-               } else {
-                       _io->connect_output (_io->output(r), p, 0);
-               }
-       } else {
-               if (!_offer_inputs) {
-                       _io->disconnect_input (_io->input(r), p, 0);
-               } else {
-                       _io->disconnect_output (_io->output(r), p, 0);
+       ARDOUR::Bundle::PortList const& our_ports = ab->channel_ports (ac);
+       ARDOUR::Bundle::PortList const& other_ports = bb->channel_ports (bc);
+
+       for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
+               for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
+
+                       Port* f = _session.engine().get_port_by_name (*i);
+                       if (!f) {
+                               return;
+                       }
+
+                       if (s) {
+                               if (!offering_input()) {
+                                       _io->connect_input (f, *j, 0);
+                               } else {
+                                       _io->connect_output (f, *j, 0);
+                               }
+                       } else {
+                               if (!offering_input()) {
+                                       _io->disconnect_input (f, *j, 0);
+                               } else {
+                                       _io->disconnect_output (f, *j, 0);
+                               }
+                       }
                }
        }
 }
 
 bool
-IOSelector::get_state (int r, std::string const & p) const
+IOSelector::get_state (
+       boost::shared_ptr<ARDOUR::Bundle> ab,
+       uint32_t ac,
+       boost::shared_ptr<ARDOUR::Bundle> bb,
+       uint32_t bc
+       ) const
 {
-       vector<string> connections;
+       ARDOUR::Bundle::PortList const& our_ports = ab->channel_ports (ac);
+       ARDOUR::Bundle::PortList const& other_ports = bb->channel_ports (bc);
 
-       if (_offer_inputs) {
-               _io->output(r)->get_connections (connections);
-       } else {
-               _io->input(r)->get_connections (connections);
+       for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
+               for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
+
+                       Port* f = _session.engine().get_port_by_name (*i);
+                       if (!f) {
+                               return false;
+                       }
+
+                       if (!f->connected_to (*j)) {
+                               /* if any one thing is not connected, all bets are off */
+                               return false;
+                       }
+               }
        }
 
-       return (std::find (connections.begin (), connections.end (), p) != connections.end ());
+       return true;
 }
 
 uint32_t
 IOSelector::n_rows () const
 {
-       if (!_offer_inputs) {
+       if (!offering_input()) {
                return _io->inputs().num_ports (_io->default_type());
        } else {
                return _io->outputs().num_ports (_io->default_type());
@@ -127,7 +178,7 @@ IOSelector::n_rows () const
 uint32_t
 IOSelector::maximum_rows () const
 {
-       if (!_offer_inputs) {
+       if (!offering_input()) {
                return _io->input_maximum ().get (_io->default_type());
        } else {
                return _io->output_maximum ().get (_io->default_type());
@@ -138,39 +189,22 @@ IOSelector::maximum_rows () const
 uint32_t
 IOSelector::minimum_rows () const
 {
-       if (!_offer_inputs) {
+       if (!offering_input()) {
                return _io->input_minimum ().get (_io->default_type());
        } else {
                return _io->output_minimum ().get (_io->default_type());
        }
 }
 
-std::string
-IOSelector::row_name (int r) const
-{
-       string n;
-       string::size_type pos;
-
-       if (!_offer_inputs) {
-               n = _io->input(r)->name();
-       } else {
-               n = _io->output(r)->name();
-       }
-       
-       if ((pos = n.find ('/')) != string::npos) {
-               return n.substr (pos+1);
-       } else {
-               return n;
-       }
-}
-
 void
-IOSelector::add_row ()
+IOSelector::add_channel (boost::shared_ptr<ARDOUR::Bundle> b)
 {
+       /* we ignore the bundle parameter, as we know what it is that we're adding to */
+       
        // The IO selector only works for single typed IOs
        const ARDOUR::DataType t = _io->default_type ();
 
-       if (!_offer_inputs) {
+       if (!offering_input()) {
 
                try {
                        _io->add_input_port ("", this);
@@ -195,24 +229,20 @@ IOSelector::add_row ()
 }
 
 void
-IOSelector::remove_row (int r)
+IOSelector::remove_channel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c)
 {
-       // The IO selector only works for single typed IOs
-       const ARDOUR::DataType t = _io->default_type ();
+       Port* f = _session.engine().get_port_by_name (b->channel_ports(c)[0]);
+       if (!f) {
+               return;
+       }
        
-       if (!_offer_inputs) {
-               _io->remove_input_port (_io->input (r), this);
+       if (offering_input()) {
+               _io->remove_output_port (f, this);
        } else {
-               _io->remove_output_port (_io->output (r), this);
+               _io->remove_input_port (f, this);
        }
 }
 
-std::string
-IOSelector::row_descriptor () const
-{
-       return _("port");
-}
-
 IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool for_input, bool can_cancel)
        : ArdourDialog ("I/O selector")
        , _selector (session, io, !for_input)
@@ -223,30 +253,34 @@ IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<
        , rescan_button (_("Rescan"))
 
 {
+       /* XXX: what's this for? */
        add_events (Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
+       
        set_name ("IOSelectorWindow2");
 
+       /* Disconnect All button */
        disconnect_button.set_name ("IOSelectorButton");
        disconnect_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DISCONNECT, Gtk::ICON_SIZE_BUTTON)));
+       disconnect_button.signal_clicked().connect (sigc::mem_fun (_selector, &IOSelector::disassociate_all));
        get_action_area()->pack_start (disconnect_button, false, false);
 
+       /* Add Port button */
        if (_selector.maximum_rows() > _selector.n_rows()) {
                add_button.set_name ("IOSelectorButton");
                add_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::ADD, Gtk::ICON_SIZE_BUTTON)));
                get_action_area()->pack_start (add_button, false, false);
-               add_button.signal_clicked().connect (sigc::mem_fun (_selector, &IOSelector::add_row));
+               add_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (_selector, &IOSelector::add_channel), boost::shared_ptr<Bundle> ()));
        } 
 
-       if (!for_input) {
-               io->output_changed.connect (mem_fun(*this, &IOSelectorWindow::ports_changed));
-       } else {
-               io->input_changed.connect (mem_fun(*this, &IOSelectorWindow::ports_changed));
-       }
-
-       rescan_button.set_name ("IOSelectorButton");
+       /* Rescan button */
+       rescan_button.set_name ("IOSelectorButton");
        rescan_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::REFRESH, Gtk::ICON_SIZE_BUTTON)));
+       rescan_button.signal_clicked().connect (sigc::mem_fun (_selector, &IOSelector::setup));
        get_action_area()->pack_start (rescan_button, false, false);
 
+       io->PortCountChanged.connect (sigc::hide (mem_fun (*this, &IOSelectorWindow::ports_changed)));
+
+       /* Cancel button */
        if (can_cancel) {
                cancel_button.set_name ("IOSelectorButton");
                cancel_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CANCEL, Gtk::ICON_SIZE_BUTTON)));
@@ -254,37 +288,32 @@ IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<
        } else {
                cancel_button.hide();
        }
-               
+       cancel_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::cancel));
+
+       /* OK button */
        ok_button.set_name ("IOSelectorButton");
        if (!can_cancel) {
                ok_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CLOSE, Gtk::ICON_SIZE_BUTTON)));
        }
+       ok_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::accept));
        get_action_area()->pack_start (ok_button, false, false);
 
        get_vbox()->set_spacing (8);
-       get_vbox()->pack_start (_selector, true, true);
 
-       suggestion.set_alignment (0.5, 0.5);
-       suggestion_box.pack_start (suggestion, true, true);
-       get_vbox()->pack_start (suggestion_box, false, false);
-
-       ok_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::accept));
-       cancel_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::cancel));
-       rescan_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::rescan));
+       /* XXX: do we still need the ScrolledWindow? */
+       Gtk::ScrolledWindow* sel_scroll = Gtk::manage (new Gtk::ScrolledWindow);
+       sel_scroll->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
+       sel_scroll->add (_selector);
+       get_vbox()->pack_start (*sel_scroll, true, true);
 
        set_position (Gtk::WIN_POS_MOUSE);
 
        io_name_changed (this);
-       ports_changed (IOChange (0), this);
-       leave_scroller ((GdkEventCrossing*) 0);
+       ports_changed ();
 
        show_all ();
 
        signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), this));
-
-       _selector.scrolled_window().add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
-       _selector.scrolled_window().signal_enter_notify_event().connect (mem_fun (*this, &IOSelectorWindow::enter_scroller), false);
-       _selector.scrolled_window().signal_leave_notify_event().connect (mem_fun (*this, &IOSelectorWindow::leave_scroller), false);
 }
 
 IOSelectorWindow::~IOSelectorWindow()
@@ -292,24 +321,8 @@ IOSelectorWindow::~IOSelectorWindow()
        
 }
 
-bool
-IOSelectorWindow::enter_scroller (GdkEventCrossing* ignored)
-{
-       cerr << "IN\n";
-       suggestion.set_text (_("Click to connect. Ctrl-click to disconnect. Shift-click for cross-connect"));
-       return false;
-}
-
-bool
-IOSelectorWindow::leave_scroller (GdkEventCrossing* ignored)
-{
-       cerr << "OUT, ev = " << ignored << "\n";
-       suggestion.set_text (_("Right-click on individual port names for per-port operations"));
-       return false;
-}
-
 void
-IOSelectorWindow::ports_changed (ARDOUR::IOChange change, void *src)
+IOSelectorWindow::ports_changed ()
 {
        if (_selector.maximum_rows() > _selector.n_rows()) {
                add_button.set_sensitive (true);
@@ -318,12 +331,6 @@ IOSelectorWindow::ports_changed (ARDOUR::IOChange change, void *src)
        }
 }
 
-void
-IOSelectorWindow::rescan ()
-{
-       _selector.setup ();
-}
-
 void
 IOSelectorWindow::cancel ()
 {
@@ -365,10 +372,8 @@ PortInsertUI::PortInsertUI (ARDOUR::Session& sess, boost::shared_ptr<ARDOUR::Por
        : input_selector (sess, pi->io(), true),
          output_selector (sess, pi->io(), false)
 {
-       hbox.pack_start (output_selector, true, true);
-       hbox.pack_start (input_selector, true, true);
-
-       pack_start (hbox);
+       pack_start (output_selector, true, true);
+       pack_start (input_selector, true, true);
 }
 
 void
@@ -420,7 +425,6 @@ PortInsertWindow::PortInsertWindow (ARDOUR::Session& sess, boost::shared_ptr<ARD
 
        ok_button.signal_clicked().connect (mem_fun (*this, &PortInsertWindow::accept));
        cancel_button.signal_clicked().connect (mem_fun (*this, &PortInsertWindow::cancel));
-       rescan_button.signal_clicked().connect (mem_fun (*this, &PortInsertWindow::rescan));
 
        signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this))); 
 
@@ -444,12 +448,6 @@ PortInsertWindow::on_map ()
 }
 
 
-void
-PortInsertWindow::rescan ()
-{
-       _portinsertui.redisplay ();
-}
-
 void
 PortInsertWindow::cancel ()
 {
index 57c6e6db86c3238804248af0571385860d527f22..fb12de36bac6ba076009e7f2960c762016361b94 100644 (file)
 #include "ardour_dialog.h"
 #include "port_matrix.h"
 
+namespace ARDOUR {
+       class PortInsert;
+}
+
 class IOSelector : public PortMatrix {
   public:
        IOSelector (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool);
 
-       void set_state (int, std::string const &, bool, uint32_t);
-       bool get_state (int, std::string const &) const;
+       void set_state (
+               boost::shared_ptr<ARDOUR::Bundle>,
+               uint32_t,
+               boost::shared_ptr<ARDOUR::Bundle>,
+               uint32_t,
+               bool,
+               uint32_t
+               );
+       
+       bool get_state (
+               boost::shared_ptr<ARDOUR::Bundle>,
+               uint32_t,
+               boost::shared_ptr<ARDOUR::Bundle>,
+               uint32_t
+               ) const;
+
+       void add_channel (boost::shared_ptr<ARDOUR::Bundle>);
+       void remove_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t);
+       bool can_rename_channels () const {
+               return false;
+       }
+       
        uint32_t n_rows () const;
        uint32_t maximum_rows () const;
        uint32_t minimum_rows () const;
-       std::string row_name (int) const;
-       void add_row ();
-       void remove_row (int);
-       std::string row_descriptor () const;
-       boost::shared_ptr<ARDOUR::IO> const io() { return _io; }
+       boost::shared_ptr<ARDOUR::IO> const io () { return _io; }
+       void setup ();
 
   private:
+       ARDOUR::Session& _session;
        boost::shared_ptr<ARDOUR::IO> _io;
        
-       void ports_changed (ARDOUR::IOChange, void*);
+       void ports_changed ();
 };
 
 class IOSelectorWindow : public ArdourDialog
@@ -66,17 +88,11 @@ class IOSelectorWindow : public ArdourDialog
        Gtk::Button cancel_button;
        Gtk::Button rescan_button;
 
-       Gtk::HBox  suggestion_box;
-       Gtk::Label suggestion;
-
-       void rescan ();
        void cancel ();
        void accept ();
 
-       void ports_changed (ARDOUR::IOChange change, void *src);
+       void ports_changed ();
        void io_name_changed (void *src);
-       bool enter_scroller (GdkEventCrossing*);
-       bool leave_scroller (GdkEventCrossing*);
 };
 
 
@@ -89,7 +105,6 @@ class PortInsertUI : public Gtk::VBox
        void finished (IOSelector::Result);
 
   private:
-       Gtk::HBox hbox;
        IOSelector input_selector;
        IOSelector output_selector;
 };
@@ -111,7 +126,6 @@ class PortInsertWindow : public ArdourDialog
        Gtk::Button rescan_button;
        Gtk::Frame button_frame;
        
-       void rescan ();
        void cancel ();
        void accept ();
 
diff --git a/gtk2_ardour/matrix.cc b/gtk2_ardour/matrix.cc
deleted file mode 100644 (file)
index b670817..0000000
+++ /dev/null
@@ -1,511 +0,0 @@
-#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"
-#include "port_matrix.h"
-
-using namespace std;
-using namespace Gtk;
-using namespace ARDOUR;
-
-Matrix::Matrix (PortMatrix* p) : _port_matrix (p)
-{
-       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;
-
-       border = 10;
-
-       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));
-       }
-
-       if (pg.visible) {
-               reset_size ();
-       }
-}
-
-
-void
-Matrix::clear ()
-{
-       others.clear ();
-       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;
-               }
-       }
-
-       if (pg.visible) {
-               reset_size ();
-       }
-}
-
-void
-Matrix::hide_group (PortGroup& pg)
-{
-       reset_size();
-}
-
-void
-Matrix::show_group (PortGroup& pg)
-{
-       reset_size ();
-}
-
-void
-Matrix::setup_nodes ()
-{
-       for (vector<MatrixNode*>::iterator p = nodes.begin(); p != nodes.end(); ++p) {
-               delete *p;
-       }
-       
-       nodes.clear ();
-
-       nodes.assign (ours.size() * get_visible_others (), 0);
-
-       int n, x, y;
-       list<string>::iterator m;
-       list<OtherPort>::iterator s;
-       
-       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 ()) {
-                               bool const c = _port_matrix->get_state (y, s->name());
-                               nodes[n] = new MatrixNode (*m, *s, c, x, y);
-                               n++;
-                               x++;
-                       }
-               }
-       }
-}
-
-
-void
-Matrix::other_name_size_information (double* rotated_width, double* rotated_height, double* typical_height) const
-{
-       double w = 0;
-       double h = 0;
-
-       GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
-       gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
-       cairo_t* cr = gdk_cairo_create (pm);
-
-       for (list<OtherPort>::const_iterator s = others.begin(); s != others.end(); ++s) {
-               if (s->visible()) {
-                       
-                       cairo_text_extents_t extents;
-                       cairo_text_extents (cr, s->short_name().c_str(), &extents);
-                       
-                       if (extents.width > w) {
-                               w = extents.width;
-                               h = extents.height;
-                       }
-               }
-       }
-
-       cairo_destroy (cr);
-       gdk_pixmap_unref (pm);
-
-       /* transform */
-
-       *rotated_width = fabs (w * cos (angle_radians) + h * sin (angle_radians));
-       *rotated_height = fabs (w * sin (angle_radians) + h * cos (angle_radians));
-       *typical_height = h;
-}
-
-
-std::pair<int, int>
-Matrix::ideal_size () const
-{
-       double rw;
-       double rh;
-       double th;
-
-       other_name_size_information (&rw, &rh, &th);
-
-       double const ideal_xstep = th * 2;
-       double const ideal_ystep = 16;
-
-       uint32_t const visible_others = get_visible_others ();
-
-       return std::make_pair (
-               int (rw + (2 * border) + ideal_xstep * visible_others),
-               int (rh + (2 * border) + ideal_ystep * ours.size ())
-               );
-}
-
-
-void
-Matrix::reset_size ()
-{
-       double rw;
-       double rh;
-       double th;
-                         
-       other_name_size_information (&rw, &rh, &th);
-
-       /* y shift is the largest transformed text height plus a bit for luck */
-       labels_y_shift = int (ceil (rh) + 10);
-       /* x shift is the width of the leftmost label */
-       labels_x_shift = int (ceil (rw));
-
-       uint32_t const visible_others = get_visible_others ();
-
-       if (!visible_others) {
-               xstep = 1;
-               ystep = 1;
-               line_width = 1;
-               line_height = 1;
-               arc_radius = 3;
-               return;
-       }
-
-       if (ours.size () > 1) {
-
-               xstep = (alloc_width - labels_x_shift - (2 * border)) / visible_others;
-               line_width = xstep * (visible_others - 1);
-
-               ystep = (alloc_height - labels_y_shift - (2 * border)) / (ours.size() - 1);
-               line_height = ystep * (ours.size() - 1);
-
-       } else {
-
-               /* we have <= 1 of our ports, so steps don't matter */
-               
-               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);
-
-
-       setup_nodes ();
-
-       // cerr << "Based on ours = " << ours.size() << " others = " << others.size()
-       //      << " dimens = "
-       //      << " xstep " << xstep << endl
-       //      << " ystep " << ystep << endl
-       //      << " line_width " << line_width << endl
-       //      << " line_height " << line_height << endl
-       //      << " border " << border << endl
-       //      << " arc_radius " << arc_radius << endl
-       //      << " labels_x_shift " << labels_x_shift << endl
-       //      << " labels_y_shift " << labels_y_shift << endl;
-}
-
-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)
-{
-       std::pair<int, int> const is = ideal_size ();
-       req->width = is.first;
-       req->height = is.second;
-}
-
-MatrixNode*
-Matrix::get_node (int32_t x, int32_t y)
-{
-       int const half_xstep = xstep / 2;
-       int const 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 * get_visible_others () + x;
-
-       if (x >= int32_t (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) {
-               node->set_connected (!node->connected());
-               _port_matrix->set_state (node->y (), node->their_name (), node->connected (), 0);
-               drawn = false;
-               queue_draw();
-               return true;
-       }
-
-       return false;
-}
-
-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;
-
-       cairo_t* 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);
-       
-       int32_t const top_shift = labels_y_shift + border;
-       int32_t const left_shift = labels_x_shift + border;
-
-       /* 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->short_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_fill (cr);
-                       } else {
-                               cairo_set_source_rgba (cr, 1.0, 0, 0, 0.7);
-                               cairo_stroke (cr);
-                       }
-               }
-       }
-
-       /* motion indicators */
-
-       if (motion_x >= left_shift && motion_y >= top_shift) {
-               
-               int col_left = left_shift + ((motion_x + (xstep / 2) + - left_shift) / xstep) * xstep;
-               int row_top = top_shift + ((motion_y + (ystep / 2) - 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;
-}
-
-uint32_t
-Matrix::get_visible_others () const
-{
-       uint32_t v = 0;
-       
-       for (list<OtherPort>::const_iterator s = others.begin(); s != others.end(); ++s) {
-               if (s->visible()) {
-                       ++v;
-               }
-       }
-
-       return v;
-}
-
-MatrixNode::MatrixNode (std::string a, OtherPort o, bool c, int32_t x, int32_t y)
-       : _name (a), them (o), _connected (c), _x(x), _y(y)
-{
-       
-}
-
-std::string
-OtherPort::name () const
-{
-       return _group.prefix + _short_name;
-}
diff --git a/gtk2_ardour/matrix.h b/gtk2_ardour/matrix.h
deleted file mode 100644 (file)
index a02f2fb..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-#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"
-
-/// One of the other ports that we're connecting ours to
-class OtherPort {
-public:
-    OtherPort (const std::string& n, PortGroup& g)
-           : _short_name (n), _group (g) {}
-
-    std::string name () const;
-    std::string short_name () const { return _short_name; }
-    PortGroup& group() const { return _group; }
-    bool visible() const { return _group.visible; }
-
-public:
-    std::string _short_name;
-    PortGroup& _group;
-};
-
-/// A node on the matrix
-class MatrixNode {
-  public:
-    MatrixNode (std::string, OtherPort, bool, int32_t, int32_t);
-    ~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 (PortMatrix*);
-
-    void set_ports (const std::list<std::string>&);
-    void add_group (PortGroup&);
-    void remove_group (PortGroup&);
-    void hide_group (PortGroup&);
-    void show_group (PortGroup&);
-    void clear ();
-
-    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:
-    PortMatrix* _port_matrix; ///< the PortMatrix that we're working for
-    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 ();
-    uint32_t get_visible_others () const;
-    void other_name_size_information (double *, double *, double *) const;
-    std::pair<int, int> ideal_size () const;
-
-    GdkPixmap* pixmap;
-};
-
-#endif /* __gtk_ardour_matrix_h__ */
index 12f82ccbfdc7481b39c56db49bb0533b09c80991..935197a0ca98572fa38dff2bbe985e7620c8e500 100644 (file)
@@ -1120,11 +1120,11 @@ OptionEditor::setup_click_editor ()
        click_path_entry.set_sensitive (true);
        click_emphasis_path_entry.set_sensitive (true);
 
-       click_io_selector = new IOSelector (*session, session->click_io(), false);
+       click_io_selector = new IOSelector (*session, session->click_io(), true);
        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_io_selector, true, true);
        click_hpacker.pack_start (*click_gpm, false, false);
 
        click_packer.show_all ();
@@ -1163,11 +1163,11 @@ OptionEditor::setup_auditioner_editor ()
 void
 OptionEditor::connect_audition_editor ()
 {
-       auditioner_io_selector = new IOSelector (*session, session->the_auditioner(), false);
+       auditioner_io_selector = new IOSelector (*session, session->the_auditioner(), true);
        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_io_selector, true, true);
        audition_hpacker.pack_start (*auditioner_gpm, false, false);
 
        auditioner_io_selector->show_all ();
index 3de45eee73da44a36d1b419f585cb8b471dbaca3..4157348d8eb2689c06df5cac03ed9513114500da 100644 (file)
 */
 
 #include "port_group.h"
+#include "port_matrix.h"
 #include "i18n.h"
 #include "ardour/session.h"
 #include "ardour/audio_track.h"
 #include "ardour/midi_track.h"
 #include "ardour/audioengine.h"
+#include "ardour/bundle.h"
 #include <boost/shared_ptr.hpp>
 #include <cstring>
 
 using namespace std;
 using namespace Gtk;
 
+/** Add a bundle to a group.
+ *  @param b Bundle.
+ */
+void
+PortGroup::add_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
+{
+       bundles.push_back (b);
+}
+
 /** Add a port to a group.
- *  @param p Port name, with or without prefix.
+ *  @param p Port.
  */
 void
-PortGroup::add (std::string const & p)
+PortGroup::add_port (std::string const &p)
 {
-       if (prefix.empty() == false && p.substr (0, prefix.length()) == prefix) {
-               ports.push_back (p.substr (prefix.length()));
-       } else {
-               ports.push_back (p);
-       }
+       ports.push_back (p);
+}
+
+void
+PortGroup::clear ()
+{
+       bundles.clear ();
+       ports.clear ();
 }
 
 /** PortGroupUI constructor.
@@ -47,14 +61,14 @@ PortGroup::add (std::string const & p)
  *  @Param g PortGroup to represent.
  */
 
-PortGroupUI::PortGroupUI (PortMatrix& m, PortGroup& g)
+PortGroupUI::PortGroupUI (PortMatrix* m, PortGroup* g)
        : _port_matrix (m)
        , _port_group (g)
-       , _ignore_check_button_toggle (false)
-       , _visibility_checkbutton (g.name)
+       , _visibility_checkbutton (g->name)
 {
-       _port_group.visible = true;
-       _ignore_check_button_toggle = false;
+       _port_group->visible = true;
+       setup_visibility_checkbutton ();
+       
        _visibility_checkbutton.signal_toggled().connect (sigc::mem_fun (*this, &PortGroupUI::visibility_checkbutton_toggled));
 }
 
@@ -62,66 +76,49 @@ PortGroupUI::PortGroupUI (PortMatrix& m, PortGroup& g)
 void
 PortGroupUI::visibility_checkbutton_toggled ()
 {
-       _port_group.visible = _visibility_checkbutton.get_active ();
+       _port_group->visible = _visibility_checkbutton.get_active ();
+       setup_visibility_checkbutton ();
+       _port_matrix->setup ();
 }
 
-/** @return Checkbutton used to toggle visibility */
-Widget&
-PortGroupUI::get_visibility_checkbutton ()
-{
-       return _visibility_checkbutton;
-}
-
-
-/** Handle a toggle of a port check button */
+/** Set up the visibility checkbutton according to PortGroup::visible */
 void
-PortGroupUI::port_checkbutton_toggled (CheckButton* b, int r, int c)
+PortGroupUI::setup_visibility_checkbutton ()
 {
-       if (_ignore_check_button_toggle == false) {
-               // _port_matrix.hide_group (_port_group);
-       }
-}
-
-/** Set up visibility of the port group according to PortGroup::visible */
-void
-PortGroupUI::setup_visibility ()
-{
-       if (_visibility_checkbutton.get_active () != _port_group.visible) {
-               _visibility_checkbutton.set_active (_port_group.visible);
+       if (_visibility_checkbutton.get_active () != _port_group->visible) {
+               _visibility_checkbutton.set_active (_port_group->visible);
        }
 }
 
 /** PortGroupList constructor.
- *  @param session Session to get ports from.
- *  @param type Type of ports to offer (audio or MIDI)
- *  @param offer_inputs true to offer output ports, otherwise false.
+ *  @param session Session to get bundles from.
+ *  @param type Type of bundles to offer (audio or MIDI)
+ *  @param offer_inputs true to offer output bundles, otherwise false.
  *  @param mask Mask of groups to make visible by default.
  */
 
 PortGroupList::PortGroupList (ARDOUR::Session & session, ARDOUR::DataType type, bool offer_inputs, Mask mask)
        : _session (session), _type (type), _offer_inputs (offer_inputs),
-         _buss (_("Bus"), "ardour:", mask & BUSS),
-         _track (_("Track"), "ardour:", mask & TRACK),
-         _system (_("System"), "system:", mask & SYSTEM),
-         _other (_("Other"), "", mask & OTHER)
+         _buss (_("Bus"), mask & BUSS),
+         _track (_("Track"), mask & TRACK),
+         _system (_("System"), mask & SYSTEM),
+         _other (_("Other"), mask & OTHER)
 {
        refresh ();
 }
 
-/** Find or re-find all our ports and set up our lists */
+/** Find or re-find all our bundles and set up our lists */
 void
 PortGroupList::refresh ()
 {
        clear ();
-       
-       _buss.ports.clear ();
-       _track.ports.clear ();
-       _system.ports.clear ();
-       _other.ports.clear ();
 
-       /* Find the ports provided by ardour; we can't derive their type just from their
-          names, so we'll have to be more devious. 
-       */
+       _buss.clear ();
+       _track.clear ();
+       _system.clear ();
+       _other.clear ();
+
+       /* Find the bundles for routes */
 
        boost::shared_ptr<ARDOUR::Session::RouteList> routes = _session.get_routes ();
 
@@ -148,14 +145,12 @@ PortGroupList::refresh ()
                } 
                        
                if (g) {
-                       ARDOUR::PortSet const & p = _offer_inputs ? ((*i)->inputs()) : ((*i)->outputs());
-                       for (uint32_t j = 0; j < p.num_ports(); ++j) {
-                               g->add (p.port(j)->name ());
-                       }
-
-                       std::sort (g->ports.begin(), g->ports.end());
+                       g->add_bundle (_offer_inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs ());
                }
        }
+
+       /* Bundles created by the session */
+       _session.foreach_bundle (sigc::mem_fun (*this, &PortGroupList::maybe_add_session_bundle));
        
        /* XXX: inserts, sends, plugin inserts? */
        
@@ -163,9 +158,9 @@ PortGroupList::refresh ()
           finding all the ports that we can connect to. 
        */
 
-       const char **ports = _session.engine().get_ports ("", _type.to_jack_type(), _offer_inputs ? 
-                                                         JackPortIsInput : JackPortIsOutput);
-       if (ports) {
+       const char **ports = _session.engine().get_ports ("", _type.to_jack_type(), _offer_inputs ? 
+                                                         JackPortIsInput : JackPortIsOutput);
+       if (ports) {
 
                int n = 0;
                string client_matching_string;
@@ -178,11 +173,11 @@ PortGroupList::refresh ()
 
                        if (p.substr(0, strlen ("system:")) == "system:") {
                                /* system: prefix */
-                               _system.add (p);
+                               _system.add_port (p);
                        } else {
                                if (p.substr(0, client_matching_string.length()) != client_matching_string) {
                                        /* other (non-ardour) prefix */
-                                       _other.add (p);
+                                       _other.add_port (p);
                                }
                        }
 
@@ -198,41 +193,6 @@ PortGroupList::refresh ()
        push_back (&_other);
 }
 
-int
-PortGroupList::n_visible_ports () const
-{
-       int n = 0;
-       
-       for (const_iterator i = begin(); i != end(); ++i) {
-               if ((*i)->visible) {
-                       n += (*i)->ports.size();
-               }
-       }
-
-       return n;
-}
-
-std::string
-PortGroupList::get_port_by_index (int n, bool with_prefix) const
-{
-       /* XXX: slightly inefficient algorithm */
-
-       for (const_iterator i = begin(); i != end(); ++i) {
-               for (std::vector<std::string>::const_iterator j = (*i)->ports.begin(); j != (*i)->ports.end(); ++j) {
-                       if (n == 0) {
-                               if (with_prefix) {
-                                       return (*i)->prefix + *j;
-                               } else {
-                                       return *j;
-                               }
-                       }
-                       --n;
-               }
-       }
-
-       return "";
-}
-
 void
 PortGroupList::set_type (ARDOUR::DataType t)
 {
@@ -245,3 +205,10 @@ PortGroupList::set_offer_inputs (bool i)
        _offer_inputs = i;
 }
 
+void
+PortGroupList::maybe_add_session_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
+{
+       if (b->ports_are_inputs () == _offer_inputs) {
+               _system.bundles.push_back (b);
+       }
+}
index 9a38bfc39a6677587f0684b0e0483b77ab149935..0641d231ef7b43c64a21b7207d690b40285e3a1e 100644 (file)
 
 #include <vector>
 #include <string>
-
 #include <gtkmm/widget.h>
 #include <gtkmm/checkbutton.h>
-
+#include <boost/shared_ptr.hpp>
 #include <ardour/data_type.h>
 
 namespace ARDOUR {
        class Session;
-       class IO;
-       class PortInsert;
+       class Bundle;
 }
 
 class PortMatrix;
 
-/// A list of port names, grouped by some aspect of their type e.g. busses, tracks, system
+/** A list of bundles and ports, grouped by some aspect of their
+ *  type e.g. busses, tracks, system.  Each group has 0 or more bundles
+ *  and 0 or more ports, where the ports are not in the bundles.
+ */
 class PortGroup
 {
   public:
        /** PortGroup constructor.
         * @param n Name.
-        * @param p Port name prefix (including trailing :)
         * @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) {}
+       PortGroup (std::string const & n, bool v)
+               : name (n), visible (v) {}
 
-       void add (std::string const & p);
+       void add_bundle (boost::shared_ptr<ARDOUR::Bundle>);
+       void add_port (std::string const &);
+       void clear ();
 
        std::string name; ///< name for the group
-       std::string prefix; ///< prefix e.g. "ardour:"
-       std::vector<std::string> ports; ///< port names
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > bundles;
+       std::vector<std::string> ports;
        bool visible; ///< true if the group is visible in the UI
 };
 
@@ -60,20 +62,18 @@ class PortGroup
 class PortGroupUI
 {
   public:
-       PortGroupUI (PortMatrix&, PortGroup&);
+       PortGroupUI (PortMatrix*, PortGroup*);
 
-       Gtk::Widget& get_visibility_checkbutton ();
-       PortGroup& port_group () { return _port_group; }
-       void setup_visibility ();
+       Gtk::Widget& visibility_checkbutton () {
+               return _visibility_checkbutton;
+       }
 
   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 ();
+       void setup_visibility_checkbutton ();
 
-       PortMatrix& _port_matrix; ///< the PortMatrix that we are working for
-       PortGroup& _port_group; ///< the PortGroup that we are representing
-       bool _ignore_check_button_toggle;
+       PortMatrix* _port_matrix; ///< the PortMatrix that we are working for
+       PortGroup* _port_group; ///< the PortGroup that we are representing
        Gtk::CheckButton _visibility_checkbutton;
 };
 
@@ -91,12 +91,12 @@ class PortGroupList : public std::list<PortGroup*>
        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:
+       void maybe_add_session_bundle (boost::shared_ptr<ARDOUR::Bundle>);
+       
        ARDOUR::Session& _session;
        ARDOUR::DataType _type;
        bool _offer_inputs;
index e04dd3b252db2d7343822c21a573a18c0f1b9b5e..1e9227a5251c729f4d33273f9b05607672e7d07c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2002-2007 Paul Davis 
+    Copyright (C) 2002-2009 Paul Davis 
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
 */
 
+#include <iostream>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/adjustment.h>
 #include <gtkmm/label.h>
-#include <gtkmm/enums.h>
-#include <gtkmm/menu.h>
-#include <gtkmm/menu_elems.h>
-#include <gtkmm/menuitem.h>
-#include <gtkmm/menushell.h>
-#include <glibmm/objectbase.h>
-#include <gtkmm2ext/doi.h>
-#include "ardour/data_type.h"
-#include "i18n.h"
+#include "ardour/bundle.h"
 #include "port_matrix.h"
+#include "i18n.h"
 
-using namespace Gtk;
-
+/** PortMatrix constructor.
+ *  @param session Our session.
+ *  @param type Port type that we are handling.
+ *  @param offer_inputs true to offer inputs, otherwise false.
+ *  @param mask Mask of port groups to offer.
+ */
 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), matrix (this)
+       : _offer_inputs (offer_inputs),
+         _port_group_list (session, type, offer_inputs, mask),
+         _type (type),
+         _body (this)
 {
-       _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);
+       /* checkbuttons for visibility of groups */
+       Gtk::HBox* visibility_buttons = Gtk::manage (new Gtk::HBox);
 
-       _scrolled_window.add (matrix);
+       visibility_buttons->pack_start (*Gtk::manage (new Gtk::Label (_("Show:"))), Gtk::PACK_SHRINK);
+       
+       for (std::list<PortGroup*>::iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
+               _port_group_uis.push_back (new PortGroupUI (this, *i));
+       }
 
-       if (offer_inputs) {
-               _overall_hbox.pack_start (_side_vbox, false, false, 6);
-               _overall_hbox.pack_start (_scrolled_window, true, true);
-       } else {
-               _overall_hbox.pack_start (_scrolled_window, true, true, 6);
-               _overall_hbox.pack_start (_side_vbox, false, false);
+       for (std::list<PortGroupUI*>::iterator i = _port_group_uis.begin(); i != _port_group_uis.end(); ++i) {
+               visibility_buttons->pack_start ((*i)->visibility_checkbutton(), Gtk::PACK_SHRINK);
        }
 
-       pack_start (_overall_hbox);
-}
+       pack_start (*visibility_buttons, Gtk::PACK_SHRINK);
+       pack_start (_hscroll, Gtk::PACK_SHRINK);
+       Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox);
+       hbox->pack_start (_body);
+       hbox->pack_start (_vscroll, Gtk::PACK_SHRINK);
+       pack_start (*hbox);
 
-PortMatrix::~PortMatrix ()
-{
-       clear ();
-}
+       _hscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::hscroll_changed));
+       _vscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::vscroll_changed));
+       setup_scrollbars ();
 
-void 
-PortMatrix::set_ports (const std::list<std::string>& ports)
-{
-       matrix.set_ports (ports);
+       /* XXX hard-coded initial size suggestion */
+       set_size_request (400, 200);
+       show_all ();
 }
 
-/** Clear out the things that change when the number of source or destination ports changes */
-void
-PortMatrix::clear ()
+PortMatrix::~PortMatrix ()
 {
-       /* remove lurking, invisible label and padding */
-       
-       _side_vbox.children().clear ();
-
-       delete _side_vbox_pad;
-       _side_vbox_pad = 0;
-
-       for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
-               _visibility_checkbutton_box.remove ((*i)->get_visibility_checkbutton());
+       for (std::list<PortGroupUI*>::iterator i = _port_group_uis.begin(); i != _port_group_uis.end(); ++i) {
                delete *i;
        }
-
-       _port_group_ui.clear ();
 }
 
-/** Set up the dialogue */
 void
 PortMatrix::setup ()
 {
-       /* sort out the ports that we'll offer to connect to */
        _port_group_list.refresh ();
-       
-       clear ();
 
-       _side_vbox_pad = new Label (""); /* unmanaged, explicitly deleted */
-
-       _side_vbox.pack_start (*_side_vbox_pad, false, false);
-       _side_vbox.pack_start (*manage (new Label ("")));
-
-       matrix.clear ();
-
-       /* Matrix and visibility checkbuttons */
-       for (PortGroupList::iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
-
-               PortGroupUI* t = new PortGroupUI (*this, **i);
-               
-               _port_group_ui.push_back (t);
-
-               matrix.add_group (**i);
-
-               _visibility_checkbutton_box.pack_start (t->get_visibility_checkbutton(), false, false);
-
-               CheckButton* chk = dynamic_cast<CheckButton*>(&t->get_visibility_checkbutton());
-
-               if (chk) { 
-                       chk->signal_toggled().connect (sigc::mem_fun (*this, &PortMatrix::reset_visibility));
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > column;
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > row;
+
+       for (PortGroupList::iterator i = _port_group_list.begin (); i != _port_group_list.end (); ++i) {
+               if ((*i)->visible) {
+                       
+                       std::copy ((*i)->bundles.begin(), (*i)->bundles.end(), std::back_inserter (column));
+                       
+                       /* make a bundle for the ports, if there are any */
+                       if (!(*i)->ports.empty()) {
+
+                               boost::shared_ptr<ARDOUR::Bundle> b (new ARDOUR::Bundle ("", _type, !_offer_inputs));
+                               
+                               std::string const pre = common_prefix ((*i)->ports);
+                               if (!pre.empty()) {
+                                       b->set_name (pre.substr (0, pre.length() - 1));
+                               }
+
+                               for (uint32_t j = 0; j < (*i)->ports.size(); ++j) {
+                                       std::string const p = (*i)->ports[j];
+                                       b->add_channel (p.substr (pre.length()));
+                                       b->set_port (j, p);
+                               }
+                                       
+                               column.push_back (b);
+                       }
                }
        }
 
-       show_all ();
+       row.push_back (_our_bundle);
 
-       reset_visibility ();
+       _body.setup (row, column);
+       setup_scrollbars ();
+       queue_draw ();
 }
 
 void
-PortMatrix::reset_visibility ()
+PortMatrix::set_offer_inputs (bool s)
 {
-       for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
+       _offer_inputs = s;
+       _port_group_list.set_offer_inputs (s);
+       setup ();
+}
 
-               (*i)->setup_visibility ();
-               
-               if ((*i)->port_group().visible) {
-                       matrix.show_group ((*i)->port_group());
-               } else {
-                       matrix.hide_group ((*i)->port_group());
-               }
-       }
+void
+PortMatrix::set_type (ARDOUR::DataType t)
+{
+       _type = t;
+       _port_group_list.set_type (t);
+       setup ();
 }
 
+void
+PortMatrix::hscroll_changed ()
+{
+       _body.set_xoffset (_hscroll.get_adjustment()->get_value());
+}
 
-/** Handle a button press on a row label */
-bool
-PortMatrix::row_label_button_pressed (GdkEventButton* e, int r)
+void
+PortMatrix::vscroll_changed ()
 {
-       if (e->type != GDK_BUTTON_PRESS || e->button != 3) {
-               return false;
-       }
+       _body.set_yoffset (_vscroll.get_adjustment()->get_value());
+}
 
-       Menu* menu = manage (new Menu);
-       Menu_Helpers::MenuList& items = menu->items ();
-       menu->set_name ("ArdourContextMenu");
+void
+PortMatrix::setup_scrollbars ()
+{
+       Gtk::Adjustment* a = _hscroll.get_adjustment ();
+       a->set_lower (0);
+       a->set_upper (_body.full_scroll_width());
+       a->set_page_size (_body.alloc_scroll_width());
+       a->set_step_increment (32);
+       a->set_page_increment (128);
+
+       a = _vscroll.get_adjustment ();
+       a->set_lower (0);
+       a->set_upper (_body.full_scroll_height());
+       a->set_page_size (_body.alloc_scroll_height());
+       a->set_step_increment (32);
+       a->set_page_increment (128);
+}
 
-       bool const can_add = maximum_rows () > n_rows ();
-       bool const can_remove = minimum_rows () < n_rows ();
-       std::string const name = row_name (r);
+std::string
+PortMatrix::common_prefix (std::vector<std::string> const & p) const
+{
+       /* common prefix before '/' ? */
+       if (p[0].find_first_of ("/") != std::string::npos) {
+               std::string const fp = p[0].substr (0, (p[0].find_first_of ("/") + 1));
+               uint32_t j = 1;
+               while (j < p.size()) {
+                       if (p[j].substr (0, fp.length()) != fp) {
+                               break;
+                       }
+                       ++j;
+               }
+               
+               if (j == p.size()) {
+                       return fp;
+               }
+       }
        
-       items.push_back (
-               Menu_Helpers::MenuElem (string_compose(_("Add %1"), row_descriptor()), sigc::mem_fun (*this, &PortMatrix::add_row))
-               );
-
-       items.back().set_sensitive (can_add);
-
-       items.push_back (
-               Menu_Helpers::MenuElem (string_compose(_("Remove %1 \"%2\""), row_descriptor(), name), sigc::bind (sigc::mem_fun (*this, &PortMatrix::remove_row), r))
-               );
-
-       items.back().set_sensitive (can_remove);
+       /* or before ':' ? */
+       if (p[0].find_first_of (":") != std::string::npos) {
+               std::string const fp = p[0].substr (0, (p[0].find_first_of (":") + 1));
+               uint32_t j = 1;
+               while (j < p.size()) {
+                       if (p[j].substr (0, fp.length()) != fp) {
+                               break;
+                       }
+                       ++j;
+               }
+               
+               if (j == p.size()) {
+                       return fp;
+               }
+       }
 
-       menu->popup (e->button, e->time);
-       
-       return true;
+       return "";
 }
 
 void
-PortMatrix::set_type (ARDOUR::DataType t)
+PortMatrix::disassociate_all ()
 {
-       _type = t;
-       _port_group_list.set_type (t);
-       setup ();
-}
+       for (PortGroupList::iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
+               
+               for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator j = (*i)->bundles.begin(); j != (*i)->bundles.end(); ++j) {
 
-void
-PortMatrix::set_offer_inputs (bool i)
-{
-       _offer_inputs = i;
-       _port_group_list.set_offer_inputs (i);
-       setup ();
-}
+                       for (uint32_t k = 0; k < (*j)->nchannels(); ++k) {
+
+                               for (uint32_t l = 0; l < _our_bundle->nchannels(); ++l) {
 
+                                       set_state (
+                                               _our_bundle, l, *j, k, false, 0
+                                               );
+                               }
+                       }
+               }
+       }
+
+       _body.repaint_grid ();
+}
index 27f295b89dad6e6a0964d0e3827a1b8f6a61cbce..37c05553f1c2c3ba0836a6642475f5f2408d20b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2002-2007 Paul Davis 
+    Copyright (C) 2002-2009 Paul Davis 
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
 */
 
-#ifndef __ardour_ui_port_matrix_h__
-#define __ardour_ui_port_matrix_h__
+#ifndef __gtk_ardour_port_matrix_h__
+#define __gtk_ardour_port_matrix_h__
 
+#include <list>
 #include <gtkmm/box.h>
-#include <gtkmm/checkbutton.h>
-#include <gtkmm/table.h>
-#include <gtkmm/frame.h>
-#include <gtkmm/eventbox.h>
-#include <gtkmm/scrolledwindow.h>
-
-#include "ardour_dialog.h"
+#include <gtkmm/scrollbar.h>
+#include <boost/shared_ptr.hpp>
+#include "port_matrix_body.h"
 #include "port_group.h"
-#include "matrix.h"
+
+/** The `port matrix' UI.  This is a widget which lets the user alter
+ *  associations between one set of ports and another.  e.g. to connect
+ *  things together.
+ *
+ *  The columns are labelled with various ports from around Ardour and the
+ *  system.
+ *
+ *  It is made up of a body, PortMatrixBody, which is rendered using cairo,
+ *  and some scrollbars.  All of this is arranged inside the VBox that we
+ *  inherit from.
+ */
 
 namespace ARDOUR {
-       class Session;
-       class IO;
-       class PortInsert;
+       class Bundle;
 }
 
-class PortMatrix : public Gtk::VBox {
-  public:
+class PortMatrix : public Gtk::VBox
+{
+public:
        PortMatrix (ARDOUR::Session&, ARDOUR::DataType, bool, PortGroupList::Mask);
        ~PortMatrix ();
 
-       void setup ();
+       virtual void setup ();
+       void set_offer_inputs (bool);
+       void set_type (ARDOUR::DataType);
+       bool offering_input () const { return _offer_inputs; }
+       void disassociate_all ();
 
        enum Result {
                Cancelled,
@@ -51,55 +62,63 @@ class PortMatrix : public Gtk::VBox {
 
        sigc::signal<void, Result> Finished;
 
-       void set_type (ARDOUR::DataType);
-       void set_offer_inputs (bool);
-       bool offering_input() const { return _offer_inputs; }
-
-       /** @param r Our row index.
-        *  @param p Other port.
+       /** @param ab Our bundle.
+        *  @param ac Channel on our bundle.
+        *  @param bb Other bundle.
+        *  @arapm bc Channel on other bundle.
         *  @param s New state.
         *  @param k XXX
         */
-       virtual void set_state (int r, std::string const & p, bool s, uint32_t k) = 0;
-
-       /** @param r Our row index.
-        *  @param p Other port.
+       virtual void set_state (
+               boost::shared_ptr<ARDOUR::Bundle> ab,
+               uint32_t ac,
+               boost::shared_ptr<ARDOUR::Bundle> bb,
+               uint32_t bc,
+               bool s,
+               uint32_t k
+               ) = 0;
+
+       /** @param ab Our bundle.
+        *  @param ac Channel on our bundle.
+        *  @param bb Other bundle.
+        *  @arapm bc Channel on other bundle.
         *  @return true if r is connected to p, otherwise false.
         */
-       virtual bool get_state (int r, std::string const &p) const = 0;
+       virtual bool get_state (
+               boost::shared_ptr<ARDOUR::Bundle> ab,
+               uint32_t ac,
+               boost::shared_ptr<ARDOUR::Bundle> bb,
+               uint32_t bc
+               ) const = 0;
+
+       virtual void add_channel (boost::shared_ptr<ARDOUR::Bundle>) = 0;
+       virtual void remove_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t) = 0;
+       virtual bool can_rename_channels () const = 0;
+       virtual void rename_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t) {}
        
-       virtual uint32_t n_rows () const = 0;
-       virtual uint32_t maximum_rows () const = 0;
-       virtual uint32_t minimum_rows () const = 0;
-       virtual std::string row_name (int) const = 0;
-       virtual void add_row () = 0;
-       virtual void remove_row (int) = 0;
-       virtual std::string row_descriptor () const = 0;
-
-       Gtk::Widget& scrolled_window() { return _scrolled_window; }
+       void setup_scrollbars ();
 
-  protected:
+protected:
+       /// our bundle
+       boost::shared_ptr<ARDOUR::Bundle> _our_bundle;
+       
+private:
 
+       void hscroll_changed ();
+       void vscroll_changed ();
+       std::string common_prefix (std::vector<std::string> const &) const;
+       
+       /// true to offer inputs, otherwise false
        bool _offer_inputs;
-       void set_ports (const std::list<std::string>&);
-
-  private:
+       /// list of port groups
        PortGroupList _port_group_list;
+       /// port type that we are working with
        ARDOUR::DataType _type;
-       Matrix matrix;
-       std::vector<PortGroupUI*> _port_group_ui;
-       std::vector<Gtk::EventBox*> _row_labels;
-       Gtk::VBox* _row_labels_vbox;
-       Gtk::HBox _overall_hbox;
-       Gtk::VBox _side_vbox;
-       Gtk::HBox _port_group_hbox;
-       Gtk::ScrolledWindow _scrolled_window;
-       Gtk::Label* _side_vbox_pad;
-       Gtk::HBox _visibility_checkbutton_box;
-
-       void clear ();
-       bool row_label_button_pressed (GdkEventButton*, int);
-       void reset_visibility ();
+
+       PortMatrixBody _body;
+       Gtk::HScrollbar _hscroll;
+       Gtk::VScrollbar _vscroll;
+       std::list<PortGroupUI*> _port_group_uis;
 };
 
 #endif
diff --git a/gtk2_ardour/port_matrix_body.cc b/gtk2_ardour/port_matrix_body.cc
new file mode 100644 (file)
index 0000000..d30dca5
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include "ardour/bundle.h"
+#include "port_matrix_body.h"
+#include "port_matrix.h"
+
+PortMatrixBody::PortMatrixBody (PortMatrix* p)
+       : _port_matrix (p),
+         _column_labels (this),
+         _row_labels (p, this),
+         _grid (p, this),
+         _alloc_width (0),
+         _alloc_height (0),
+         _alloc_xdiv (0),
+         _alloc_ydiv (0),
+         _xoffset (0),
+         _yoffset (0)
+{
+
+}
+
+
+bool
+PortMatrixBody::on_expose_event (GdkEventExpose* event)
+{
+       Gdk::Rectangle const exposure (
+               event->area.x, event->area.y, event->area.width, event->area.height
+               );
+
+       Gdk::Rectangle const col (0, 0, _alloc_width, _alloc_ydiv);
+       Gdk::Rectangle const row (_alloc_xdiv, _alloc_ydiv, _alloc_width - _alloc_xdiv, _alloc_height - _alloc_ydiv);
+       Gdk::Rectangle const grid (0, _alloc_ydiv, _alloc_xdiv, _alloc_height - _alloc_ydiv);
+
+       bool intersects;
+       Gdk::Rectangle r = exposure;
+       r.intersect (col, intersects);
+
+       if (intersects) {
+               gdk_draw_drawable (
+                       get_window()->gobj(),
+                       get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
+                       _column_labels.get_pixmap (get_window()->gobj()),
+                       r.get_x() + _xoffset,
+                       r.get_y(),
+                       r.get_x(),
+                       r.get_y(),
+                       r.get_width(),
+                       r.get_height()
+                       );
+       }
+
+       r = exposure;
+       r.intersect (row, intersects);
+
+       if (intersects) {
+               gdk_draw_drawable (
+                       get_window()->gobj(),
+                       get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
+                       _row_labels.get_pixmap (get_window()->gobj()),
+                       r.get_x() - _alloc_xdiv,
+                       r.get_y() + _yoffset - _alloc_ydiv,
+                       r.get_x(),
+                       r.get_y(),
+                       r.get_width(),
+                       r.get_height()
+                       );
+       }
+
+       r = exposure;
+       r.intersect (grid, intersects);
+
+       if (intersects) {
+               gdk_draw_drawable (
+                       get_window()->gobj(),
+                       get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
+                       _grid.get_pixmap (get_window()->gobj()),
+                       r.get_x() + _xoffset,
+                       r.get_y() + _yoffset - _alloc_ydiv,
+                       r.get_x(),
+                       r.get_y(),
+                       r.get_width(),
+                       r.get_height()
+                       );
+       }
+
+       return true;
+}
+
+void
+PortMatrixBody::on_size_request (Gtk::Requisition *req)
+{
+       std::pair<int, int> const col = _column_labels.dimensions ();
+       std::pair<int, int> const row = _row_labels.dimensions ();
+       std::pair<int, int> const grid = _grid.dimensions ();
+
+       req->width = std::max (col.first, grid.first + row.first);
+       req->height = col.second + grid.second;
+}
+
+void
+PortMatrixBody::on_size_allocate (Gtk::Allocation& alloc)
+{
+       Gtk::EventBox::on_size_allocate (alloc);
+       set_allocation (alloc);
+
+       _alloc_width = alloc.get_width ();
+       _alloc_height = alloc.get_height ();
+
+       compute_divs ();
+       _port_matrix->setup_scrollbars ();
+}
+
+void
+PortMatrixBody::compute_divs ()
+{
+       std::pair<uint32_t, uint32_t> const col = _column_labels.dimensions ();
+       if (_alloc_height > col.second) {
+               /* allocated height is enough for the column labels */
+               _alloc_ydiv = col.second;
+       } else {
+               /* not enough space for the column labels */
+               _alloc_ydiv = _alloc_height;
+       }
+
+       std::pair<uint32_t, uint32_t> const grid = _grid.dimensions ();
+       std::pair<uint32_t, uint32_t> const row = _row_labels.dimensions ();
+
+       if (_alloc_width > (grid.first + row.first)) {
+               /* allocated width is larger than we need, so
+                  put the x division at the extent of the grid */
+               _alloc_xdiv = grid.first;
+       } else if (_alloc_width > row.first) {
+               /* allocated width is large enough for the row labels
+                  but not for the whole grid, so display the whole
+                  row label section and cut part of the grid off */
+               _alloc_xdiv = _alloc_width - row.first;
+       } else {
+               /* allocated width isn't even enough for the row labels */
+               _alloc_xdiv = 0;
+       }
+}
+
+void
+PortMatrixBody::setup (
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & row,
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & column
+       )
+{
+       for (std::list<sigc::connection>::iterator i = _bundle_connections.begin(); i != _bundle_connections.end(); ++i) {
+               i->disconnect ();
+       }
+
+       _bundle_connections.clear ();
+       
+       _row_bundles = row;
+       _column_bundles = column;
+
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator i = _row_bundles.begin(); i != _row_bundles.end(); ++i) {
+               
+               _bundle_connections.push_back (
+                       (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::repaint_row_labels))
+                       );
+               
+       }
+
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator i = _column_bundles.begin(); i != _column_bundles.end(); ++i) {
+               _bundle_connections.push_back (
+                       (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::repaint_column_labels))
+                       );
+       }
+       
+       _column_labels.setup ();
+       _row_labels.setup ();
+       _grid.setup ();
+
+       compute_divs ();
+}
+
+uint32_t
+PortMatrixBody::full_scroll_width ()
+{
+       return _grid.dimensions().first;
+
+}
+
+uint32_t
+PortMatrixBody::alloc_scroll_width ()
+{
+       return _alloc_xdiv;
+}
+
+uint32_t
+PortMatrixBody::full_scroll_height ()
+{
+       return _grid.dimensions().second;
+}
+
+uint32_t
+PortMatrixBody::alloc_scroll_height ()
+{
+       return _alloc_height - _alloc_ydiv;
+}
+
+void
+PortMatrixBody::set_xoffset (uint32_t xo)
+{
+       _xoffset = xo;
+       queue_draw ();
+}
+
+void
+PortMatrixBody::set_yoffset (uint32_t yo)
+{
+       _yoffset = yo;
+       queue_draw ();
+}
+
+bool
+PortMatrixBody::on_button_press_event (GdkEventButton* ev)
+{
+       if (ev->x < _alloc_xdiv && ev->y > _alloc_ydiv) {
+               _grid.button_press (ev->x + _xoffset, ev->y + _yoffset - _alloc_ydiv, ev->button);
+       } else if (ev->x > _alloc_xdiv && ev->y > _alloc_ydiv) {
+               _row_labels.button_press (ev->x - _alloc_xdiv, ev->y + _yoffset - _alloc_ydiv, ev->button, ev->time);
+       } else {
+               return false;
+       }
+
+       return true;
+}
+
+void
+PortMatrixBody::repaint_grid ()
+{
+       _grid.require_render ();
+       queue_draw ();
+}
+
+void
+PortMatrixBody::repaint_column_labels ()
+{
+       _column_labels.require_render ();
+       queue_draw ();
+}
+
+void
+PortMatrixBody::repaint_row_labels ()
+{
+       _row_labels.require_render ();
+       queue_draw ();
+}
diff --git a/gtk2_ardour/port_matrix_body.h b/gtk2_ardour/port_matrix_body.h
new file mode 100644 (file)
index 0000000..503bb3a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtk_ardour_port_matrix_body_h__
+#define __gtk_ardour_port_matrix_body_h__
+
+#include "port_matrix_column_labels.h"
+#include "port_matrix_row_labels.h"
+#include "port_matrix_grid.h"
+
+class PortMatrix;
+
+/** The main body of the port matrix.  It is made up of three parts:
+ *  column labels, grid and row labels, each drawn using cairo.
+ *  This class handles the arrangement of these parts.
+ */
+class PortMatrixBody : public Gtk::EventBox
+{
+public:
+       PortMatrixBody (PortMatrix *);
+
+       /** @return bundles to offer for columns */
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & column_bundles () {
+               return _column_bundles;
+       }
+
+       /** @return bundles to offer for rows */
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & row_bundles () {
+               return _row_bundles;
+       }
+       
+       void setup (
+               std::vector<boost::shared_ptr<ARDOUR::Bundle> > const &,
+               std::vector<boost::shared_ptr<ARDOUR::Bundle> > const &
+               );
+
+       uint32_t full_scroll_width ();
+       uint32_t alloc_scroll_width ();
+       uint32_t full_scroll_height ();
+       uint32_t alloc_scroll_height ();
+
+       void set_xoffset (uint32_t);
+       void set_yoffset (uint32_t);
+
+       void repaint_grid ();
+
+protected:
+       bool on_expose_event (GdkEventExpose *);
+       void on_size_request (Gtk::Requisition *);
+       void on_size_allocate (Gtk::Allocation &);
+       bool on_button_press_event (GdkEventButton *);
+
+private:
+       void compute_divs ();
+       void repaint_column_labels ();
+       void repaint_row_labels ();
+       
+       PortMatrix* _port_matrix;
+       PortMatrixColumnLabels _column_labels;
+       PortMatrixRowLabels _row_labels;
+       PortMatrixGrid _grid;
+
+       uint32_t _alloc_width; ///< allocated width
+       uint32_t _alloc_height; ///< allocated height
+       uint32_t _alloc_xdiv; ///< position of the division between grid and row labels
+       uint32_t _alloc_ydiv; ///< position of the division between column labels and grid
+       uint32_t _xoffset;
+       uint32_t _yoffset;
+
+       /// bundles to offer for columns
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > _column_bundles;
+       /// bundles to offer for rows
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > _row_bundles;
+
+       std::list<sigc::connection> _bundle_connections;
+};
+
+#endif
diff --git a/gtk2_ardour/port_matrix_column_labels.cc b/gtk2_ardour/port_matrix_column_labels.cc
new file mode 100644 (file)
index 0000000..343d225
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include "ardour/bundle.h"
+#include "port_matrix_column_labels.h"
+#include "port_matrix.h"
+
+PortMatrixColumnLabels::PortMatrixColumnLabels (PortMatrixBody* b)
+       : PortMatrixComponent (b)
+{
+       
+}
+
+void
+PortMatrixColumnLabels::compute_dimensions ()
+{
+       GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
+       gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
+       cairo_t* cr = gdk_cairo_create (pm);
+
+       /* width of the longest bundle name */
+       _longest_bundle_name = 0;
+       /* width of the longest channel name */
+       _longest_channel_name = 0;
+       /* height of highest bit of text */
+       _highest_text = 0;
+       
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin (); i != _body->column_bundles().end(); ++i) {
+
+               cairo_text_extents_t ext;
+               cairo_text_extents (cr, (*i)->name().c_str(), &ext);
+               if (ext.width > _longest_bundle_name) {
+                       _longest_bundle_name = ext.width;
+               }
+               if (ext.height > _highest_text) {
+                       _highest_text = ext.height;
+               }
+
+               for (uint32_t j = 0; j < (*i)->nchannels (); ++j) {
+                       
+                       cairo_text_extents (
+                               cr,
+                               (*i)->channel_name (j).c_str(),
+                               &ext
+                               );
+                       
+                       if (ext.width > _longest_channel_name) {
+                               _longest_channel_name = ext.width;
+                       }
+                       if (ext.height > _highest_text) {
+                               _highest_text = ext.height;
+                       }
+               }
+       }
+
+       cairo_destroy (cr);
+       gdk_pixmap_unref (pm);
+
+       /* width and height of the whole thing */
+       
+       _width = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin (); i != _body->column_bundles().end(); ++i) {
+               _width += (*i)->nchannels() * column_width();
+       }
+
+       _height =
+               (_longest_bundle_name + _longest_channel_name + 4 * name_pad()) * sin (angle())
+               + _highest_text * cos (angle());
+
+       _width += _height / tan (angle ());
+}
+
+uint32_t
+PortMatrixColumnLabels::basic_text_x_pos (int c) const
+{
+       return column_width() / 2 +
+               _highest_text / (2 * sin (angle ()));
+}
+
+void
+PortMatrixColumnLabels::render (cairo_t* cr)
+{
+       /* BACKGROUND */
+
+       set_source_rgb (cr, background_colour());
+       cairo_rectangle (cr, 0, 0, _width, _height);
+       cairo_fill (cr);
+
+        /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
+
+       uint32_t x = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin (); i != _body->column_bundles().end(); ++i) {
+
+               Gdk::Color colour = get_a_bundle_colour (i - _body->column_bundles().begin ());
+               set_source_rgb (cr, colour);
+
+               uint32_t const w = (*i)->nchannels() * column_width();
+
+               uint32_t x_ = x;
+               uint32_t y_ = _height;
+               
+               cairo_move_to (cr, x_, y_);
+               x_ += w;
+               cairo_line_to (cr, x_, y_);
+               x_ += _height / tan (angle ());
+               y_ -= _height;
+               cairo_line_to (cr, x_, y_);
+               x_ -= w;
+               cairo_line_to (cr, x_, y_);
+               cairo_line_to (cr, x, _height);
+               cairo_fill_preserve (cr);
+               set_source_rgb (cr, background_colour());
+               cairo_set_line_width (cr, label_border_width());
+               cairo_stroke (cr);
+
+               set_source_rgb (cr, text_colour());
+
+               uint32_t const rl = 3 * name_pad() + _longest_channel_name;
+
+               cairo_move_to (
+                       cr,
+                       x + basic_text_x_pos (0) + rl * cos (angle()),
+                       _height - rl * sin (angle())
+                       );
+               
+               cairo_save (cr);
+               cairo_rotate (cr, -angle());
+               cairo_show_text (cr, (*i)->name().c_str());
+               cairo_restore (cr);
+               
+               x += (*i)->nchannels () * column_width();
+       }
+       
+
+       /* PORT NAMES */
+
+       x = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin(); i != _body->column_bundles().end(); ++i) {
+               
+               for (uint32_t j = 0; j < (*i)->nchannels(); ++j) {
+
+                       uint32_t const p = _longest_channel_name + (2 * name_pad());
+                       uint32_t const w = column_width();
+
+                       uint32_t x_ = x;
+                       uint32_t y_ = _height;
+                       cairo_move_to (cr, x_, y_);
+                       x_ += w;
+                       cairo_line_to (cr, x_, y_);
+                       x_ += p * cos (angle());
+                       y_ -= p * sin (angle());
+                       cairo_line_to (cr, x_, y_);
+                       x_ -= column_width() * pow (sin (angle()), 2);
+                       y_ -= column_width() * sin (angle()) * cos (angle());
+                       cairo_line_to (cr, x_, y_);
+                       cairo_line_to (cr, x, _height);
+
+                       Gdk::Color colour = get_a_bundle_colour (i - _body->column_bundles().begin());
+                       set_source_rgb (cr, colour);
+                       cairo_fill_preserve (cr);
+                       set_source_rgb (cr, background_colour());
+                       cairo_set_line_width (cr, label_border_width());
+                       cairo_stroke (cr);
+
+                       set_source_rgb (cr, text_colour());
+                       cairo_move_to (cr, x + basic_text_x_pos(j), _height - name_pad() * sin (angle()));
+                       
+                       cairo_save (cr);
+                       cairo_rotate (cr, -angle());
+
+                       cairo_show_text (
+                               cr,
+                               (*i)->channel_name(j).c_str()
+                               );
+                       
+                       cairo_restore (cr);
+
+                       x += column_width();
+               }
+       }
+}
+
diff --git a/gtk2_ardour/port_matrix_column_labels.h b/gtk2_ardour/port_matrix_column_labels.h
new file mode 100644 (file)
index 0000000..3c9ff41
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __port_matrix_column_labels_h__
+#define __port_matrix_column_labels_h__
+
+#include <boost/shared_ptr.hpp>
+#include "port_matrix_component.h"
+
+class PortMatrixBody;
+
+namespace ARDOUR {
+       class Bundle;
+}
+
+/** The column labels part of the port matrix */
+class PortMatrixColumnLabels : public PortMatrixComponent
+{
+public:
+       PortMatrixColumnLabels (PortMatrixBody *);
+
+private:
+       void render (cairo_t *);
+       void compute_dimensions ();
+       uint32_t basic_text_x_pos (int) const;
+
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > _bundles;
+       uint32_t _longest_bundle_name;
+       uint32_t _longest_channel_name;
+       uint32_t _highest_text;
+};
+
+#endif
diff --git a/gtk2_ardour/port_matrix_component.cc b/gtk2_ardour/port_matrix_component.cc
new file mode 100644 (file)
index 0000000..e2d1e07
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include "port_matrix_component.h"
+
+/** Constructor.
+ *  @param p Port matrix that we're in.
+ */
+PortMatrixComponent::PortMatrixComponent (PortMatrixBody* b)
+       : _body (b),
+         _pixmap (0),
+         _render_required (true),
+         _dimension_computation_required (true)
+{
+       
+}
+
+/** Destructor */
+PortMatrixComponent::~PortMatrixComponent ()
+{
+       if (_pixmap) {
+               gdk_pixmap_unref (_pixmap);
+       }
+}
+
+void
+PortMatrixComponent::setup ()
+{
+       _dimension_computation_required = true;
+       _render_required = true;
+}
+
+GdkPixmap *
+PortMatrixComponent::get_pixmap (GdkDrawable *drawable)
+{
+       if (_render_required) {
+
+               if (_dimension_computation_required) {
+                       compute_dimensions ();
+                       _dimension_computation_required = false;
+               }
+
+               /* we may be zero width or height; if so, just
+                  use the smallest allowable pixmap */
+               if (_width == 0) {
+                       _width = 1;
+               }
+               if (_height == 0) {
+                       _height = 1;
+               }
+
+               /* make a pixmap of the right size */
+               if (_pixmap) {
+                       gdk_pixmap_unref (_pixmap);
+               }
+               _pixmap = gdk_pixmap_new (drawable, _width, _height, -1);
+
+               /* render */
+               cairo_t* cr = gdk_cairo_create (_pixmap);
+               render (cr);
+               cairo_destroy (cr);
+
+               _render_required = false;
+       }
+
+       return _pixmap;
+}
+
+void
+PortMatrixComponent::set_source_rgb (cairo_t *cr, Gdk::Color const & c)
+{
+       cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
+}
+
+void
+PortMatrixComponent::set_source_rgba (cairo_t *cr, Gdk::Color const & c, double a)
+{
+       cairo_set_source_rgba (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p(), a);
+}
+
+std::pair<uint32_t, uint32_t>
+PortMatrixComponent::dimensions ()
+{
+       if (_dimension_computation_required) {
+               compute_dimensions ();
+               _dimension_computation_required = false;
+       }
+
+       return std::make_pair (_width, _height);
+}
diff --git a/gtk2_ardour/port_matrix_component.h b/gtk2_ardour/port_matrix_component.h
new file mode 100644 (file)
index 0000000..a041c80
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtk_ardour_port_matrix_component_h__
+#define __gtk_ardour_port_matrix_component_h__
+
+#include <gtkmm/eventbox.h>
+
+class PortMatrixBody;
+
+/** One component of the PortMatrix.  This is a cairo-rendered
+ *  Pixmap.
+ */
+class PortMatrixComponent
+{
+public:
+       PortMatrixComponent (PortMatrixBody *);
+       virtual ~PortMatrixComponent ();
+
+       void setup ();
+       GdkPixmap* get_pixmap (GdkDrawable *);
+       std::pair<uint32_t, uint32_t> dimensions ();
+       void require_render () {
+               _render_required = true;
+       }
+
+       /** @return width of columns in the grid */
+       static uint32_t column_width () {
+               return 32;
+       }
+
+       /** @return height of rows in the grid */
+       static uint32_t row_height () {
+               return 32;
+       }
+
+protected:
+
+       /** @return width of borders drawn around labels */
+       static uint32_t label_border_width () {
+               return 1;
+       }
+
+       /** @return padding between a name and the nearest line */
+       static uint32_t name_pad () {
+               return 8;
+       }
+
+       /** @return width of thin lines in the grid */
+       static uint32_t thin_grid_line_width () {
+               return 1;
+       }
+
+       /** @return width of thick lines in the grid */
+       static uint32_t thick_grid_line_width () {
+               return 2;
+       }
+
+       /** @return space around the connection indicator */
+       static uint32_t connection_indicator_pad () {
+               return 8;
+       }
+
+       /** @return angle of column labels, in radians */
+       static double angle () {
+               return M_PI / 4;
+       }
+
+       /* XXX I guess these colours should come from a theme, or something */
+
+       /* @return background colour */
+       static Gdk::Color background_colour () {
+               return Gdk::Color ("#000000");
+       }
+
+       /* @return text colour */
+       static Gdk::Color text_colour () {
+               return Gdk::Color ("#ffffff");
+       }
+
+       /* @return grid line colour */
+       static Gdk::Color grid_colour () {
+               return Gdk::Color ("#333333");
+       }
+
+       /* @return colour of association blobs */
+       static Gdk::Color association_colour () {
+               return Gdk::Color ("#00ff00");
+       }
+
+       /* XXX */
+       static Gdk::Color get_a_bundle_colour (int x) {
+               if ((x % 2) == 0) {
+                       return Gdk::Color ("#547027");
+               } else {
+                       return Gdk::Color ("#3552a6");
+               }
+       }
+
+       void set_source_rgb (cairo_t *, Gdk::Color const &);
+       void set_source_rgba (cairo_t *, Gdk::Color const &, double);
+
+       /** Render the complete component to a cairo context. */
+       virtual void render (cairo_t *) = 0;
+       /** Compute any required dimensions.  This must set up
+        *  _width and _height.
+        */
+       virtual void compute_dimensions () = 0;
+
+       PortMatrixBody* _body; ///< the PortMatrixBody that we're in
+       uint32_t _width; ///< full width of the contents
+       uint32_t _height; ///< full height of the contents
+
+private:       
+       GdkPixmap* _pixmap; ///< pixmap
+       bool _render_required; ///< true if the rendered pixmap is out of date
+       bool _dimension_computation_required; ///< true if the dimensions are out of date
+};
+
+#endif
diff --git a/gtk2_ardour/port_matrix_grid.cc b/gtk2_ardour/port_matrix_grid.cc
new file mode 100644 (file)
index 0000000..461e9f5
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <cairo/cairo.h>
+#include "ardour/bundle.h"
+#include "port_matrix_grid.h"
+#include "port_matrix.h"
+
+PortMatrixGrid::PortMatrixGrid (PortMatrix* p, PortMatrixBody* b)
+       : PortMatrixComponent (b),
+         _port_matrix (p)
+{
+       
+}
+
+void
+PortMatrixGrid::compute_dimensions ()
+{
+       _width = 0;
+       for (uint32_t i = 0; i < _body->column_bundles().size(); ++i) {
+               _width += _body->column_bundles()[i]->nchannels() * column_width();
+       }
+
+       _height = 0;
+       for (uint32_t i = 0; i < _body->row_bundles().size(); ++i) {
+               _height += _body->row_bundles()[i]->nchannels() * row_height();
+       }
+}
+
+
+void
+PortMatrixGrid::render (cairo_t* cr)
+{
+       /* BACKGROUND */
+       
+       set_source_rgb (cr, background_colour());
+       cairo_rectangle (cr, 0, 0, _width, _height);
+       cairo_fill (cr);
+
+       /* VERTICAL GRID LINES */
+       
+       set_source_rgb (cr, grid_colour());
+       uint32_t x = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::size_type i = 0; i < _body->column_bundles().size(); ++i) {
+
+               cairo_set_line_width (cr, thin_grid_line_width());
+               for (uint32_t j = 1; j < _body->column_bundles()[i]->nchannels(); ++j) {
+                       x += column_width();
+                       cairo_move_to (cr, x, 0);
+                       cairo_line_to (cr, x, _height);
+                       cairo_stroke (cr);
+               }
+
+               if (i < (_body->column_bundles().size() - 1)) {
+                       x += column_width();
+                       cairo_set_line_width (cr, thick_grid_line_width());
+                       cairo_move_to (cr, x, 0);
+                       cairo_line_to (cr, x, _height);
+                       cairo_stroke (cr);
+               }
+        }
+               
+       uint32_t grid_width = x + column_width();
+
+       /* HORIZONTAL GRID LINES */
+       
+       uint32_t y = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::size_type i = 0; i < _body->row_bundles().size(); ++i) {
+
+               cairo_set_line_width (cr, thin_grid_line_width());
+               for (uint32_t j = 1; j < _body->row_bundles()[i]->nchannels(); ++j) {
+                       y += row_height();
+                       cairo_move_to (cr, 0, y);
+                       cairo_line_to (cr, grid_width, y);
+                       cairo_stroke (cr);
+               }
+
+               if (i < (_body->row_bundles().size() - 1)) {
+                       y += row_height();
+                       cairo_set_line_width (cr, thick_grid_line_width());
+                       cairo_move_to (cr, 0, y);
+                       cairo_line_to (cr, grid_width, y);
+                       cairo_stroke (cr);
+               }
+       }
+
+       /* ASSOCIATION INDICATORS */
+       
+       uint32_t bx = 0;
+       uint32_t by = 0;
+       
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin(); i < _body->column_bundles().end(); ++i) {
+               by = 0;
+               
+               for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator j = _body->row_bundles().begin(); j < _body->row_bundles().end(); ++j) {
+
+                       x = bx;
+                       for (uint32_t k = 0; k < (*i)->nchannels (); k++) {
+
+                               y = by;
+                               for (uint32_t l = 0; l < (*j)->nchannels (); ++l) {
+                                       
+                                       if (_port_matrix->get_state (*j, l, *i, k)) {
+                                               
+                                               set_source_rgba (cr, association_colour(), 0.5);
+                                               cairo_arc (
+                                                       cr,
+                                                       x + column_width() / 2,
+                                                       y + column_width() / 2,
+                                                       (column_width() - (2 * connection_indicator_pad())) / 2,
+                                                       0,
+                                                       2 * M_PI
+                                                       );
+
+                                               cairo_fill (cr);
+                                       
+                                       }
+                                       y += row_height();
+                               }
+                               x += column_width();
+                       }
+                       
+                       by += (*j)->nchannels () * row_height();
+               }
+               
+               bx += (*i)->nchannels () * column_width();
+       }
+}
+
+
+void
+PortMatrixGrid::button_press (double x, double y, int b)
+{
+       uint32_t grid_column = x / column_width ();
+       uint32_t grid_row = y / row_height ();
+
+       boost::shared_ptr<ARDOUR::Bundle> our_bundle;
+       uint32_t our_channel = 0;
+       boost::shared_ptr<ARDOUR::Bundle> other_bundle;
+       uint32_t other_channel = 0;
+
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+               if (grid_row < (*i)->nchannels ()) {
+                       our_bundle = *i;
+                       our_channel = grid_row;
+                       break;
+               } else {
+                       grid_row -= (*i)->nchannels ();
+               }
+       }
+
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin(); i != _body->column_bundles().end(); ++i) {
+               if (grid_column < (*i)->nchannels ()) {
+                       other_bundle = *i;
+                       other_channel = grid_column;
+                       break;
+               } else {
+                       grid_column -= (*i)->nchannels ();
+               }
+       }
+
+       if (our_bundle && other_bundle) {
+               
+               bool const s = _port_matrix->get_state (
+                       our_bundle, our_channel, other_bundle, other_channel
+                       );
+                               
+               _port_matrix->set_state (
+                       our_bundle, our_channel, other_bundle, other_channel,
+                       !s, 0
+                       );
+
+               require_render ();
+               _body->queue_draw ();
+       }
+}
+
+
diff --git a/gtk2_ardour/port_matrix_grid.h b/gtk2_ardour/port_matrix_grid.h
new file mode 100644 (file)
index 0000000..298d33c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef  __gtk_ardour_port_matrix_grid_h__ 
+#define  __gtk_ardour_port_matrix_grid_h__ 
+
+#include <string>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include "port_matrix_component.h"
+
+class PortMatrix;
+class PortMatrixBody;
+
+namespace ARDOUR {
+       class Bundle;
+}
+
+/// The grid part of the port matrix
+class PortMatrixGrid : public PortMatrixComponent
+{
+public:
+       PortMatrixGrid (PortMatrix *, PortMatrixBody *);
+
+       void button_press (double, double, int);
+
+private:
+       void compute_dimensions ();
+       void render (cairo_t *);
+
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > _column_bundles;
+       std::vector<boost::shared_ptr<ARDOUR::Bundle> > _row_bundles;
+
+       PortMatrix* _port_matrix;
+};
+
+#endif
diff --git a/gtk2_ardour/port_matrix_row_labels.cc b/gtk2_ardour/port_matrix_row_labels.cc
new file mode 100644 (file)
index 0000000..18e4799
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <boost/weak_ptr.hpp>
+#include <gtkmm/menu.h>
+#include <gtkmm/menushell.h>
+#include <gtkmm/menu_elems.h>
+#include <cairo/cairo.h>
+#include "ardour/bundle.h"
+#include "port_matrix_row_labels.h"
+#include "port_matrix.h"
+#include "i18n.h"
+
+PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* p, PortMatrixBody* b)
+       : PortMatrixComponent (b), _port_matrix (p), _menu (0)
+{
+       
+}
+
+PortMatrixRowLabels::~PortMatrixRowLabels ()
+{
+       delete _menu;
+}
+
+void
+PortMatrixRowLabels::compute_dimensions ()
+{
+       GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
+       gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
+       cairo_t* cr = gdk_cairo_create (pm);
+       
+       _longest_port_name = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+               for (uint32_t j = 0; j < (*i)->nchannels(); ++j) {
+                       cairo_text_extents_t ext;
+                       cairo_text_extents (cr, (*i)->channel_name(j).c_str(), &ext);
+                       if (ext.width > _longest_port_name) {
+                               _longest_port_name = ext.width;
+                       }
+               }
+       }
+
+       _longest_bundle_name = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+               cairo_text_extents_t ext;
+               cairo_text_extents (cr, (*i)->name().c_str(), &ext);
+               if (ext.width > _longest_bundle_name) {
+                       _longest_bundle_name = ext.width;
+               }
+       }
+
+       cairo_destroy (cr);
+       gdk_pixmap_unref (pm);
+
+       _height = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+               _height += (*i)->nchannels() * row_height();
+       }
+
+       _width = _longest_port_name +
+               name_pad() * 4 +
+               _longest_bundle_name + name_pad() * 2;
+}
+
+
+void
+PortMatrixRowLabels::render (cairo_t* cr)
+{
+       /* BACKGROUND */
+       
+       set_source_rgb (cr, background_colour());
+       cairo_rectangle (cr, 0, 0, _width, _height);
+       cairo_fill (cr);
+
+       /* SIDE BUNDLE NAMES */
+
+       uint32_t x = _longest_port_name + name_pad() * 3;
+
+       uint32_t y = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+
+               Gdk::Color const colour = get_a_bundle_colour (i - _body->row_bundles().begin ());
+               set_source_rgb (cr, colour);
+               cairo_rectangle (
+                       cr,
+                       0,
+                       y,
+                       _longest_port_name + name_pad() * 4 + _longest_bundle_name + name_pad() * 2,
+                       row_height() * (*i)->nchannels()
+                       );
+               cairo_fill_preserve (cr);
+               set_source_rgb (cr, background_colour());
+               cairo_set_line_width (cr, label_border_width ());
+               cairo_stroke (cr);
+
+               uint32_t off = 0;
+               if ((*i)->nchannels () > 0) {
+                       /* use the extent of our first channel name so that the bundle name is vertically aligned with it */
+                       cairo_text_extents_t ext;
+                       cairo_text_extents (cr, (*i)->channel_name(0).c_str(), &ext);
+                       off = (row_height() - ext.height) / 2;
+               } else {
+                       off = row_height() / 2;
+               }
+
+               set_source_rgb (cr, text_colour());
+               cairo_move_to (cr, x, y + name_pad() + off);
+               cairo_show_text (cr, (*i)->name().c_str());
+               
+               y += row_height() * (*i)->nchannels ();
+       }
+       
+
+       /* SIDE PORT NAMES */
+
+       y = 0;
+       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+               for (uint32_t j = 0; j < (*i)->nchannels(); ++j) {
+
+                       Gdk::Color const colour = get_a_bundle_colour (i - _body->row_bundles().begin ());
+                       set_source_rgb (cr, colour);
+                       cairo_rectangle (
+                               cr,
+                               0,
+                               y,
+                               _longest_port_name + (name_pad() * 2),
+                               row_height()
+                               );
+                       cairo_fill_preserve (cr);
+                       set_source_rgb (cr, background_colour());
+                       cairo_set_line_width (cr, label_border_width ());
+                       cairo_stroke (cr);
+
+                       cairo_text_extents_t ext;
+                       cairo_text_extents (cr, (*i)->channel_name(j).c_str(), &ext);
+                       uint32_t const off = (row_height() - ext.height) / 2;
+
+                       set_source_rgb (cr, text_colour());
+                       cairo_move_to (cr, name_pad(), y + name_pad() + off);
+                       cairo_show_text (cr, (*i)->channel_name(j).c_str());
+
+                       y += row_height();
+               }
+       }
+}
+
+void
+PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t)
+{
+       if (b == 3 && x < (_longest_port_name + name_pad() * 2) ) {
+
+               delete _menu;
+               
+               _menu = new Gtk::Menu;
+               _menu->set_name ("ArdourContextMenu");
+               
+               Gtk::Menu_Helpers::MenuList& items = _menu->items ();
+
+               
+               uint32_t row = y / row_height ();
+
+               boost::shared_ptr<ARDOUR::Bundle> bundle;
+               uint32_t channel;
+               
+               for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+                       if (row < (*i)->nchannels ()) {
+                               bundle = *i;
+                               channel = row;
+                               break;
+                       } else {
+                               row -= (*i)->nchannels ();
+                       }
+               }
+
+               if (bundle) {
+                       char buf [64];
+
+                       if (_port_matrix->can_rename_channels ()) {
+                               snprintf (buf, sizeof (buf), _("Rename '%s'..."), bundle->channel_name (channel).c_str());
+                               items.push_back (
+                                       Gtk::Menu_Helpers::MenuElem (
+                                               buf,
+                                               sigc::bind (sigc::mem_fun (*this, &PortMatrixRowLabels::rename_channel_proxy), bundle, channel)
+                                               )
+                                       );
+                       }
+                       
+                       snprintf (buf, sizeof (buf), _("Remove '%s'"), bundle->channel_name (channel).c_str());
+                       items.push_back (
+                               Gtk::Menu_Helpers::MenuElem (
+                                       buf,
+                                       sigc::bind (sigc::mem_fun (*this, &PortMatrixRowLabels::remove_channel_proxy), bundle, channel)
+                                       )
+                               );
+
+                       _menu->popup (1, t);
+               }
+       }
+}
+
+
+void
+PortMatrixRowLabels::remove_channel_proxy (boost::weak_ptr<ARDOUR::Bundle> b, uint32_t c)
+{
+       boost::shared_ptr<ARDOUR::Bundle> sb = b.lock ();
+       if (!sb) {
+               return;
+       }
+
+       _port_matrix->remove_channel (sb, c);
+
+}
+
+void
+PortMatrixRowLabels::rename_channel_proxy (boost::weak_ptr<ARDOUR::Bundle> b, uint32_t c)
+{
+       boost::shared_ptr<ARDOUR::Bundle> sb = b.lock ();
+       if (!sb) {
+               return;
+       }
+
+       _port_matrix->rename_channel (sb, c);
+}
diff --git a/gtk2_ardour/port_matrix_row_labels.h b/gtk2_ardour/port_matrix_row_labels.h
new file mode 100644 (file)
index 0000000..74af109
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+    Copyright (C) 2002-2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __port_matrix_row_labels_h__
+#define __port_matrix_row_labels_h__
+
+#include <boost/shared_ptr.hpp>
+#include "port_matrix_component.h"
+
+class PortMatrix;
+class PortMatrixBody;
+
+namespace ARDOUR {
+       class Bundle;
+}
+
+namespace Gtk {
+       class Menu;
+}
+
+class PortMatrixRowLabels : public PortMatrixComponent
+{
+public:
+       PortMatrixRowLabels (PortMatrix *, PortMatrixBody *);
+       ~PortMatrixRowLabels ();
+
+       void button_press (double, double, int, uint32_t);
+  
+private:
+       void render (cairo_t *);
+       void compute_dimensions ();
+       void remove_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t);
+       void rename_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t);
+
+       PortMatrix* _port_matrix;
+       uint32_t _longest_port_name;
+       uint32_t _longest_bundle_name;
+       Gtk::Menu* _menu;
+};
+
+#endif
index 670635fb4d172725137ddb1dac680e985a79a14e..13807a15214ab21324963f7a2eacaa3375da4c76 100644 (file)
@@ -320,13 +320,13 @@ RouteParams_UI::setup_io_frames()
        cleanup_io_frames();
        
        // input
-       _input_iosel = new IOSelector (*session, _route, true);
+       _input_iosel = new IOSelector (*session, _route, false);
        _input_iosel->setup ();
        input_frame.add (*_input_iosel);
        input_frame.show_all();
        
        // output
-       _output_iosel = new IOSelector (*session, _route, false);
+       _output_iosel = new IOSelector (*session, _route, true);
        _output_iosel->setup ();
        output_frame.add (*_output_iosel);
        output_frame.show_all();
index 1b029dc2b4584d68a4e67c003224e5954bcc9e49..8b1af39e756d711db249f765059619df511d653f 100644 (file)
 #define __ardour_bundle_h__
 
 #include <string>
+#include <vector>
+#include <glibmm/thread.h>
 #include <sigc++/signal.h>
 #include "ardour/data_type.h"
 
 namespace ARDOUR {
   
 /** A set of `channels', each of which is associated with 0 or more ports.
+ *  Each channel has a name which can be anything useful.
  *  Intended for grouping things like, for example, a buss' outputs.
  *  `Channel' is a rather overloaded term but I can't think of a better
  *  one right now.
  */
-class Bundle : public sigc::trackable {
+class Bundle : public sigc::trackable
+{
   public:
 
        /// List of ports associated with a channel.  We can't use a
@@ -39,6 +43,17 @@ class Bundle : public sigc::trackable {
        /// (ie those without a Port object)
        typedef std::vector<std::string> PortList;
 
+       struct Channel {
+               Channel (std::string n) : name (n) {}
+
+               bool operator== (Channel const &o) const {
+                       return name == o.name && ports == o.ports;
+               }
+               
+               std::string name;
+               PortList ports;
+       };
+
        /** Construct an audio bundle.
         *  @param i true if ports are inputs, otherwise false.
         */
@@ -50,6 +65,13 @@ class Bundle : public sigc::trackable {
         */
        Bundle (std::string const & n, bool i = true) : _name (n), _type (DataType::AUDIO), _ports_are_inputs (i) {}
 
+       /** Construct a bundle.
+        *  @param n Name.
+        *  @param t Type.
+        *  @param i true if ports are inputs, otherwise false.
+        */
+       Bundle (std::string const & n, DataType t, bool i = true) : _name (n), _type (t), _ports_are_inputs (i) {}
+
        virtual ~Bundle() {}
 
        /** @return Number of channels that this Bundle has */
@@ -60,13 +82,16 @@ class Bundle : public sigc::trackable {
         */
        PortList const & channel_ports (uint32_t) const;
 
-       void add_channel ();
+       void add_channel (std::string const &);
+       std::string channel_name (uint32_t) const;
+       void set_channel_name (uint32_t, std::string const &);
        void add_port_to_channel (uint32_t, std::string);
        void set_port (uint32_t, std::string);
        void remove_port_from_channel (uint32_t, std::string);
-       void set_nchannels (uint32_t);
        bool port_attached_to_channel (uint32_t, std::string);
+       bool uses_port (std::string) const;
        void remove_channel (uint32_t);
+       void remove_channels ();
 
        /** Set the name.
         *  @param n New name.
@@ -94,7 +119,7 @@ class Bundle : public sigc::trackable {
 
        bool operator== (Bundle const &) const;
 
-       /** Emitted when the name changes */
+       /** Emitted when the bundle name or a channel name has changed */
        sigc::signal<void> NameChanged;
        /** The number of channels has changed */
        sigc::signal<void> ConfigurationChanged;
@@ -103,10 +128,10 @@ class Bundle : public sigc::trackable {
 
   protected:
        
-       /// mutex for _ports;
+       /// mutex for _channel_ports and _channel_names
        /// XXX: is this necessary?
-       mutable Glib::Mutex _ports_mutex;
-       std::vector<PortList> _ports;
+       mutable Glib::Mutex _channel_mutex;
+       std::vector<Channel> _channel;
 
   private:
        int set_channels (std::string const &);
index bdad9d364da0141eaa0faeefd215ae63d6feef01..379a3d4c2be687e7698b64ed7b966fe135dace21 100644 (file)
@@ -32,8 +32,8 @@ using namespace PBD;
 uint32_t
 Bundle::nchannels () const
 {
-       Glib::Mutex::Lock lm (_ports_mutex);
-       return _ports.size ();
+       Glib::Mutex::Lock lm (_channel_mutex);
+       return _channel.size ();
 }
 
 Bundle::PortList const &
@@ -41,8 +41,8 @@ Bundle::channel_ports (uint32_t c) const
 {
        assert (c < nchannels());
 
-       Glib::Mutex::Lock lm (_ports_mutex);
-       return _ports[c];
+       Glib::Mutex::Lock lm (_channel_mutex);
+       return _channel[c].ports;
 }
 
 /** Add an association between one of our channels and a port.
@@ -55,8 +55,8 @@ Bundle::add_port_to_channel (uint32_t ch, string portname)
        assert (ch < nchannels());
 
        {
-               Glib::Mutex::Lock lm (_ports_mutex);
-               _ports[ch].push_back (portname);
+               Glib::Mutex::Lock lm (_channel_mutex);
+               _channel[ch].ports.push_back (portname);
        }
        
        PortsChanged (ch); /* EMIT SIGNAL */
@@ -74,8 +74,8 @@ Bundle::remove_port_from_channel (uint32_t ch, string portname)
        bool changed = false;
 
        {
-               Glib::Mutex::Lock lm (_ports_mutex);
-               PortList& pl = _ports[ch];
+               Glib::Mutex::Lock lm (_channel_mutex);
+               PortList& pl = _channel[ch].ports;
                PortList::iterator i = find (pl.begin(), pl.end(), portname);
                
                if (i != pl.end()) {
@@ -95,48 +95,31 @@ Bundle::remove_port_from_channel (uint32_t ch, string portname)
 bool
 Bundle::operator== (const Bundle& other) const
 {
-       return other._ports == _ports;
+       return other._channel == _channel;
 }
 
 
-/** Set the number of channels.
- * @param n New number of channels.
- */
-
-void
-Bundle::set_nchannels (uint32_t n)
-{
-       {
-               Glib::Mutex::Lock lm (_ports_mutex);
-               _ports.clear ();
-               for (uint32_t i = 0; i < n; ++i) {
-                       _ports.push_back (PortList());
-               }
-       }
-
-       ConfigurationChanged (); /* EMIT SIGNAL */
-}
-
 void
 Bundle::set_port (uint32_t ch, string portname)
 {
        assert (ch < nchannels());
 
        {
-               Glib::Mutex::Lock lm (_ports_mutex);
-               _ports[ch].clear ();
-               _ports[ch].push_back (portname);
+               Glib::Mutex::Lock lm (_channel_mutex);
+               _channel[ch].ports.clear ();
+               _channel[ch].ports.push_back (portname);
        }
 
        PortsChanged (ch); /* EMIT SIGNAL */
 }
 
+/** @param n Channel name */
 void
-Bundle::add_channel ()
+Bundle::add_channel (std::string const & n)
 {
        {
-               Glib::Mutex::Lock lm (_ports_mutex);
-               _ports.push_back (PortList ());
+               Glib::Mutex::Lock lm (_channel_mutex);
+               _channel.push_back (Channel (n));
        }
 
        ConfigurationChanged (); /* EMIT SIGNAL */
@@ -147,8 +130,8 @@ Bundle::port_attached_to_channel (uint32_t ch, std::string portname)
 {
        assert (ch < nchannels());
        
-       Glib::Mutex::Lock lm (_ports_mutex);
-       return (std::find (_ports[ch].begin (), _ports[ch].end (), portname) != _ports[ch].end ());
+       Glib::Mutex::Lock lm (_channel_mutex);
+       return (std::find (_channel[ch].ports.begin (), _channel[ch].ports.end (), portname) != _channel[ch].ports.end ());
 }
 
 void
@@ -156,6 +139,52 @@ Bundle::remove_channel (uint32_t ch)
 {
        assert (ch < nchannels ());
 
-       Glib::Mutex::Lock lm (_ports_mutex);
-       _ports.erase (_ports.begin () + ch);
+       Glib::Mutex::Lock lm (_channel_mutex);
+       _channel.erase (_channel.begin () + ch);
+}
+
+void
+Bundle::remove_channels ()
+{
+       Glib::Mutex::Lock lm (_channel_mutex);
+
+       _channel.clear ();
+}
+
+bool
+Bundle::uses_port (std::string p) const
+{
+       Glib::Mutex::Lock lm (_channel_mutex);
+
+       for (std::vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
+               for (PortList::const_iterator j = i->ports.begin(); j != i->ports.end(); ++j) {
+                       if (*j == p) {
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+std::string
+Bundle::channel_name (uint32_t ch) const
+{
+       assert (ch < nchannels());
+
+       Glib::Mutex::Lock lm (_channel_mutex);
+       return _channel[ch].name;
+}
+
+void
+Bundle::set_channel_name (uint32_t ch, std::string const & n)
+{
+       assert (ch < nchannels());
+
+       {
+               Glib::Mutex::Lock lm (_channel_mutex);
+               _channel[ch].name = n;
+       }
+
+       NameChanged (); /* EMIT SIGNAL */
 }
index ed1064f0e858575a8ef3bb184a085aa35abefa1c..2b8f12680fcf69df9a37a7a6466638bcf1a93d9f 100644 (file)
@@ -593,7 +593,7 @@ IO::remove_output_port (Port* port, void* src)
                PortCountChanged (n_outputs()); /* EMIT SIGNAL */
        }
 
-       if (change == ConnectionsChanged) {
+       if (change == ConfigurationChanged) {
                setup_bundles_for_inputs_and_outputs ();
        }
 
@@ -2592,19 +2592,24 @@ IO::setup_bundles_for_inputs_and_outputs ()
 {
         char buf[32];
 
+       _bundle_for_inputs->remove_channels ();
+       _bundle_for_outputs->remove_channels ();
+               
         snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
         _bundle_for_inputs->set_name (buf);
        uint32_t const ni = inputs().num_ports();
-       _bundle_for_inputs->set_nchannels (ni);
        for (uint32_t i = 0; i < ni; ++i) {
+               snprintf (buf, sizeof(buf), _("in %d"), (i + 1));
+               _bundle_for_inputs->add_channel (buf);
                _bundle_for_inputs->set_port (i, inputs().port(i)->name());
        }
 
         snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
         _bundle_for_outputs->set_name (buf);
        uint32_t const no = outputs().num_ports();
-       _bundle_for_outputs->set_nchannels (no);
        for (uint32_t i = 0; i < no; ++i) {
+               snprintf (buf, sizeof(buf), _("out %d"), (i + 1));
+               _bundle_for_outputs->add_channel (buf);
                _bundle_for_outputs->set_port (i, outputs().port(i)->name());
        }
 }
index c020509924a3e87ea8d0addbb08e5912a8b60616..2b4d264bbbdcbfbe21acda962a4346ddfff4d06c 100644 (file)
@@ -598,7 +598,7 @@ Session::when_engine_running ()
                snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
 
                shared_ptr<Bundle> c (new Bundle (buf, true));
-               c->set_nchannels (1);
+               c->add_channel (_("mono"));
                c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
 
                add_bundle (c);
@@ -609,7 +609,7 @@ Session::when_engine_running ()
                snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
 
                shared_ptr<Bundle> c (new Bundle (buf, false));
-               c->set_nchannels (1);
+               c->add_channel (_("mono"));
                c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
 
                add_bundle (c);
@@ -622,8 +622,9 @@ Session::when_engine_running ()
                snprintf (buf, sizeof (buf), _("out %" PRIu32 "+%" PRIu32), np+1, np+2);
 
                shared_ptr<Bundle> c (new Bundle (buf, true));
-               c->set_nchannels (2);
+               c->add_channel (_("left"));
                c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
+               c->add_channel (_("right"));
                c->set_port (1, _engine.get_nth_physical_output (DataType::AUDIO, np + 1));
 
                add_bundle (c);
@@ -634,8 +635,9 @@ Session::when_engine_running ()
                snprintf (buf, sizeof (buf), _("in %" PRIu32 "+%" PRIu32), np+1, np+2);
 
                shared_ptr<Bundle> c (new Bundle (buf, false));
-               c->set_nchannels (2);
+               c->add_channel (_("left"));
                c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
+               c->add_channel (_("right"));
                c->set_port (1, _engine.get_nth_physical_input (DataType::AUDIO, np + 1));
 
                add_bundle (c);
@@ -2003,13 +2005,6 @@ Session::add_routes (RouteList& new_routes, bool save)
                if ((*x)->is_control()) {
                        _control_out = (*x);
                }
-
-               /* only busses get automatic bundles formed */
-
-               if (!boost::dynamic_pointer_cast<Track> (*x)) {
-                       add_bundle ((*x)->bundle_for_inputs());
-                       add_bundle ((*x)->bundle_for_outputs());
-               }
        }
 
        if (_control_out && IO::connecting_legal) {
index d53bf8b155764c7622fc803bc5e74ef59a61677d..2dee0af01eeaa74836d7b1becaae1dc9d7cdb49b 100644 (file)
@@ -45,7 +45,7 @@ ARDOUR::UserBundle::set_state (XMLNode const & node)
                        return -1;
                }
 
-               add_channel ();
+               add_channel ("XXX");
 
                XMLNodeList const ports = (*i)->children ();
 
@@ -83,13 +83,13 @@ ARDOUR::UserBundle::get_state ()
        node->add_property ("name", name ());
 
        {
-               Glib::Mutex::Lock lm (_ports_mutex);
+               Glib::Mutex::Lock lm (_channel_mutex);
 
-               for (std::vector<PortList>::iterator i = _ports.begin(); i != _ports.end(); ++i) {
-                       
+               for (std::vector<Channel>::iterator i = _channel.begin(); i != _channel.end(); ++i) {
                        XMLNode* c = new XMLNode ("Channel");
+                       c->add_property ("name", i->name);
                        
-                       for (PortList::iterator j = i->begin(); j != i->end(); ++j) {
+                       for (PortList::iterator j = i->ports.begin(); j != i->ports.end(); ++j) {
                                XMLNode* p = new XMLNode ("Port");
                                p->add_property ("name", *j);
                                c->add_child_nocopy (*p);