Drag a line in the port matrix to connect a group of things together in one go. ...
authorCarl Hetherington <carl@carlh.net>
Sat, 18 Jul 2009 02:10:15 +0000 (02:10 +0000)
committerCarl Hetherington <carl@carlh.net>
Sat, 18 Jul 2009 02:10:15 +0000 (02:10 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@5375 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/port_matrix_body.cc
gtk2_ardour/port_matrix_column_labels.cc
gtk2_ardour/port_matrix_column_labels.h
gtk2_ardour/port_matrix_component.cc
gtk2_ardour/port_matrix_component.h
gtk2_ardour/port_matrix_grid.cc
gtk2_ardour/port_matrix_grid.h
gtk2_ardour/port_matrix_row_labels.cc

index 593c365d3ced7a3a8b9ee63311dd153942a0d4cf..a29f2483e34afd081001e0cc9ce961b5da22100e 100644 (file)
@@ -347,6 +347,14 @@ PortMatrixBody::on_button_release_event (GdkEventButton* ev)
                _row_labels->clear_channel_highlights ();
                _column_labels->clear_channel_highlights ();
                
+       } else if (Gdk::Region (_grid->parent_rectangle()).point_in (ev->x, ev->y)) {
+
+               _grid->button_release (
+                       _grid->parent_to_component_x (ev->x),
+                       _grid->parent_to_component_y (ev->y),
+                       ev->button, ev->time
+                       );
+
        }
 
        return true;
@@ -387,11 +395,14 @@ bool
 PortMatrixBody::on_motion_notify_event (GdkEventMotion* ev)
 {
        if (Gdk::Region (_grid->parent_rectangle()).point_in (ev->x, ev->y)) {
-               _grid->mouseover_event (
+               
+               _grid->motion (
                        _grid->parent_to_component_x (ev->x),
                        _grid->parent_to_component_y (ev->y)
                        );
+               
                _mouse_over_grid = true;
+               
        } else {
                if (_mouse_over_grid) {
                        set_mouseover (PortMatrixNode ());
@@ -417,8 +428,6 @@ PortMatrixBody::set_mouseover (PortMatrixNode const & n)
        _column_labels->mouseover_changed (old);
 }
 
-
-
 void
 PortMatrixBody::highlight_associated_channels (int dim, ARDOUR::BundleChannel h)
 {
index adef4c6eb755a54baecbee3d9493211e6226ccf8..148397d0c53350ae897d391dd90d778586c892a8 100644 (file)
@@ -79,9 +79,9 @@ PortMatrixColumnLabels::compute_dimensions ()
                }
 
                if (_matrix->show_only_bundles()) {
-                       _width += column_width();
+                       _width += grid_spacing();
                } else {
-                       _width += i->bundle->nchannels() * column_width();
+                       _width += i->bundle->nchannels() * grid_spacing();
                }
        }
 
@@ -94,7 +94,7 @@ PortMatrixColumnLabels::compute_dimensions ()
                                _highest_group_name = ext.height;
                        }
                } else {
-                       _width += column_width ();
+                       _width += grid_spacing ();
                }
        }
 
@@ -119,7 +119,7 @@ PortMatrixColumnLabels::compute_dimensions ()
 double
 PortMatrixColumnLabels::basic_text_x_pos (int c) const
 {
-       return column_width() / 2 +
+       return grid_spacing() / 2 +
                _highest_text / (2 * sin (angle ()));
 }
 
@@ -151,12 +151,12 @@ PortMatrixColumnLabels::render (cairo_t* cr)
                /* compute width of this group */
                uint32_t w = 0;
                if (!(*i)->visible() || (*i)->bundles().empty()) {
-                       w = column_width ();
+                       w = grid_spacing ();
                } else {
                        if (_matrix->show_only_bundles()) {
-                               w = (*i)->bundles().size() * column_width();
+                               w = (*i)->bundles().size() * grid_spacing();
                        } else {
-                               w = (*i)->total_channels() * column_width();
+                               w = (*i)->total_channels() * grid_spacing();
                        }
                        }
                
@@ -199,9 +199,9 @@ PortMatrixColumnLabels::render (cairo_t* cr)
                                render_bundle_name (cr, c, x, 0, j->bundle);
                                
                                if (_matrix->show_only_bundles()) {
-                                       x += column_width();
+                                       x += grid_spacing();
                                } else {
-                                       x += j->bundle->nchannels () * column_width();
+                                       x += j->bundle->nchannels () * grid_spacing();
                                }
 
                                ++N;
@@ -209,7 +209,7 @@ PortMatrixColumnLabels::render (cairo_t* cr)
 
                } else {
 
-                       x += column_width ();
+                       x += grid_spacing ();
 
                }
        }
@@ -230,7 +230,7 @@ PortMatrixColumnLabels::render (cairo_t* cr)
                                        for (uint32_t k = 0; k < j->bundle->nchannels(); ++k) {
                                                Gdk::Color c = j->has_colour ? j->colour : get_a_bundle_colour (N);
                                                render_channel_name (cr, c, x, 0, ARDOUR::BundleChannel (j->bundle, k));
-                                               x += column_width();
+                                               x += grid_spacing();
                                        }
                                        
                                        ++N;
@@ -238,7 +238,7 @@ PortMatrixColumnLabels::render (cairo_t* cr)
 
                        } else {
 
-                               x += column_width ();
+                               x += grid_spacing ();
 
                        }
                }
@@ -284,7 +284,7 @@ PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
        vector<pair<double, double> > shape;
        
        double const lc = _longest_channel_name + name_pad();
-       double const w = column_width();
+       double const w = grid_spacing();
        
        if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
 
@@ -310,8 +310,8 @@ PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
                x_ += lc * cos (angle());
                y_ -= lc * sin (angle());
                shape.push_back (make_pair (x_, y_));
-               x_ -= column_width() * pow (sin (angle()), 2);
-               y_ -= column_width() * sin (angle()) * cos (angle());
+               x_ -= grid_spacing() * pow (sin (angle()), 2);
+               y_ -= grid_spacing() * sin (angle()) * cos (angle());
                shape.push_back (make_pair (x_, y_));
        }
 
@@ -327,9 +327,9 @@ PortMatrixColumnLabels::render_bundle_name (
 
        double w = 0;
        if (_matrix->show_only_bundles()) {
-               w = column_width ();
+               w = grid_spacing ();
        } else {
-               w = b->nchannels() * column_width();
+               w = b->nchannels() * grid_spacing();
        }
        
        double x_ = xoff;
@@ -440,24 +440,7 @@ PortMatrixColumnLabels::render_channel_name (
 double
 PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel const &bc) const
 {
-       uint32_t n = 0;
-
-       PortGroup::BundleList const & b = _matrix->columns()->bundles ();
-       PortGroup::BundleList::const_iterator i = b.begin();
-       while (i != b.end() && i->bundle != bc.bundle) {
-               if (_matrix->show_only_bundles()) {
-                       n += 1;
-               } else {
-                       n += i->bundle->nchannels ();
-               }
-               ++i;
-       }
-
-       if (!_matrix->show_only_bundles()) {
-               n += bc.channel;
-       }
-
-       return n * column_width();
+       return channel_to_position (bc, _matrix->columns()) * grid_spacing ();
 }
 
 double
@@ -478,7 +461,7 @@ PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
                _body->queue_draw_area (
                        component_to_parent_x (channel_x (bc)),
                        component_to_parent_y (0),
-                       column_width() + _height * tan (angle()),
+                       grid_spacing() + _height * tan (angle()),
                        _height
                        );
                
@@ -486,14 +469,14 @@ PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
                
                double const x = channel_x (bc);
                double const lc = _longest_channel_name + name_pad();
-               double const h = lc * sin (angle ()) + column_width() * sin (angle()) * cos (angle());
+               double const h = lc * sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
                
                if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
 
                        _body->queue_draw_area (
                                component_to_parent_x (x),
                                component_to_parent_y (_height - h),
-                               column_width() + lc * cos (angle()),
+                               grid_spacing() + lc * cos (angle()),
                                h
                                );
                        
@@ -504,7 +487,7 @@ PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
                        _body->queue_draw_area (
                                component_to_parent_x (x_),
                                component_to_parent_y (0),
-                               column_width() + lc * cos (angle()),
+                               grid_spacing() + lc * cos (angle()),
                                h
                                );
                        
@@ -513,8 +496,8 @@ PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
        }
 }
 
-pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel>
-PortMatrixColumnLabels::x_position_to_group_and_channel (double x, double y) const
+void
+PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t)
 {
        uint32_t cx = 0;
        uint32_t const gh = _highest_group_name + 2 * name_pad();
@@ -536,70 +519,14 @@ PortMatrixColumnLabels::x_position_to_group_and_channel (double x, double y) con
                }
        }
 
-       uint32_t px = 0;
-
-       pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> gc;
-       
-       for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) {
-
-               if (!(*i)->visible()) {
-
-                       uint32_t const gw = group_width (*i);
-                       
-                       if (px <= cx && cx < (px + gw)) {
-                               return make_pair (*i, ARDOUR::BundleChannel ());
-                       } else {
-                               px += gw;
-                       }
-
-               } else {
-                               
-                       PortGroup::BundleList bundles = (*i)->bundles ();
-                       for (PortGroup::BundleList::iterator j = bundles.begin(); j != bundles.end(); ++j) {
-
-                               if (_matrix->show_only_bundles()) {
-                                       
-                                       if (px <= cx && cx < (px + column_width())) {
-                                               return make_pair (*i, ARDOUR::BundleChannel (j->bundle, 0));
-                                       } else {
-                                               px += column_width ();
-                                       }
-                                       
-                               } else {
-
-                                       for (uint32_t k = 0; k < j->bundle->nchannels(); ++k) {
-
-                                               if (px <= cx && cx < (px + column_width())) {
-                                                       if (group_name) {
-                                                               return make_pair (*i, ARDOUR::BundleChannel ());
-                                                       } else {
-                                                               return make_pair (*i, ARDOUR::BundleChannel (j->bundle, k));
-                                                       }
-                                               }
-                                               
-                                               px += column_width ();
-                                       }
-                               }
-
-                       }
-               }
-               
-       }
-
-       return make_pair (boost::shared_ptr<PortGroup> (), ARDOUR::BundleChannel ());
-}
-
-void
-PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t)
-{
-       pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> gc = x_position_to_group_and_channel (x, y);
+       pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> gc = position_to_group_and_channel (cx / grid_spacing(), _matrix->columns());
        
        if (b == 1) {
 
-               if (gc.second.bundle) {
-                       _body->highlight_associated_channels (_matrix->column_index(), gc.second);
-               } else if (gc.first) {
+               if (group_name && gc.first) {
                        gc.first->set_visible (!gc.first->visible ());
+               } else if (gc.second.bundle) {
+                       _body->highlight_associated_channels (_matrix->column_index(), gc.second);
                }
                
        } else if (b == 3) {
index 7ff3bc9138aa6f1b2cb932cfb2097e4f1c4b3d1d..c735eb7e394c130cc1d3ac206dbc3d2818eb6985 100644 (file)
@@ -64,8 +64,6 @@ private:
                return _height - _highest_group_name - 2 * name_pad();
        }
 
-       std::pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> x_position_to_group_and_channel (double, double) const;
-
        double _longest_bundle_name;
        double _longest_channel_name;
        double _highest_text;
index 6a60110f3e4cd36909ff01b6d314ce09ab14236a..2f5a498d416d5fadd6a0a0e945c608429414af6f 100644 (file)
@@ -118,80 +118,114 @@ PortMatrixComponent::background_colour ()
        return _matrix->get_style()->get_bg (Gtk::STATE_NORMAL);
 }
 
+/** @param g Group.
+ *  @return Visible size of the group in grid units, taking visibility and show_only_bundles into account.
+ */
 uint32_t
-PortMatrixComponent::group_width (boost::shared_ptr<const PortGroup> g) const
+PortMatrixComponent::group_size (boost::shared_ptr<const PortGroup> g) const
 {
-       uint32_t width = 0;
+       uint32_t s = 0;
        
        if (g->visible()) {
                PortGroup::BundleList const & bundles = g->bundles ();
                if (_matrix->show_only_bundles()) {
-                       width = bundles.size() * column_width ();
+                       s = bundles.size();
                } else {
                        for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
-                               width += i->bundle->nchannels() * column_width ();
+                               s += i->bundle->nchannels();
                        }
                }
        } else {
-               width = column_width ();
+               s = 1;
        }
 
-       return width;
+       return s;
 }
 
+/** @param bc Channel.
+ *  @param groups List of groups.
+ *  @return Position of bc in groups in grid units, taking visibility and show_only_bundles into account.
+ */
 uint32_t
-PortMatrixComponent::group_height (boost::shared_ptr<const PortGroup> g) const
+PortMatrixComponent::channel_to_position (ARDOUR::BundleChannel bc, PortGroupList const * groups) const
 {
-       uint32_t height = 0;
+       uint32_t p = 0;
+
+       for (PortGroupList::List::const_iterator i = groups->begin(); i != groups->end(); ++i) {
+
+               PortGroup::BundleList const & bundles = (*i)->bundles ();
+
+               for (PortGroup::BundleList::const_iterator j = bundles.begin(); j != bundles.end(); ++j) {
+
+                       if (j->bundle == bc.bundle) {
+
+                               /* found the bundle */
+                               
+                               if (_matrix->show_only_bundles() || !(*i)->visible()) {
+                                       return p;
+                               } else {
+                                       return p + bc.channel;
+                               }
 
-       if (g->visible ()) {
-               PortGroup::BundleList const & bundles = g->bundles ();
-               if (_matrix->show_only_bundles()) {
-                       height = bundles.size() * row_height ();
-               } else {
-                       for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
-                               height += i->bundle->nchannels() * row_height ();
+                       }
+
+                       if ((*i)->visible()) {
+
+                               /* move past this bundle */
+
+                               if (_matrix->show_only_bundles()) {
+                                       p += 1;
+                               } else {
+                                       p += j->bundle->nchannels ();
+                               }
                        }
                }
-       } else {
-               height = row_height ();
+
+               if (!(*i)->visible()) {
+                       /* if this group isn't visible we won't have updated p, so do it now */
+                       p += 1;
+               }
        }
 
-       return height;
+       return 0;
 }
 
 
 pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel>
-PortMatrixComponent::y_position_to_group_and_channel (double y) const
+PortMatrixComponent::position_to_group_and_channel (uint32_t p, PortGroupList const * groups) const
 {
-       PortGroupList::List::const_iterator i = _matrix->rows()->begin();
+       PortGroupList::List::const_iterator i = groups->begin ();
 
-       while (i != _matrix->rows()->end()) {
+       while (i != groups->end()) {
 
-               uint32_t const gh = group_height (*i);
+               uint32_t const gs = group_size (*i);
 
-               if (y < gh) {
+               if (p < gs) {
 
                        /* it's in this group */
 
+                       if (!(*i)->visible()) {
+                               return make_pair (*i, ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), 0));
+                       }
+
                        PortGroup::BundleList const & bundles = (*i)->bundles ();
                        for (PortGroup::BundleList::const_iterator j = bundles.begin(); j != bundles.end(); ++j) {
 
                                if (_matrix->show_only_bundles()) {
                                        
-                                       if (y < row_height()) {
+                                       if (p == 0) {
                                                return make_pair (*i, ARDOUR::BundleChannel (j->bundle, 0));
                                        } else {
-                                               y -= row_height ();
+                                               p -= 1;
                                        }
                                        
                                } else {
 
-                                       uint32_t const h = j->bundle->nchannels () * row_height ();
-                                       if (y < h) {
-                                               return make_pair (*i, ARDOUR::BundleChannel (j->bundle, y / row_height()));
+                                       uint32_t const s = j->bundle->nchannels ();
+                                       if (p < s) {
+                                               return make_pair (*i, ARDOUR::BundleChannel (j->bundle, p));
                                        } else {
-                                               y -= h;
+                                               p -= s;
                                        }
 
                                }
@@ -200,7 +234,7 @@ PortMatrixComponent::y_position_to_group_and_channel (double y) const
 
                } else {
 
-                       y -= gh;
+                       p -= gs;
 
                }
 
index 34dc18e932435f7acdd78aec97995b1acaec3657..7e5ed3d8a25ccfcd8b86c9f9ccde515961d5cdbd 100644 (file)
@@ -28,6 +28,7 @@ class PortMatrix;
 class PortMatrixBody;
 class PortMatrixNode;
 class PortGroup;
+class PortGroupList;
 
 namespace ARDOUR {
        class BundleChannel;
@@ -71,13 +72,8 @@ public:
                return _parent_rectangle;
        }
 
-       /** @return width of columns in the grid */
-       static uint32_t column_width () {
-               return 32;
-       }
-
-       /** @return height of rows in the grid */
-       static uint32_t row_height () {
+       /** @return grid spacing */
+       static uint32_t grid_spacing () {
                return 32;
        }
 
@@ -172,9 +168,9 @@ protected:
        
        void set_source_rgb (cairo_t *, Gdk::Color const &);
        void set_source_rgba (cairo_t *, Gdk::Color const &, double);
-       uint32_t group_width (boost::shared_ptr<const PortGroup>) const;
-       uint32_t group_height (boost::shared_ptr<const PortGroup>) const;
-       std::pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> y_position_to_group_and_channel (double) const;
+       uint32_t group_size (boost::shared_ptr<const PortGroup>) const;
+       uint32_t channel_to_position (ARDOUR::BundleChannel, PortGroupList const *) const;
+       std::pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> position_to_group_and_channel (uint32_t, PortGroupList const *) const;
 
        /** Render the complete component to a cairo context. */
        virtual void render (cairo_t *) = 0;
index 3ad9f66cbb88eec75c5f791e8ca6ace7cd2d72e6..06c1925ec9ab1f444efbdf1e252767fedba9e832 100644 (file)
@@ -28,7 +28,9 @@
 using namespace std;
 
 PortMatrixGrid::PortMatrixGrid (PortMatrix* m, PortMatrixBody* b)
-       : PortMatrixComponent (m, b)
+       : PortMatrixComponent (m, b),
+         _dragging (false),
+         _moved (false)
 {
        
 }
@@ -38,12 +40,12 @@ PortMatrixGrid::compute_dimensions ()
 {
        _width = 0;
        for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) {
-               _width += group_width (*i);
+               _width += group_size (*i) * grid_spacing ();
        }
 
        _height = 0;
        for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) {
-               _height += group_height (*i);
+               _height += group_size (*i) * grid_spacing ();
        }
 }
 
@@ -65,10 +67,10 @@ PortMatrixGrid::render (cairo_t* cr)
                                render_group_pair (cr, *r, *c, x, y);
                        }
 
-                       y += group_height (*r);
+                       y += group_size (*r) * grid_spacing ();
                }
 
-               x += group_width (*c);
+               x += group_size (*c) * grid_spacing ();
        }
 }
 
@@ -79,7 +81,7 @@ PortMatrixGrid::render_group_pair (cairo_t* cr, boost::shared_ptr<const PortGrou
        PortGroup::BundleList const & column_bundles = column->bundles();
 
        /* unfortunately we need to compute the height of the row group here */
-       uint32_t height = group_height (row);
+       uint32_t height = group_size (row) * grid_spacing ();
        
        uint32_t tx = x;
 
@@ -98,7 +100,7 @@ PortMatrixGrid::render_group_pair (cairo_t* cr, boost::shared_ptr<const PortGrou
                if (!_matrix->show_only_bundles()) {
                        cairo_set_line_width (cr, thin_grid_line_width());
                        for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) {
-                               tx += column_width ();
+                               tx += grid_spacing ();
                                cairo_move_to (cr, tx, y);
                                cairo_line_to (cr, tx, y + height);
                                cairo_stroke (cr);
@@ -106,7 +108,7 @@ PortMatrixGrid::render_group_pair (cairo_t* cr, boost::shared_ptr<const PortGrou
                        
                } else {
                        
-                       tx += column_width ();
+                       tx += grid_spacing ();
                        
                }
                
@@ -130,7 +132,7 @@ PortMatrixGrid::render_group_pair (cairo_t* cr, boost::shared_ptr<const PortGrou
                if (!_matrix->show_only_bundles()) {
                        cairo_set_line_width (cr, thin_grid_line_width());
                        for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) {
-                               ty += row_height ();
+                               ty += grid_spacing ();
                                cairo_move_to (cr, x, ty);
                                cairo_line_to (cr, x + width, ty);
                                cairo_stroke (cr);
@@ -138,7 +140,7 @@ PortMatrixGrid::render_group_pair (cairo_t* cr, boost::shared_ptr<const PortGrou
 
                } else {
 
-                       ty += row_height ();
+                       ty += grid_spacing ();
 
                }
                
@@ -172,10 +174,10 @@ PortMatrixGrid::render_group_pair (cairo_t* cr, boost::shared_ptr<const PortGrou
                                        break;
                                }
                                
-                               by += row_height();
+                               by += grid_spacing();
                        }
                        
-                       bx += column_width();
+                       bx += grid_spacing();
                        
                }
 
@@ -214,16 +216,16 @@ PortMatrixGrid::render_group_pair (cairo_t* cr, boost::shared_ptr<const PortGrou
                                                        break;
                                                }
                                                
-                                               ty += row_height();
+                                               ty += grid_spacing();
                                        }
                                        
-                                       tx += column_width();
+                                       tx += grid_spacing();
                                }
                                
-                               by += j->bundle->nchannels () * row_height();
+                               by += j->bundle->nchannels () * grid_spacing();
                        }
                        
-                       bx += i->bundle->nchannels () * column_width();
+                       bx += i->bundle->nchannels () * grid_spacing();
                }
        }
 }
@@ -232,11 +234,12 @@ void
 PortMatrixGrid::draw_association_indicator (cairo_t* cr, uint32_t x, uint32_t y, double p)
 {
        set_source_rgba (cr, association_colour(), 0.5);
+
        cairo_arc (
                cr,
-               x + column_width() / 2,
-               y + column_width() / 2,
-               (column_width() - (2 * connection_indicator_pad())) / 2,
+               x + grid_spacing() / 2,
+               y + grid_spacing() / 2,
+               (grid_spacing() - (2 * connection_indicator_pad())) / 2,
                0,
                p * 2 * M_PI
                );
@@ -252,174 +255,128 @@ PortMatrixGrid::draw_unknown_indicator (cairo_t* cr, uint32_t x, uint32_t y)
                cr,
                x + thick_grid_line_width(),
                y + thick_grid_line_width(),
-               column_width() - 2 * thick_grid_line_width(),
-               row_height() - 2 * thick_grid_line_width()
+               grid_spacing() - 2 * thick_grid_line_width(),
+               grid_spacing() - 2 * thick_grid_line_width()
                );
        cairo_fill (cr);
 }
 
 PortMatrixNode
-PortMatrixGrid::position_to_node (double x, double y) const
+PortMatrixGrid::position_to_node (uint32_t x, uint32_t y) const
 {
        return PortMatrixNode (
-               y_position_to_group_and_channel (y).second,
-               x_position_to_group_and_channel (x).second
+               position_to_group_and_channel (y, _matrix->rows()).second,
+               position_to_group_and_channel (x, _matrix->columns()).second
                );
 }
 
-
-pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel>
-PortMatrixGrid::x_position_to_group_and_channel (double x) const
+void
+PortMatrixGrid::button_press (double x, double y, int b, uint32_t t)
 {
-       PortGroupList::List::const_iterator i = _matrix->columns()->begin();
-
-       while (i != _matrix->columns()->end()) {
-
-               uint32_t const gw = group_width (*i);
-
-               if (x < gw) {
-
-                       /* it's in this group */
-
-                       PortGroup::BundleList const & bundles = (*i)->bundles ();
-                       for (PortGroup::BundleList::const_iterator j = bundles.begin(); j != bundles.end(); ++j) {
-
-                               if (_matrix->show_only_bundles()) {
-                                       
-                                       if (x < column_width()) {
-                                               return make_pair (*i, ARDOUR::BundleChannel (j->bundle, 0));
-                                       } else {
-                                               x -= column_width ();
-                                       }
-                                       
-                               } else {
-
-                                       uint32_t const w = j->bundle->nchannels () * column_width ();
-                                       if (x < w) {
-                                               return make_pair (*i, ARDOUR::BundleChannel (j->bundle, x / column_width()));
-                                       } else {
-                                               x -= w;
-                                       }
-
-                               }
-
-                       }
-
-               } else {
+       if (b == 1) {
 
-                       x -= gw;
+               _dragging = true;
+               _moved = false;
+               _drag_start_x = x / grid_spacing ();
+               _drag_start_y = y / grid_spacing ();
 
-               }
+       } else if (b == 3) {
 
-               ++i;
+               _matrix->popup_menu (
+                       position_to_group_and_channel (x / grid_spacing(), _matrix->columns()),
+                       position_to_group_and_channel (y / grid_spacing(), _matrix->rows()), t);
+               
        }
-
-       return make_pair (boost::shared_ptr<PortGroup> (), ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), 0));
 }
 
-
-
-double
-PortMatrixGrid::channel_position (
-       ARDOUR::BundleChannel bc,
-       PortGroup::BundleList const& bundles,
-       double inc) const
+void
+PortMatrixGrid::button_release (double x, double y, int b, uint32_t t)
 {
-       double p = 0;
-       
-       PortGroup::BundleList::const_iterator i = bundles.begin ();
-       while (i != bundles.end() && i->bundle != bc.bundle) {
+       if (b == 1) {
 
-               if (_matrix->show_only_bundles()) {
-                       p += inc;
-               } else {
-                       p += inc * i->bundle->nchannels();
-               }
-               
-               ++i;
-       }
+               if (_dragging && _moved) {
 
-       if (i == bundles.end()) {
-               return 0;
-       }
+                       list<PortMatrixNode> const p = nodes_on_line (_drag_start_x, _drag_start_y, _drag_x, _drag_y);
 
-       p += inc * bc.channel;
+                       if (_matrix->show_only_bundles()) {
+                               /* XXX: err... */
+                       } else {
+                               for (list<PortMatrixNode>::const_iterator i = p.begin(); i != p.end(); ++i) {
 
-       return p;
-}
-
-void
-PortMatrixGrid::button_press (double x, double y, int b, uint32_t t)
-{
-       if (b == 1) {
-               
-               PortMatrixNode const node = position_to_node (x, y);
-               
-               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);
+                                       c[_matrix->row_index()] = i->row;
+                                       c[_matrix->column_index()] = i->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);
                                        }
                                }
                        }
-                       
+
+                       require_render ();
+                       _body->queue_draw ();
+
                } else {
+
+                       PortMatrixNode const node = position_to_node (x / grid_spacing(), y / grid_spacing());
                        
-                       if (node.row.bundle && node.column.bundle) {
+                       if (_matrix->show_only_bundles()) {
                                
-                               ARDOUR::BundleChannel c[2];
-                               c[_matrix->row_index()] = node.row;
-                               c[_matrix->column_index()] = node.column;
+                               PortMatrixNode::State const s = bundle_to_bundle_state (node.column.bundle, node.row.bundle);
                                
-                               PortMatrixNode::State const s = _matrix->get_state (c);
+                               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);
+                                               }
+                                       }
+                               }
                                
-                               if (s == PortMatrixNode::ASSOCIATED || s == PortMatrixNode::NOT_ASSOCIATED) {
-                                       
-                                       bool const n = !(s == PortMatrixNode::ASSOCIATED);
+                       } 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, n);
+                                       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);
+                                       }
+                                       
                                }
-                               
                        }
+                       
+                       require_render ();
+                       _body->queue_draw ();
                }
-               
-               require_render ();
-               _body->queue_draw ();
-
-       } else if (b == 3) {
-
-               _matrix->popup_menu (x_position_to_group_and_channel (x), y_position_to_group_and_channel (y), t);
-               
        }
+
+       _dragging = false;
 }
 
+
 void
 PortMatrixGrid::draw_extra (cairo_t* cr)
 {
        set_source_rgba (cr, mouseover_line_colour(), 0.3);
        cairo_set_line_width (cr, mouseover_line_width());
 
-       double const x = component_to_parent_x (
-               channel_position (_body->mouseover().column, _matrix->columns()->bundles(), column_width()) + column_width() / 2
-               );
-       
-       double const y = component_to_parent_y (
-               channel_position (_body->mouseover().row, _matrix->rows()->bundles(), row_height()) + row_height() / 2
-               );
+       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) {
 
@@ -442,6 +399,35 @@ PortMatrixGrid::draw_extra (cairo_t* cr)
                }
                cairo_stroke (cr);
        }
+
+       if (_dragging && _moved) {
+               
+               set_source_rgba (cr, association_colour (), 0.3);
+
+               cairo_move_to (
+                       cr,
+                       component_to_parent_x (_drag_start_x * grid_spacing() + grid_spacing() / 2),
+                       component_to_parent_y (_drag_start_y * grid_spacing() + grid_spacing() / 2)
+                       );
+               
+               cairo_line_to (
+                       cr,
+                       component_to_parent_x (_drag_x * grid_spacing() + grid_spacing() / 2),
+                       component_to_parent_y (_drag_y * grid_spacing() + grid_spacing() / 2)
+                       );
+               
+               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 ())
+                               );
+               }
+       }
 }
 
 void
@@ -452,9 +438,22 @@ PortMatrixGrid::mouseover_changed (PortMatrixNode const& old)
 }
 
 void
-PortMatrixGrid::mouseover_event (double x, double y)
+PortMatrixGrid::motion (double x, double y)
 {
-       _body->set_mouseover (position_to_node (x, y));
+       _body->set_mouseover (position_to_node (x / grid_spacing(), y / grid_spacing()));
+
+       int const px = x / grid_spacing ();
+       int const py = y / grid_spacing ();
+
+       if (_dragging && !_moved && ( (px != _drag_start_x || py != _drag_start_x) )) {
+               _moved = true;
+       }
+
+       if (_dragging && _moved) {
+               _drag_x = px;
+               _drag_y = py;
+               _body->queue_draw ();
+       }
 }
 
 void
@@ -462,23 +461,23 @@ PortMatrixGrid::queue_draw_for (PortMatrixNode const &n)
 {
        if (n.row.bundle) {
 
-               double const y = channel_position (n.row, _matrix->rows()->bundles(), row_height());
+               double const y = channel_to_position (n.row, _matrix->rows()) * grid_spacing ();
                _body->queue_draw_area (
                        _parent_rectangle.get_x(),
                        component_to_parent_y (y),
                        _parent_rectangle.get_width(),
-                       row_height()
+                       grid_spacing()
                        );
        }
 
        if (n.column.bundle) {
 
-               double const x = channel_position (n.column, _matrix->columns()->bundles(), column_width());
+               double const x = channel_to_position (n.column, _matrix->columns()) * grid_spacing ();
                
                _body->queue_draw_area (
                        component_to_parent_x (x),
                        _parent_rectangle.get_y(),
-                       column_width(),
+                       grid_spacing(),
                        _parent_rectangle.get_height()
                        );
        }
@@ -562,4 +561,55 @@ PortMatrixGrid::bundle_to_bundle_state (boost::shared_ptr<ARDOUR::Bundle> a, boo
        return PortMatrixNode::PARTIAL;
 }
 
+list<PortMatrixNode>
+PortMatrixGrid::nodes_on_line (int x0, int y0, int x1, int y1) const
+{
+       list<PortMatrixNode> p;
+
+       bool const steep = abs (y1 - y0) > abs (x1 - x0);
+       if (steep) {
+               int tmp = x0;
+               x0 = y0;
+               y0 = tmp;
+
+               tmp = y1;
+               y1 = x1;
+               x1 = tmp;
+       }
+
+       if (x0 > x1) {
+               int tmp = x0;
+               x0 = x1;
+               x1 = tmp;
+
+               tmp = y0;
+               y0 = y1;
+               y1 = tmp;
+       }
+
+       int dx = x1 - x0;
+       int dy = abs (y1 - y0);
        
+       double err = 0;
+       double derr = double (dy) / dx;
+
+       int y = y0;
+       int const ystep = y0 < y1 ? 1 : -1;
+
+       for (int x = x0; x <= x1; ++x) {
+               if (steep) {
+                       p.push_back (position_to_node (y, x));
+               } else {
+                       p.push_back (position_to_node (x, y));
+               }
+
+               err += derr;
+
+               if (err >= 0.5) {
+                       y += ystep;
+                       err -= 1;
+               }
+       }
+
+       return p;
+}
index 543ea8533fb408d4b621fa0a627894e2d1eadaae..22050ece87415d0da91da5554628a32b9306a13d 100644 (file)
@@ -42,7 +42,8 @@ public:
        PortMatrixGrid (PortMatrix *, PortMatrixBody *);
 
        void button_press (double, double, int, uint32_t);
-       void mouseover_event (double, double);
+       void button_release (double, double, int, uint32_t);
+       void motion (double, double);
 
        double component_to_parent_x (double x) const;
        double parent_to_component_x (double x) const;
@@ -57,14 +58,19 @@ private:
        void render (cairo_t *);
        void render_group_pair (cairo_t *, boost::shared_ptr<const PortGroup>, boost::shared_ptr<const PortGroup>, uint32_t, uint32_t);
 
-       double channel_position (ARDOUR::BundleChannel, PortGroup::BundleList const &, double) const;
-       PortMatrixNode position_to_node (double, double) const;
-       std::pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> x_position_to_group_and_channel (double) const;
+       PortMatrixNode position_to_node (uint32_t, uint32_t) const;
        void queue_draw_for (PortMatrixNode const &);
        void draw_association_indicator (cairo_t *, uint32_t, uint32_t, double p = 1);
        void draw_unknown_indicator (cairo_t *, uint32_t, uint32_t);
        PortMatrixNode::State bundle_to_bundle_state (boost::shared_ptr<ARDOUR::Bundle>, boost::shared_ptr<ARDOUR::Bundle>) const;
-       
+       std::list<PortMatrixNode> nodes_on_line (int, int, int, int) const;
+
+       bool _dragging;
+       bool _moved;
+       int _drag_start_x;
+       int _drag_start_y;
+       int _drag_x;
+       int _drag_y;
 };
 
 #endif
index 880f3adc3a1927af6954b2e5d64c9ea3b4475bc5..2cad8dda3e14ae1bff3052e46580f6ad96ae4f9a 100644 (file)
@@ -63,9 +63,9 @@ PortMatrixRowLabels::compute_dimensions ()
                }
 
                if (_matrix->show_only_bundles()) {
-                       _height += row_height ();
+                       _height += grid_spacing ();
                } else {
-                       _height += i->bundle->nchannels() * row_height();
+                       _height += i->bundle->nchannels() * grid_spacing();
                }
        }
 
@@ -78,8 +78,8 @@ PortMatrixRowLabels::compute_dimensions ()
                                _highest_group_name = ext.height;
                        }
                } else {
-                       /* add another row_height for a tab for this hidden group */
-                       _height += row_height ();
+                       /* add another grid_spacing for a tab for this hidden group */
+                       _height += grid_spacing ();
                }
        }
                        
@@ -122,12 +122,12 @@ PortMatrixRowLabels::render (cairo_t* cr)
                /* compute height of this group */
                double h = 0;
                if (!(*i)->visible() || (*i)->bundles().empty()) {
-                       h = row_height ();
+                       h = grid_spacing ();
                } else {
                        if (_matrix->show_only_bundles()) {
-                               h = (*i)->bundles().size() * row_height();
+                               h = (*i)->bundles().size() * grid_spacing();
                        } else {
-                               h = (*i)->total_channels () * row_height();
+                               h = (*i)->total_channels () * grid_spacing();
                        }
                }
                
@@ -170,11 +170,11 @@ PortMatrixRowLabels::render (cairo_t* cr)
                                        for (uint32_t k = 0; k < j->bundle->nchannels(); ++k) {
                                                Gdk::Color c = j->has_colour ? j->colour : get_a_bundle_colour (M);
                                                render_channel_name (cr, c, 0, y, ARDOUR::BundleChannel (j->bundle, k));
-                                               y += row_height();
+                                               y += grid_spacing();
                                                ++M;
                                        }
                                } else {
-                                       y += row_height();
+                                       y += grid_spacing();
                                }
                                
                                ++N;
@@ -182,7 +182,7 @@ PortMatrixRowLabels::render (cairo_t* cr)
                        
                } else {
 
-                       y += row_height ();
+                       y += grid_spacing ();
                }
        }
 }
@@ -192,7 +192,7 @@ PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t)
 {
        uint32_t const gw = (_highest_group_name + 2 * name_pad());
 
-       pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> w = y_position_to_group_and_channel (y);
+       pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel> w = position_to_group_and_channel (y / grid_spacing (), _matrix->rows());
 
        if (
                (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < gw) ||
@@ -214,24 +214,11 @@ PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t)
 
        } else if (b == 3) {
 
-               if (
-                       (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < (_longest_port_name + name_pad() * 2)) ||
-                       (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_longest_port_name + name_pad() * 2))
-                       
-                       ) {
-                       
-                       _matrix->popup_menu (
-                               make_pair (boost::shared_ptr<PortGroup> (), ARDOUR::BundleChannel ()),
-                               make_pair (w.first, ARDOUR::BundleChannel ()),
-                               t
-                               );
-               } else {
-                       _matrix->popup_menu (
-                               make_pair (boost::shared_ptr<PortGroup> (), ARDOUR::BundleChannel ()),
-                               make_pair (w.first, ARDOUR::BundleChannel ()),
-                               t
-                               );
-               }
+               _matrix->popup_menu (
+                       make_pair (boost::shared_ptr<PortGroup> (), ARDOUR::BundleChannel ()),
+                       w,
+                       t
+                       );
        }
 }
 
@@ -299,19 +286,19 @@ PortMatrixRowLabels::render_bundle_name (
        
        int const n = _matrix->show_only_bundles() ? 1 : b->nchannels();
        set_source_rgb (cr, colour);
-       cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, row_height() * n);
+       cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, grid_spacing() * n);
        cairo_fill_preserve (cr);
        set_source_rgb (cr, background_colour());
        cairo_set_line_width (cr, label_border_width ());
        cairo_stroke (cr);
 
-       double const off = row_height() / 2;
+       double const off = grid_spacing() / 2;
 
 //     if ((*i)->nchannels () > 0 && !_matrix->show_only_bundles()) {
 //             /* use the extent of our first channel name so that the bundle name is vertically aligned with it */
 //             cairo_text_extents_t ext;
 //             cairo_text_extents (cr, (*i)->channel_name(0).c_str(), &ext);
-//             off = (row_height() - ext.height) / 2;
+//             off = (grid_spacing() - ext.height) / 2;
 //     }
 
        set_source_rgb (cr, text_colour());
@@ -325,7 +312,7 @@ PortMatrixRowLabels::render_channel_name (
        )
 {
        set_source_rgb (cr, colour);
-       cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, row_height());
+       cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, grid_spacing());
        cairo_fill_preserve (cr);
        set_source_rgb (cr, background_colour());
        cairo_set_line_width (cr, label_border_width ());
@@ -333,7 +320,7 @@ PortMatrixRowLabels::render_channel_name (
        
        cairo_text_extents_t ext;
        cairo_text_extents (cr, bc.bundle->channel_name(bc.channel).c_str(), &ext);
-       double const off = (row_height() - ext.height) / 2;
+       double const off = (grid_spacing() - ext.height) / 2;
        
        set_source_rgb (cr, text_colour());
        cairo_move_to (cr, port_name_x() + xoff + name_pad(), yoff + name_pad() + off);
@@ -349,24 +336,7 @@ PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel const& bc) const
 double
 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const
 {
-       uint32_t n = 0;
-
-       PortGroup::BundleList const & bundles = _matrix->rows()->bundles();
-       PortGroup::BundleList::const_iterator i = bundles.begin ();
-       while (i != bundles.end() && i->bundle != bc.bundle) {
-               if (_matrix->show_only_bundles()) {
-                       n += 1;
-               } else {
-                       n += i->bundle->nchannels ();
-               }
-               ++i;
-       }
-
-       if (!_matrix->show_only_bundles()) {
-               n += bc.channel;
-       }
-       
-       return n * row_height();
+       return channel_to_position (bc, _matrix->rows()) * grid_spacing ();
 }
 
 void
@@ -379,14 +349,14 @@ PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
                                component_to_parent_x (bundle_name_x()),
                                component_to_parent_y (channel_y (bc)),
                                _longest_bundle_name + name_pad() * 2,
-                               row_height()
+                               grid_spacing()
                                );
                } else {
                        _body->queue_draw_area (
                                component_to_parent_x (port_name_x()),
                                component_to_parent_y (channel_y (bc)),
                                _longest_port_name + name_pad() * 2,
-                               row_height()
+                               grid_spacing()
                                );
                }
        }