From ee42a6dd97045253d1a9bb32fc2e571d235f9967 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 9 Feb 2009 03:18:10 +0000 Subject: Fixes to bundle manager to make it vaguely usable. Rework signal handling for bundles so that all changes should now be noticed by port matrices. git-svn-id: svn://localhost/ardour2/branches/3.0@4501 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/ardour_ui_ed.cc | 1 - gtk2_ardour/bundle_manager.cc | 64 +++++-- gtk2_ardour/bundle_manager.h | 5 +- gtk2_ardour/global_port_matrix.cc | 15 +- gtk2_ardour/global_port_matrix.h | 6 +- gtk2_ardour/io_selector.cc | 73 +++---- gtk2_ardour/io_selector.h | 18 +- gtk2_ardour/port_group.cc | 319 +++++++++++++++++++++---------- gtk2_ardour/port_group.h | 58 ++++-- gtk2_ardour/port_matrix.cc | 84 +++++++- gtk2_ardour/port_matrix.h | 7 +- gtk2_ardour/port_matrix_body.cc | 6 +- gtk2_ardour/port_matrix_column_labels.cc | 26 +-- gtk2_ardour/port_matrix_column_labels.h | 1 - gtk2_ardour/port_matrix_row_labels.cc | 13 +- 15 files changed, 451 insertions(+), 245 deletions(-) (limited to 'gtk2_ardour') diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index cd7e632271..703b7ed06a 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -205,7 +205,6 @@ ARDOUR_UI::install_actions () ActionManager::register_toggle_action (common_actions, X_("ToggleOptionsEditor"), _("Preferences"), mem_fun(*this, &ARDOUR_UI::toggle_options_window)); act = ActionManager::register_toggle_action (common_actions, X_("ToggleInspector"), _("Track/Bus Inspector"), mem_fun(*this, &ARDOUR_UI::toggle_route_params_window)); ActionManager::session_sensitive_actions.push_back (act); - act = ActionManager::register_toggle_action (common_actions, X_("ToggleConnections"), _("Connections"), mem_fun(*this, &ARDOUR_UI::toggle_connection_editor)); ActionManager::session_sensitive_actions.push_back (act); act = ActionManager::register_toggle_action (common_actions, X_("ToggleLocations"), _("Locations"), mem_fun(*this, &ARDOUR_UI::toggle_location_window)); ActionManager::session_sensitive_actions.push_back (act); diff --git a/gtk2_ardour/bundle_manager.cc b/gtk2_ardour/bundle_manager.cc index 79bdd3e6f5..91b06e3df1 100644 --- a/gtk2_ardour/bundle_manager.cc +++ b/gtk2_ardour/bundle_manager.cc @@ -37,15 +37,21 @@ BundleEditorMatrix::BundleEditorMatrix ( _bundle (bundle) { _port_group = boost::shared_ptr (new PortGroup ("")); - _port_group->add_bundle (bundle); - _ports[OURS].add_group (_port_group); + _port_group->add_bundle (_bundle); } void -BundleEditorMatrix::setup () +BundleEditorMatrix::setup_ports (int dim) { - _ports[OTHER].gather (_session, _bundle->ports_are_inputs()); - PortMatrix::setup (); + if (dim == OURS) { + _ports[OURS].clear (); + _ports[OURS].add_group (_port_group); + } else { + _ports[OTHER].suspend_signals (); + _ports[OTHER].gather (_session, _bundle->ports_are_inputs()); + _ports[OTHER].remove_bundle (_bundle); + _ports[OTHER].resume_signals (); + } } void @@ -85,14 +91,14 @@ BundleEditorMatrix::add_channel (boost::shared_ptr b) } _bundle->add_channel (d.get_name()); - setup (); + setup_ports (OURS); } void BundleEditorMatrix::remove_channel (ARDOUR::BundleChannel bc) { bc.bundle->remove_channel (bc.channel); - setup (); + setup_ports (OURS); } void @@ -108,6 +114,12 @@ BundleEditorMatrix::rename_channel (ARDOUR::BundleChannel bc) bc.bundle->set_channel_name (bc.channel, d.get_name ()); } +bool +BundleEditorMatrix::list_is_global (int dim) const +{ + return (dim == OTHER); +} + BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr bundle, bool add) : ArdourDialog (_("Edit Bundle")), _matrix (session, bundle), _bundle (bundle) { @@ -133,9 +145,9 @@ BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptrports_are_inputs()) { - _input_or_output.set_active_text (_("Output")); - } else { _input_or_output.set_active_text (_("Input")); + } else { + _input_or_output.set_active_text (_("Output")); } _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed)); @@ -174,10 +186,10 @@ BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptrsignal_clicked().connect (sigc::bind (sigc::mem_fun (_matrix, &BundleEditorMatrix::add_channel), boost::shared_ptr ())); if (add) { - add_button (Gtk::Stock::CANCEL, 1); - add_button (Gtk::Stock::ADD, 0); + add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT); } else { - add_button (Gtk::Stock::CLOSE, 0); + add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT); } show_all (); @@ -192,18 +204,22 @@ BundleEditor::name_changed () void BundleEditor::input_or_output_changed () { + _bundle->remove_ports_from_channels (); + if (_input_or_output.get_active_text() == _("Output")) { - _bundle->set_ports_are_inputs (); - } else { _bundle->set_ports_are_outputs (); + } else { + _bundle->set_ports_are_inputs (); } - _matrix.setup (); + _matrix.setup_all_ports (); } void BundleEditor::type_changed () { + _bundle->remove_ports_from_channels (); + ARDOUR::DataType const t = _type.get_active_text() == _("Audio") ? ARDOUR::DataType::AUDIO : ARDOUR::DataType::MIDI; @@ -214,7 +230,7 @@ BundleEditor::type_changed () void BundleEditor::on_map () { - _matrix.setup (); + _matrix.setup_all_ports (); Window::on_map (); } @@ -284,7 +300,8 @@ BundleManager::new_clicked () b->add_channel (""); BundleEditor e (_session, b, true); - if (e.run () == 0) { + + if (e.run () == Gtk::RESPONSE_ACCEPT) { _session.add_bundle (b); add_bundle (b); } @@ -297,9 +314,10 @@ BundleManager::edit_clicked () if (i) { boost::shared_ptr b = (*i)[_list_model_columns.bundle]; BundleEditor e (_session, b, false); - e.run (); + if (e.run () == Gtk::RESPONSE_ACCEPT) { + _session.set_dirty (); + } } - } void @@ -325,12 +343,16 @@ BundleManager::add_bundle (boost::shared_ptr b) (*i)[_list_model_columns.name] = u->name (); (*i)[_list_model_columns.bundle] = u; - u->NameChanged.connect (sigc::bind (sigc::mem_fun (*this, &BundleManager::bundle_name_changed), u)); + u->Changed.connect (sigc::bind (sigc::mem_fun (*this, &BundleManager::bundle_changed), u)); } void -BundleManager::bundle_name_changed (boost::shared_ptr b) +BundleManager::bundle_changed (ARDOUR::Bundle::Change c, boost::shared_ptr b) { + if ((c & ARDOUR::Bundle::NameChanged) == 0) { + return; + } + Gtk::TreeModel::iterator i = _list_model->children().begin (); while (i != _list_model->children().end()) { boost::shared_ptr t = (*i)[_list_model_columns.bundle]; diff --git a/gtk2_ardour/bundle_manager.h b/gtk2_ardour/bundle_manager.h index aa13967bff..266e9eadad 100644 --- a/gtk2_ardour/bundle_manager.h +++ b/gtk2_ardour/bundle_manager.h @@ -47,7 +47,8 @@ class BundleEditorMatrix : public PortMatrix return d == OURS; } void rename_channel (ARDOUR::BundleChannel); - void setup (); + void setup_ports (int); + bool list_is_global (int) const; private: enum { @@ -90,7 +91,7 @@ class BundleManager : public ArdourDialog void edit_clicked (); void delete_clicked (); void add_bundle (boost::shared_ptr); - void bundle_name_changed (boost::shared_ptr); + void bundle_changed (ARDOUR::Bundle::Change, boost::shared_ptr); void set_button_sensitivity (); class ModelColumns : public Gtk::TreeModelColumnRecord diff --git a/gtk2_ardour/global_port_matrix.cc b/gtk2_ardour/global_port_matrix.cc index 4cd6a78aea..24ff101c61 100644 --- a/gtk2_ardour/global_port_matrix.cc +++ b/gtk2_ardour/global_port_matrix.cc @@ -27,16 +27,15 @@ GlobalPortMatrix::GlobalPortMatrix (ARDOUR::Session& s, ARDOUR::DataType t) : PortMatrix (s, t) { - setup (); + setup_all_ports (); } void -GlobalPortMatrix::setup () +GlobalPortMatrix::setup_ports (int dim) { - _ports[IN].gather (_session, true); - _ports[OUT].gather (_session, false); - - PortMatrix::setup (); + _ports[dim].suspend_signals (); + _ports[dim].gather (_session, dim == IN); + _ports[dim].resume_signals (); } void @@ -70,12 +69,14 @@ GlobalPortMatrix::set_state (ARDOUR::BundleChannel c[2], bool s) } } - PortMatrix::State GlobalPortMatrix::get_state (ARDOUR::BundleChannel c[2]) const { ARDOUR::Bundle::PortList const & in_ports = c[IN].bundle->channel_ports (c[IN].channel); ARDOUR::Bundle::PortList const & out_ports = c[OUT].bundle->channel_ports (c[OUT].channel); + if (in_ports.empty() || out_ports.empty()) { + return NOT_ASSOCIATED; + } for (ARDOUR::Bundle::PortList::const_iterator i = in_ports.begin(); i != in_ports.end(); ++i) { for (ARDOUR::Bundle::PortList::const_iterator j = out_ports.begin(); j != out_ports.end(); ++j) { diff --git a/gtk2_ardour/global_port_matrix.h b/gtk2_ardour/global_port_matrix.h index fe7f56394e..cb402fc3cf 100644 --- a/gtk2_ardour/global_port_matrix.h +++ b/gtk2_ardour/global_port_matrix.h @@ -29,7 +29,7 @@ class GlobalPortMatrix : public PortMatrix public: GlobalPortMatrix (ARDOUR::Session&, ARDOUR::DataType); - void setup (); + void setup_ports (int); void set_state (ARDOUR::BundleChannel c[2], bool); State get_state (ARDOUR::BundleChannel c[2]) const; @@ -43,6 +43,10 @@ public: return false; } + bool list_is_global (int) const { + return true; + } + private: /* see PortMatrix: signal flow from 0 to 1 (out to in) */ enum { diff --git a/gtk2_ardour/io_selector.cc b/gtk2_ardour/io_selector.cc index 1f529cf3c5..76892dcd3d 100644 --- a/gtk2_ardour/io_selector.cc +++ b/gtk2_ardour/io_selector.cc @@ -46,9 +46,6 @@ IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr , _io (io) , _find_inputs_for_io_outputs (in) { - /* Listen for ports changing on the IO */ - _io->PortCountChanged.connect (sigc::hide (mem_fun (*this, &IOSelector::ports_changed))); - /* signal flow from 0 to 1 */ if (_find_inputs_for_io_outputs) { _other = 1; @@ -61,54 +58,27 @@ IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr _port_group = boost::shared_ptr (new PortGroup ("")); _ports[_ours].add_group (_port_group); - setup (); + setup_all_ports (); } void -IOSelector::setup () +IOSelector::setup_ports (int dim) { - _ports[_other].gather (_session, _find_inputs_for_io_outputs); - - _port_group->clear (); - _port_group->add_bundle (boost::shared_ptr (new ARDOUR::Bundle)); - _port_group->only_bundle()->set_name (_io->name()); + _ports[dim].suspend_signals (); - if (_find_inputs_for_io_outputs) { - const PortSet& ps (_io->outputs()); - - int j = 0; - for (PortSet::const_iterator i = ps.begin(); i != ps.end(); ++i) { - char buf[32]; - snprintf (buf, sizeof(buf), _("out %d"), j + 1); - _port_group->only_bundle()->add_channel (buf); - _port_group->only_bundle()->add_port_to_channel (j, _session.engine().make_port_name_non_relative (i->name())); - ++j; - } + if (dim == _other) { + + _ports[_other].gather (_session, _find_inputs_for_io_outputs); } else { - - const PortSet& ps (_io->inputs()); - - int j = 0; - for (PortSet::const_iterator i = ps.begin(); i != ps.end(); ++i) { - char buf[32]; - snprintf (buf, sizeof(buf), _("in %d"), j + 1); - _port_group->only_bundle()->add_channel (buf); - _port_group->only_bundle()->add_port_to_channel (j, _session.engine().make_port_name_non_relative (i->name())); - ++j; - } + _port_group->clear (); + _port_group->add_bundle ( + _find_inputs_for_io_outputs ? _io->bundle_for_outputs() : _io->bundle_for_inputs() + ); } - PortMatrix::setup (); -} - -void -IOSelector::ports_changed () -{ - ENSURE_GUI_THREAD (mem_fun (*this, &IOSelector::ports_changed)); - - setup (); + _ports[dim].resume_signals (); } void @@ -245,6 +215,12 @@ IOSelector::remove_channel (ARDOUR::BundleChannel bc) } } +bool +IOSelector::list_is_global (int dim) const +{ + return (dim == _other); +} + IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr io, bool for_input, bool can_cancel) : ArdourDialog ("I/O selector") , _selector (session, io, !for_input) @@ -277,7 +253,7 @@ IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr< /* 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)); + rescan_button.signal_clicked().connect (sigc::mem_fun (*this, &IOSelectorWindow::rescan)); get_action_area()->pack_start (rescan_button, false, false); io->PortCountChanged.connect (sigc::hide (mem_fun (*this, &IOSelectorWindow::ports_changed))); @@ -324,6 +300,12 @@ IOSelectorWindow::ports_changed () } } +void +IOSelectorWindow::rescan () +{ + _selector.setup_ports (_selector.other()); +} + void IOSelectorWindow::cancel () { @@ -341,7 +323,7 @@ IOSelectorWindow::accept () void IOSelectorWindow::on_map () { - _selector.setup (); + _selector.setup_all_ports (); Window::on_map (); } @@ -372,8 +354,8 @@ PortInsertUI::PortInsertUI (ARDOUR::Session& sess, boost::shared_ptr const io () { return _io; } - void setup (); + void setup_ports (int); + bool list_is_global (int) const; bool find_inputs_for_io_outputs () const { return _find_inputs_for_io_outputs; } + int ours () const { + return _ours; + } + + int other () const { + return _other; + } + + private: int _other; int _ours; - boost::shared_ptr _io; boost::shared_ptr _port_group; bool _find_inputs_for_io_outputs; - - void ports_changed (); }; class IOSelectorWindow : public ArdourDialog @@ -89,7 +96,8 @@ class IOSelectorWindow : public ArdourDialog void cancel (); void accept (); - + void rescan (); + void ports_changed (); void io_name_changed (void *src); }; diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc index 52d6d6a089..3ff074f9d7 100644 --- a/gtk2_ardour/port_group.cc +++ b/gtk2_ardour/port_group.cc @@ -23,6 +23,7 @@ #include "ardour/audio_track.h" #include "ardour/audioengine.h" #include "ardour/bundle.h" +#include "ardour/user_bundle.h" #include "ardour/io_processor.h" #include "ardour/midi_track.h" #include "ardour/port.h" @@ -36,6 +37,15 @@ using namespace std; using namespace Gtk; +/** PortGroup constructor. + * @param n Name. + */ +PortGroup::PortGroup (std::string const & n) + : name (n), _visible (true) +{ + +} + /** Add a bundle to a group. * @param b Bundle. */ @@ -45,25 +55,47 @@ PortGroup::add_bundle (boost::shared_ptr b) assert (b.get()); _bundles.push_back (b); + _bundle_changed_connections[b] = + b->Changed.connect (sigc::mem_fun (*this, &PortGroup::bundle_changed)); + Modified (); } -/** Add a port to a group. - * @param p Port. - */ void -PortGroup::add_port (std::string const &p) +PortGroup::remove_bundle (boost::shared_ptr b) { - ports.push_back (p); + assert (b.get()); + ARDOUR::BundleList::iterator i = std::find (_bundles.begin(), _bundles.end(), b); + if (i == _bundles.end()) { + return; + } + + _bundles.erase (i); + _bundle_changed_connections[b].disconnect (); + Modified (); } +void +PortGroup::bundle_changed (ARDOUR::Bundle::Change c) +{ + BundleChanged (c); +} + + void PortGroup::clear () { _bundles.clear (); - ports.clear (); + + for (ConnectionList::iterator i = _bundle_changed_connections.begin(); i != _bundle_changed_connections.end(); ++i) { + + i->second.disconnect (); + + } + + _bundle_changed_connections.clear (); Modified (); } @@ -77,12 +109,6 @@ PortGroup::has_port (std::string const& p) const } } - for (vector::const_iterator i = ports.begin(); i != ports.end(); ++i) { - if (*i == p) { - return true; - } - } - return false; } @@ -95,15 +121,13 @@ PortGroup::only_bundle () uint32_t -PortGroup::total_ports () const +PortGroup::total_channels () const { uint32_t n = 0; for (ARDOUR::BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) { n += (*i)->nchannels (); } - n += ports.size(); - return n; } @@ -111,7 +135,7 @@ PortGroup::total_ports () const /** PortGroupList constructor. */ PortGroupList::PortGroupList () - : _type (ARDOUR::DataType::AUDIO), _bundles_dirty (true) + : _type (ARDOUR::DataType::AUDIO), _signals_suspended (false), _pending_change (false) { } @@ -134,20 +158,20 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs) boost::shared_ptr system (new PortGroup (_("System"))); boost::shared_ptr other (new PortGroup (_("Other"))); - /* Find the bundles for routes. We take their bundles, copy them, - and add ports from the route's processors */ + /* Find the bundles for routes. We use the RouteBundle class to join + the route's IO bundles and processor bundles together so that they + are presented as one bundle in the matrix. */ boost::shared_ptr routes = session.get_routes (); for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) { - /* Copy the appropriate bundle from the route */ - boost::shared_ptr bundle ( - new ARDOUR::Bundle ( - inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs () + + boost::shared_ptr rb ( + new RouteBundle ( + inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs() ) ); - /* Add ports from the route's processors */ uint32_t n = 0; while (1) { boost::shared_ptr p = (*i)->nth_processor (n); @@ -158,9 +182,10 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs) boost::shared_ptr iop = boost::dynamic_pointer_cast (p); if (iop) { - boost::shared_ptr pb = inputs ? - iop->io()->bundle_for_inputs() : iop->io()->bundle_for_outputs(); - bundle->add_channels_from_bundle (pb); + rb->add_processor_bundle ( + inputs ? iop->io()->bundle_for_inputs() : iop->io()->bundle_for_outputs() + ); + } ++n; @@ -187,22 +212,29 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs) } if (g) { - g->add_bundle (bundle); + g->add_bundle (rb); } } - /* Bundles created by the session. We only add the mono ones, + /* Bundles owned by the session. We only add the mono ones and the User ones otherwise there is duplication of the same ports within the matrix */ boost::shared_ptr b = session.bundles (); for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { - if ((*i)->nchannels() == 1 && (*i)->ports_are_inputs() == inputs && (*i)->type() == _type) { - system->add_bundle (*i); + if ((*i)->ports_are_inputs() == inputs && (*i)->type() == _type) { + + if ((*i)->nchannels() == 1 || boost::dynamic_pointer_cast (*i)) { + system->add_bundle (*i); + } + } } /* Now find all other ports that we haven't thought of yet */ + std::vector extra_system; + std::vector extra_other; + const char **ports = session.engine().get_ports ("", _type.to_jack_type(), inputs ? JackPortIsInput : JackPortIsOutput); if (ports) { @@ -222,9 +254,9 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs) if (port_has_prefix (p, "system:") || port_has_prefix (p, "alsa_pcm") || port_has_prefix (p, "ardour:")) { - system->add_port (p); + extra_system.push_back (p); } else { - other->add_port (p); + extra_other.push_back (p); } } @@ -234,12 +266,38 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs) free (ports); } + if (!extra_system.empty()) { + system->add_bundle (make_bundle_from_ports (extra_system, inputs)); + } + + if (!extra_other.empty()) { + other->add_bundle (make_bundle_from_ports (extra_other, inputs)); + } + add_group (system); add_group (bus); add_group (track); add_group (other); - _bundles_dirty = true; + emit_changed (); +} + +boost::shared_ptr +PortGroupList::make_bundle_from_ports (std::vector const & p, bool inputs) const +{ + boost::shared_ptr b (new ARDOUR::Bundle ("", _type, inputs)); + + std::string const pre = common_prefix (p); + if (!pre.empty()) { + b->set_name (pre.substr (0, pre.length() - 1)); + } + + for (uint32_t j = 0; j < p.size(); ++j) { + b->add_channel (p[j].substr (pre.length())); + b->set_port (j, p[j]); + } + + return b; } bool @@ -247,75 +305,47 @@ PortGroupList::port_has_prefix (const std::string& n, const std::string& p) cons { return n.substr (0, p.length()) == p; } - -void -PortGroupList::update_bundles () const +std::string +PortGroupList::common_prefix_before (std::vector const & p, std::string const & s) const { - _bundles.clear (); - - for (PortGroupList::List::const_iterator i = begin (); i != end (); ++i) { - if ((*i)->visible()) { - - std::copy ((*i)->bundles().begin(), (*i)->bundles().end(), std::back_inserter (_bundles)); - - /* make a bundle for the ports, if there are any */ - if (!(*i)->ports.empty()) { + /* we must have some strings and the first must contain the separator string */ + if (p.empty() || p[0].find_first_of (s) == std::string::npos) { + return ""; + } - boost::shared_ptr 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)); - } + /* prefix of the first string */ + std::string const fp = p[0].substr (0, p[0].find_first_of (s) + 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); - } - - _bundles.push_back (b); - } + /* see if the other strings also start with fp */ + uint32_t j = 1; + while (j < p.size()) { + if (p[j].substr (0, fp.length()) != fp) { + break; } + ++j; + } + + if (j != p.size()) { + return ""; } - _bundles_dirty = false; + return fp; } + std::string PortGroupList::common_prefix (std::vector 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; - } + std::string cp = common_prefix_before (p, "/"); + if (!cp.empty()) { + return cp; } - - /* 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; - } + + cp = common_prefix_before (p, ":"); + if (!cp.empty()) { + return cp; } return ""; @@ -325,43 +355,134 @@ void PortGroupList::clear () { _groups.clear (); - _bundles_dirty = true; + + for (std::vector::iterator i = _bundle_changed_connections.begin(); i != _bundle_changed_connections.end(); ++i) { + i->disconnect (); + } + + _bundle_changed_connections.clear (); + + emit_changed (); } + ARDOUR::BundleList const & PortGroupList::bundles () const { - if (_bundles_dirty) { - update_bundles (); + _bundles.clear (); + + for (PortGroupList::List::const_iterator i = begin (); i != end (); ++i) { + if ((*i)->visible()) { + std::copy ((*i)->bundles().begin(), (*i)->bundles().end(), std::back_inserter (_bundles)); + } } return _bundles; } uint32_t -PortGroupList::total_visible_ports () const +PortGroupList::total_visible_channels () const { uint32_t n = 0; for (PortGroupList::List::const_iterator i = begin(); i != end(); ++i) { if ((*i)->visible()) { - n += (*i)->total_ports (); + n += (*i)->total_channels (); } } return n; } + void -PortGroupList::group_modified () +PortGroupList::add_group (boost::shared_ptr g) { - _bundles_dirty = true; + _groups.push_back (g); + + g->Modified.connect (sigc::mem_fun (*this, &PortGroupList::emit_changed)); + + _bundle_changed_connections.push_back ( + g->BundleChanged.connect (sigc::hide (sigc::mem_fun (*this, &PortGroupList::emit_changed))) + ); + + emit_changed (); } void -PortGroupList::add_group (boost::shared_ptr g) +PortGroupList::remove_bundle (boost::shared_ptr b) { - _groups.push_back (g); - g->Modified.connect (sigc::mem_fun (*this, &PortGroupList::group_modified)); - _bundles_dirty = true; + for (List::iterator i = _groups.begin(); i != _groups.end(); ++i) { + (*i)->remove_bundle (b); + } + + emit_changed (); +} + +void +PortGroupList::emit_changed () +{ + if (_signals_suspended) { + _pending_change = true; + } else { + Changed (); + } } + +void +PortGroupList::suspend_signals () +{ + _signals_suspended = true; +} + +void +PortGroupList::resume_signals () +{ + if (_pending_change) { + Changed (); + _pending_change = false; + } + + _signals_suspended = false; +} + +RouteBundle::RouteBundle (boost::shared_ptr r) + : _route (r) +{ + _route->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles))); + reread_component_bundles (); +} + +void +RouteBundle::reread_component_bundles () +{ + suspend_signals (); + + remove_channels (); + + set_name (_route->name()); + + for (uint32_t i = 0; i < _route->nchannels(); ++i) { + add_channel (_route->channel_name (i)); + PortList const & pl = _route->channel_ports (i); + for (uint32_t j = 0; j < pl.size(); ++j) { + add_port_to_channel (i, pl[j]); + } + } + + for (std::vector >::iterator i = _processor.begin(); i != _processor.end(); ++i) { + add_channels_from_bundle (*i); + } + + resume_signals (); +} + +void +RouteBundle::add_processor_bundle (boost::shared_ptr p) +{ + p->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles))); + _processor.push_back (p); + + reread_component_bundles (); +} + diff --git a/gtk2_ardour/port_group.h b/gtk2_ardour/port_group.h index c2961c4925..c2daae341a 100644 --- a/gtk2_ardour/port_group.h +++ b/gtk2_ardour/port_group.h @@ -42,20 +42,15 @@ class PortMatrix; class PortGroup : public sigc::trackable { public: - /** PortGroup constructor. - * @param n Name. - */ - PortGroup (std::string const & n) - : name (n), _visible (true) {} + PortGroup (std::string const & n); void add_bundle (boost::shared_ptr); + void remove_bundle (boost::shared_ptr); boost::shared_ptr only_bundle (); - void add_port (std::string const &); void clear (); - uint32_t total_ports () const; + uint32_t total_channels () const; std::string name; ///< name for the group - std::vector ports; ARDOUR::BundleList const & bundles () const { return _bundles; @@ -73,14 +68,21 @@ public: bool has_port (std::string const &) const; sigc::signal Modified; + sigc::signal BundleChanged; -private: +private: + void bundle_changed (ARDOUR::Bundle::Change); + ARDOUR::BundleList _bundles; + + typedef std::map, sigc::connection> ConnectionList; + ConnectionList _bundle_changed_connections; + bool _visible; ///< true if the group is visible in the UI }; /// A list of PortGroups -class PortGroupList +class PortGroupList : public sigc::trackable { public: PortGroupList (); @@ -90,14 +92,17 @@ class PortGroupList void add_group (boost::shared_ptr); void set_type (ARDOUR::DataType); void gather (ARDOUR::Session &, bool); - void set_offer_inputs (bool); ARDOUR::BundleList const & bundles () const; void clear (); - uint32_t total_visible_ports () const; + void remove_bundle (boost::shared_ptr); + uint32_t total_visible_channels () const; uint32_t size () const { return _groups.size(); } + void suspend_signals (); + void resume_signals (); + List::const_iterator begin () const { return _groups.begin(); } @@ -105,18 +110,37 @@ class PortGroupList List::const_iterator end () const { return _groups.end(); } - + + sigc::signal Changed; + private: bool port_has_prefix (std::string const &, std::string const &) const; std::string common_prefix (std::vector const &) const; - void update_bundles () const; - void group_modified (); + std::string common_prefix_before (std::vector const &, std::string const &) const; + void emit_changed (); + boost::shared_ptr make_bundle_from_ports (std::vector const &, bool) const; ARDOUR::DataType _type; - bool _offer_inputs; mutable ARDOUR::BundleList _bundles; - mutable bool _bundles_dirty; List _groups; + std::vector _bundle_changed_connections; + bool _signals_suspended; + bool _pending_change; +}; + + +class RouteBundle : public ARDOUR::Bundle +{ +public: + RouteBundle (boost::shared_ptr); + + void add_processor_bundle (boost::shared_ptr); + +private: + void reread_component_bundles (); + + boost::shared_ptr _route; + std::vector > _processor; }; #endif /* __gtk_ardour_port_group_h__ */ diff --git a/gtk2_ardour/port_matrix.cc b/gtk2_ardour/port_matrix.cc index 6c04b8feb4..2ca3c7cd76 100644 --- a/gtk2_ardour/port_matrix.cc +++ b/gtk2_ardour/port_matrix.cc @@ -48,9 +48,13 @@ PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type) _column_index (1) { _body = new PortMatrixBody (this); - - _ports[0].set_type (type); - _ports[1].set_type (type); + + for (int i = 0; i < 2; ++i) { + _ports[i].set_type (type); + + /* watch for the content of _ports[] changing */ + _ports[i].Changed.connect (sigc::mem_fun (*this, &PortMatrix::setup)); + } _row_visibility_box.pack_start (_row_visibility_label, Gtk::PACK_SHRINK); _column_visibility_box.pack_start (_column_visibility_label, Gtk::PACK_SHRINK); @@ -60,6 +64,9 @@ PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type) /* watch for routes being added or removed */ _session.RouteAdded.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrix::routes_changed))); + + /* and also bundles */ + _session.BundleAdded.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrix::setup_global_ports))); reconnect_to_routes (); @@ -93,7 +100,7 @@ PortMatrix::reconnect_to_routes () boost::shared_ptr routes = _session.get_routes (); for (ARDOUR::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { _route_connections.push_back ( - (*i)->processors_changed.connect (sigc::mem_fun (*this, &PortMatrix::setup)) + (*i)->processors_changed.connect (sigc::mem_fun (*this, &PortMatrix::setup_global_ports)) ); } } @@ -103,10 +110,10 @@ void PortMatrix::routes_changed () { reconnect_to_routes (); - setup (); + setup_global_ports (); } -/** Set up everything that changes about the matrix */ +/** Set up everything that depends on the content of _ports[] */ void PortMatrix::setup () { @@ -235,7 +242,8 @@ PortMatrix::set_type (ARDOUR::DataType t) _type = t; _ports[0].set_type (_type); _ports[1].set_type (_type); - setup (); + + setup_all_ports (); } void @@ -300,11 +308,11 @@ void PortMatrix::select_arrangement () { uint32_t const N[2] = { - _ports[0].total_visible_ports (), - _ports[1].total_visible_ports () + _ports[0].total_visible_channels (), + _ports[1].total_visible_channels () }; - /* The list with the most ports goes on left or right, so that the most port + /* The list with the most channels goes on left or right, so that the most channel names are printed horizontally and hence more readable. However we also maintain notional `signal flow' vaguely from left to right. Subclasses should choose where to put ports based on signal flowing from _ports[0] @@ -380,6 +388,7 @@ PortMatrix::popup_channel_context_menu (int dim, uint32_t N, uint32_t t) if (bc.bundle) { char buf [64]; + bool have_one = false; if (can_rename_channels (dim)) { snprintf (buf, sizeof (buf), _("Rename '%s'..."), bc.bundle->channel_name (bc.channel).c_str()); @@ -390,6 +399,8 @@ PortMatrix::popup_channel_context_menu (int dim, uint32_t N, uint32_t t) sigc::bind (sigc::mem_fun (*this, &PortMatrix::rename_channel_proxy), w, bc.channel) ) ); + + have_one = true; } if (can_remove_channels (dim)) { @@ -401,7 +412,20 @@ PortMatrix::popup_channel_context_menu (int dim, uint32_t N, uint32_t t) sigc::bind (sigc::mem_fun (*this, &PortMatrix::remove_channel_proxy), w, bc.channel) ) ); + + have_one = true; + } + + if (have_one) { + items.push_back (Gtk::Menu_Helpers::SeparatorElem ()); } + + boost::weak_ptr w (bc.bundle); + items.push_back (Gtk::Menu_Helpers::MenuElem ( + _("Disassociate all"), + sigc::bind (sigc::mem_fun (*this, &PortMatrix::disassociate_all_on_channel), w, bc.channel, dim) + ) + ); _menu->popup (1, t); } @@ -431,3 +455,43 @@ PortMatrix::rename_channel_proxy (boost::weak_ptr b, uint32_t c) rename_channel (ARDOUR::BundleChannel (sb, c)); } + +void +PortMatrix::disassociate_all_on_channel (boost::weak_ptr bundle, uint32_t channel, int dim) +{ + boost::shared_ptr sb = bundle.lock (); + if (!sb) { + return; + } + + ARDOUR::BundleList a = _ports[1-dim].bundles (); + + for (ARDOUR::BundleList::iterator i = a.begin(); i != a.end(); ++i) { + for (uint32_t j = 0; j < (*i)->nchannels(); ++j) { + + ARDOUR::BundleChannel c[2]; + c[dim] = ARDOUR::BundleChannel (sb, channel); + c[1-dim] = ARDOUR::BundleChannel (*i, j); + + set_state (c, false); + } + } +} + +void +PortMatrix::setup_global_ports () +{ + for (int i = 0; i < 2; ++i) { + if (list_is_global (i)) { + setup_ports (i); + } + } +} + + +void +PortMatrix::setup_all_ports () +{ + setup_ports (0); + setup_ports (1); +} diff --git a/gtk2_ardour/port_matrix.h b/gtk2_ardour/port_matrix.h index a789ea6203..8514306544 100644 --- a/gtk2_ardour/port_matrix.h +++ b/gtk2_ardour/port_matrix.h @@ -89,7 +89,9 @@ public: return &_ports[d]; } - virtual void setup (); + void setup (); + virtual void setup_ports (int) = 0; + void setup_all_ports (); /** @param c Channels; where c[0] is from _ports[0] and c[1] is from _ports[1]. * @param s New state. @@ -106,6 +108,7 @@ public: * @return state */ virtual State get_state (ARDOUR::BundleChannel c[2]) const = 0; + virtual bool list_is_global (int) const = 0; virtual void add_channel (boost::shared_ptr) = 0; virtual bool can_remove_channels (int) const = 0; @@ -141,6 +144,8 @@ private: void select_arrangement (); void remove_channel_proxy (boost::weak_ptr, uint32_t); void rename_channel_proxy (boost::weak_ptr, uint32_t); + void disassociate_all_on_channel (boost::weak_ptr, uint32_t, int); + void setup_global_ports (); /// port type that we are working with ARDOUR::DataType _type; diff --git a/gtk2_ardour/port_matrix_body.cc b/gtk2_ardour/port_matrix_body.cc index 4d7720207b..3f8fcdc0c6 100644 --- a/gtk2_ardour/port_matrix_body.cc +++ b/gtk2_ardour/port_matrix_body.cc @@ -59,7 +59,7 @@ PortMatrixBody::on_expose_event (GdkEventExpose* event) Gdk::Rectangle r = exposure; /* the get_pixmap call may cause things to be rerendered and sizes to change, - so fetch the pixmaps before calculating where to put it */ + so fetch the pixmap before calculating where to put it */ GdkPixmap* p = _column_labels->get_pixmap (get_window()->gobj()); r.intersect (_column_labels->parent_rectangle(), intersects); @@ -278,7 +278,7 @@ PortMatrixBody::setup () for (ARDOUR::BundleList::iterator i = r.begin(); i != r.end(); ++i) { _bundle_connections.push_back ( - (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_row_labels)) + (*i)->Changed.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_row_labels))) ); } @@ -286,7 +286,7 @@ PortMatrixBody::setup () ARDOUR::BundleList c = _matrix->columns()->bundles (); for (ARDOUR::BundleList::iterator i = c.begin(); i != c.end(); ++i) { _bundle_connections.push_back ( - (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_column_labels)) + (*i)->Changed.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_column_labels))) ); } diff --git a/gtk2_ardour/port_matrix_column_labels.cc b/gtk2_ardour/port_matrix_column_labels.cc index 06a635b41d..2790c0537e 100644 --- a/gtk2_ardour/port_matrix_column_labels.cc +++ b/gtk2_ardour/port_matrix_column_labels.cc @@ -134,16 +134,12 @@ PortMatrixColumnLabels::render (cairo_t* cr) int g = 0; for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) { - if (!(*i)->visible() || ((*i)->bundles().empty() && (*i)->ports.empty()) ) { + if (!(*i)->visible() || (*i)->bundles().empty()) { continue; } /* compute width of this group */ - uint32_t w = 0; - for (ARDOUR::BundleList::const_iterator j = (*i)->bundles().begin(); j != (*i)->bundles().end(); ++j) { - w += (*j)->nchannels() * column_width(); - } - w += (*i)->ports.size() * column_width(); + uint32_t w = (*i)->total_channels() * column_width(); /* rectangle */ set_source_rgb (cr, get_a_group_colour (g)); @@ -413,15 +409,14 @@ PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc) ); } - - + } } void PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t) { - uint32_t N = _matrix->columns()->total_visible_ports (); + uint32_t N = _matrix->columns()->total_visible_channels (); uint32_t i = 0; for (; i < N; ++i) { @@ -453,19 +448,8 @@ PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t) _body->highlight_associated_channels (_matrix->column_index(), i); break; case 3: - maybe_popup_context_menu (i, t); + _matrix->popup_channel_context_menu (_matrix->column_index(), i, t); break; } } - -void -PortMatrixColumnLabels::maybe_popup_context_menu (int i, uint32_t t) -{ - if (!_matrix->can_rename_channels (_matrix->column_index()) && - !_matrix->can_remove_channels (_matrix->column_index())) { - return; - } - - _matrix->popup_channel_context_menu (_matrix->column_index(), i, t); -} diff --git a/gtk2_ardour/port_matrix_column_labels.h b/gtk2_ardour/port_matrix_column_labels.h index 4cf59ad732..c58a1e5054 100644 --- a/gtk2_ardour/port_matrix_column_labels.h +++ b/gtk2_ardour/port_matrix_column_labels.h @@ -49,7 +49,6 @@ private: double channel_x (ARDOUR::BundleChannel const &) const; double channel_y (ARDOUR::BundleChannel const &) const; void queue_draw_for (ARDOUR::BundleChannel const &); - void maybe_popup_context_menu (int, uint32_t); void render (cairo_t *); void compute_dimensions (); diff --git a/gtk2_ardour/port_matrix_row_labels.cc b/gtk2_ardour/port_matrix_row_labels.cc index 8d5b31693b..98b185591d 100644 --- a/gtk2_ardour/port_matrix_row_labels.cc +++ b/gtk2_ardour/port_matrix_row_labels.cc @@ -104,16 +104,12 @@ PortMatrixRowLabels::render (cairo_t* cr) int g = 0; for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) { - if (!(*i)->visible() || ((*i)->bundles().empty() && (*i)->ports.empty()) ) { + if (!(*i)->visible() || (*i)->bundles().empty()) { continue; } /* compute height of this group */ - double h = 0; - for (ARDOUR::BundleList::const_iterator j = (*i)->bundles().begin(); j != (*i)->bundles().end(); ++j) { - h += (*j)->nchannels() * row_height(); - } - h += (*i)->ports.size() * row_height(); + double h = (*i)->total_channels () * row_height(); /* rectangle */ set_source_rgb (cr, get_a_group_colour (g)); @@ -202,11 +198,6 @@ PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t) void PortMatrixRowLabels::maybe_popup_context_menu (double x, double y, uint32_t t) { - if (!_matrix->can_rename_channels (_matrix->row_index()) && - !_matrix->can_remove_channels (_matrix->row_index())) { - return; - } - if ( (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x > (_longest_bundle_name + name_pad() * 2)) || (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x < (_longest_port_name + name_pad() * 2)) ) { -- cgit v1.2.3