+
+void
+MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
+{
+ using namespace Menu_Helpers;
+
+ if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
+ return;
+ }
+
+ list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
+ while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
+ ++i;
+ }
+
+ if (i != output_menu_bundles.end()) {
+ return;
+ }
+
+ output_menu_bundles.push_back (b);
+
+ MenuList& citems = output_menu.items();
+
+ std::string n = b->name ();
+ replace_all (n, "_", " ");
+
+ citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
+}
+
+void
+MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
+{
+
+ ARDOUR::BundleList current = _route->output()->bundles_connected ();
+
+ if (std::find (current.begin(), current.end(), c) == current.end()) {
+ _route->output()->connect_ports_to_bundle (c, true, this);
+ } else {
+ _route->output()->disconnect_ports_from_bundle (c, this);
+ }
+}
+
+gint
+MonitorSection::output_release (GdkEventButton *ev)
+{
+ switch (ev->button) {
+ case 3:
+ edit_output_configuration ();
+ break;
+ }
+
+ return false;
+}
+
+struct RouteCompareByName {
+ bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
+ return a->name().compare (b->name()) < 0;
+ }
+};
+
+gint
+MonitorSection::output_press (GdkEventButton *ev)
+{
+ using namespace Menu_Helpers;
+ if (!_session) {
+ MessageDialog msg (_("No session - no I/O changes are possible"));
+ msg.run ();
+ return true;
+ }
+
+ MenuList& citems = output_menu.items();
+ switch (ev->button) {
+
+ case 3:
+ return false; //wait for the mouse-up to pop the dialog
+
+ case 1:
+ {
+ output_menu.set_name ("ArdourContextMenu");
+ citems.clear ();
+ output_menu_bundles.clear ();
+
+ citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
+
+ citems.push_back (SeparatorElem());
+ uint32_t const n_with_separator = citems.size ();
+
+ ARDOUR::BundleList current = _route->output()->bundles_connected ();
+
+ boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
+
+ /* give user bundles first chance at being in the menu */
+
+ for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
+ if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
+ maybe_add_bundle_to_output_menu (*i, current);
+ }
+ }
+
+ for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
+ if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
+ maybe_add_bundle_to_output_menu (*i, current);
+ }
+ }
+
+ boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
+ RouteList copy = *routes;
+ copy.sort (RouteCompareByName ());
+ for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
+ maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
+ }
+
+ if (citems.size() == n_with_separator) {
+ /* no routes added; remove the separator */
+ citems.pop_back ();
+ }
+
+ citems.push_back (SeparatorElem());
+ citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
+
+ output_menu.popup (1, ev->time);
+ break;
+ }
+
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+void
+MonitorSection::update_output_display ()
+{
+ if (!_route || !_monitor || _session->deletion_in_progress()) {
+ return;
+ }
+
+ uint32_t io_count;
+ uint32_t io_index;
+ boost::shared_ptr<Port> port;
+ vector<string> port_connections;
+
+ uint32_t total_connection_count = 0;
+ uint32_t io_connection_count = 0;
+ uint32_t ardour_connection_count = 0;
+ uint32_t system_connection_count = 0;
+ uint32_t other_connection_count = 0;
+
+ ostringstream label;
+
+ bool have_label = false;
+ bool each_io_has_one_connection = true;
+
+ string connection_name;
+ string ardour_track_name;
+ string other_connection_type;
+ string system_ports;
+ string system_port;
+
+ ostringstream tooltip;
+ char * tooltip_cstr;
+
+ io_count = _route->n_outputs().n_total();
+ tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
+
+
+ for (io_index = 0; io_index < io_count; ++io_index) {
+
+ port = _route->output()->nth (io_index);
+
+ //ignore any port connections that don't match our DataType
+ if (port->type() != DataType::AUDIO) {
+ continue;
+ }
+
+ port_connections.clear ();
+ port->get_connections(port_connections);
+ io_connection_count = 0;
+
+ if (!port_connections.empty()) {
+ for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
+ string pn = "";
+ string& connection_name (*i);
+
+ if (connection_name.find("system:") == 0) {
+ pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
+ }
+
+ if (io_connection_count == 0) {
+ tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
+ << " -> "
+ << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
+ } else {
+ tooltip << ", "
+ << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
+ }
+
+ if (connection_name.find(RouteUI::program_port_prefix) == 0) {
+ if (ardour_track_name.empty()) {
+ // "ardour:Master/in 1" -> "ardour:Master/"
+ string::size_type slash = connection_name.find("/");
+ if (slash != string::npos) {
+ ardour_track_name = connection_name.substr(0, slash + 1);
+ }
+ }
+
+ if (connection_name.find(ardour_track_name) == 0) {
+ ++ardour_connection_count;
+ }
+ } else if (!pn.empty()) {
+ if (system_ports.empty()) {
+ system_ports += pn;
+ } else {
+ system_ports += "/" + pn;
+ }
+ if (connection_name.find("system:") == 0) {
+ ++system_connection_count;
+ }
+ } else if (connection_name.find("system:") == 0) {
+ // "system:playback_123" -> "123"
+ system_port = connection_name.substr(16);
+ if (system_ports.empty()) {
+ system_ports += system_port;
+ } else {
+ system_ports += "/" + system_port;
+ }
+
+ ++system_connection_count;
+ } else {
+ if (other_connection_type.empty()) {
+ // "jamin:in 1" -> "jamin:"
+ other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
+ }
+
+ if (connection_name.find(other_connection_type) == 0) {
+ ++other_connection_count;
+ }
+ }
+
+ ++total_connection_count;
+ ++io_connection_count;
+ }
+ }
+
+ if (io_connection_count != 1) {
+ each_io_has_one_connection = false;
+ }
+ }
+
+ if (total_connection_count == 0) {
+ tooltip << endl << _("Disconnected");
+ }
+
+ tooltip_cstr = new char[tooltip.str().size() + 1];
+ strcpy(tooltip_cstr, tooltip.str().c_str());
+
+ set_tooltip (output_button, tooltip_cstr, "");
+
+ if (each_io_has_one_connection) {
+ if (total_connection_count == ardour_connection_count) {
+ // all connections are to the same track in ardour
+ // "ardour:Master/" -> "Master"
+ string::size_type slash = ardour_track_name.find("/");
+ if (slash != string::npos) {
+ label << ardour_track_name.substr(7, slash - 7);
+ have_label = true;
+ }
+ } else if (total_connection_count == system_connection_count) {
+ // all connections are to system ports
+ label << system_ports;
+ have_label = true;
+ } else if (total_connection_count == other_connection_count) {
+ // all connections are to the same external program eg jamin
+ // "jamin:" -> "jamin"
+ label << other_connection_type.substr(0, other_connection_type.size() - 1);
+ have_label = true;
+ }
+ }
+
+ if (!have_label) {
+ if (total_connection_count == 0) {
+ // Disconnected
+ label << "-";
+ } else {
+ // Odd configuration
+ label << "*" << total_connection_count << "*";
+ }
+ }
+
+ output_button->set_text (label.str());
+}
+
+void
+MonitorSection::disconnect_output ()
+{
+ if (_route) {
+ _route->output()->disconnect(this);
+ }
+}
+
+void
+MonitorSection::edit_output_configuration ()
+{
+ if (_output_selector == 0) {
+ _output_selector = new MonitorSelectorWindow (_session, _route->output());
+ }
+ _output_selector->present ();
+}
+
+void
+MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
+{
+ if (!_route) {
+ return;
+ }
+ boost::shared_ptr<Port> a = wa.lock ();
+ boost::shared_ptr<Port> b = wb.lock ();
+ if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
+ update_output_display ();
+ }
+}
+
+void
+MonitorSection::load_bindings ()
+{
+ bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
+}
+
+void
+MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
+{
+ boost::shared_ptr<Processor> processor (p.lock ());
+ if (!processor || !processor->display_to_user()) {
+ return;
+ }
+ if (boost::dynamic_pointer_cast<Amp>(processor)) {
+ return;
+ }
+ ++(*cnt);
+}
+
+uint32_t
+MonitorSection::count_processors ()
+{
+ uint32_t processor_count = 0;
+ if (_route) {
+ _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
+ }
+ return processor_count;
+}
+
+void
+MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
+{
+ update_processor_box ();
+}
+
+void
+MonitorSection::action_proxy0 (enum MonitorActions action)
+{
+ MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
+ if (!ms) {
+ return;
+ }
+ switch (action) {
+ case MonitorMono:
+ ms->mono ();
+ break;
+ case MonitorCutAll:
+ ms->cut_all ();
+ break;
+ case MonitorDimAll:
+ ms->dim_all ();
+ break;
+ case ToggleExclusiveSolo:
+ ms->toggle_exclusive_solo ();
+ break;
+ case ToggleMuteOverridesSolo:
+ ms->toggle_mute_overrides_solo ();
+ break;
+ case SoloUseInPlace:
+ ms->solo_use_in_place ();
+ break;
+ case SoloUseAFL:
+ ms->solo_use_afl ();
+ break;
+ case SoloUsePFL:
+ ms->solo_use_pfl ();
+ break;
+ case ToggleMonitorProcessorBox:
+ ms->update_processor_box ();
+ break;
+ }
+}
+
+void
+MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
+{
+ MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
+ if (!ms) {
+ return;
+ }
+ switch (action) {
+ case CutChannel:
+ ms->cut_channel (chn);
+ break;
+ case DimChannel:
+ ms->dim_channel (chn);
+ break;
+ case SoloChannel:
+ ms->solo_channel (chn);
+ break;
+ case InvertChannel:
+ ms->invert_channel (chn);
+ break;
+ }
+}