+
+bool
+PortMatrixBody::on_leave_notify_event (GdkEventCrossing* ev)
+{
+ if (ev->type == GDK_LEAVE_NOTIFY) {
+ set_mouseover (PortMatrixNode ());
+ }
+
+ return true;
+}
+
+bool
+PortMatrixBody::on_motion_notify_event (GdkEventMotion* ev)
+{
+ bool done = false;
+
+ for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
+ if (Gdk::Region ((*i)->parent_rectangle()).point_in (ev->x, ev->y)) {
+ (*i)->motion (
+ (*i)->parent_to_component_x (ev->x),
+ (*i)->parent_to_component_y (ev->y)
+ );
+
+ done = true;
+ }
+ }
+
+
+ if (!done) {
+ set_mouseover (PortMatrixNode ());
+ }
+
+ return true;
+}
+
+void
+PortMatrixBody::set_mouseover (PortMatrixNode const & n)
+{
+ list<PortMatrixNode> m;
+ m.push_back (n);
+ set_mouseover (m);
+}
+
+void
+PortMatrixBody::set_mouseover (list<PortMatrixNode> const & n)
+{
+ if (n == _mouseover) {
+ return;
+ }
+
+ /* Channel highlights are set up only on mouseovers, so
+ it's reasonable to remove all channel highlights here.
+ We can't let individual components clear their own highlights
+ because of the case where, say, the row labels set up some column
+ highlights, and then we ask the column labels to set up their
+ own highlights and they clear them out before they start.
+ */
+
+ _row_labels->clear_channel_highlights ();
+ _column_labels->clear_channel_highlights ();
+
+ list<PortMatrixNode> old = _mouseover;
+ _mouseover = n;
+
+ for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
+ (*i)->mouseover_changed (old);
+ }
+}
+
+void
+PortMatrixBody::highlight_associated_channels (int dim, ARDOUR::BundleChannel h)
+{
+ ARDOUR::BundleChannel bc[2];
+ bc[dim] = h;
+
+ if (!PortMatrix::bundle_with_channels (bc[dim].bundle)) {
+ return;
+ }
+
+ if (dim == _matrix->column_index()) {
+ _column_labels->add_channel_highlight (bc[dim]);
+ } else {
+ _row_labels->add_channel_highlight (bc[dim]);
+ }
+
+ PortGroup::BundleList const b = _matrix->visible_ports(1 - dim)->bundles ();
+
+ for (PortGroup::BundleList::const_iterator i = b.begin(); i != b.end(); ++i) {
+ for (uint32_t j = 0; j < (*i)->bundle->nchannels().n_total(); ++j) {
+
+ if (!_matrix->should_show ((*i)->bundle->channel_type(j))) {
+ continue;
+ }
+
+ bc[1 - dim] = ARDOUR::BundleChannel ((*i)->bundle, j);
+
+ PortMatrixNode n;
+ n.row = bc[_matrix->row_index()];
+ n.column = bc[_matrix->column_index()];
+
+ if (_matrix->get_association(n) != PortMatrixNode::NOT_ASSOCIATED) {
+ if (dim == _matrix->column_index()) {
+ _row_labels->add_channel_highlight (bc[1 - dim]);
+ } else {
+ _column_labels->add_channel_highlight (bc[1 - dim]);
+ }
+ }
+ }
+ }
+}
+
+void
+PortMatrixBody::set_cairo_clip (cairo_t* cr, Gdk::Rectangle const & r) const
+{
+ cairo_rectangle (cr, r.get_x(), r.get_y(), r.get_width(), r.get_height());
+ cairo_clip (cr);
+}
+
+void
+PortMatrixBody::component_size_changed ()
+{
+ if (_ignore_component_size_changed) {
+ return;
+ }
+
+ compute_rectangles ();
+ _matrix->setup_scrollbars ();
+}
+
+pair<uint32_t, uint32_t>
+PortMatrixBody::max_size () const
+{
+ pair<uint32_t, uint32_t> const col = _column_labels->dimensions ();
+ pair<uint32_t, uint32_t> const row = _row_labels->dimensions ();
+ pair<uint32_t, uint32_t> const grid = _grid->dimensions ();
+
+ return make_pair (std::max (row.first, _column_labels->overhang()) + grid.first, col.second + grid.second);
+}
+
+/** @return x position at which the column labels meet the border of the matrix */
+uint32_t
+PortMatrixBody::column_labels_border_x () const
+{
+ return _column_labels_border_x;
+}
+
+uint32_t
+PortMatrixBody::column_labels_height () const
+{
+ return _column_labels_height;
+}