PortMatrixGrid::PortMatrixGrid (PortMatrix* m, PortMatrixBody* b)
: PortMatrixComponent (m, b),
_dragging (false),
+ _drag_valid (false),
_moved (false)
{
PortMatrixGrid::compute_dimensions ()
{
_width = 0;
+
for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) {
_width += group_size (*i) * grid_spacing ();
}
for (PortGroup::BundleList::const_iterator j = row_bundles.begin(); j != row_bundles.end(); ++j) {
- PortMatrixNode::State s = bundle_to_bundle_state (i->bundle, j->bundle);
+ PortMatrixNode::State s = get_association (PortMatrixNode (
+ ARDOUR::BundleChannel (i->bundle, 0),
+ ARDOUR::BundleChannel (j->bundle, 0)
+ ));
switch (s) {
case PortMatrixNode::UNKNOWN:
draw_unknown_indicator (cr, bx, by);
cairo_fill (cr);
}
+void
+PortMatrixGrid::draw_empty_square (cairo_t* cr, uint32_t x, uint32_t y)
+{
+ set_source_rgb (cr, background_colour());
+ cairo_rectangle (
+ cr,
+ x + thick_grid_line_width(),
+ y + thick_grid_line_width(),
+ grid_spacing() - 2 * thick_grid_line_width(),
+ grid_spacing() - 2 * thick_grid_line_width()
+ );
+ cairo_fill (cr);
+}
+
void
PortMatrixGrid::draw_unknown_indicator (cairo_t* cr, uint32_t x, uint32_t y)
{
void
PortMatrixGrid::button_press (double x, double y, int b, uint32_t t)
{
+ pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> px = position_to_group_and_channel (x / grid_spacing(), _matrix->columns());
+ pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> py = position_to_group_and_channel (y / grid_spacing(), _matrix->rows());
+
if (b == 1) {
_dragging = true;
+ _drag_valid = (px.second.bundle && py.second.bundle);
+
_moved = false;
_drag_start_x = x / grid_spacing ();
_drag_start_y = y / grid_spacing ();
} else if (b == 3) {
- _matrix->popup_menu (
- position_to_group_and_channel (x / grid_spacing(), _matrix->columns()),
- position_to_group_and_channel (y / grid_spacing(), _matrix->rows()), t);
+ _matrix->popup_menu (px, py, t);
}
}
-void
-PortMatrixGrid::set_association (PortMatrixNode node)
+PortMatrixNode::State
+PortMatrixGrid::get_association (PortMatrixNode node) const
{
if (_matrix->show_only_bundles()) {
-
- for (uint32_t i = 0; i < node.column.bundle->nchannels(); ++i) {
- for (uint32_t j = 0; j < node.row.bundle->nchannels(); ++j) {
+
+ bool have_unknown = false;
+ 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 (); ++i) {
+
+ for (uint32_t j = 0; j < node.column.bundle->nchannels (); ++j) {
ARDOUR::BundleChannel c[2];
- c[_matrix->column_index()] = ARDOUR::BundleChannel (node.column.bundle, i);
- c[_matrix->row_index()] = ARDOUR::BundleChannel (node.row.bundle, j);
- _matrix->set_state (c, true);
+ c[_matrix->column_index()] = ARDOUR::BundleChannel (node.row.bundle, i);
+ c[_matrix->row_index()] = ARDOUR::BundleChannel (node.column.bundle, j);
+
+ PortMatrixNode::State const s = _matrix->get_state (c);
+
+ switch (s) {
+ case PortMatrixNode::ASSOCIATED:
+ if (i == j) {
+ have_diagonal_association = true;
+ } else {
+ have_off_diagonal_association = true;
+ }
+ break;
+
+ case PortMatrixNode::UNKNOWN:
+ have_unknown = true;
+ break;
+
+ case PortMatrixNode::NOT_ASSOCIATED:
+ if (i == j) {
+ have_diagonal_not_association = true;
+ }
+ break;
+
+ default:
+ break;
+ }
}
}
- } else {
-
- if (node.row.bundle && node.column.bundle) {
-
- ARDOUR::BundleChannel c[2];
- c[_matrix->row_index()] = node.row;
- c[_matrix->column_index()] = node.column;
- _matrix->set_state (c, true);
+ if (have_unknown) {
+ return PortMatrixNode::UNKNOWN;
+ } else 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[_matrix->column_index()] = node.column;
+ c[_matrix->row_index()] = node.row;
+ return _matrix->get_state (c);
+
}
+
+ return PortMatrixNode::UNKNOWN;
}
void
-PortMatrixGrid::toggle_association (PortMatrixNode node)
+PortMatrixGrid::set_association (PortMatrixNode node, bool s)
{
if (_matrix->show_only_bundles()) {
- PortMatrixNode::State const s = bundle_to_bundle_state (node.column.bundle, node.row.bundle);
-
for (uint32_t i = 0; i < node.column.bundle->nchannels(); ++i) {
for (uint32_t j = 0; j < node.row.bundle->nchannels(); ++j) {
ARDOUR::BundleChannel c[2];
c[_matrix->column_index()] = ARDOUR::BundleChannel (node.column.bundle, i);
c[_matrix->row_index()] = ARDOUR::BundleChannel (node.row.bundle, j);
- if (s == PortMatrixNode::NOT_ASSOCIATED || s == PortMatrixNode::PARTIAL) {
- _matrix->set_state (c, i == j);
- } else {
- _matrix->set_state (c, false);
- }
+ _matrix->set_state (c, s && (i == j));
}
}
ARDOUR::BundleChannel c[2];
c[_matrix->row_index()] = node.row;
c[_matrix->column_index()] = node.column;
-
- PortMatrixNode::State const s = _matrix->get_state (c);
-
- if (s == PortMatrixNode::ASSOCIATED || s == PortMatrixNode::NOT_ASSOCIATED) {
- bool const n = !(s == PortMatrixNode::ASSOCIATED);
- _matrix->set_state (c, n);
- }
-
+ _matrix->set_state (c, s);
}
}
}
void
-PortMatrixGrid::button_release (double x, double y, int b, uint32_t t)
+PortMatrixGrid::button_release (double x, double y, int b, uint32_t /*t*/)
{
if (b == 1) {
if (_dragging && _moved) {
- list<PortMatrixNode> const p = nodes_on_line (_drag_start_x, _drag_start_y, _drag_x, _drag_y);
-
- for (list<PortMatrixNode>::const_iterator i = p.begin(); i != p.end(); ++i) {
- set_association (*i);
+ if (_drag_valid) {
+ list<PortMatrixNode> const p = nodes_on_line (_drag_start_x, _drag_start_y, _drag_x, _drag_y);
+
+ if (!p.empty()) {
+ PortMatrixNode::State const s = get_association (p.front());
+ for (list<PortMatrixNode>::const_iterator i = p.begin(); i != p.end(); ++i) {
+ set_association (*i, toggle_state (s));
+ }
+ }
}
} else {
- toggle_association (position_to_node (x / grid_spacing(), y / grid_spacing()));
+ PortMatrixNode const n = position_to_node (x / grid_spacing(), y / grid_spacing());
+ if (n.row.bundle && n.column.bundle) {
+ PortMatrixNode::State const s = get_association (n);
+ set_association (n, toggle_state (s));
+ }
}
require_render ();
double const x = component_to_parent_x (channel_to_position (_body->mouseover().column, _matrix->columns()) * grid_spacing()) + grid_spacing() / 2;
double const y = component_to_parent_y (channel_to_position (_body->mouseover().row, _matrix->rows()) * grid_spacing()) + grid_spacing() / 2;
-
- if (_body->mouseover().row.bundle) {
+
+ if (_body->mouseover().row.bundle && _body->mouseover().column.bundle) {
cairo_move_to (cr, x, y);
if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
cairo_line_to (cr, _parent_rectangle.get_x() + _parent_rectangle.get_width(), y);
}
cairo_stroke (cr);
- }
-
- if (_body->mouseover().column.bundle) {
cairo_move_to (cr, x, y);
if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
cairo_stroke (cr);
}
- if (_dragging && _moved) {
+ if (_dragging && _drag_valid && _moved) {
+
+ list<PortMatrixNode> const p = nodes_on_line (_drag_start_x, _drag_start_y, _drag_x, _drag_y);
+
+ if (!p.empty()) {
+
+ bool const s = toggle_state (get_association (p.front()));
+
+ for (list<PortMatrixNode>::const_iterator i = p.begin(); i != p.end(); ++i) {
+ if (s) {
+ draw_association_indicator (
+ cr,
+ component_to_parent_x (channel_to_position (i->column, _matrix->columns()) * grid_spacing ()),
+ component_to_parent_y (channel_to_position (i->row, _matrix->rows()) * grid_spacing ())
+ );
+ } else {
+ draw_empty_square (
+ cr,
+ component_to_parent_x (channel_to_position (i->column, _matrix->columns()) * grid_spacing ()),
+ component_to_parent_y (channel_to_position (i->row, _matrix->rows()) * grid_spacing ())
+ );
+ }
+ }
+ }
set_source_rgba (cr, association_colour (), 0.3);
cairo_stroke (cr);
- list<PortMatrixNode> const p = nodes_on_line (_drag_start_x, _drag_start_y, _drag_x, _drag_y);
-
- for (list<PortMatrixNode>::const_iterator i = p.begin(); i != p.end(); ++i) {
- draw_association_indicator (
- cr,
- component_to_parent_x (channel_to_position (i->column, _matrix->columns()) * grid_spacing ()),
- component_to_parent_y (channel_to_position (i->row, _matrix->rows()) * grid_spacing ())
- );
- }
}
}
_moved = true;
}
- if (_dragging && _moved) {
+ if (_dragging && _drag_valid && _moved) {
_drag_x = px;
_drag_y = py;
_body->queue_draw ();
return y + _body->yoffset() - _parent_rectangle.get_y();
}
-PortMatrixNode::State
-PortMatrixGrid::bundle_to_bundle_state (boost::shared_ptr<ARDOUR::Bundle> a, boost::shared_ptr<ARDOUR::Bundle> b) const
-{
- bool have_unknown = false;
- bool have_off_diagonal_association = false;
- bool have_diagonal_association = false;
- bool have_diagonal_not_association = false;
-
- for (uint32_t i = 0; i < a->nchannels (); ++i) {
-
- for (uint32_t j = 0; j < b->nchannels (); ++j) {
-
- ARDOUR::BundleChannel c[2];
- c[_matrix->column_index()] = ARDOUR::BundleChannel (a, i);
- c[_matrix->row_index()] = ARDOUR::BundleChannel (b, j);
-
- PortMatrixNode::State const s = _matrix->get_state (c);
-
- switch (s) {
- case PortMatrixNode::ASSOCIATED:
- if (i == j) {
- have_diagonal_association = true;
- } else {
- have_off_diagonal_association = true;
- }
- break;
-
- case PortMatrixNode::UNKNOWN:
- have_unknown = true;
- break;
-
- case PortMatrixNode::NOT_ASSOCIATED:
- if (i == j) {
- have_diagonal_not_association = true;
- }
- break;
-
- default:
- break;
- }
- }
- }
-
- if (have_unknown) {
- return PortMatrixNode::UNKNOWN;
- } else 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;
-}
-
list<PortMatrixNode>
PortMatrixGrid::nodes_on_line (int x0, int y0, int x1, int y1) const
{
for (int x = x0; x <= x1; ++x) {
if (steep) {
- p.push_back (position_to_node (y, x));
+ PortMatrixNode n = position_to_node (y, x);
+ if (n.row.bundle && n.column.bundle) {
+ p.push_back (n);
+ }
} else {
- p.push_back (position_to_node (x, y));
+ PortMatrixNode n = position_to_node (x, y);
+ if (n.row.bundle && n.column.bundle) {
+ p.push_back (n);
+ }
}
err += derr;
return p;
}
+
+bool
+PortMatrixGrid::toggle_state (PortMatrixNode::State s) const
+{
+ return (s == PortMatrixNode::NOT_ASSOCIATED || s == PortMatrixNode::PARTIAL);
+}