diff --git a/gtk2_ardour/bundle_manager.cc b/gtk2_ardour/bundle_manager.cc index 04bf240f7c..0f4bdb3c75 100644 --- a/gtk2_ardour/bundle_manager.cc +++ b/gtk2_ardour/bundle_manager.cc @@ -36,7 +36,7 @@ BundleEditorMatrix::BundleEditorMatrix ( : PortMatrix (session, bundle->type(), bundle->ports_are_inputs()) { _port_group = new PortGroup ("", true); - _port_group->bundles.push_back (bundle); + _port_group->add_bundle (bundle); _row_ports.push_back (_port_group); } @@ -93,14 +93,14 @@ BundleEditorMatrix::add_channel (boost::shared_ptr b) return; } - _port_group->bundles.front()->add_channel (d.get_name()); + _port_group->only_bundle()->add_channel (d.get_name()); setup (); } void BundleEditorMatrix::remove_channel (boost::shared_ptr b, uint32_t c) { - _port_group->bundles.front()->remove_channel (c); + _port_group->only_bundle()->remove_channel (c); setup (); } diff --git a/gtk2_ardour/io_selector.cc b/gtk2_ardour/io_selector.cc index cb1a07ce14..b472c8eb71 100644 --- a/gtk2_ardour/io_selector.cc +++ b/gtk2_ardour/io_selector.cc @@ -63,9 +63,9 @@ IOSelector::~IOSelector () void IOSelector::setup () { - _port_group->bundles.clear (); - _port_group->bundles.push_back (boost::shared_ptr (new ARDOUR::Bundle)); - _port_group->bundles.front()->set_name (_io->name()); + _port_group->clear (); + _port_group->add_bundle (boost::shared_ptr (new ARDOUR::Bundle)); + _port_group->only_bundle()->set_name (_io->name()); if (offering_input ()) { const PortSet& ps (_io->outputs()); @@ -74,8 +74,8 @@ IOSelector::setup () for (PortSet::const_iterator i = ps.begin(); i != ps.end(); ++i) { char buf[32]; snprintf (buf, sizeof(buf), _("out %d"), j + 1); - _port_group->bundles.front()->add_channel (buf); - _port_group->bundles.front()->add_port_to_channel (j, _session.engine().make_port_name_non_relative (i->name())); + _port_group->only_bundle()->add_channel (buf); + _port_group->only_bundle()->add_port_to_channel (j, _session.engine().make_port_name_non_relative (i->name())); ++j; } @@ -87,8 +87,8 @@ IOSelector::setup () for (PortSet::const_iterator i = ps.begin(); i != ps.end(); ++i) { char buf[32]; snprintf (buf, sizeof(buf), _("in %d"), j + 1); - _port_group->bundles.front()->add_channel (buf); - _port_group->bundles.front()->add_port_to_channel (j, _session.engine().make_port_name_non_relative (i->name())); + _port_group->only_bundle()->add_channel (buf); + _port_group->only_bundle()->add_port_to_channel (j, _session.engine().make_port_name_non_relative (i->name())); ++j; } diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc index 086e0b75d9..2544268586 100644 --- a/gtk2_ardour/port_group.cc +++ b/gtk2_ardour/port_group.cc @@ -38,7 +38,8 @@ using namespace Gtk; void PortGroup::add_bundle (boost::shared_ptr b) { - bundles.push_back (b); + assert (b.get()); + _bundles.push_back (b); } /** Add a port to a group. @@ -53,14 +54,14 @@ PortGroup::add_port (std::string const &p) void PortGroup::clear () { - bundles.clear (); + _bundles.clear (); ports.clear (); } bool PortGroup::has_port (std::string const& p) const { - for (ARDOUR::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) { + for (ARDOUR::BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) { if ((*i)->offers_port_alone (p)) { return true; } @@ -74,6 +75,13 @@ PortGroup::has_port (std::string const& p) const return false; } + +boost::shared_ptr +PortGroup::only_bundle () +{ + assert (_bundles.size() == 1); + return _bundles.front(); +} /** PortGroupUI constructor. @@ -116,7 +124,7 @@ PortGroupUI::setup_visibility_checkbutton () */ PortGroupList::PortGroupList (ARDOUR::DataType type, bool offer_inputs) - : _type (type), _offer_inputs (offer_inputs), + : _type (type), _offer_inputs (offer_inputs), _bundles_dirty (true), _buss (_("Bus"), true), _track (_("Track"), true), _system (_("System"), true), @@ -185,7 +193,7 @@ PortGroupList::gather (ARDOUR::Session& session) boost::shared_ptr b = session.bundles (); for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { if ((*i)->ports_are_inputs() == _offer_inputs && (*i)->type() == _type) { - _system.bundles.push_back (*i); + _system.add_bundle (*i); } } @@ -232,6 +240,8 @@ PortGroupList::gather (ARDOUR::Session& session) (*i)->VisibilityChanged.connect (sigc::mem_fun (*this, &PortGroupList::visibility_changed)) ); } + + _bundles_dirty = true; } bool @@ -245,24 +255,26 @@ void PortGroupList::set_type (ARDOUR::DataType t) { _type = t; + _bundles_dirty = true; } void PortGroupList::set_offer_inputs (bool i) { _offer_inputs = i; + _bundles_dirty = true; } -ARDOUR::BundleList -PortGroupList::bundles () const +void +PortGroupList::update_bundles () const { - ARDOUR::BundleList bundles; + _bundles.clear (); for (const_iterator i = begin (); i != end (); ++i) { if ((*i)->visible()) { - std::copy ((*i)->bundles.begin(), (*i)->bundles.end(), std::back_inserter (bundles)); - + std::copy ((*i)->bundles().begin(), (*i)->bundles().end(), std::back_inserter (_bundles)); + /* make a bundle for the ports, if there are any */ if (!(*i)->ports.empty()) { @@ -279,12 +291,12 @@ PortGroupList::bundles () const b->set_port (j, p); } - bundles.push_back (b); + _bundles.push_back (b); } } } - return bundles; + _bundles_dirty = false; } std::string @@ -359,4 +371,15 @@ PortGroupList::clear_list () } _visibility_connections.clear (); + _bundles_dirty = true; +} + +ARDOUR::BundleList const & +PortGroupList::bundles () const +{ + if (_bundles_dirty) { + update_bundles (); + } + + return _bundles; } diff --git a/gtk2_ardour/port_group.h b/gtk2_ardour/port_group.h index 17e9842f93..d6008b61ba 100644 --- a/gtk2_ardour/port_group.h +++ b/gtk2_ardour/port_group.h @@ -50,12 +50,17 @@ public: : name (n), _visible (v) {} void add_bundle (boost::shared_ptr); + boost::shared_ptr only_bundle (); void add_port (std::string const &); void clear (); std::string name; ///< name for the group - ARDOUR::BundleList bundles; std::vector ports; + + ARDOUR::BundleList const & bundles () const { + return _bundles; + } + bool visible () const { return _visible; } @@ -70,6 +75,7 @@ public: sigc::signal VisibilityChanged; private: + ARDOUR::BundleList _bundles; bool _visible; ///< true if the group is visible in the UI }; @@ -101,7 +107,7 @@ class PortGroupList : public std::list, public sigc::trackable void gather (ARDOUR::Session &); void set_type (ARDOUR::DataType); void set_offer_inputs (bool); - ARDOUR::BundleList bundles () const; + ARDOUR::BundleList const & bundles () const; void take_visibility_from (PortGroupList const &); void clear_list (); @@ -111,9 +117,12 @@ class PortGroupList : public std::list, public sigc::trackable bool port_has_prefix (std::string const &, std::string const &) const; std::string common_prefix (std::vector const &) const; void visibility_changed (); + void update_bundles () const; ARDOUR::DataType _type; bool _offer_inputs; + mutable ARDOUR::BundleList _bundles; + mutable bool _bundles_dirty; PortGroup _buss; PortGroup _track; diff --git a/gtk2_ardour/port_matrix_body.cc b/gtk2_ardour/port_matrix_body.cc index 3531712a56..d30fd58c6a 100644 --- a/gtk2_ardour/port_matrix_body.cc +++ b/gtk2_ardour/port_matrix_body.cc @@ -31,10 +31,12 @@ PortMatrixBody::PortMatrixBody (PortMatrix* p, Arrangement a) _arrangement (a), _xoffset (0), _yoffset (0), + _pointer_inside (false), _column_ports (_port_matrix->type(), _port_matrix->offering_input()), _row_ports (_port_matrix->type(), !_port_matrix->offering_input()) { modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#00000")); + add_events (Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::POINTER_MOTION_MASK); } @@ -47,15 +49,15 @@ PortMatrixBody::on_expose_event (GdkEventExpose* event) bool intersects; Gdk::Rectangle r = exposure; - r.intersect (_column_labels_rect, intersects); + r.intersect (_column_labels.parent_rectangle(), intersects); if (intersects) { gdk_draw_drawable ( get_window()->gobj(), get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(), _column_labels.get_pixmap (get_window()->gobj()), - r.get_x() - _column_labels_rect.get_x() + _xoffset, - r.get_y() - _column_labels_rect.get_y(), + _column_labels.parent_to_component_x (r.get_x()), + _column_labels.parent_to_component_y (r.get_y()), r.get_x(), r.get_y(), r.get_width(), @@ -64,15 +66,15 @@ PortMatrixBody::on_expose_event (GdkEventExpose* event) } r = exposure; - r.intersect (_row_labels_rect, intersects); + r.intersect (_row_labels.parent_rectangle(), intersects); if (intersects) { gdk_draw_drawable ( get_window()->gobj(), get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(), _row_labels.get_pixmap (get_window()->gobj()), - r.get_x() - _row_labels_rect.get_x(), - r.get_y() - _row_labels_rect.get_y() + _yoffset, + _row_labels.parent_to_component_x (r.get_x()), + _row_labels.parent_to_component_y (r.get_y()), r.get_x(), r.get_y(), r.get_width(), @@ -81,15 +83,15 @@ PortMatrixBody::on_expose_event (GdkEventExpose* event) } r = exposure; - r.intersect (_grid_rect, intersects); + r.intersect (_grid.parent_rectangle(), intersects); if (intersects) { gdk_draw_drawable ( get_window()->gobj(), get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(), _grid.get_pixmap (get_window()->gobj()), - r.get_x() - _grid_rect.get_x() + _xoffset, - r.get_y() - _grid_rect.get_y() + _yoffset, + _grid.parent_to_component_x (r.get_x()), + _grid.parent_to_component_y (r.get_y()), r.get_x(), r.get_y(), r.get_width(), @@ -97,6 +99,12 @@ PortMatrixBody::on_expose_event (GdkEventExpose* event) ); } + cairo_t* cr = gdk_cairo_create (get_window()->gobj()); + _grid.draw_extra (cr); + _row_labels.draw_extra (cr); + _column_labels.draw_extra (cr); + cairo_destroy (cr); + return true; } @@ -132,18 +140,22 @@ PortMatrixBody::compute_rectangles () std::pair const row = _row_labels.dimensions (); std::pair const grid = _grid.dimensions (); + Gdk::Rectangle col_rect; + Gdk::Rectangle row_rect; + Gdk::Rectangle grid_rect; + if (_arrangement == TOP_AND_RIGHT) { /* build from top left */ - _column_labels_rect.set_x (0); - _column_labels_rect.set_y (0); - _grid_rect.set_x (0); + col_rect.set_x (0); + col_rect.set_y (0); + grid_rect.set_x (0); if (_alloc_width > col.first) { - _column_labels_rect.set_width (col.first); + col_rect.set_width (col.first); } else { - _column_labels_rect.set_width (_alloc_width); + col_rect.set_width (_alloc_width); } /* move down to y division */ @@ -155,11 +167,11 @@ PortMatrixBody::compute_rectangles () y = _alloc_height; } - _column_labels_rect.set_height (y); - _row_labels_rect.set_y (y); - _row_labels_rect.set_height (_alloc_height - y); - _grid_rect.set_y (y); - _grid_rect.set_height (_alloc_height - y); + col_rect.set_height (y); + row_rect.set_y (y); + row_rect.set_height (_alloc_height - y); + grid_rect.set_y (y); + grid_rect.set_height (_alloc_height - y); /* move right to x division */ @@ -170,9 +182,9 @@ PortMatrixBody::compute_rectangles () x = _alloc_width - row.first; } - _grid_rect.set_width (x); - _row_labels_rect.set_x (x); - _row_labels_rect.set_width (_alloc_width - x); + grid_rect.set_width (x); + row_rect.set_x (x); + row_rect.set_width (_alloc_width - x); } else if (_arrangement == BOTTOM_AND_LEFT) { @@ -188,13 +200,13 @@ PortMatrixBody::compute_rectangles () x = _alloc_width - row.first; } - _grid_rect.set_x (_alloc_width - x); - _grid_rect.set_width (x); - _column_labels_rect.set_width (col.first - grid.first + x); - _column_labels_rect.set_x (_alloc_width - _column_labels_rect.get_width()); + grid_rect.set_x (_alloc_width - x); + grid_rect.set_width (x); + col_rect.set_width (col.first - grid.first + x); + col_rect.set_x (_alloc_width - col_rect.get_width()); - _row_labels_rect.set_width (std::min (_alloc_width - x, row.first)); - _row_labels_rect.set_x (_alloc_width - x - _row_labels_rect.get_width()); + row_rect.set_width (std::min (_alloc_width - x, row.first)); + row_rect.set_x (_alloc_width - x - row_rect.get_width()); /* move up to the y division */ @@ -205,16 +217,19 @@ PortMatrixBody::compute_rectangles () y = _alloc_height; } - _column_labels_rect.set_y (_alloc_height - y); - _column_labels_rect.set_height (y); + col_rect.set_y (_alloc_height - y); + col_rect.set_height (y); - _grid_rect.set_height (std::min (grid.second, _alloc_height - y)); - _grid_rect.set_y (_alloc_height - y - _grid_rect.get_height()); - - _row_labels_rect.set_height (_grid_rect.get_height()); - _row_labels_rect.set_y (_grid_rect.get_y()); + grid_rect.set_height (std::min (grid.second, _alloc_height - y)); + grid_rect.set_y (_alloc_height - y - grid_rect.get_height()); + row_rect.set_height (grid_rect.get_height()); + row_rect.set_y (grid_rect.get_y()); } + + _row_labels.set_parent_rectangle (row_rect); + _column_labels.set_parent_rectangle (col_rect); + _grid.set_parent_rectangle (grid_rect); } void @@ -262,7 +277,7 @@ PortMatrixBody::full_scroll_width () uint32_t PortMatrixBody::alloc_scroll_width () { - return _grid_rect.get_width(); + return _grid.parent_rectangle().get_width(); } uint32_t @@ -274,7 +289,7 @@ PortMatrixBody::full_scroll_height () uint32_t PortMatrixBody::alloc_scroll_height () { - return _grid_rect.get_height(); + return _grid.parent_rectangle().get_height(); } void @@ -294,19 +309,19 @@ PortMatrixBody::set_yoffset (uint32_t yo) bool PortMatrixBody::on_button_press_event (GdkEventButton* ev) { - if (Gdk::Region (_grid_rect).point_in (ev->x, ev->y)) { + if (Gdk::Region (_grid.parent_rectangle()).point_in (ev->x, ev->y)) { _grid.button_press ( - ev->x - _grid_rect.get_x() + _xoffset, - ev->y - _grid_rect.get_y() + _yoffset, + _grid.parent_to_component_x (ev->x), + _grid.parent_to_component_y (ev->y), ev->button ); - } else if (Gdk::Region (_row_labels_rect).point_in (ev->x, ev->y)) { + } else if (Gdk::Region (_row_labels.parent_rectangle()).point_in (ev->x, ev->y)) { _row_labels.button_press ( - ev->x - _row_labels_rect.get_x(), - ev->y - _row_labels_rect.get_y() + _yoffset, + _row_labels.parent_to_component_x (ev->x), + _row_labels.parent_to_component_y (ev->y), ev->button, ev->time ); @@ -339,3 +354,43 @@ PortMatrixBody::rebuild_and_draw_row_labels () _row_labels.require_rebuild (); queue_draw (); } + +bool +PortMatrixBody::on_enter_notify_event (GdkEventCrossing* ev) +{ + if (ev->type == GDK_ENTER_NOTIFY) { + _pointer_inside = true; + } else if (ev->type == GDK_LEAVE_NOTIFY) { + _pointer_inside = false; + } + + return true; +} + +bool +PortMatrixBody::on_motion_notify_event (GdkEventMotion* ev) +{ + if (_pointer_inside && Gdk::Region (_grid.parent_rectangle()).point_in (ev->x, ev->y)) { + _grid.mouseover_event ( + _grid.parent_to_component_x (ev->x), + _grid.parent_to_component_y (ev->y) + ); + } + + return true; +} + +void +PortMatrixBody::set_mouseover (PortMatrixNode const & n) +{ + if (n == _mouseover) { + return; + } + + PortMatrixNode old = _mouseover; + _mouseover = n; + + _grid.mouseover_changed (old); + _row_labels.mouseover_changed (old); + _column_labels.mouseover_changed (old); +} diff --git a/gtk2_ardour/port_matrix_body.h b/gtk2_ardour/port_matrix_body.h index c9fd8bdb65..2a68a251bf 100644 --- a/gtk2_ardour/port_matrix_body.h +++ b/gtk2_ardour/port_matrix_body.h @@ -24,6 +24,7 @@ #include "port_matrix_row_labels.h" #include "port_matrix_grid.h" #include "port_group.h" +#include "port_matrix_types.h" class PortMatrix; @@ -58,21 +59,35 @@ public: uint32_t full_scroll_height (); uint32_t alloc_scroll_height (); + uint32_t xoffset () const { + return _xoffset; + } void set_xoffset (uint32_t); + uint32_t yoffset () const { + return _yoffset; + } void set_yoffset (uint32_t); void rebuild_and_draw_grid (); - + + void set_mouseover (PortMatrixNode const &); + PortMatrixNode mouseover () const { + return _mouseover; + } + protected: bool on_expose_event (GdkEventExpose *); void on_size_request (Gtk::Requisition *); void on_size_allocate (Gtk::Allocation &); bool on_button_press_event (GdkEventButton *); - + bool on_enter_notify_event (GdkEventCrossing *); + bool on_motion_notify_event (GdkEventMotion *); + private: void compute_rectangles (); void rebuild_and_draw_column_labels (); void rebuild_and_draw_row_labels (); + void update_bundles (); PortMatrix* _port_matrix; PortMatrixColumnLabels _column_labels; @@ -87,12 +102,15 @@ private: Gdk::Rectangle _grid_rect; uint32_t _xoffset; uint32_t _yoffset; + bool _pointer_inside; /// bundles to offer for columns PortGroupList _column_ports; /// bundles to offer for rows PortGroupList _row_ports; + PortMatrixNode _mouseover; + std::list _bundle_connections; }; diff --git a/gtk2_ardour/port_matrix_column_labels.cc b/gtk2_ardour/port_matrix_column_labels.cc index 3ef501d89b..bd6a14e6fa 100644 --- a/gtk2_ardour/port_matrix_column_labels.cc +++ b/gtk2_ardour/port_matrix_column_labels.cc @@ -133,13 +133,13 @@ PortMatrixColumnLabels::render (cairo_t* cr) int g = 0; for (PortGroupList::const_iterator i = _body->column_ports().begin(); i != _body->column_ports().end(); ++i) { - if (!(*i)->visible() || ((*i)->bundles.empty() && (*i)->ports.empty()) ) { + if (!(*i)->visible() || ((*i)->bundles().empty() && (*i)->ports.empty()) ) { continue; } /* compute width of this group */ uint32_t w = 0; - for (ARDOUR::BundleList::const_iterator j = (*i)->bundles.begin(); j != (*i)->bundles.end(); ++j) { + for (ARDOUR::BundleList::const_iterator j = (*i)->bundles().begin(); j != (*i)->bundles().end(); ++j) { w += (*j)->nchannels() * column_width(); } w += (*i)->ports.size() * column_width(); @@ -236,71 +236,183 @@ PortMatrixColumnLabels::render (cairo_t* cr) for (uint32_t j = 0; j < (*i)->nchannels(); ++j) { - double const lc = _longest_channel_name + name_pad(); - double const w = column_width(); - double const ph = _height - _highest_group_name - 2 * name_pad(); - - if (_location == BOTTOM) { - - double x_ = x + ph / tan (angle()) + w; - double const ix = x_; - double y_ = 0; - cairo_move_to (cr, x_, y_); - x_ -= w; - cairo_line_to (cr, x_, y_); - x_ -= lc * cos (angle()); - y_ += lc * sin (angle()); - cairo_line_to (cr, x_, y_); - x_ += w * pow (sin (angle()), 2); - y_ += w * sin (angle()) * cos (angle()); - cairo_line_to (cr, x_, y_); - cairo_line_to (cr, ix, 0); - - } else if (_location == TOP) { - - double x_ = x; - double y_ = _height; - cairo_move_to (cr, x_, y_); - x_ += w; - cairo_line_to (cr, x_, y_); - x_ += lc * cos (angle()); - y_ -= lc * sin (angle()); - cairo_line_to (cr, x_, y_); - x_ -= column_width() * pow (sin (angle()), 2); - y_ -= column_width() * sin (angle()) * cos (angle()); - cairo_line_to (cr, x_, y_); - cairo_line_to (cr, x, _height); - - } - - Gdk::Color colour = get_a_bundle_colour (i - c.begin()); - set_source_rgb (cr, colour); - cairo_fill_preserve (cr); - set_source_rgb (cr, background_colour()); - cairo_set_line_width (cr, label_border_width()); - cairo_stroke (cr); - - set_source_rgb (cr, text_colour()); - - if (_location == TOP) { - cairo_move_to (cr, x + basic_text_x_pos(j), _height - name_pad() * sin (angle())); - } else if (_location == BOTTOM) { - double const rl = 3 * name_pad() + _longest_bundle_name; - cairo_move_to (cr, x + basic_text_x_pos(j) + rl * cos (angle ()), ph - rl * sin (angle())); - } - - cairo_save (cr); - cairo_rotate (cr, -angle()); - - cairo_show_text ( - cr, - (*i)->channel_name(j).c_str() - ); - - cairo_restore (cr); - + render_port_name (cr, get_a_bundle_colour (i - c.begin()), x, 0, PortMatrixBundleChannel (*i, j)); x += column_width(); } } } +double +PortMatrixColumnLabels::component_to_parent_x (double x) const +{ + return x - _body->xoffset() + _parent_rectangle.get_x(); +} + +double +PortMatrixColumnLabels::parent_to_component_x (double x) const +{ + return x + _body->xoffset() - _parent_rectangle.get_x(); +} + +double +PortMatrixColumnLabels::component_to_parent_y (double y) const +{ + return y + _parent_rectangle.get_y(); +} + +double +PortMatrixColumnLabels::parent_to_component_y (double y) const +{ + return y - _parent_rectangle.get_y(); +} + +void +PortMatrixColumnLabels::mouseover_changed (PortMatrixNode const& old) +{ + queue_draw_for (old); + queue_draw_for (_body->mouseover()); +} + +void +PortMatrixColumnLabels::draw_extra (cairo_t* cr) +{ + if (_body->mouseover().column.bundle) { + render_port_name ( + cr, + mouseover_port_colour (), + component_to_parent_x (channel_x (_body->mouseover().column)), + component_to_parent_y (0), + _body->mouseover().column + ); + } + +} + +void +PortMatrixColumnLabels::render_port_name (cairo_t* cr, Gdk::Color colour, double x, double y, PortMatrixBundleChannel const &bc) +{ + double const lc = _longest_channel_name + name_pad(); + double const w = column_width(); + double const ph = _height - _highest_group_name - 2 * name_pad(); + + if (_location == BOTTOM) { + + double x_ = x + ph / tan (angle()) + w; + double const ix = x_; + double y_ = y; + cairo_move_to (cr, x_, y_); + x_ -= w; + cairo_line_to (cr, x_, y_); + x_ -= lc * cos (angle()); + y_ += lc * sin (angle()); + cairo_line_to (cr, x_, y_); + x_ += w * pow (sin (angle()), 2); + y_ += w * sin (angle()) * cos (angle()); + cairo_line_to (cr, x_, y_); + cairo_line_to (cr, ix, y); + + } else if (_location == TOP) { + + double x_ = x; + double y_ = y + _height; + cairo_move_to (cr, x_, y_); + x_ += w; + cairo_line_to (cr, x_, y_); + x_ += lc * cos (angle()); + y_ -= lc * sin (angle()); + cairo_line_to (cr, x_, y_); + x_ -= column_width() * pow (sin (angle()), 2); + y_ -= column_width() * sin (angle()) * cos (angle()); + cairo_line_to (cr, x_, y_); + cairo_line_to (cr, x, y + _height); + + } + + set_source_rgb (cr, colour); + cairo_fill_preserve (cr); + set_source_rgb (cr, background_colour()); + cairo_set_line_width (cr, label_border_width()); + cairo_stroke (cr); + + set_source_rgb (cr, text_colour()); + + if (_location == TOP) { + + cairo_move_to ( + cr, + x + basic_text_x_pos(bc.channel), + y + _height - name_pad() * sin (angle()) + ); + + } else if (_location == BOTTOM) { + + double const rl = 3 * name_pad() + _longest_bundle_name; + cairo_move_to ( + cr, + x + basic_text_x_pos(bc.channel) + rl * cos (angle ()), + y + ph - rl * sin (angle()) + ); + } + + cairo_save (cr); + cairo_rotate (cr, -angle()); + + cairo_show_text ( + cr, + bc.bundle->channel_name(bc.channel).c_str() + ); + + cairo_restore (cr); +} + +double +PortMatrixColumnLabels::channel_x (PortMatrixBundleChannel const &bc) const +{ + double x = 0; + + ARDOUR::BundleList::const_iterator i = _body->column_ports().bundles().begin(); + while (i != _body->column_ports().bundles().end() && *i != bc.bundle) { + x += column_width() * (*i)->nchannels(); + ++i; + } + + x += column_width() * bc.channel; + + return x; +} + +void +PortMatrixColumnLabels::queue_draw_for (PortMatrixNode const& n) +{ + if (n.column.bundle) { + + double const x = channel_x (n.column); + double const lc = _longest_channel_name + name_pad(); + double const h = lc * sin (angle ()) + column_width() * sin (angle()) * cos (angle()); + if (_location == TOP) { + + _body->queue_draw_area ( + component_to_parent_x (x), + component_to_parent_y (_height - h), + column_width() + lc * cos (angle()), + h + ); + + } else if (_location == BOTTOM) { + + double const ph = _height - _highest_group_name - 2 * name_pad(); + double const w = column_width() + lc * cos (angle()); + double const x_ = x + ph / tan (angle()) - lc * cos (angle()); + + _body->queue_draw_area ( + component_to_parent_x (x_), + component_to_parent_y (0), + column_width() + lc * cos (angle()), + h + ); + + } + + + } +} diff --git a/gtk2_ardour/port_matrix_column_labels.h b/gtk2_ardour/port_matrix_column_labels.h index 5bdd7a2930..213b760a25 100644 --- a/gtk2_ardour/port_matrix_column_labels.h +++ b/gtk2_ardour/port_matrix_column_labels.h @@ -23,12 +23,13 @@ #include #include "port_matrix_component.h" -class PortMatrixBody; - namespace ARDOUR { class Bundle; } +class PortMatrixNode; +class PortMatrixBundleChannel; + /** The column labels part of the port matrix */ class PortMatrixColumnLabels : public PortMatrixComponent { @@ -41,10 +42,20 @@ public: PortMatrixColumnLabels (PortMatrixBody *, Location); + double component_to_parent_x (double x) const; + double parent_to_component_x (double x) const; + double component_to_parent_y (double y) const; + double parent_to_component_y (double y) const; + void mouseover_changed (PortMatrixNode const &); + void draw_extra (cairo_t *); + private: void render (cairo_t *); void compute_dimensions (); double basic_text_x_pos (int) const; + void render_port_name (cairo_t *, Gdk::Color, double, double, PortMatrixBundleChannel const &); + double channel_x (PortMatrixBundleChannel const &) const; + void queue_draw_for (PortMatrixNode const &); std::vector > _bundles; double _longest_bundle_name; diff --git a/gtk2_ardour/port_matrix_component.h b/gtk2_ardour/port_matrix_component.h index cc0f082695..7531e44bdd 100644 --- a/gtk2_ardour/port_matrix_component.h +++ b/gtk2_ardour/port_matrix_component.h @@ -23,6 +23,7 @@ #include class PortMatrixBody; +class PortMatrixNode; /** One component of the PortMatrix. This is a cairo-rendered * Pixmap. @@ -33,6 +34,13 @@ public: PortMatrixComponent (PortMatrixBody *); virtual ~PortMatrixComponent (); + virtual double component_to_parent_x (double x) const = 0; + virtual double parent_to_component_x (double x) const = 0; + virtual double component_to_parent_y (double y) const = 0; + virtual double parent_to_component_y (double y) const = 0; + virtual void mouseover_changed (PortMatrixNode const &) = 0; + virtual void draw_extra (cairo_t *) = 0; + void setup (); GdkPixmap* get_pixmap (GdkDrawable *); std::pair dimensions (); @@ -46,6 +54,14 @@ public: _render_required = true; } + void set_parent_rectangle (Gdk::Rectangle const & r) { + _parent_rectangle = r; + } + + Gdk::Rectangle parent_rectangle () const { + return _parent_rectangle; + } + /** @return width of columns in the grid */ static uint32_t column_width () { return 32; @@ -83,6 +99,10 @@ protected: return 8; } + static uint32_t mouseover_line_width () { + return 4; + } + /** @return angle of column labels, in radians */ static double angle () { return M_PI / 4; @@ -115,6 +135,16 @@ protected: return Gdk::Color ("#cccccc"); } + /** @return colour to paint mouseover lines */ + static Gdk::Color mouseover_line_colour () { + return Gdk::Color ("#ff0000"); + } + + /** @return colour to paint mouseover lines */ + static Gdk::Color mouseover_port_colour () { + return Gdk::Color ("#777777"); + } + /* XXX */ static Gdk::Color get_a_bundle_colour (int x) { if ((x % 2) == 0) { @@ -147,6 +177,7 @@ protected: PortMatrixBody* _body; ///< the PortMatrixBody that we're in uint32_t _width; ///< full width of the contents uint32_t _height; ///< full height of the contents + Gdk::Rectangle _parent_rectangle; private: GdkPixmap* _pixmap; ///< pixmap diff --git a/gtk2_ardour/port_matrix_grid.cc b/gtk2_ardour/port_matrix_grid.cc index bab229efaf..2343cb4c08 100644 --- a/gtk2_ardour/port_matrix_grid.cc +++ b/gtk2_ardour/port_matrix_grid.cc @@ -168,52 +168,75 @@ PortMatrixGrid::render (cairo_t* cr) } +PortMatrixNode +PortMatrixGrid::position_to_node (double x, double y) const +{ + return PortMatrixNode ( + position_to_channel (y, _body->row_ports().bundles(), row_height()), + position_to_channel (x, _body->column_ports().bundles(), column_width()) + ); +} + + +PortMatrixBundleChannel +PortMatrixGrid::position_to_channel (double p, ARDOUR::BundleList const& bundles, double inc) const +{ + uint32_t pos = p / inc; + + for (ARDOUR::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) { + if (pos < (*i)->nchannels()) { + return PortMatrixBundleChannel (*i, pos); + } else { + pos -= (*i)->nchannels(); + } + } + + return PortMatrixBundleChannel (boost::shared_ptr (), 0); +} + + +double +PortMatrixGrid::channel_position ( + PortMatrixBundleChannel bc, + ARDOUR::BundleList const& bundles, + double inc) const +{ + double p = 0; + + ARDOUR::BundleList::const_iterator i = bundles.begin (); + while (i != bundles.end() && *i != bc.bundle) { + p += inc * (*i)->nchannels(); + ++i; + } + + if (i == bundles.end()) { + return 0; + } + + p += inc * bc.channel; + + return p; +} + void PortMatrixGrid::button_press (double x, double y, int b) { - uint32_t grid_column = x / column_width (); - uint32_t grid_row = y / row_height (); - - boost::shared_ptr our_bundle; - uint32_t our_channel = 0; - boost::shared_ptr other_bundle; - uint32_t other_channel = 0; - - ARDOUR::BundleList const r = _body->row_ports().bundles(); - for (ARDOUR::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { - if (grid_row < (*i)->nchannels ()) { - our_bundle = *i; - our_channel = grid_row; - break; - } else { - grid_row -= (*i)->nchannels (); - } - } - - ARDOUR::BundleList const c = _body->column_ports().bundles(); - for (ARDOUR::BundleList::const_iterator i = c.begin(); i != c.end(); ++i) { - if (grid_column < (*i)->nchannels ()) { - other_bundle = *i; - other_channel = grid_column; - break; - } else { - grid_column -= (*i)->nchannels (); - } - } - + PortMatrixNode const node = position_to_node (x, y); - if (our_bundle && other_bundle) { + if (node.row.bundle && node.column.bundle) { PortMatrix::State const s = _port_matrix->get_state ( - our_bundle, our_channel, other_bundle, other_channel + node.row.bundle, node.row.channel, node.column.bundle, node.column.channel ); + if (s == PortMatrix::ASSOCIATED || s == PortMatrix::NOT_ASSOCIATED) { bool const n = !(s == PortMatrix::ASSOCIATED); _port_matrix->set_state ( - our_bundle, our_channel, other_bundle, other_channel, + node.row.bundle, node.row.channel, + node.column.bundle, node.column.channel, n, 0 ); } @@ -223,4 +246,96 @@ PortMatrixGrid::button_press (double x, double y, int b) } } +void +PortMatrixGrid::draw_extra (cairo_t* cr) +{ + set_source_rgba (cr, mouseover_line_colour(), 0.3); + cairo_set_line_width (cr, mouseover_line_width()); + + if (_body->mouseover().row.bundle) { + + double const y = component_to_parent_y ( + channel_position (_body->mouseover().row, _body->row_ports().bundles(), row_height()) + row_height() / 2 + ); + + cairo_move_to (cr, _parent_rectangle.get_x(), y); + cairo_line_to (cr, _parent_rectangle.get_x() + _parent_rectangle.get_width(), y); + cairo_stroke (cr); + } + + if (_body->mouseover().column.bundle) { + + double const x = component_to_parent_x ( + channel_position (_body->mouseover().column, _body->column_ports().bundles(), column_width()) + column_width() / 2 + ); + + cairo_move_to (cr, x, _parent_rectangle.get_y()); + cairo_line_to (cr, x, _parent_rectangle.get_y() + _parent_rectangle.get_height()); + cairo_stroke (cr); + } +} + +void +PortMatrixGrid::mouseover_changed (PortMatrixNode const& old) +{ + queue_draw_for (old); + queue_draw_for (_body->mouseover()); +} + +void +PortMatrixGrid::mouseover_event (double x, double y) +{ + _body->set_mouseover (position_to_node (x, y)); +} + +void +PortMatrixGrid::queue_draw_for (PortMatrixNode const &n) +{ + if (n.row.bundle) { + + double const y = channel_position (n.row, _body->row_ports().bundles(), row_height()); + _body->queue_draw_area ( + _parent_rectangle.get_x(), + component_to_parent_y (y), + _parent_rectangle.get_width(), + row_height() + ); + } + + if (n.column.bundle) { + + double const x = channel_position (n.column, _body->column_ports().bundles(), column_width()); + + _body->queue_draw_area ( + component_to_parent_x (x), + _parent_rectangle.get_y(), + column_width(), + _parent_rectangle.get_height() + ); + } +} + +double +PortMatrixGrid::component_to_parent_x (double x) const +{ + return x - _body->xoffset() + _parent_rectangle.get_x(); +} + +double +PortMatrixGrid::parent_to_component_x (double x) const +{ + return x + _body->xoffset() - _parent_rectangle.get_x(); +} + +double +PortMatrixGrid::component_to_parent_y (double y) const +{ + return y - _body->yoffset() + _parent_rectangle.get_y(); +} + +double +PortMatrixGrid::parent_to_component_y (double y) const +{ + return y + _body->yoffset() - _parent_rectangle.get_y(); +} diff --git a/gtk2_ardour/port_matrix_grid.h b/gtk2_ardour/port_matrix_grid.h index 7441d3c79d..945ba5a2e6 100644 --- a/gtk2_ardour/port_matrix_grid.h +++ b/gtk2_ardour/port_matrix_grid.h @@ -23,7 +23,9 @@ #include #include #include +#include "ardour/types.h" #include "port_matrix_component.h" +#include "port_matrix_types.h" class PortMatrix; class PortMatrixBody; @@ -39,11 +41,25 @@ public: PortMatrixGrid (PortMatrix *, PortMatrixBody *); void button_press (double, double, int); + void mouseover_event (double, double); + + double component_to_parent_x (double x) const; + double parent_to_component_x (double x) const; + double component_to_parent_y (double y) const; + double parent_to_component_y (double y) const; + void mouseover_changed (PortMatrixNode const &); + void draw_extra (cairo_t *); private: + void compute_dimensions (); void render (cairo_t *); + double channel_position (PortMatrixBundleChannel, ARDOUR::BundleList const &, double) const; + PortMatrixNode position_to_node (double, double) const; + PortMatrixBundleChannel position_to_channel (double, ARDOUR::BundleList const &, double) const; + void queue_draw_for (PortMatrixNode const &); + PortMatrix* _port_matrix; }; diff --git a/gtk2_ardour/port_matrix_row_labels.cc b/gtk2_ardour/port_matrix_row_labels.cc index 7740d9cf18..278ae8e003 100644 --- a/gtk2_ardour/port_matrix_row_labels.cc +++ b/gtk2_ardour/port_matrix_row_labels.cc @@ -111,13 +111,13 @@ PortMatrixRowLabels::render (cairo_t* cr) int g = 0; for (PortGroupList::const_iterator i = _body->row_ports().begin(); i != _body->row_ports().end(); ++i) { - if (!(*i)->visible() || ((*i)->bundles.empty() && (*i)->ports.empty()) ) { + if (!(*i)->visible() || ((*i)->bundles().empty() && (*i)->ports.empty()) ) { continue; } /* compute height of this group */ double h = 0; - for (ARDOUR::BundleList::const_iterator j = (*i)->bundles.begin(); j != (*i)->bundles.end(); ++j) { + for (ARDOUR::BundleList::const_iterator j = (*i)->bundles().begin(); j != (*i)->bundles().end(); ++j) { h += (*j)->nchannels() * row_height(); } h += (*i)->ports.size() * row_height(); @@ -143,7 +143,7 @@ PortMatrixRowLabels::render (cairo_t* cr) ++g; } - /* SIDE BUNDLE NAMES */ + /* BUNDLE NAMES */ x = 0; if (_location == LEFT) { @@ -182,41 +182,12 @@ PortMatrixRowLabels::render (cairo_t* cr) } - /* SIDE PORT NAMES */ + /* PORT NAMES */ y = 0; for (ARDOUR::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { for (uint32_t j = 0; j < (*i)->nchannels(); ++j) { - - double x = 0; - if (_location == LEFT) { - x = _longest_bundle_name + _highest_group_name + name_pad() * 4; - } else if (_location == RIGHT) { - x = 0; - } - - Gdk::Color const colour = get_a_bundle_colour (i - r.begin ()); - set_source_rgb (cr, colour); - cairo_rectangle ( - cr, - x, - y, - _longest_port_name + (name_pad() * 2), - row_height() - ); - cairo_fill_preserve (cr); - set_source_rgb (cr, background_colour()); - cairo_set_line_width (cr, label_border_width ()); - cairo_stroke (cr); - - cairo_text_extents_t ext; - cairo_text_extents (cr, (*i)->channel_name(j).c_str(), &ext); - double const off = (row_height() - ext.height) / 2; - - set_source_rgb (cr, text_colour()); - cairo_move_to (cr, x + name_pad(), y + name_pad() + off); - cairo_show_text (cr, (*i)->channel_name(j).c_str()); - + render_port_name (cr, get_a_bundle_colour (i - r.begin()), port_name_x(), y, PortMatrixBundleChannel (*i, j)); y += row_height(); } } @@ -305,3 +276,113 @@ PortMatrixRowLabels::rename_channel_proxy (boost::weak_ptr b, ui _port_matrix->rename_channel (sb, c); } + + +double +PortMatrixRowLabels::component_to_parent_x (double x) const +{ + return x + _parent_rectangle.get_x(); +} + +double +PortMatrixRowLabels::parent_to_component_x (double x) const +{ + return x - _parent_rectangle.get_x(); +} + +double +PortMatrixRowLabels::component_to_parent_y (double y) const +{ + return y - _body->yoffset() + _parent_rectangle.get_y(); +} + +double +PortMatrixRowLabels::parent_to_component_y (double y) const +{ + return y + _body->yoffset() - _parent_rectangle.get_y(); +} + +double +PortMatrixRowLabels::port_name_x () const +{ + if (_location == LEFT) { + return _longest_bundle_name + _highest_group_name + name_pad() * 4; + } else if (_location == RIGHT) { + return 0; + } + + return 0; +} + +void +PortMatrixRowLabels::render_port_name ( + cairo_t* cr, Gdk::Color colour, double x, double y, PortMatrixBundleChannel const& bc + ) +{ + set_source_rgb (cr, colour); + cairo_rectangle (cr, x, y, _longest_port_name + name_pad() * 2, row_height()); + cairo_fill_preserve (cr); + set_source_rgb (cr, background_colour()); + cairo_set_line_width (cr, label_border_width ()); + cairo_stroke (cr); + + 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; + + set_source_rgb (cr, text_colour()); + cairo_move_to (cr, x + name_pad(), y + name_pad() + off); + cairo_show_text (cr, bc.bundle->channel_name(bc.channel).c_str()); +} + +double +PortMatrixRowLabels::channel_y (PortMatrixBundleChannel const& bc) const +{ + double y = 0; + + ARDOUR::BundleList::const_iterator i = _body->row_ports().bundles().begin(); + while (i != _body->row_ports().bundles().end() && *i != bc.bundle) { + y += row_height() * (*i)->nchannels(); + ++i; + } + + y += row_height() * bc.channel; + + return y; +} + +void +PortMatrixRowLabels::queue_draw_for (PortMatrixNode const& n) +{ + if (n.row.bundle) { + + _body->queue_draw_area ( + component_to_parent_x (port_name_x()), + component_to_parent_y (channel_y (n.row)), + _longest_port_name + name_pad() * 2, + row_height() + ); + } + +} + +void +PortMatrixRowLabels::mouseover_changed (PortMatrixNode const& old) +{ + queue_draw_for (old); + queue_draw_for (_body->mouseover()); +} + +void +PortMatrixRowLabels::draw_extra (cairo_t* cr) +{ + if (_body->mouseover().row.bundle) { + render_port_name ( + cr, + mouseover_port_colour (), + component_to_parent_x (port_name_x()), + component_to_parent_y (channel_y (_body->mouseover().row)), + _body->mouseover().row + ); + } +} diff --git a/gtk2_ardour/port_matrix_row_labels.h b/gtk2_ardour/port_matrix_row_labels.h index dff6b71d26..ce77dc8294 100644 --- a/gtk2_ardour/port_matrix_row_labels.h +++ b/gtk2_ardour/port_matrix_row_labels.h @@ -21,10 +21,13 @@ #define __port_matrix_row_labels_h__ #include +#include #include "port_matrix_component.h" class PortMatrix; class PortMatrixBody; +class PortMatrixNode; +class PortMatrixBundleChannel; namespace ARDOUR { class Bundle; @@ -47,11 +50,22 @@ public: void button_press (double, double, int, uint32_t); + double component_to_parent_x (double x) const; + double parent_to_component_x (double x) const; + double component_to_parent_y (double y) const; + double parent_to_component_y (double y) const; + void mouseover_changed (PortMatrixNode const &); + void draw_extra (cairo_t* cr); + private: void render (cairo_t *); void compute_dimensions (); void remove_channel_proxy (boost::weak_ptr, uint32_t); void rename_channel_proxy (boost::weak_ptr, uint32_t); + void render_port_name (cairo_t *, Gdk::Color, double, double, PortMatrixBundleChannel const &); + double channel_y (PortMatrixBundleChannel const &) const; + void queue_draw_for (PortMatrixNode const &); + double port_name_x () const; PortMatrix* _port_matrix; double _longest_port_name; diff --git a/gtk2_ardour/port_matrix_types.h b/gtk2_ardour/port_matrix_types.h new file mode 100644 index 0000000000..66dcf619b7 --- /dev/null +++ b/gtk2_ardour/port_matrix_types.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2009 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_gtk_port_matrix_types_h__ +#define __ardour_gtk_port_matrix_types_h__ + +struct PortMatrixBundleChannel { + PortMatrixBundleChannel () : channel (0) {} + PortMatrixBundleChannel (boost::shared_ptr b, uint32_t c) + : bundle (b), channel (c) {} + + bool operator== (PortMatrixBundleChannel const& other) const { + return bundle == other.bundle && channel == other.channel; + } + bool operator!= (PortMatrixBundleChannel const& other) const { + return bundle != other.bundle || channel != other.channel; + } + + boost::shared_ptr bundle; + uint32_t channel; +}; + +struct PortMatrixNode { + PortMatrixNode () {} + PortMatrixNode (PortMatrixBundleChannel r, PortMatrixBundleChannel c) : row (r), column (c) {} + + bool operator== (PortMatrixNode const& other) const { + return row == other.row && column == other.column; + } + bool operator!= (PortMatrixNode const& other) const { + return row != other.row || column != other.column; + } + + PortMatrixBundleChannel row; + PortMatrixBundleChannel column; +}; + +#endif