X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fport_matrix.cc;h=81a62d52c808c81e6daf0e11ea3e89ff42723fc6;hb=a7f4f660956250cc98cc519321ad5b8e715f9d0f;hp=2ca3c7cd76e60485cebac98231332d22a6b45371;hpb=ee42a6dd97045253d1a9bb32fc2e571d235f9967;p=ardour.git diff --git a/gtk2_ardour/port_matrix.cc b/gtk2_ardour/port_matrix.cc index 2ca3c7cd76..81a62d52c8 100644 --- a/gtk2_ardour/port_matrix.cc +++ b/gtk2_ardour/port_matrix.cc @@ -24,28 +24,37 @@ #include #include #include +#include #include "ardour/bundle.h" #include "ardour/types.h" #include "ardour/session.h" #include "ardour/route.h" #include "port_matrix.h" #include "port_matrix_body.h" +#include "port_matrix_component.h" #include "i18n.h" +using namespace std; +using namespace sigc; +using namespace Gtk; +using namespace ARDOUR; + /** PortMatrix constructor. * @param session Our session. * @param type Port type that we are handling. */ -PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type) - : _session (session), +PortMatrix::PortMatrix (Window* parent, Session& session, DataType type) + : Table (2, 2), + _session (session), + _parent (parent), _type (type), - _column_visibility_box_added (false), - _row_visibility_box_added (false), _menu (0), - _setup_once (false), _arrangement (TOP_TO_RIGHT), _row_index (0), - _column_index (1) + _column_index (1), + _min_height_divisor (1), + _show_only_bundles (false), + _inhibit_toggle_show_only_bundles (false) { _body = new PortMatrixBody (this); @@ -53,38 +62,30 @@ PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type) _ports[i].set_type (type); /* watch for the content of _ports[] changing */ - _ports[i].Changed.connect (sigc::mem_fun (*this, &PortMatrix::setup)); + _ports[i].Changed.connect (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); - - _hscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::hscroll_changed)); - _vscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::vscroll_changed)); + _hscroll.signal_value_changed().connect (mem_fun (*this, &PortMatrix::hscroll_changed)); + _vscroll.signal_value_changed().connect (mem_fun (*this, &PortMatrix::vscroll_changed)); /* watch for routes being added or removed */ - _session.RouteAdded.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrix::routes_changed))); + _session.RouteAdded.connect (sigc::hide (mem_fun (*this, &PortMatrix::routes_changed))); /* and also bundles */ - _session.BundleAdded.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrix::setup_global_ports))); + _session.BundleAdded.connect (sigc::hide (mem_fun (*this, &PortMatrix::setup_global_ports))); reconnect_to_routes (); + attach (*_body, 0, 1, 0, 1); + attach (_vscroll, 1, 2, 0, 1, SHRINK); + attach (_hscroll, 0, 1, 1, 2, FILL | EXPAND, SHRINK); + show_all (); } PortMatrix::~PortMatrix () { delete _body; - - for (std::vector::iterator i = _column_visibility_buttons.begin(); i != _column_visibility_buttons.end(); ++i) { - delete *i; - } - - for (std::vector::iterator i = _row_visibility_buttons.begin(); i != _row_visibility_buttons.end(); ++i) { - delete *i; - } - delete _menu; } @@ -92,15 +93,15 @@ PortMatrix::~PortMatrix () void PortMatrix::reconnect_to_routes () { - for (std::vector::iterator i = _route_connections.begin(); i != _route_connections.end(); ++i) { + for (vector::iterator i = _route_connections.begin(); i != _route_connections.end(); ++i) { i->disconnect (); } _route_connections.clear (); - boost::shared_ptr routes = _session.get_routes (); - for (ARDOUR::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { + boost::shared_ptr routes = _session.get_routes (); + for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { _route_connections.push_back ( - (*i)->processors_changed.connect (sigc::mem_fun (*this, &PortMatrix::setup_global_ports)) + (*i)->processors_changed.connect (mem_fun (*this, &PortMatrix::setup_global_ports)) ); } } @@ -117,127 +118,19 @@ PortMatrix::routes_changed () void PortMatrix::setup () { - select_arrangement (); + if ((get_flags () & Gtk::REALIZED) == 0) { + select_arrangement (); + } + _body->setup (); setup_scrollbars (); queue_draw (); - if (_setup_once) { - - /* we've set up before, so we need to clean up before re-setting-up */ - /* XXX: we ought to be able to do this by just getting a list of children - from each container widget, but I couldn't make that work */ - - for (std::vector::iterator i = _column_visibility_buttons.begin(); i != _column_visibility_buttons.end(); ++i) { - _column_visibility_box.remove (**i); - delete *i; - } - - _column_visibility_buttons.clear (); - - for (std::vector::iterator i = _row_visibility_buttons.begin(); i != _row_visibility_buttons.end(); ++i) { - _row_visibility_box.remove (**i); - delete *i; - } - - _row_visibility_buttons.clear (); - - _scroller_table.remove (_vscroll); - _scroller_table.remove (*_body); - _scroller_table.remove (_hscroll); - - _main_hbox.remove (_scroller_table); - if (_row_visibility_box_added) { - _main_hbox.remove (_row_visibility_box); - } - - if (_column_visibility_box_added) { - remove (_column_visibility_box); - } - remove (_main_hbox); - } - - if (_column_index == 0) { - _column_visibility_label.set_text (_("Show Outputs")); - _row_visibility_label.set_text (_("Show Inputs")); - } else { - _column_visibility_label.set_text (_("Show Inputs")); - _row_visibility_label.set_text (_("Show Outputs")); - } - - for (PortGroupList::List::const_iterator i = columns()->begin(); i != columns()->end(); ++i) { - Gtk::CheckButton* b = new Gtk::CheckButton ((*i)->name); - b->set_active ((*i)->visible()); - boost::weak_ptr w (*i); - b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &PortMatrix::visibility_toggled), w, b)); - _column_visibility_buttons.push_back (b); - _column_visibility_box.pack_start (*b, Gtk::PACK_SHRINK); - } - - for (PortGroupList::List::const_iterator i = rows()->begin(); i != rows()->end(); ++i) { - Gtk::CheckButton* b = new Gtk::CheckButton ((*i)->name); - b->set_active ((*i)->visible()); - boost::weak_ptr w (*i); - b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &PortMatrix::visibility_toggled), w, b)); - _row_visibility_buttons.push_back (b); - _row_visibility_box.pack_start (*b, Gtk::PACK_SHRINK); - } - - if (_arrangement == TOP_TO_RIGHT) { - - _scroller_table.attach (_hscroll, 0, 1, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK); - _scroller_table.attach (*_body, 0, 1, 1, 2); - _scroller_table.attach (_vscroll, 1, 2, 1, 2, Gtk::SHRINK); - - _main_hbox.pack_start (_scroller_table); - - if (rows()->size() > 1) { - _main_hbox.pack_start (_row_visibility_box, Gtk::PACK_SHRINK); - _row_visibility_box_added = true; - } else { - _row_visibility_box_added = false; - } - - if (columns()->size() > 1) { - pack_start (_column_visibility_box, Gtk::PACK_SHRINK); - _column_visibility_box_added = true; - } else { - _column_visibility_box_added = false; - } - - pack_start (_main_hbox); - - } else { - _scroller_table.attach (_vscroll, 0, 1, 0, 1, Gtk::SHRINK); - _scroller_table.attach (*_body, 1, 2, 0, 1); - _scroller_table.attach (_hscroll, 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK); - - if (rows()->size() > 1) { - _main_hbox.pack_start (_row_visibility_box, Gtk::PACK_SHRINK); - _row_visibility_box_added = true; - } else { - _row_visibility_box_added = false; - } - - _main_hbox.pack_start (_scroller_table); - - pack_start (_main_hbox); - - if (columns()->size() > 1) { - pack_start (_column_visibility_box, Gtk::PACK_SHRINK); - _column_visibility_box_added = true; - } else { - _column_visibility_box_added = false; - } - } - - _setup_once = true; - show_all (); } void -PortMatrix::set_type (ARDOUR::DataType t) +PortMatrix::set_type (DataType t) { _type = t; _ports[0].set_type (_type); @@ -261,7 +154,7 @@ PortMatrix::vscroll_changed () void PortMatrix::setup_scrollbars () { - Gtk::Adjustment* a = _hscroll.get_adjustment (); + Adjustment* a = _hscroll.get_adjustment (); a->set_lower (0); a->set_upper (_body->full_scroll_width()); a->set_page_size (_body->alloc_scroll_width()); @@ -280,20 +173,22 @@ PortMatrix::setup_scrollbars () void PortMatrix::disassociate_all () { - ARDOUR::BundleList a = _ports[0].bundles (); - ARDOUR::BundleList b = _ports[1].bundles (); - - for (ARDOUR::BundleList::iterator i = a.begin(); i != a.end(); ++i) { - for (uint32_t j = 0; j < (*i)->nchannels(); ++j) { - for (ARDOUR::BundleList::iterator k = b.begin(); k != b.end(); ++k) { - for (uint32_t l = 0; l < (*k)->nchannels(); ++l) { + PortGroup::BundleList a = _ports[0].bundles (); + PortGroup::BundleList b = _ports[1].bundles (); + + for (PortGroup::BundleList::iterator i = a.begin(); i != a.end(); ++i) { + for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) { + for (PortGroup::BundleList::iterator k = b.begin(); k != b.end(); ++k) { + for (uint32_t l = 0; l < k->bundle->nchannels(); ++l) { - ARDOUR::BundleChannel c[2] = { - ARDOUR::BundleChannel (*i, j), - ARDOUR::BundleChannel (*k, l) + BundleChannel c[2] = { + BundleChannel (i->bundle, j), + BundleChannel (k->bundle, l) }; - - set_state (c, false); + + if (get_state (c) == PortMatrixNode::ASSOCIATED) { + set_state (c, false); + } } } @@ -346,136 +241,200 @@ PortMatrix::rows () const return &_ports[_row_index]; } -/** A group visibility checkbutton has been toggled. - * @param w Group. - * @param b Button. - */ void -PortMatrix::visibility_toggled (boost::weak_ptr w, Gtk::CheckButton* b) +PortMatrix::popup_menu ( + pair, BundleChannel> column, + pair, BundleChannel> row, + uint32_t t + ) { - boost::shared_ptr g = w.lock (); - if (!g) { - return; - } + using namespace Menu_Helpers; - g->set_visible (b->get_active()); - _body->setup (); - setup_scrollbars (); - queue_draw (); -} - -void -PortMatrix::popup_channel_context_menu (int dim, uint32_t N, uint32_t t) -{ delete _menu; - _menu = new Gtk::Menu; + _menu = new Menu; _menu->set_name ("ArdourContextMenu"); - Gtk::Menu_Helpers::MenuList& items = _menu->items (); + MenuList& items = _menu->items (); - ARDOUR::BundleChannel bc; + boost::shared_ptr pg[2]; + pg[_column_index] = column.first; + pg[_row_index] = row.first; - ARDOUR::BundleList const r = _ports[dim].bundles(); - for (ARDOUR::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { - if (N < (*i)->nchannels ()) { - bc = ARDOUR::BundleChannel (*i, N); - break; - } else { - N -= (*i)->nchannels (); - } - } + BundleChannel bc[2]; + bc[_column_index] = column.second; + bc[_row_index] = row.second; - 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()); - boost::weak_ptr w (bc.bundle); - items.push_back ( - Gtk::Menu_Helpers::MenuElem ( - buf, - sigc::bind (sigc::mem_fun (*this, &PortMatrix::rename_channel_proxy), w, bc.channel) - ) - ); + char buf [64]; + bool need_separator = false; - have_one = true; - } + for (int dim = 0; dim < 2; ++dim) { + + if (bc[dim].bundle) { + + Menu* m = manage (new Menu); + MenuList& sub = m->items (); + + boost::weak_ptr w (bc[dim].bundle); - if (can_remove_channels (dim)) { - snprintf (buf, sizeof (buf), _("Remove '%s'"), bc.bundle->channel_name (bc.channel).c_str()); - boost::weak_ptr w (bc.bundle); - items.push_back ( - Gtk::Menu_Helpers::MenuElem ( - buf, - sigc::bind (sigc::mem_fun (*this, &PortMatrix::remove_channel_proxy), w, bc.channel) - ) + if (can_add_channel (bc[dim].bundle)) { + snprintf (buf, sizeof (buf), _("Add %s"), channel_noun().c_str()); + sub.push_back (MenuElem (buf, bind (mem_fun (*this, &PortMatrix::add_channel_proxy), w))); + } + + + if (can_rename_channels (bc[dim].bundle)) { + snprintf (buf, sizeof (buf), _("Rename '%s'..."), bc[dim].bundle->channel_name (bc[dim].channel).c_str()); + sub.push_back ( + MenuElem ( + buf, + bind (mem_fun (*this, &PortMatrix::rename_channel_proxy), w, bc[dim].channel) + ) + ); + } + + sub.push_back (SeparatorElem ()); + + if (can_remove_channels (bc[dim].bundle)) { + snprintf (buf, sizeof (buf), _("Remove '%s'"), bc[dim].bundle->channel_name (bc[dim].channel).c_str()); + sub.push_back ( + MenuElem ( + buf, + bind (mem_fun (*this, &PortMatrix::remove_channel_proxy), w, bc[dim].channel) + ) + ); + } + + if (_show_only_bundles) { + snprintf (buf, sizeof (buf), _("%s all"), disassociation_verb().c_str()); + } else { + snprintf ( + buf, sizeof (buf), _("%s all from '%s'"), + disassociation_verb().c_str(), + bc[dim].bundle->channel_name (bc[dim].channel).c_str() + ); + } + + sub.push_back ( + MenuElem (buf, bind (mem_fun (*this, &PortMatrix::disassociate_all_on_channel), w, bc[dim].channel, dim)) ); - have_one = true; + items.push_back (MenuElem (bc[dim].bundle->name().c_str(), *m)); + need_separator = 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) - ) - ); + } + + if (need_separator) { + items.push_back (SeparatorElem ()); + } + + need_separator = false; + + for (int dim = 0; dim < 2; ++dim) { + + if (pg[dim]) { + + boost::weak_ptr wp (pg[dim]); - _menu->popup (1, t); + if (pg[dim]->visible()) { + if (dim == 0) { + if (pg[dim]->name.empty()) { + snprintf (buf, sizeof (buf), _("Hide sources")); + } else { + snprintf (buf, sizeof (buf), _("Hide '%s' sources"), pg[dim]->name.c_str()); + } + } else { + if (pg[dim]->name.empty()) { + snprintf (buf, sizeof (buf), _("Hide destinations")); + } else { + snprintf (buf, sizeof (buf), _("Hide '%s' destinations"), pg[dim]->name.c_str()); + } + } + + items.push_back (MenuElem (buf, bind (mem_fun (*this, &PortMatrix::hide_group), wp))); + } else { + if (dim == 0) { + if (pg[dim]->name.empty()) { + snprintf (buf, sizeof (buf), _("Show sources")); + } else { + snprintf (buf, sizeof (buf), _("Show '%s' sources"), pg[dim]->name.c_str()); + } + } else { + if (pg[dim]->name.empty()) { + snprintf (buf, sizeof (buf), _("Show destinations")); + } else { + snprintf (buf, sizeof (buf), _("Show '%s' destinations"), pg[dim]->name.c_str()); + } + } + items.push_back (MenuElem (buf, bind (mem_fun (*this, &PortMatrix::show_group), wp))); + } + + need_separator = true; + } + } + + if (need_separator) { + items.push_back (SeparatorElem ()); } + + items.push_back (MenuElem (_("Rescan"), mem_fun (*this, &PortMatrix::setup_all_ports))); + items.push_back (CheckMenuElem (_("Show individual ports"), mem_fun (*this, &PortMatrix::toggle_show_only_bundles))); + CheckMenuItem* i = dynamic_cast (&items.back()); + _inhibit_toggle_show_only_bundles = true; + i->set_active (!_show_only_bundles); + _inhibit_toggle_show_only_bundles = false; + _menu->popup (1, t); } - void -PortMatrix::remove_channel_proxy (boost::weak_ptr b, uint32_t c) +PortMatrix::remove_channel_proxy (boost::weak_ptr b, uint32_t c) { - boost::shared_ptr sb = b.lock (); + boost::shared_ptr sb = b.lock (); if (!sb) { return; } - remove_channel (ARDOUR::BundleChannel (sb, c)); + remove_channel (BundleChannel (sb, c)); } void -PortMatrix::rename_channel_proxy (boost::weak_ptr b, uint32_t c) +PortMatrix::rename_channel_proxy (boost::weak_ptr b, uint32_t c) { - boost::shared_ptr sb = b.lock (); + boost::shared_ptr sb = b.lock (); if (!sb) { return; } - rename_channel (ARDOUR::BundleChannel (sb, c)); + rename_channel (BundleChannel (sb, c)); } void -PortMatrix::disassociate_all_on_channel (boost::weak_ptr bundle, uint32_t channel, int dim) +PortMatrix::disassociate_all_on_channel (boost::weak_ptr bundle, uint32_t channel, int dim) { - boost::shared_ptr sb = bundle.lock (); + boost::shared_ptr sb = bundle.lock (); if (!sb) { return; } - ARDOUR::BundleList a = _ports[1-dim].bundles (); + PortGroup::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) { + for (PortGroup::BundleList::iterator i = a.begin(); i != a.end(); ++i) { + for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) { - ARDOUR::BundleChannel c[2]; - c[dim] = ARDOUR::BundleChannel (sb, channel); - c[1-dim] = ARDOUR::BundleChannel (*i, j); + BundleChannel c[2]; + c[dim] = BundleChannel (sb, channel); + c[1-dim] = BundleChannel (i->bundle, j); - set_state (c, false); + if (get_state (c) == PortMatrixNode::ASSOCIATED) { + set_state (c, false); + } } } + + _body->rebuild_and_draw_grid (); } void @@ -488,10 +447,152 @@ PortMatrix::setup_global_ports () } } - void PortMatrix::setup_all_ports () { setup_ports (0); setup_ports (1); } + +void +PortMatrix::toggle_show_only_bundles () +{ + if (_inhibit_toggle_show_only_bundles) { + return; + } + + _show_only_bundles = !_show_only_bundles; + _body->setup (); + setup_scrollbars (); + queue_draw (); +} + +void +PortMatrix::hide_group (boost::weak_ptr w) +{ + boost::shared_ptr g = w.lock (); + if (!g) { + return; + } + + g->set_visible (false); +} + +void +PortMatrix::show_group (boost::weak_ptr w) +{ + boost::shared_ptr g = w.lock (); + if (!g) { + return; + } + + g->set_visible (true); +} + +pair +PortMatrix::max_size () const +{ + pair m = _body->max_size (); + + m.first += _vscroll.get_width (); + m.second += _hscroll.get_height (); + + return m; +} + +void +PortMatrix::setup_max_size () +{ + if (!_parent) { + return; + } + + pair const m = max_size (); + + GdkGeometry g; + g.max_width = m.first; + g.max_height = m.second; + + _parent->set_geometry_hints (*this, g, Gdk::HINT_MAX_SIZE); +} + +bool +PortMatrix::on_scroll_event (GdkEventScroll* ev) +{ + double const h = _hscroll.get_value (); + double const v = _vscroll.get_value (); + + switch (ev->direction) { + case GDK_SCROLL_UP: + _vscroll.set_value (v - PortMatrixComponent::grid_spacing ()); + break; + case GDK_SCROLL_DOWN: + _vscroll.set_value (v + PortMatrixComponent::grid_spacing ()); + break; + case GDK_SCROLL_LEFT: + _hscroll.set_value (h - PortMatrixComponent::grid_spacing ()); + break; + case GDK_SCROLL_RIGHT: + _hscroll.set_value (h + PortMatrixComponent::grid_spacing ()); + break; + } + + return true; +} + +boost::shared_ptr +PortMatrix::io_from_bundle (boost::shared_ptr b) const +{ + boost::shared_ptr io = _ports[0].io_from_bundle (b); + if (!io) { + io = _ports[1].io_from_bundle (b); + } + + return io; +} + +bool +PortMatrix::can_add_channel (boost::shared_ptr b) const +{ + return io_from_bundle (b); +} + +void +PortMatrix::add_channel (boost::shared_ptr b) +{ + boost::shared_ptr io = io_from_bundle (b); + + if (io) { + io->add_port ("", this, _type); + } +} + +bool +PortMatrix::can_remove_channels (boost::shared_ptr b) const +{ + return io_from_bundle (b); +} + +void +PortMatrix::remove_channel (ARDOUR::BundleChannel b) +{ + boost::shared_ptr io = io_from_bundle (b.bundle); + + if (io) { + Port* p = io->nth (b.channel); + if (p) { + io->remove_port (p, this); + } + } +} + +void +PortMatrix::add_channel_proxy (boost::weak_ptr w) +{ + boost::shared_ptr b = w.lock (); + if (!b) { + return; + } + + add_channel (b); +}