From 50437bff22279473cd364d007d5e474af2a542bc Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 17 Jul 2009 22:54:45 +0000 Subject: [PATCH] Various tweaks to the port matrix: open to full size; remove buttons and move their functionality into a context menu; set maximum size hint to stop port matrix windows being resized beyond their useful size; remove visibility checkbuttons - visibility now controlled through menu or by clicking on group names; port groups fold down to a small tab when hidden; don't swap the orientation of the matrix once it has been opened. git-svn-id: svn://localhost/ardour2/branches/3.0@5373 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/global_port_matrix.cc | 36 +-- gtk2_ardour/global_port_matrix.h | 2 +- gtk2_ardour/io_selector.cc | 107 ++----- gtk2_ardour/io_selector.h | 17 +- gtk2_ardour/port_matrix.cc | 358 ++++++++++------------- gtk2_ardour/port_matrix.h | 26 +- gtk2_ardour/port_matrix_body.cc | 112 +++---- gtk2_ardour/port_matrix_body.h | 3 +- gtk2_ardour/port_matrix_column_labels.cc | 216 ++++++++++---- gtk2_ardour/port_matrix_column_labels.h | 8 +- gtk2_ardour/port_matrix_component.cc | 98 ++++++- gtk2_ardour/port_matrix_component.h | 9 + gtk2_ardour/port_matrix_grid.cc | 324 +++++++++++--------- gtk2_ardour/port_matrix_grid.h | 5 +- gtk2_ardour/port_matrix_row_labels.cc | 129 +++++--- gtk2_ardour/port_matrix_row_labels.h | 1 - 16 files changed, 786 insertions(+), 665 deletions(-) diff --git a/gtk2_ardour/global_port_matrix.cc b/gtk2_ardour/global_port_matrix.cc index 2b3b9c2131..b19c383565 100644 --- a/gtk2_ardour/global_port_matrix.cc +++ b/gtk2_ardour/global_port_matrix.cc @@ -28,6 +28,8 @@ #include "i18n.h" +using namespace std; + GlobalPortMatrix::GlobalPortMatrix (ARDOUR::Session& s, ARDOUR::DataType t) : PortMatrix (s, t) { @@ -119,27 +121,25 @@ GlobalPortMatrixWindow::GlobalPortMatrixWindow (ARDOUR::Session& s, ARDOUR::Data break; } - Gtk::HBox* buttons_hbox = Gtk::manage (new Gtk::HBox); - - _rescan_button.set_label (_("Rescan")); - _rescan_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::REFRESH, Gtk::ICON_SIZE_BUTTON))); - _rescan_button.signal_clicked().connect (sigc::mem_fun (_port_matrix, &GlobalPortMatrix::setup_all_ports)); - buttons_hbox->pack_start (_rescan_button, Gtk::PACK_SHRINK); - - _show_ports_button.set_label (_("Show individual ports")); - _show_ports_button.set_active (true); - _show_ports_button.signal_toggled().connect (sigc::mem_fun (*this, &GlobalPortMatrixWindow::show_ports_toggled)); - buttons_hbox->pack_start (_show_ports_button, Gtk::PACK_SHRINK); - - Gtk::VBox* vbox = Gtk::manage (new Gtk::VBox); - vbox->pack_start (_port_matrix); - vbox->pack_start (*buttons_hbox, Gtk::PACK_SHRINK); - add (*vbox); + add (_port_matrix); show_all (); + + /* XXX: hack to make the window full-size on opening. This may not work for + people with very large monitors */ + + resize (32768, 32768); } void -GlobalPortMatrixWindow::show_ports_toggled () +GlobalPortMatrixWindow::on_realize () { - _port_matrix.set_show_only_bundles (!_show_ports_button.get_active()); + Window::on_realize (); + + pair const m = _port_matrix.max_size (); + + GdkGeometry g; + g.max_width = m.first; + g.max_height = m.second; + + set_geometry_hints (*this, g, Gdk::HINT_MAX_SIZE); } diff --git a/gtk2_ardour/global_port_matrix.h b/gtk2_ardour/global_port_matrix.h index 98b898f8aa..1e383a094a 100644 --- a/gtk2_ardour/global_port_matrix.h +++ b/gtk2_ardour/global_port_matrix.h @@ -63,7 +63,7 @@ public: GlobalPortMatrixWindow (ARDOUR::Session&, ARDOUR::DataType); private: - void show_ports_toggled (); + void on_realize (); GlobalPortMatrix _port_matrix; Gtk::Button _rescan_button; diff --git a/gtk2_ardour/io_selector.cc b/gtk2_ardour/io_selector.cc index 4333efd8ea..3c1e4c91ed 100644 --- a/gtk2_ardour/io_selector.cc +++ b/gtk2_ardour/io_selector.cc @@ -181,100 +181,22 @@ IOSelector::list_is_global (int dim) const } IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr io, bool can_cancel) - : ArdourDialog ("I/O selector") - , _selector (session, io) - , add_button (_("Add Port")) - , disconnect_button (_("Disconnect All")) - , ok_button (can_cancel ? _("OK"): _("Close")) - , cancel_button (_("Cancel")) - , rescan_button (_("Rescan")) - + : _selector (session, io) { - /* XXX: what's this for? */ - add_events (Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); - set_name ("IOSelectorWindow2"); + set_title (_("I/O selector")); - /* Disconnect All button */ - disconnect_button.set_name ("IOSelectorButton"); - disconnect_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DISCONNECT, Gtk::ICON_SIZE_BUTTON))); - disconnect_button.signal_clicked().connect (sigc::mem_fun (_selector, &IOSelector::disassociate_all)); - get_action_area()->pack_start (disconnect_button, false, false); - - /* Add Port button */ - add_button.set_name ("IOSelectorButton"); - add_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::ADD, Gtk::ICON_SIZE_BUTTON))); - get_action_area()->pack_start (add_button, false, false); - add_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (_selector, &IOSelector::add_channel), boost::shared_ptr ())); - - /* Rescan button */ - rescan_button.set_name ("IOSelectorButton"); - rescan_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::REFRESH, Gtk::ICON_SIZE_BUTTON))); - rescan_button.signal_clicked().connect (sigc::mem_fun (*this, &IOSelectorWindow::rescan)); - get_action_area()->pack_start (rescan_button, false, false); - - io->PortCountChanged.connect (sigc::hide (mem_fun (*this, &IOSelectorWindow::ports_changed))); - - /* Cancel button */ - if (can_cancel) { - cancel_button.set_name ("IOSelectorButton"); - cancel_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CANCEL, Gtk::ICON_SIZE_BUTTON))); - get_action_area()->pack_start (cancel_button, false, false); - } else { - cancel_button.hide(); - } - cancel_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::cancel)); - - /* OK button */ - ok_button.set_name ("IOSelectorButton"); - if (!can_cancel) { - ok_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CLOSE, Gtk::ICON_SIZE_BUTTON))); - } - ok_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::accept)); - get_action_area()->pack_start (ok_button, false, false); - - get_vbox()->set_spacing (8); - - get_vbox()->pack_start (_selector, true, true); + add (_selector); set_position (Gtk::WIN_POS_MOUSE); io_name_changed (this); - ports_changed (); show_all (); signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), this)); -} -void -IOSelectorWindow::ports_changed () -{ - /* XXX make this insensitive based on port connectivity, not - port counts. - */ - - add_button.set_sensitive (true); -} - -void -IOSelectorWindow::rescan () -{ - _selector.setup_ports (_selector.other()); -} - -void -IOSelectorWindow::cancel () -{ - _selector.Finished (IOSelector::Cancelled); - hide (); -} - -void -IOSelectorWindow::accept () -{ - _selector.Finished (IOSelector::Accepted); - hide (); + resize (32768, 32768); } void @@ -300,6 +222,21 @@ IOSelectorWindow::io_name_changed (void* src) set_title (title); } +void +IOSelectorWindow::on_realize () +{ + Window::on_realize (); + + pair const m = _selector.max_size (); + + GdkGeometry g; + g.max_width = m.first; + g.max_height = m.second; + + set_geometry_hints (*this, g, Gdk::HINT_MAX_SIZE); +} + + PortInsertUI::PortInsertUI (ARDOUR::Session& sess, boost::shared_ptr pi) : input_selector (sess, pi->input()) , output_selector (sess, pi->output()) @@ -330,8 +267,7 @@ PortInsertWindow::PortInsertWindow (ARDOUR::Session& sess, boost::shared_ptrpack_start (rescan_button, false, false); if (can_cancel) { cancel_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CANCEL, Gtk::ICON_SIZE_BUTTON))); get_action_area()->pack_start (cancel_button, false, false); diff --git a/gtk2_ardour/io_selector.h b/gtk2_ardour/io_selector.h index d6b00254be..24e99e27ec 100644 --- a/gtk2_ardour/io_selector.h +++ b/gtk2_ardour/io_selector.h @@ -71,7 +71,7 @@ class IOSelector : public PortMatrix bool _find_inputs_for_io_outputs; }; -class IOSelectorWindow : public ArdourDialog +class IOSelectorWindow : public Gtk::Window { public: IOSelectorWindow (ARDOUR::Session&, boost::shared_ptr, bool can_cancel = false); @@ -80,23 +80,11 @@ class IOSelectorWindow : public ArdourDialog protected: void on_map (); + void on_realize (); private: IOSelector _selector; - - /* overall operation buttons */ - - Gtk::Button add_button; - Gtk::Button disconnect_button; - Gtk::Button ok_button; - Gtk::Button cancel_button; - Gtk::Button rescan_button; - - void cancel (); - void accept (); - void rescan (); - void ports_changed (); void io_name_changed (void *src); }; @@ -128,7 +116,6 @@ class PortInsertWindow : public ArdourDialog Gtk::Button ok_button; Gtk::Button cancel_button; - Gtk::Button rescan_button; Gtk::Frame button_frame; void cancel (); diff --git a/gtk2_ardour/port_matrix.cc b/gtk2_ardour/port_matrix.cc index b2c43ad35a..820920ed14 100644 --- a/gtk2_ardour/port_matrix.cc +++ b/gtk2_ardour/port_matrix.cc @@ -32,23 +32,26 @@ #include "port_matrix_body.h" #include "i18n.h" +using namespace std; +using namespace sigc; +using namespace Gtk; + /** PortMatrix constructor. * @param session Our session. * @param type Port type that we are handling. */ PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type) - : Gtk::Table (2, 2), + : Table (2, 2), _session (session), _type (type), - _column_visibility_box_added (false), - _row_visibility_box_added (false), _menu (0), - _setup_once (false), _arrangement (TOP_TO_RIGHT), _row_index (0), _column_index (1), _min_height_divisor (1), - _show_only_bundles (false) + _show_only_bundles (false), + _inhibit_toggle_show_only_bundles (false), + _first_setup (true) { _body = new PortMatrixBody (this); @@ -56,38 +59,30 @@ PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type) _ports[i].set_type (type); /* watch for the content of _ports[] changing */ - _ports[i].Changed.connect (sigc::mem_fun (*this, &PortMatrix::setup)); + _ports[i].Changed.connect (mem_fun (*this, &PortMatrix::setup)); } - _row_visibility_box.pack_start (_row_visibility_label, Gtk::PACK_SHRINK); - _column_visibility_box.pack_start (_column_visibility_label, Gtk::PACK_SHRINK); - - _hscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::hscroll_changed)); - _vscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::vscroll_changed)); + _hscroll.signal_value_changed().connect (mem_fun (*this, &PortMatrix::hscroll_changed)); + _vscroll.signal_value_changed().connect (mem_fun (*this, &PortMatrix::vscroll_changed)); /* watch for routes being added or removed */ - _session.RouteAdded.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrix::routes_changed))); + _session.RouteAdded.connect (sigc::hide (mem_fun (*this, &PortMatrix::routes_changed))); /* and also bundles */ - _session.BundleAdded.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrix::setup_global_ports))); + _session.BundleAdded.connect (sigc::hide (mem_fun (*this, &PortMatrix::setup_global_ports))); reconnect_to_routes (); + attach (*_body, 0, 1, 0, 1); + attach (_vscroll, 1, 2, 0, 1, SHRINK); + attach (_hscroll, 0, 1, 1, 2, FILL | EXPAND, SHRINK); + show_all (); } PortMatrix::~PortMatrix () { delete _body; - - for (std::vector::iterator i = _column_visibility_buttons.begin(); i != _column_visibility_buttons.end(); ++i) { - delete *i; - } - - for (std::vector::iterator i = _row_visibility_buttons.begin(); i != _row_visibility_buttons.end(); ++i) { - delete *i; - } - delete _menu; } @@ -95,7 +90,7 @@ PortMatrix::~PortMatrix () void PortMatrix::reconnect_to_routes () { - for (std::vector::iterator i = _route_connections.begin(); i != _route_connections.end(); ++i) { + for (vector::iterator i = _route_connections.begin(); i != _route_connections.end(); ++i) { i->disconnect (); } _route_connections.clear (); @@ -103,7 +98,7 @@ PortMatrix::reconnect_to_routes () boost::shared_ptr routes = _session.get_routes (); for (ARDOUR::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { _route_connections.push_back ( - (*i)->processors_changed.connect (sigc::mem_fun (*this, &PortMatrix::setup_global_ports)) + (*i)->processors_changed.connect (mem_fun (*this, &PortMatrix::setup_global_ports)) ); } } @@ -120,117 +115,16 @@ PortMatrix::routes_changed () void PortMatrix::setup () { - select_arrangement (); + if (_first_setup) { + select_arrangement (); + } + _body->setup (); setup_scrollbars (); queue_draw (); - if (_setup_once) { - - /* we've set up before, so we need to clean up before re-setting-up */ - /* XXX: we ought to be able to do this by just getting a list of children - from each container widget, but I couldn't make that work */ - - for (std::vector::iterator i = _column_visibility_buttons.begin(); i != _column_visibility_buttons.end(); ++i) { - _column_visibility_box.remove (**i); - delete *i; - } - - _column_visibility_buttons.clear (); - - for (std::vector::iterator i = _row_visibility_buttons.begin(); i != _row_visibility_buttons.end(); ++i) { - _row_visibility_box.remove (**i); - delete *i; - } - - _row_visibility_buttons.clear (); - - _scroller_table.remove (_vscroll); - _scroller_table.remove (*_body); - _scroller_table.remove (_hscroll); - - remove (_scroller_table); - if (_row_visibility_box_added) { - remove (_row_visibility_box); - } - - if (_column_visibility_box_added) { - remove (_column_visibility_box); - } - } - - if (_column_index == 0) { - _column_visibility_label.set_text (_("Show Outputs")); - _row_visibility_label.set_text (_("Show Inputs")); - } else { - _column_visibility_label.set_text (_("Show Inputs")); - _row_visibility_label.set_text (_("Show Outputs")); - } - - for (PortGroupList::List::const_iterator i = columns()->begin(); i != columns()->end(); ++i) { - Gtk::CheckButton* b = new Gtk::CheckButton ((*i)->name); - b->set_active ((*i)->visible()); - boost::weak_ptr w (*i); - b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &PortMatrix::visibility_toggled), w, b)); - _column_visibility_buttons.push_back (b); - _column_visibility_box.pack_start (*b, Gtk::PACK_SHRINK); - } - - for (PortGroupList::List::const_iterator i = rows()->begin(); i != rows()->end(); ++i) { - Gtk::CheckButton* b = new Gtk::CheckButton ((*i)->name); - b->set_active ((*i)->visible()); - boost::weak_ptr w (*i); - b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &PortMatrix::visibility_toggled), w, b)); - _row_visibility_buttons.push_back (b); - _row_visibility_box.pack_start (*b, Gtk::PACK_SHRINK); - } - - if (_arrangement == TOP_TO_RIGHT) { - - _scroller_table.attach (_hscroll, 0, 1, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK); - _scroller_table.attach (*_body, 0, 1, 1, 2); - _scroller_table.attach (_vscroll, 1, 2, 1, 2, Gtk::SHRINK); - - attach (_scroller_table, 0, 1, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::FILL | Gtk::EXPAND); - - if (rows()->size() > 1) { - attach (_row_visibility_box, 1, 2, 1, 2, Gtk::SHRINK, Gtk::SHRINK); - _row_visibility_box_added = true; - } else { - _row_visibility_box_added = false; - } - - if (columns()->size() > 1) { - attach (_column_visibility_box, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK); - _column_visibility_box_added = true; - } else { - _column_visibility_box_added = false; - } - - } else { - _scroller_table.attach (_vscroll, 0, 1, 0, 1, Gtk::SHRINK); - _scroller_table.attach (*_body, 1, 2, 0, 1); - _scroller_table.attach (_hscroll, 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK); - - if (rows()->size() > 1) { - attach (_row_visibility_box, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK); - _row_visibility_box_added = true; - } else { - _row_visibility_box_added = false; - } - - attach (_scroller_table, 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL | Gtk::EXPAND); - - if (columns()->size() > 1) { - attach (_column_visibility_box, 1, 2, 1, 2, Gtk::SHRINK, Gtk::SHRINK); - _column_visibility_box_added = true; - } else { - _column_visibility_box_added = false; - } - } - - _setup_once = true; - + _first_setup = false; + show_all (); } @@ -259,7 +153,7 @@ PortMatrix::vscroll_changed () void PortMatrix::setup_scrollbars () { - Gtk::Adjustment* a = _hscroll.get_adjustment (); + Adjustment* a = _hscroll.get_adjustment (); a->set_lower (0); a->set_upper (_body->full_scroll_width()); a->set_page_size (_body->alloc_scroll_width()); @@ -346,90 +240,113 @@ PortMatrix::rows () const return &_ports[_row_index]; } -/** A group visibility checkbutton has been toggled. - * @param w Group. - * @param b Button. - */ void -PortMatrix::visibility_toggled (boost::weak_ptr w, Gtk::CheckButton* b) +PortMatrix::popup_menu ( + pair, ARDOUR::BundleChannel> column, + pair, ARDOUR::BundleChannel> row, + uint32_t t + ) { - boost::shared_ptr g = w.lock (); - if (!g) { - return; - } + using namespace Menu_Helpers; - g->set_visible (b->get_active()); - _body->setup (); - setup_scrollbars (); - queue_draw (); -} - -void -PortMatrix::popup_channel_context_menu (int dim, uint32_t N, uint32_t t) -{ delete _menu; - _menu = new Gtk::Menu; + _menu = new Menu; _menu->set_name ("ArdourContextMenu"); - Gtk::Menu_Helpers::MenuList& items = _menu->items (); + MenuList& items = _menu->items (); - ARDOUR::BundleChannel bc; + boost::shared_ptr pg[2]; + pg[_column_index] = column.first; + pg[_row_index] = row.first; - PortGroup::BundleList const r = _ports[dim].bundles(); - for (PortGroup::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { - if (N < i->bundle->nchannels ()) { - bc = ARDOUR::BundleChannel (i->bundle, N); - break; - } else { - N -= i->bundle->nchannels (); - } - } + ARDOUR::BundleChannel bc[2]; + bc[_column_index] = column.second; + bc[_row_index] = row.second; - if (bc.bundle) { - char buf [64]; - bool have_one = false; + char buf [64]; - if (can_rename_channels (dim)) { - snprintf (buf, sizeof (buf), _("Rename '%s'..."), bc.bundle->channel_name (bc.channel).c_str()); - boost::weak_ptr w (bc.bundle); - items.push_back ( - Gtk::Menu_Helpers::MenuElem ( - buf, - sigc::bind (sigc::mem_fun (*this, &PortMatrix::rename_channel_proxy), w, bc.channel) - ) - ); + for (int dim = 0; dim < 2; ++dim) { - have_one = true; - } + if (pg[dim]) { - if (can_remove_channels (dim)) { - snprintf (buf, sizeof (buf), _("Remove '%s'"), bc.bundle->channel_name (bc.channel).c_str()); - boost::weak_ptr w (bc.bundle); - items.push_back ( - Gtk::Menu_Helpers::MenuElem ( - buf, - sigc::bind (sigc::mem_fun (*this, &PortMatrix::remove_channel_proxy), w, bc.channel) - ) - ); - - have_one = true; - } - - if (have_one) { - items.push_back (Gtk::Menu_Helpers::SeparatorElem ()); - } - - boost::weak_ptr w (bc.bundle); - items.push_back (Gtk::Menu_Helpers::MenuElem ( - _("Disassociate all"), - sigc::bind (sigc::mem_fun (*this, &PortMatrix::disassociate_all_on_channel), w, bc.channel, dim) - ) - ); + boost::weak_ptr wp (pg[dim]); - _menu->popup (1, t); + if (pg[dim]->visible()) { + if (dim == 0) { + snprintf (buf, sizeof (buf), _("Hide '%s' sources"), pg[dim]->name.c_str()); + } else { + snprintf (buf, sizeof (buf), _("Hide '%s' destinations"), pg[dim]->name.c_str()); + } + + items.push_back (MenuElem (buf, bind (mem_fun (*this, &PortMatrix::hide_group), wp))); + } else { + if (dim == 0) { + snprintf (buf, sizeof (buf), _("Show '%s' sources"), pg[dim]->name.c_str()); + } else { + snprintf (buf, sizeof (buf), _("Show '%s' destinations"), pg[dim]->name.c_str()); + } + items.push_back (MenuElem (buf, bind (mem_fun (*this, &PortMatrix::show_group), wp))); + } + } + + if (bc[dim].bundle) { + bool have_one = false; + + if (can_rename_channels (dim)) { + snprintf (buf, sizeof (buf), _("Rename '%s'..."), bc[dim].bundle->channel_name (bc[dim].channel).c_str()); + boost::weak_ptr w (bc[dim].bundle); + items.push_back ( + MenuElem ( + buf, + bind (mem_fun (*this, &PortMatrix::rename_channel_proxy), w, bc[dim].channel) + ) + ); + + have_one = true; + } + + if (can_remove_channels (dim)) { + snprintf (buf, sizeof (buf), _("Remove '%s'"), bc[dim].bundle->channel_name (bc[dim].channel).c_str()); + boost::weak_ptr w (bc[dim].bundle); + items.push_back ( + MenuElem ( + buf, + bind (mem_fun (*this, &PortMatrix::remove_channel_proxy), w, bc[dim].channel) + ) + ); + + have_one = true; + } + + boost::weak_ptr w (bc[dim].bundle); + + if (_show_only_bundles) { + snprintf (buf, sizeof (buf), _("Disassociate all from '%s'"), bc[dim].bundle->name().c_str()); + } else { + snprintf ( + buf, sizeof (buf), _("Disassociate all from '%s/%s'"), + bc[dim].bundle->name().c_str(), bc[dim].bundle->channel_name (bc[dim].channel).c_str() + ); + } + + items.push_back ( + MenuElem (buf, bind (mem_fun (*this, &PortMatrix::disassociate_all_on_channel), w, bc[dim].channel, dim)) + ); + + } } + + items.push_back (SeparatorElem ()); + + items.push_back (MenuElem (_("Rescan"), mem_fun (*this, &PortMatrix::setup_all_ports))); + items.push_back (CheckMenuElem (_("Show individual ports"), mem_fun (*this, &PortMatrix::toggle_show_only_bundles))); + CheckMenuItem* i = dynamic_cast (&items.back()); + _inhibit_toggle_show_only_bundles = true; + i->set_active (!_show_only_bundles); + _inhibit_toggle_show_only_bundles = false; + _menu->popup (1, t); } @@ -500,10 +417,47 @@ PortMatrix::setup_all_ports () } void -PortMatrix::set_show_only_bundles (bool s) +PortMatrix::toggle_show_only_bundles () { - _show_only_bundles = s; + if (_inhibit_toggle_show_only_bundles) { + return; + } + + _show_only_bundles = !_show_only_bundles; _body->setup (); setup_scrollbars (); queue_draw (); } + +void +PortMatrix::hide_group (boost::weak_ptr w) +{ + boost::shared_ptr g = w.lock (); + if (!g) { + return; + } + + g->set_visible (false); +} + +void +PortMatrix::show_group (boost::weak_ptr w) +{ + boost::shared_ptr g = w.lock (); + if (!g) { + return; + } + + g->set_visible (true); +} + +pair +PortMatrix::max_size () const +{ + pair m = _body->max_size (); + + m.first += _vscroll.get_width (); + m.second += _hscroll.get_height (); + + return m; +} diff --git a/gtk2_ardour/port_matrix.h b/gtk2_ardour/port_matrix.h index 531fdf6978..76f6d09a6a 100644 --- a/gtk2_ardour/port_matrix.h +++ b/gtk2_ardour/port_matrix.h @@ -60,7 +60,11 @@ public: void disassociate_all (); void setup_scrollbars (); - void popup_channel_context_menu (int, uint32_t, uint32_t); + void popup_menu ( + std::pair, ARDOUR::BundleChannel>, + std::pair, ARDOUR::BundleChannel>, + uint32_t + ); int min_height_divisor () const { return _min_height_divisor; @@ -83,8 +87,6 @@ public: return _show_only_bundles; } - void set_show_only_bundles (bool); - PortGroupList const * columns () const; /** @return index into the _ports array for the list which is displayed as columns */ @@ -107,6 +109,8 @@ public: virtual void setup_ports (int) = 0; void setup_all_ports (); + std::pair max_size () const; + /** @param c Channels; where c[0] is from _ports[0] and c[1] is from _ports[1]. * @param s New state. */ @@ -148,12 +152,14 @@ private: void vscroll_changed (); void routes_changed (); void reconnect_to_routes (); - void visibility_toggled (boost::weak_ptr, Gtk::CheckButton *); void select_arrangement (); void remove_channel_proxy (boost::weak_ptr, uint32_t); void rename_channel_proxy (boost::weak_ptr, uint32_t); void disassociate_all_on_channel (boost::weak_ptr, uint32_t, int); void setup_global_ports (); + void hide_group (boost::weak_ptr); + void show_group (boost::weak_ptr); + void toggle_show_only_bundles (); /// port type that we are working with ARDOUR::DataType _type; @@ -162,22 +168,14 @@ private: PortMatrixBody* _body; Gtk::HScrollbar _hscroll; Gtk::VScrollbar _vscroll; - Gtk::HBox _column_visibility_box; - bool _column_visibility_box_added; - Gtk::Label _column_visibility_label; - std::vector _column_visibility_buttons; - Gtk::VBox _row_visibility_box; - bool _row_visibility_box_added; - Gtk::Label _row_visibility_label; - std::vector _row_visibility_buttons; - Gtk::Table _scroller_table; Gtk::Menu* _menu; - bool _setup_once; Arrangement _arrangement; int _row_index; int _column_index; int _min_height_divisor; bool _show_only_bundles; + bool _inhibit_toggle_show_only_bundles; + bool _first_setup; }; #endif diff --git a/gtk2_ardour/port_matrix_body.cc b/gtk2_ardour/port_matrix_body.cc index bad39b3f3f..593c365d3c 100644 --- a/gtk2_ardour/port_matrix_body.cc +++ b/gtk2_ardour/port_matrix_body.cc @@ -26,6 +26,8 @@ #include "port_matrix_row_labels.h" #include "port_matrix_grid.h" +using namespace std; + PortMatrixBody::PortMatrixBody (PortMatrix* p) : _matrix (p), _xoffset (0), @@ -138,9 +140,9 @@ PortMatrixBody::on_expose_event (GdkEventExpose* event) void PortMatrixBody::on_size_request (Gtk::Requisition *req) { - std::pair const col = _column_labels->dimensions (); - std::pair const row = _row_labels->dimensions (); - std::pair const grid = _grid->dimensions (); + pair const col = _column_labels->dimensions (); + pair const row = _row_labels->dimensions (); + pair const grid = _grid->dimensions (); /* don't ask for the maximum size of our contents, otherwise GTK won't let the containing window shrink below this size */ @@ -149,8 +151,8 @@ PortMatrixBody::on_size_request (Gtk::Requisition *req) int const min_width = 512; int const min_height = 512; - req->width = std::min (min_width, std::max (col.first, grid.first + row.first)); - req->height = std::min (min_height / _matrix->min_height_divisor(), col.second + grid.second); + req->width = min (min_width, max (col.first, grid.first + row.first)); + req->height = min (min_height / _matrix->min_height_divisor(), col.second + grid.second); } void @@ -169,9 +171,10 @@ void PortMatrixBody::compute_rectangles () { /* full sizes of components */ - std::pair const col = _column_labels->dimensions (); - std::pair const row = _row_labels->dimensions (); - std::pair const grid = _grid->dimensions (); + pair const col = _column_labels->dimensions (); + uint32_t col_overhang = _column_labels->overhang (); + pair const row = _row_labels->dimensions (); + pair const grid = _grid->dimensions (); Gdk::Rectangle col_rect; Gdk::Rectangle row_rect; @@ -179,35 +182,19 @@ PortMatrixBody::compute_rectangles () if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { - /* build from top left */ - col_rect.set_x (0); col_rect.set_y (0); grid_rect.set_x (0); - if (_alloc_width > col.first) { - col_rect.set_width (col.first); - } else { - col_rect.set_width (_alloc_width); - } - - /* move down to y division */ - - uint32_t y = 0; - if (_alloc_height > col.second) { - y = col.second; - } else { - y = _alloc_height; - } + col_rect.set_width (min (col.first, _alloc_width)); + uint32_t const y = min (_alloc_height, col.second); 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 */ - uint32_t x = 0; if (_alloc_width > (grid.first + row.first)) { x = grid.first; @@ -222,42 +209,22 @@ PortMatrixBody::compute_rectangles () } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { - /* build from bottom right */ - - /* move left to x division */ - - uint32_t x = 0; - if (_alloc_width > (grid.first + row.first)) { - x = grid.first; - } else if (_alloc_width > row.first) { - x = _alloc_width - row.first; - } - - 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_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 */ + col_rect.set_height (min (_alloc_height, col.second)); - uint32_t y = 0; - if (_alloc_height > col.second) { - y = col.second; - } else { - y = _alloc_height; - } + row_rect.set_x (0); + row_rect.set_y (0); + row_rect.set_width (min (_alloc_width, row.first)); + row_rect.set_height (std::min (_alloc_height - col_rect.get_height(), row.second)); - col_rect.set_y (_alloc_height - y); - col_rect.set_height (y); + grid_rect.set_x (row_rect.get_width()); + grid_rect.set_y (0); + grid_rect.set_width (std::min (_alloc_width - row_rect.get_width(), grid.first)); + grid_rect.set_height (row_rect.get_height ()); - 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()); + col_rect.set_width (grid_rect.get_width () + col_overhang); + col_rect.set_x (row_rect.get_width() + grid_rect.get_width() - col_rect.get_width()); + col_rect.set_y (row_rect.get_height()); + } _row_labels->set_parent_rectangle (row_rect); @@ -270,7 +237,7 @@ PortMatrixBody::setup () { /* Discard any old connections to bundles */ - for (std::list::iterator i = _bundle_connections.begin(); i != _bundle_connections.end(); ++i) { + for (list::iterator i = _bundle_connections.begin(); i != _bundle_connections.end(); ++i) { i->disconnect (); } _bundle_connections.clear (); @@ -348,7 +315,7 @@ PortMatrixBody::on_button_press_event (GdkEventButton* ev) _grid->button_press ( _grid->parent_to_component_x (ev->x), _grid->parent_to_component_y (ev->y), - ev->button + ev->button, ev->time ); } else if (Gdk::Region (_row_labels->parent_rectangle()).point_in (ev->x, ev->y)) { @@ -453,19 +420,10 @@ PortMatrixBody::set_mouseover (PortMatrixNode const & n) void -PortMatrixBody::highlight_associated_channels (int dim, uint32_t N) +PortMatrixBody::highlight_associated_channels (int dim, ARDOUR::BundleChannel h) { ARDOUR::BundleChannel bc[2]; - - PortGroup::BundleList const a = _matrix->ports(dim)->bundles (); - for (PortGroup::BundleList::const_iterator i = a.begin(); i != a.end(); ++i) { - if (N < i->bundle->nchannels ()) { - bc[dim] = ARDOUR::BundleChannel (i->bundle, N); - break; - } else { - N -= i->bundle->nchannels (); - } - } + bc[dim] = h; if (!bc[dim].bundle) { return; @@ -507,4 +465,12 @@ PortMatrixBody::component_size_changed () _matrix->setup_scrollbars (); } - +pair +PortMatrixBody::max_size () const +{ + pair const col = _column_labels->dimensions (); + pair const row = _row_labels->dimensions (); + pair const grid = _grid->dimensions (); + + return make_pair (std::max (row.first, _column_labels->overhang()) + grid.first, col.second + grid.second); +} diff --git a/gtk2_ardour/port_matrix_body.h b/gtk2_ardour/port_matrix_body.h index c905a98dc4..bbc72ddc7e 100644 --- a/gtk2_ardour/port_matrix_body.h +++ b/gtk2_ardour/port_matrix_body.h @@ -61,8 +61,9 @@ public: return _mouseover; } - void highlight_associated_channels (int, uint32_t); + void highlight_associated_channels (int, ARDOUR::BundleChannel); void component_size_changed (); + std::pair max_size () const; protected: bool on_expose_event (GdkEventExpose *); diff --git a/gtk2_ardour/port_matrix_column_labels.cc b/gtk2_ardour/port_matrix_column_labels.cc index 92affb1f31..adef4c6eb7 100644 --- a/gtk2_ardour/port_matrix_column_labels.cc +++ b/gtk2_ardour/port_matrix_column_labels.cc @@ -28,7 +28,8 @@ using namespace std; PortMatrixColumnLabels::PortMatrixColumnLabels (PortMatrix* m, PortMatrixBody* b) - : PortMatrixLabels (m, b) + : PortMatrixLabels (m, b), + _overhang (0) { } @@ -92,6 +93,8 @@ PortMatrixColumnLabels::compute_dimensions () if (ext.height > _highest_group_name) { _highest_group_name = ext.height; } + } else { + _width += column_width (); } } @@ -109,7 +112,8 @@ PortMatrixColumnLabels::compute_dimensions () _height = parallelogram_height + _highest_group_name + 2 * name_pad(); - _width += parallelogram_height / tan (angle ()); + _overhang = parallelogram_height / tan (angle ()); + _width += _overhang; } double @@ -144,18 +148,18 @@ PortMatrixColumnLabels::render (cairo_t* cr) int g = 0; for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) { - if (!(*i)->visible() || (*i)->bundles().empty()) { - continue; - } - /* compute width of this group */ uint32_t w = 0; - if (_matrix->show_only_bundles()) { - w = (*i)->bundles().size() * column_width(); + if (!(*i)->visible() || (*i)->bundles().empty()) { + w = column_width (); } else { - w = (*i)->total_channels() * column_width(); - } - + if (_matrix->show_only_bundles()) { + w = (*i)->bundles().size() * column_width(); + } else { + w = (*i)->total_channels() * column_width(); + } + } + /* rectangle */ set_source_rgb (cr, get_a_group_colour (g)); double const rh = _highest_group_name + 2 * name_pad(); @@ -165,36 +169,49 @@ PortMatrixColumnLabels::render (cairo_t* cr) cairo_rectangle (cr, x, _height - rh, w, rh); } cairo_fill (cr); - + string const upper = Glib::ustring ((*i)->name).uppercase (); pair const display = fit_to_pixels (cr, upper, w); - + /* plot it */ set_source_rgb (cr, text_colour()); cairo_move_to (cr, x + (w - display.second) / 2, y); cairo_show_text (cr, display.first.c_str()); - + x += w; ++g; + } /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */ x = 0; int N = 0; - PortGroup::BundleList const bundles = _matrix->columns()->bundles(); - for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) { - Gdk::Color c = i->has_colour ? i->colour : get_a_bundle_colour (N); - render_bundle_name (cr, c, x, 0, i->bundle); + for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) { + + if ((*i)->visible ()) { + + PortGroup::BundleList const & bundles = (*i)->bundles (); + for (PortGroup::BundleList::const_iterator j = bundles.begin (); j != bundles.end(); ++j) { + + Gdk::Color c = j->has_colour ? j->colour : get_a_bundle_colour (N); + render_bundle_name (cr, c, x, 0, j->bundle); + + if (_matrix->show_only_bundles()) { + x += column_width(); + } else { + x += j->bundle->nchannels () * column_width(); + } + + ++N; + } - if (_matrix->show_only_bundles()) { - x += column_width(); } else { - x += i->bundle->nchannels () * column_width(); - } - ++N; + x += column_width (); + + } } @@ -203,15 +220,27 @@ PortMatrixColumnLabels::render (cairo_t* cr) if (!_matrix->show_only_bundles()) { x = 0; N = 0; - for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) { - - for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) { - Gdk::Color c = i->has_colour ? i->colour : get_a_bundle_colour (N); - render_channel_name (cr, c, x, 0, ARDOUR::BundleChannel (i->bundle, j)); - x += column_width(); - } + for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) { - ++N; + if ((*i)->visible ()) { + + PortGroup::BundleList const & bundles = (*i)->bundles (); + for (PortGroup::BundleList::const_iterator j = bundles.begin (); j != bundles.end(); ++j) { + + 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(); + } + + ++N; + } + + } else { + + x += column_width (); + + } } } } @@ -484,43 +513,102 @@ PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc) } } +pair, ARDOUR::BundleChannel> +PortMatrixColumnLabels::x_position_to_group_and_channel (double x, double y) const +{ + uint32_t cx = 0; + uint32_t const gh = _highest_group_name + 2 * name_pad(); + + bool group_name = false; + if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { + if (y > (_height - gh)) { + group_name = true; + cx = x; + } else { + cx = x - (_height - gh - y) * tan (angle ()); + } + } else { + if (y < gh) { + group_name = true; + cx = x - _overhang; + } else { + cx = x - (_height - y) * tan (angle ()); + } + } + + uint32_t px = 0; + + pair, 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 (), ARDOUR::BundleChannel ()); +} + void PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t) { - uint32_t N = _matrix->columns()->total_visible_channels (); - uint32_t i = 0; - for (; i < N; ++i) { - - vector > const shape = port_name_shape (i * column_width(), 0); - - uint32_t j = 0; - for (; j < 4; ++j) { - uint32_t k = (j + 1) % 4; - - double const P = (y - shape[j].second) * (shape[k].first - shape[j].first) - - (x - shape[j].first) * (shape[k].second - shape[j].second); - - if (P > 0) { - break; - } - } - - if (j == 4) { - break; - } - } - - if (i == N) { - return; - } + pair, ARDOUR::BundleChannel> gc = x_position_to_group_and_channel (x, y); - switch (b) { - case 1: - _body->highlight_associated_channels (_matrix->column_index(), i); - break; - case 3: - _matrix->popup_channel_context_menu (_matrix->column_index(), i, t); - break; + if (b == 1) { + + if (gc.second.bundle) { + _body->highlight_associated_channels (_matrix->column_index(), gc.second); + } else if (gc.first) { + gc.first->set_visible (!gc.first->visible ()); + } + + } else if (b == 3) { + + _matrix->popup_menu ( + gc, + make_pair (boost::shared_ptr (), ARDOUR::BundleChannel ()), + t + ); } } diff --git a/gtk2_ardour/port_matrix_column_labels.h b/gtk2_ardour/port_matrix_column_labels.h index f91a5be204..7ff3bc9138 100644 --- a/gtk2_ardour/port_matrix_column_labels.h +++ b/gtk2_ardour/port_matrix_column_labels.h @@ -44,6 +44,10 @@ public: double parent_to_component_y (double y) const; void mouseover_changed (PortMatrixNode const &); + uint32_t overhang () const { + return _overhang; + } + private: void render_bundle_name (cairo_t *, Gdk::Color, double, double, boost::shared_ptr); void render_channel_name (cairo_t *, Gdk::Color, double, double, ARDOUR::BundleChannel const &); @@ -60,11 +64,13 @@ private: return _height - _highest_group_name - 2 * name_pad(); } -// PortGroup::BundleList _bundles; + std::pair, ARDOUR::BundleChannel> x_position_to_group_and_channel (double, double) const; + double _longest_bundle_name; double _longest_channel_name; double _highest_text; double _highest_group_name; + uint32_t _overhang; }; #endif diff --git a/gtk2_ardour/port_matrix_component.cc b/gtk2_ardour/port_matrix_component.cc index c6a26d41de..6a60110f3e 100644 --- a/gtk2_ardour/port_matrix_component.cc +++ b/gtk2_ardour/port_matrix_component.cc @@ -21,6 +21,8 @@ #include "port_matrix.h" #include "port_matrix_body.h" +using namespace std; + /** Constructor. * @param p Port matrix that we're in. */ @@ -98,7 +100,7 @@ PortMatrixComponent::set_source_rgba (cairo_t *cr, Gdk::Color const & c, double cairo_set_source_rgba (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p(), a); } -std::pair +pair PortMatrixComponent::dimensions () { if (_dimension_computation_required) { @@ -107,7 +109,7 @@ PortMatrixComponent::dimensions () _body->component_size_changed (); } - return std::make_pair (_width, _height); + return make_pair (_width, _height); } Gdk::Color @@ -115,3 +117,95 @@ PortMatrixComponent::background_colour () { return _matrix->get_style()->get_bg (Gtk::STATE_NORMAL); } + +uint32_t +PortMatrixComponent::group_width (boost::shared_ptr g) const +{ + uint32_t width = 0; + + if (g->visible()) { + PortGroup::BundleList const & bundles = g->bundles (); + if (_matrix->show_only_bundles()) { + width = bundles.size() * column_width (); + } else { + for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) { + width += i->bundle->nchannels() * column_width (); + } + } + } else { + width = column_width (); + } + + return width; +} + +uint32_t +PortMatrixComponent::group_height (boost::shared_ptr g) const +{ + uint32_t height = 0; + + 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 (); + } + } + } else { + height = row_height (); + } + + return height; +} + + +pair, ARDOUR::BundleChannel> +PortMatrixComponent::y_position_to_group_and_channel (double y) const +{ + PortGroupList::List::const_iterator i = _matrix->rows()->begin(); + + while (i != _matrix->rows()->end()) { + + uint32_t const gh = group_height (*i); + + if (y < gh) { + + /* 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 (y < row_height()) { + return make_pair (*i, ARDOUR::BundleChannel (j->bundle, 0)); + } else { + y -= row_height (); + } + + } else { + + uint32_t const h = j->bundle->nchannels () * row_height (); + if (y < h) { + return make_pair (*i, ARDOUR::BundleChannel (j->bundle, y / row_height())); + } else { + y -= h; + } + + } + + } + + } else { + + y -= gh; + + } + + ++i; + } + + return make_pair (boost::shared_ptr (), ARDOUR::BundleChannel (boost::shared_ptr (), 0)); +} diff --git a/gtk2_ardour/port_matrix_component.h b/gtk2_ardour/port_matrix_component.h index d28299b8ef..34dc18e932 100644 --- a/gtk2_ardour/port_matrix_component.h +++ b/gtk2_ardour/port_matrix_component.h @@ -22,10 +22,16 @@ #include #include +#include class PortMatrix; class PortMatrixBody; class PortMatrixNode; +class PortGroup; + +namespace ARDOUR { + class BundleChannel; +} /** One component of the PortMatrix. This is a cairo-rendered * Pixmap. @@ -166,6 +172,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; + uint32_t group_height (boost::shared_ptr) const; + std::pair, ARDOUR::BundleChannel> y_position_to_group_and_channel (double) const; /** Render the complete component to a cairo context. */ virtual void render (cairo_t *) = 0; diff --git a/gtk2_ardour/port_matrix_grid.cc b/gtk2_ardour/port_matrix_grid.cc index cb08abb460..3ad9f66cbb 100644 --- a/gtk2_ardour/port_matrix_grid.cc +++ b/gtk2_ardour/port_matrix_grid.cc @@ -25,6 +25,8 @@ #include "port_matrix.h" #include "port_matrix_body.h" +using namespace std; + PortMatrixGrid::PortMatrixGrid (PortMatrix* m, PortMatrixBody* b) : PortMatrixComponent (m, b) { @@ -35,23 +37,13 @@ void PortMatrixGrid::compute_dimensions () { _width = 0; - PortGroup::BundleList const c = _matrix->columns()->bundles(); - if (_matrix->show_only_bundles()) { - _width = c.size() * column_width(); - } else { - for (PortGroup::BundleList::const_iterator i = c.begin(); i != c.end(); ++i) { - _width += i->bundle->nchannels() * column_width(); - } + for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) { + _width += group_width (*i); } _height = 0; - PortGroup::BundleList const r = _matrix->rows()->bundles(); - if (_matrix->show_only_bundles()) { - _height = r.size() * column_width(); - } else { - for (PortGroup::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { - _height += i->bundle->nchannels() * row_height(); - } + for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) { + _height += group_height (*i); } } @@ -59,83 +51,112 @@ PortMatrixGrid::compute_dimensions () void PortMatrixGrid::render (cairo_t* cr) { - /* BACKGROUND */ - set_source_rgb (cr, background_colour()); cairo_rectangle (cr, 0, 0, _width, _height); cairo_fill (cr); + uint32_t x = 0; + for (PortGroupList::List::const_iterator c = _matrix->columns()->begin(); c != _matrix->columns()->end(); ++c) { + + uint32_t y = 0; + for (PortGroupList::List::const_iterator r = _matrix->rows()->begin(); r != _matrix->rows()->end(); ++r) { + + if ((*c)->visible() && (*r)->visible()) { + render_group_pair (cr, *r, *c, x, y); + } + + y += group_height (*r); + } + + x += group_width (*c); + } +} + +void +PortMatrixGrid::render_group_pair (cairo_t* cr, boost::shared_ptr row, boost::shared_ptr column, uint32_t const x, uint32_t const y) +{ + PortGroup::BundleList const & row_bundles = row->bundles(); + 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 tx = x; + /* VERTICAL GRID LINES */ set_source_rgb (cr, grid_colour()); - uint32_t x = 0; - PortGroup::BundleList const c = _matrix->columns()->bundles(); uint32_t N = 0; - for (PortGroup::BundleList::const_iterator i = c.begin(); i != c.end(); ++i) { - - if (!_matrix->show_only_bundles()) { - cairo_set_line_width (cr, thin_grid_line_width()); - for (uint32_t j = 1; j < i->bundle->nchannels(); ++j) { - x += column_width(); - cairo_move_to (cr, x, 0); - cairo_line_to (cr, x, _height); - cairo_stroke (cr); - } - } - - if (N < (c.size() - 1)) { - x += column_width(); - cairo_set_line_width (cr, thick_grid_line_width()); - cairo_move_to (cr, x, 0); - cairo_line_to (cr, x, _height); - cairo_stroke (cr); - } - - ++N; - } - - uint32_t grid_width = x + column_width(); - - /* HORIZONTAL GRID LINES */ - uint32_t y = 0; - N = 0; - PortGroup::BundleList const r = _matrix->rows()->bundles(); - for (PortGroup::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { + for (PortGroup::BundleList::const_iterator i = column_bundles.begin(); i != column_bundles.end(); ++i) { + cairo_set_line_width (cr, thick_grid_line_width()); + cairo_move_to (cr, tx, y); + cairo_line_to (cr, tx, y + height); + cairo_stroke (cr); + if (!_matrix->show_only_bundles()) { cairo_set_line_width (cr, thin_grid_line_width()); - for (uint32_t j = 1; j < i->bundle->nchannels(); ++j) { - y += row_height(); - cairo_move_to (cr, 0, y); - cairo_line_to (cr, grid_width, y); + for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) { + tx += column_width (); + cairo_move_to (cr, tx, y); + cairo_line_to (cr, tx, y + height); cairo_stroke (cr); } + + } else { + + tx += column_width (); + } - - if (N < (r.size() - 1)) { - y += row_height(); - cairo_set_line_width (cr, thick_grid_line_width()); - cairo_move_to (cr, 0, y); - cairo_line_to (cr, grid_width, y); - cairo_stroke (cr); - } - + ++N; } - /* ASSOCIATION INDICATORS */ + uint32_t const width = tx - x; + + uint32_t ty = y; - uint32_t bx = 0; - uint32_t by = 0; + /* HORIZONTAL GRID LINES */ + + N = 0; + for (PortGroup::BundleList::const_iterator i = row_bundles.begin(); i != row_bundles.end(); ++i) { + + cairo_set_line_width (cr, thick_grid_line_width()); + cairo_move_to (cr, x, ty); + cairo_line_to (cr, x + width, ty); + cairo_stroke (cr); + + 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 (); + cairo_move_to (cr, x, ty); + cairo_line_to (cr, x + width, ty); + cairo_stroke (cr); + } + + } else { + + ty += row_height (); + + } + + ++N; + } + + /* ASSOCIATION INDICATORS */ + + uint32_t bx = x; + uint32_t by = y; if (_matrix->show_only_bundles()) { - for (PortGroup::BundleList::const_iterator i = c.begin(); i != c.end(); ++i) { - by = 0; + for (PortGroup::BundleList::const_iterator i = column_bundles.begin(); i != column_bundles.end(); ++i) { + by = y; - for (PortGroup::BundleList::const_iterator j = r.begin(); j != r.end(); ++j) { - + for (PortGroup::BundleList::const_iterator j = row_bundles.begin(); j != row_bundles.end(); ++j) { + PortMatrixNode::State s = bundle_to_bundle_state (i->bundle, j->bundle); switch (s) { case PortMatrixNode::UNKNOWN: @@ -155,19 +176,20 @@ PortMatrixGrid::render (cairo_t* cr) } bx += column_width(); + } } else { - for (PortGroup::BundleList::const_iterator i = c.begin(); i != c.end(); ++i) { - by = 0; + for (PortGroup::BundleList::const_iterator i = column_bundles.begin(); i != column_bundles.end(); ++i) { + by = y; - for (PortGroup::BundleList::const_iterator j = r.begin(); j != r.end(); ++j) { + for (PortGroup::BundleList::const_iterator j = row_bundles.begin(); j != row_bundles.end(); ++j) { - x = bx; + tx = bx; for (uint32_t k = 0; k < i->bundle->nchannels (); ++k) { - y = by; + ty = by; for (uint32_t l = 0; l < j->bundle->nchannels (); ++l) { ARDOUR::BundleChannel c[2]; @@ -178,24 +200,24 @@ PortMatrixGrid::render (cairo_t* cr) switch (s) { case PortMatrixNode::ASSOCIATED: - draw_association_indicator (cr, x, y); + draw_association_indicator (cr, tx, ty); break; case PortMatrixNode::UNKNOWN: - draw_unknown_indicator (cr, x, y); + draw_unknown_indicator (cr, tx, ty); break; case PortMatrixNode::NOT_ASSOCIATED: break; - + default: break; } - y += row_height(); + ty += row_height(); } - x += column_width(); + tx += column_width(); } by += j->bundle->nchannels () * row_height(); @@ -240,43 +262,63 @@ PortMatrixNode PortMatrixGrid::position_to_node (double x, double y) const { return PortMatrixNode ( - position_to_channel (y, _matrix->rows()->bundles(), row_height()), - position_to_channel (x, _matrix->columns()->bundles(), column_width()) + y_position_to_group_and_channel (y).second, + x_position_to_group_and_channel (x).second ); } -ARDOUR::BundleChannel -PortMatrixGrid::position_to_channel (double p, PortGroup::BundleList const & bundles, double inc) const +pair, ARDOUR::BundleChannel> +PortMatrixGrid::x_position_to_group_and_channel (double x) const { - uint32_t pos = p / inc; + 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; + } + + } - if (_matrix->show_only_bundles()) { - - for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) { - if (pos == 0) { - return ARDOUR::BundleChannel (i->bundle, 0); - } else { - pos--; } + + } else { + + x -= gw; + } - } else { - - for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) { - if (pos < i->bundle->nchannels()) { - return ARDOUR::BundleChannel (i->bundle, pos); - } else { - pos -= i->bundle->nchannels(); - } - } - + ++i; } - - return ARDOUR::BundleChannel (boost::shared_ptr (), 0); + + return make_pair (boost::shared_ptr (), ARDOUR::BundleChannel (boost::shared_ptr (), 0)); } + double PortMatrixGrid::channel_position ( ARDOUR::BundleChannel bc, @@ -307,54 +349,62 @@ PortMatrixGrid::channel_position ( } void -PortMatrixGrid::button_press (double x, double y, int b) +PortMatrixGrid::button_press (double x, double y, int b, uint32_t t) { - 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); + 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); + } } } - } - - } else { - - if (node.row.bundle && node.column.bundle) { - ARDOUR::BundleChannel c[2]; - c[_matrix->row_index()] = node.row; - c[_matrix->column_index()] = node.column; + } else { - PortMatrixNode::State const s = _matrix->get_state (c); - - if (s == PortMatrixNode::ASSOCIATED || s == PortMatrixNode::NOT_ASSOCIATED) { - - bool const n = !(s == PortMatrixNode::ASSOCIATED); + 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); + + ARDOUR::BundleChannel c[2]; + c[_matrix->row_index()] = node.row; + c[_matrix->column_index()] = node.column; + + _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); + + } } void diff --git a/gtk2_ardour/port_matrix_grid.h b/gtk2_ardour/port_matrix_grid.h index 5d2e528e60..543ea8533f 100644 --- a/gtk2_ardour/port_matrix_grid.h +++ b/gtk2_ardour/port_matrix_grid.h @@ -41,7 +41,7 @@ class PortMatrixGrid : public PortMatrixComponent public: PortMatrixGrid (PortMatrix *, PortMatrixBody *); - void button_press (double, double, int); + void button_press (double, double, int, uint32_t); void mouseover_event (double, double); double component_to_parent_x (double x) const; @@ -55,10 +55,11 @@ private: void compute_dimensions (); void render (cairo_t *); + void render_group_pair (cairo_t *, boost::shared_ptr, boost::shared_ptr, uint32_t, uint32_t); double channel_position (ARDOUR::BundleChannel, PortGroup::BundleList const &, double) const; PortMatrixNode position_to_node (double, double) const; - ARDOUR::BundleChannel position_to_channel (double, PortGroup::BundleList const &, double) const; + std::pair, ARDOUR::BundleChannel> x_position_to_group_and_channel (double) 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); diff --git a/gtk2_ardour/port_matrix_row_labels.cc b/gtk2_ardour/port_matrix_row_labels.cc index 4802d4ca33..880f3adc3a 100644 --- a/gtk2_ardour/port_matrix_row_labels.cc +++ b/gtk2_ardour/port_matrix_row_labels.cc @@ -27,6 +27,8 @@ #include "i18n.h" #include "utils.h" +using namespace std; + PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* m, PortMatrixBody* b) : PortMatrixLabels (m, b) { @@ -43,6 +45,7 @@ PortMatrixRowLabels::compute_dimensions () _longest_port_name = 0; _longest_bundle_name = 0; _height = 0; + PortGroup::BundleList const r = _matrix->rows()->bundles(); for (PortGroup::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) { @@ -74,6 +77,9 @@ PortMatrixRowLabels::compute_dimensions () if (ext.height > _highest_group_name) { _highest_group_name = ext.height; } + } else { + /* add another row_height for a tab for this hidden group */ + _height += row_height (); } } @@ -113,28 +119,28 @@ PortMatrixRowLabels::render (cairo_t* cr) int g = 0; for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) { - if (!(*i)->visible() || (*i)->bundles().empty()) { - continue; - } - /* compute height of this group */ double h = 0; - if (_matrix->show_only_bundles()) { - h = (*i)->bundles().size() * row_height(); + if (!(*i)->visible() || (*i)->bundles().empty()) { + h = row_height (); } else { - h = (*i)->total_channels () * row_height(); + if (_matrix->show_only_bundles()) { + h = (*i)->bundles().size() * row_height(); + } else { + h = (*i)->total_channels () * row_height(); + } } - + /* rectangle */ set_source_rgb (cr, get_a_group_colour (g)); double const rw = _highest_group_name + 2 * name_pad(); cairo_rectangle (cr, x, y, rw, h); cairo_fill (cr); - + /* hence what abbreviation (or not) we need for the group name */ - std::string const upper = Glib::ustring ((*i)->name).uppercase (); - std::pair display = fit_to_pixels (cr, upper, h); - + string const upper = Glib::ustring ((*i)->name).uppercase (); + pair display = fit_to_pixels (cr, upper, h); + /* plot it */ set_source_rgb (cr, text_colour()); cairo_move_to (cr, x + rw - name_pad(), y + (h + display.second) / 2); @@ -142,35 +148,41 @@ PortMatrixRowLabels::render (cairo_t* cr) cairo_rotate (cr, - M_PI / 2); cairo_show_text (cr, display.first.c_str()); cairo_restore (cr); - + y += h; ++g; } - /* BUNDLE NAMES */ + /* BUNDLE AND PORT NAMES */ y = 0; int N = 0; - PortGroup::BundleList const r = _matrix->rows()->bundles(); - for (PortGroup::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { - render_bundle_name (cr, i->has_colour ? i->colour : get_a_bundle_colour (N), 0, y, i->bundle); - int const n = _matrix->show_only_bundles() ? 1 : i->bundle->nchannels(); - y += row_height() * n; - ++N; - } - + int M = 0; + for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) { - /* PORT NAMES */ + if ((*i)->visible ()) { + + PortGroup::BundleList const & bundles = (*i)->bundles (); + for (PortGroup::BundleList::const_iterator j = bundles.begin(); j != bundles.end(); ++j) { + render_bundle_name (cr, j->has_colour ? j->colour : get_a_bundle_colour (N), 0, y, j->bundle); - if (!_matrix->show_only_bundles()) { - y = 0; - N = 0; - for (PortGroup::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { - for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) { - render_channel_name (cr, i->has_colour ? i->colour : get_a_bundle_colour (N), 0, y, ARDOUR::BundleChannel (i->bundle, j)); - y += row_height(); + if (!_matrix->show_only_bundles()) { + 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(); + ++M; + } + } else { + y += row_height(); + } + + ++N; } - ++N; + + } else { + + y += row_height (); } } } @@ -178,25 +190,48 @@ PortMatrixRowLabels::render (cairo_t* cr) void PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t) { - switch (b) { - case 1: - _body->highlight_associated_channels (_matrix->row_index(), y / row_height ()); - break; - case 3: - maybe_popup_context_menu (x, y, t); - break; - } -} + uint32_t const gw = (_highest_group_name + 2 * name_pad()); -void -PortMatrixRowLabels::maybe_popup_context_menu (double x, double y, uint32_t t) -{ - if ( (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x > (_longest_bundle_name + name_pad() * 2)) || - (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x < (_longest_port_name + name_pad() * 2)) + pair, ARDOUR::BundleChannel> w = y_position_to_group_and_channel (y); + + if ( + (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < gw) || + (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_width - gw)) ) { - _matrix->popup_channel_context_menu (_matrix->row_index(), y / row_height(), t); - + w.second.bundle.reset (); + } + + if (b == 1) { + + if (w.second.bundle) { + _body->highlight_associated_channels (_matrix->row_index(), w.second); + } else { + if (w.first) { + w.first->set_visible (!w.first->visible()); + } + } + + } 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 (), ARDOUR::BundleChannel ()), + make_pair (w.first, ARDOUR::BundleChannel ()), + t + ); + } else { + _matrix->popup_menu ( + make_pair (boost::shared_ptr (), ARDOUR::BundleChannel ()), + make_pair (w.first, ARDOUR::BundleChannel ()), + t + ); + } } } diff --git a/gtk2_ardour/port_matrix_row_labels.h b/gtk2_ardour/port_matrix_row_labels.h index 130469a607..60a699f5f2 100644 --- a/gtk2_ardour/port_matrix_row_labels.h +++ b/gtk2_ardour/port_matrix_row_labels.h @@ -63,7 +63,6 @@ private: void rename_channel_proxy (boost::weak_ptr, uint32_t); void queue_draw_for (ARDOUR::BundleChannel const &); double port_name_x () const; - void maybe_popup_context_menu (double, double, uint32_t); double bundle_name_x () const; double _longest_port_name;