+
+void
+PortMatrix::add_remove_option (Menu_Helpers::MenuList& m, boost::weak_ptr<Bundle> w, int c)
+{
+ using namespace Menu_Helpers;
+
+ boost::shared_ptr<Bundle> b = w.lock ();
+ if (!b) {
+ return;
+ }
+
+ char buf [64];
+ snprintf (buf, sizeof (buf), _("Remove '%s'"), escape_underscores (b->channel_name (c)).c_str());
+ m.push_back (MenuElem (buf, sigc::bind (sigc::mem_fun (*this, &PortMatrix::remove_channel_proxy), w, c)));
+}
+
+void
+PortMatrix::add_disassociate_option (Menu_Helpers::MenuList& m, boost::weak_ptr<Bundle> w, int d, int c)
+{
+ using namespace Menu_Helpers;
+
+ boost::shared_ptr<Bundle> b = w.lock ();
+ if (!b) {
+ return;
+ }
+
+ char buf [64];
+ snprintf (buf, sizeof (buf), _("%s all from '%s'"), disassociation_verb().c_str(), escape_underscores (b->channel_name (c)).c_str());
+ m.push_back (MenuElem (buf, sigc::bind (sigc::mem_fun (*this, &PortMatrix::disassociate_all_on_channel), w, c, d)));
+}
+
+void
+PortMatrix::port_connected_or_disconnected ()
+{
+ _body->rebuild_and_draw_grid ();
+}
+
+string
+PortMatrix::channel_noun () const
+{
+ return _("channel");
+}
+
+/** @return true if this matrix should show bundles / ports of type \t */
+bool
+PortMatrix::should_show (DataType t) const
+{
+ return (_type == DataType::NIL || t == _type);
+}
+
+uint32_t
+PortMatrix::count_of_our_type (ChanCount c) const
+{
+ if (_type == DataType::NIL) {
+ return c.n_total ();
+ }
+
+ return c.get (_type);
+}
+
+/** @return The number of ports of our type in the given channel count,
+ * but returning 1 if there are no ports.
+ */
+uint32_t
+PortMatrix::count_of_our_type_min_1 (ChanCount c) const
+{
+ uint32_t n = count_of_our_type (c);
+ if (n == 0) {
+ n = 1;
+ }
+
+ return n;
+}
+
+PortMatrixNode::State
+PortMatrix::get_association (PortMatrixNode node) const
+{
+ if (show_only_bundles ()) {
+
+ bool have_off_diagonal_association = false;
+ bool have_diagonal_association = false;
+ bool have_diagonal_not_association = false;
+
+ for (uint32_t i = 0; i < node.row.bundle->nchannels().n_total(); ++i) {
+
+ for (uint32_t j = 0; j < node.column.bundle->nchannels().n_total(); ++j) {
+
+ if (!should_show (node.row.bundle->channel_type(i)) || !should_show (node.column.bundle->channel_type(j))) {
+ continue;
+ }
+
+ ARDOUR::BundleChannel c[2];
+ c[row_index()] = ARDOUR::BundleChannel (node.row.bundle, i);
+ c[column_index()] = ARDOUR::BundleChannel (node.column.bundle, j);
+
+ PortMatrixNode::State const s = get_state (c);
+
+ switch (s) {
+ case PortMatrixNode::ASSOCIATED:
+ if (i == j) {
+ have_diagonal_association = true;
+ } else {
+ have_off_diagonal_association = true;
+ }
+ break;
+
+ case PortMatrixNode::NOT_ASSOCIATED:
+ if (i == j) {
+ have_diagonal_not_association = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (have_diagonal_association && !have_off_diagonal_association && !have_diagonal_not_association) {
+ return PortMatrixNode::ASSOCIATED;
+ } else if (!have_diagonal_association && !have_off_diagonal_association) {
+ return PortMatrixNode::NOT_ASSOCIATED;
+ }
+
+ return PortMatrixNode::PARTIAL;
+
+ } else {
+
+ ARDOUR::BundleChannel c[2];
+ c[column_index()] = node.column;
+ c[row_index()] = node.row;
+ return get_state (c);
+
+ }
+
+ /* NOTREACHED */
+ return PortMatrixNode::NOT_ASSOCIATED;
+}
+
+/** @return true if b is a non-zero pointer and the bundle it points to has some channels */
+bool
+PortMatrix::bundle_with_channels (boost::shared_ptr<ARDOUR::Bundle> b)
+{
+ return b && b->nchannels() != ARDOUR::ChanCount::ZERO;
+}