+ /* for some reason best known to GTK, erroneous switch_page signals seem to be generated
+ when adding or removing pages to or from notebooks, so ignore them */
+
+ _ignore_notebook_page_selected = true;
+
+ remove_notebook_pages (_hnotebook);
+ remove_notebook_pages (_vnotebook);
+
+ for (PortGroupList::List::const_iterator i = _ports[_row_index].begin(); i != _ports[_row_index].end(); ++i) {
+ HBox* dummy = manage (new HBox);
+ dummy->show ();
+ Label* label = manage (new Label ((*i)->name));
+ label->set_angle (_arrangement == LEFT_TO_BOTTOM ? 90 : -90);
+ label->show ();
+ _vnotebook.prepend_page (*dummy, *label);
+ }
+
+ for (PortGroupList::List::const_iterator i = _ports[_column_index].begin(); i != _ports[_column_index].end(); ++i) {
+ HBox* dummy = manage (new HBox);
+ dummy->show ();
+ _hnotebook.append_page (*dummy, (*i)->name);
+ }
+
+ _ignore_notebook_page_selected = false;
+
+ _vnotebook.set_tab_pos (POS_LEFT);
+ _hnotebook.set_tab_pos (POS_TOP);
+
+ if (h_current_page != -1 && _hnotebook.get_n_pages() > h_current_page) {
+ _hnotebook.set_current_page (h_current_page);
+ } else {
+ _hnotebook.set_current_page (0);
+ }
+
+ if (v_current_page != -1 && _vnotebook.get_n_pages() > v_current_page) {
+ _vnotebook.set_current_page (v_current_page);
+ } else {
+ _vnotebook.set_current_page (0);
+ }
+
+ if (_hnotebook.get_n_pages() <= 1) {
+ _hbox.hide ();
+ } else {
+ _hbox.show ();
+ }
+
+ if (_vnotebook.get_n_pages() <= 1) {
+ _vbox.hide ();
+ } else {
+ _vbox.show ();
+ }
+}
+
+void
+PortMatrix::remove_notebook_pages (Notebook& n)
+{
+ int const N = n.get_n_pages ();
+
+ for (int i = 0; i < N; ++i) {
+ n.remove_page ();
+ }
+}
+
+void
+PortMatrix::notebook_page_selected (GtkNotebookPage *, guint)
+{
+ if (_ignore_notebook_page_selected) {
+ return;
+ }
+
+ _body->setup ();
+ setup_scrollbars ();
+ queue_draw ();
+}
+
+void
+PortMatrix::session_going_away ()
+{
+ _session = 0;
+}
+
+void
+PortMatrix::body_dimensions_changed ()
+{
+ _hspacer.set_size_request (_body->column_labels_border_x (), -1);
+ if (_arrangement == TOP_TO_RIGHT) {
+ _vspacer.set_size_request (-1, _body->column_labels_height ());
+ _vspacer.show ();
+ } else {
+ _vspacer.hide ();
+ }
+
+ pair<uint32_t, uint32_t> const m = max_size ();
+ resize_window_to_proportion_of_monitor (_parent, m.first, m.second);
+}
+
+
+boost::shared_ptr<const PortGroup>
+PortMatrix::visible_ports (int d) const
+{
+ PortGroupList const & p = _ports[d];
+ PortGroupList::List::const_iterator j = p.begin ();
+
+ int n = 0;
+ if (d == _row_index) {
+ n = p.size() - _vnotebook.get_current_page () - 1;
+ } else {
+ n = _hnotebook.get_current_page ();
+ }
+
+ int i = 0;
+ while (i != int (n) && j != p.end ()) {
+ ++i;
+ ++j;
+ }
+
+ if (j == p.end()) {
+ return boost::shared_ptr<const PortGroup> ();
+ }
+
+ return *j;
+}
+
+void
+PortMatrix::add_remove_option (Menu_Helpers::MenuList& m, boost::weak_ptr<Bundle> w, int c)
+{
+ using namespace Menu_Helpers;
+
+ boost::shared_ptr<Bundle> b = w.lock ();
+ if (!b) {
+ return;
+ }
+
+ char buf [64];
+ snprintf (buf, sizeof (buf), _("Remove '%s'"), escape_underscores (b->channel_name (c)).c_str());
+ m.push_back (MenuElem (buf, sigc::bind (sigc::mem_fun (*this, &PortMatrix::remove_channel_proxy), w, c)));
+}
+
+void
+PortMatrix::add_disassociate_option (Menu_Helpers::MenuList& m, boost::weak_ptr<Bundle> w, int d, int c)
+{
+ using namespace Menu_Helpers;
+
+ boost::shared_ptr<Bundle> b = w.lock ();
+ if (!b) {
+ return;
+ }
+
+ char buf [64];
+ snprintf (buf, sizeof (buf), _("%s all from '%s'"), disassociation_verb().c_str(), escape_underscores (b->channel_name (c)).c_str());
+ m.push_back (MenuElem (buf, sigc::bind (sigc::mem_fun (*this, &PortMatrix::disassociate_all_on_channel), w, c, d)));
+}
+
+void
+PortMatrix::port_connected_or_disconnected ()
+{
+ _body->rebuild_and_draw_grid ();
+}
+
+string
+PortMatrix::channel_noun () const
+{
+ return _("channel");
+}
+
+/** @return true if this matrix should show bundles / ports of type \t */
+bool
+PortMatrix::should_show (DataType t) const
+{
+ return (_type == DataType::NIL || t == _type);
+}
+
+uint32_t
+PortMatrix::count_of_our_type (ChanCount c) const
+{
+ if (_type == DataType::NIL) {
+ return c.n_total ();
+ }
+
+ return c.get (_type);