7a304d96ace37b62b72902175c81be3f32c2ecc9
[ardour.git] / gtk2_ardour / monitor_section.cc
1 /*
2   Copyright (C) 2012 Paul Davis
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program; if not, write to the Free Software
16   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <gdkmm/pixbuf.h>
21
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
25
26 #include "gtkmm2ext/actions.h"
27 #include "gtkmm2ext/utils.h"
28
29 #include <gtkmm/menu.h>
30 #include <gtkmm/menuitem.h>
31
32 #include "widgets/tearoff.h"
33 #include "widgets/tooltips.h"
34
35 #include "ardour/amp.h"
36 #include "ardour/audioengine.h"
37 #include "ardour/monitor_processor.h"
38 #include "ardour/port.h"
39 #include "ardour/route.h"
40 #include "ardour/solo_isolate_control.h"
41 #include "ardour/user_bundle.h"
42 #include "ardour/plugin_manager.h"
43
44 #include "ardour_ui.h"
45 #include "gui_thread.h"
46 #include "mixer_ui.h"
47 #include "monitor_section.h"
48 #include "public_editor.h"
49 #include "timers.h"
50 #include "ui_config.h"
51 #include "utils.h"
52
53 #include "pbd/i18n.h"
54
55 using namespace ARDOUR;
56 using namespace ArdourWidgets;
57 using namespace ARDOUR_UI_UTILS;
58 using namespace Gtk;
59 using namespace Gtkmm2ext;
60 using namespace PBD;
61 using namespace std;
62
63 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
64
65 MonitorSection::MonitorSection ()
66         : RouteUI ((Session*) 0)
67         , _tearoff (0)
68         , channel_table (0)
69         , channel_table_viewport (*channel_table_scroller.get_hadjustment()
70                                   , *channel_table_scroller.get_vadjustment ())
71         , gain_control (0)
72         , dim_control (0)
73         , solo_boost_control (0)
74         , solo_cut_control (0)
75         , gain_display (0)
76         , dim_display (0)
77         , solo_boost_display (0)
78         , solo_cut_display (0)
79         , _output_selector (0)
80         , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
81         , afl_button (_("AFL"), ArdourButton::led_default_elements)
82         , pfl_button (_("PFL"), ArdourButton::led_default_elements)
83         , exclusive_solo_button (ArdourButton::led_default_elements)
84         , solo_mute_override_button (ArdourButton::led_default_elements)
85         , toggle_processorbox_button (ArdourButton::default_elements)
86         , _inhibit_solo_model_update (false)
87         , _rr_selection ()
88         , _ui_initialized (false)
89 {
90         /* note that although this a RouteUI, we never called ::set_route() so
91          * we do not need to worry about self-destructing when the Route (the
92          * monitor out) is destroyed.
93          */
94         
95         using namespace Menu_Helpers;
96
97         Glib::RefPtr<Action> act;
98
99         load_bindings ();
100         register_actions ();
101         set_data ("ardour-bindings", bindings);
102
103         channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
104
105         _plugin_selector = new PluginSelector (PluginManager::instance());
106         insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
107         insert_box->set_no_show_all ();
108         insert_box->show ();
109         // TODO allow keyboard shortcuts in ProcessorBox
110
111         /* Rude Solo  & Solo Isolated */
112         rude_solo_button.set_text (_("Soloing"));
113         rude_solo_button.set_name ("rude solo");
114         rude_solo_button.show ();
115
116         rude_iso_button.set_text (_("Isolated"));
117         rude_iso_button.set_name ("rude isolate");
118         rude_iso_button.show ();
119
120         rude_audition_button.set_text (_("Auditioning"));
121         rude_audition_button.set_name ("rude audition");
122         rude_audition_button.show ();
123
124         Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
125
126         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
127
128         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
129         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
130
131         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
132         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
133
134         /* SIP, AFL, PFL radio */
135
136         solo_in_place_button.set_name ("monitor section solo model");
137         afl_button.set_name ("monitor section solo model");
138         pfl_button.set_name ("monitor section solo model");
139
140         solo_in_place_button.set_led_left (true);
141         afl_button.set_led_left (true);
142         pfl_button.set_led_left (true);
143
144         solo_in_place_button.show ();
145         afl_button.show ();
146         pfl_button.show ();
147
148         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
149         set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
150         if (act) {
151                 solo_in_place_button.set_related_action (act);
152         }
153
154         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
155         set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
156         if (act) {
157                 afl_button.set_related_action (act);
158         }
159
160         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
161         set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
162         if (act) {
163                 pfl_button.set_related_action (act);
164         }
165
166         /* Solo option buttons */
167         exclusive_solo_button.set_text (_("Excl. Solo"));
168         exclusive_solo_button.set_name (X_("monitor section solo option"));
169         set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
170
171         act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
172         if (act) {
173                 exclusive_solo_button.set_related_action (act);
174         }
175
176         solo_mute_override_button.set_text (_("Solo ยป Mute"));
177         solo_mute_override_button.set_name (X_("monitor section solo option"));
178         set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
179
180         solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
181
182         /* Processor Box hide/shos */
183         toggle_processorbox_button.set_text (_("Processors"));
184         toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
185         set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
186
187         proctoggle = ActionManager::get_toggle_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
188         toggle_processorbox_button.set_related_action (proctoggle);
189
190         /* Knobs */
191         Label* solo_boost_label;
192         Label* solo_cut_label;
193         Label* dim_label;
194
195         /* Solo Boost Knob */
196
197         solo_boost_control = new ArdourKnob ();
198         solo_boost_control->set_name("monitor section knob");
199         solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
200         set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
201
202         solo_boost_display = new ArdourDisplay ();
203         solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
204         solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
205         solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
206         solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
207         solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
208
209         solo_boost_label = manage (new Label (_("Solo Boost")));
210
211         /* Solo (SiP) cut */
212
213         solo_cut_control = new ArdourKnob ();
214         solo_cut_control->set_name ("monitor section knob");
215         solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
216         set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
217
218         solo_cut_display = new ArdourDisplay ();
219         solo_cut_display->set_name("monitor section dropdown"); // XXX
220         solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
221         solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
222         solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
223         solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
224         solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
225         solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
226
227         solo_cut_label = manage (new Label (_("SiP Cut")));
228
229         /* Dim */
230
231         dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
232         dim_control->set_name ("monitor section knob");
233         dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
234         set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
235
236         dim_display = new ArdourDisplay ();
237         dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
238         dim_display->add_controllable_preset(_("0 dB"), 0.0);
239         dim_display->add_controllable_preset(_("-3 dB"), -3.0);
240         dim_display->add_controllable_preset(_("-6 dB"), -6.0);
241         dim_display->add_controllable_preset(_("-12 dB"), -12.0);
242         dim_display->add_controllable_preset(_("-20 dB"), -20.0);
243
244         dim_label = manage (new Label (_("Dim")));
245
246         // mute button
247         cut_all_button.set_text (_("Mute"));
248         cut_all_button.set_name ("mute button");
249         cut_all_button.set_size_request (-1, PX_SCALE(30));
250         cut_all_button.show ();
251
252         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
253         if (act) {
254                 cut_all_button.set_related_action (act);
255         }
256
257         // dim button
258         dim_all_button.set_text (_("Dim"));
259         dim_all_button.set_name ("monitor section dim");
260         dim_all_button.set_size_request (-1, PX_SCALE(25));
261         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
262         if (act) {
263                 dim_all_button.set_related_action (act);
264         }
265
266         // mono button
267         mono_button.set_text (_("Mono"));
268         mono_button.set_name ("monitor section mono");
269         mono_button.set_size_request (-1, PX_SCALE(25));
270         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
271         if (act) {
272                 mono_button.set_related_action (act);
273         }
274
275         /* Gain */
276
277         gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
278         gain_control->set_name("monitor section knob");
279         gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
280
281         gain_display = new ArdourDisplay ();
282         gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
283         gain_display->add_controllable_preset(_("0 dB"), 0.0);
284         gain_display->add_controllable_preset(_("-3 dB"), -3.0);
285         gain_display->add_controllable_preset(_("-6 dB"), -6.0);
286         gain_display->add_controllable_preset(_("-12 dB"), -12.0);
287         gain_display->add_controllable_preset(_("-20 dB"), -20.0);
288         gain_display->add_controllable_preset(_("-30 dB"), -30.0);
289
290         Label* output_label = manage (new Label (_("Output")));
291         output_label->set_name (X_("MonitorSectionLabel"));
292
293         output_button = new ArdourButton ();
294         output_button->set_text (_("Output"));
295         output_button->set_name (X_("monitor section cut")); // XXX
296         output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
297         output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
298
299         channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
300         channel_table_scroller.set_size_request (-1, PX_SCALE(150));
301         channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
302         channel_table_scroller.show ();
303         channel_table_scroller.add (channel_table_viewport);
304
305         channel_size_group->add_widget (channel_table_header);
306         channel_table_header.resize (1, 5);
307
308         Label* l1 = manage (new Label (X_("  ")));
309         l1->set_name (X_("MonitorSectionLabel"));
310         channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
311
312         l1 = manage (new Label (_("Mute")));
313         l1->set_name (X_("MonitorSectionLabel"));
314         channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
315
316         l1 = manage (new Label (_("Dim")));
317         l1->set_name (X_("MonitorSectionLabel"));
318         channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
319
320         l1 = manage (new Label (_("Solo")));
321         l1->set_name (X_("MonitorSectionLabel"));
322         channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
323
324         l1 = manage (new Label (_("Inv")));
325         l1->set_name (X_("MonitorSectionLabel"));
326         channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
327
328         channel_table_header.show ();
329
330
331         /****************************************************************************
332          * LAYOUT  top to bottom
333          */
334
335         // solo, iso information
336         HBox* rude_box = manage (new HBox);
337         rude_box->set_spacing (PX_SCALE(4));
338         rude_box->set_homogeneous (true);
339         rude_box->pack_start (rude_solo_button, true, true);
340         rude_box->pack_start (rude_iso_button, true, true);
341
342         // solo options (right align)
343         HBox* tbx1 = manage (new HBox);
344         tbx1->pack_end (exclusive_solo_button, false, false);
345
346         HBox* tbx2 = manage (new HBox);
347         tbx2->pack_end (solo_mute_override_button, false, false);
348
349         HBox* tbx3 = manage (new HBox);
350         tbx3->pack_end (toggle_processorbox_button, false, false);
351
352         HBox* tbx0 = manage (new HBox); // space
353
354         // combined solo mode (Sip, AFL, PFL) & solo options
355         Table *solo_tbl = manage (new Table);
356         solo_tbl->attach (solo_in_place_button,   0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
357         solo_tbl->attach (pfl_button,             0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
358         solo_tbl->attach (afl_button,             0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
359         solo_tbl->attach (*tbx0,                  1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
360         solo_tbl->attach (*tbx1,                  2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
361         solo_tbl->attach (*tbx2,                  2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
362         solo_tbl->attach (*tbx3,                  2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
363
364         // boost, cut, dim  volume control
365         Table *level_tbl = manage (new Table);
366         level_tbl->attach (*solo_boost_label,    0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
367         level_tbl->attach (*solo_boost_control,  0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
368         level_tbl->attach (*solo_boost_display,  0, 2, 2, 3, EXPAND     , SHRINK, 1, 2);
369
370         level_tbl->attach (*solo_cut_label,      2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
371         level_tbl->attach (*solo_cut_control,    2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
372         level_tbl->attach (*solo_cut_display,    2, 4, 2, 3, EXPAND     , SHRINK, 1, 2);
373
374         level_tbl->attach (*dim_label,           1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
375         level_tbl->attach (*dim_control,         1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
376         level_tbl->attach (*dim_display,         1, 3, 5, 6, EXPAND     , SHRINK, 1, 2);
377
378         // mono, dim
379         HBox* mono_dim_box = manage (new HBox);
380         mono_dim_box->set_spacing (PX_SCALE(4));
381         mono_dim_box->set_homogeneous (true);
382         mono_dim_box->pack_start (mono_button, true, true);
383         mono_dim_box->pack_end (dim_all_button, true, true);
384
385         // master gain
386         Label* spin_label = manage (new Label (_("Monitor")));
387         VBox* spin_packer = manage (new VBox);
388         spin_packer->set_spacing (PX_SCALE(2));
389         spin_packer->pack_start (*spin_label, false, false);
390         spin_packer->pack_start (*gain_control, false, false);
391         spin_packer->pack_start (*gain_display, false, false);
392
393         master_packer.pack_start (*spin_packer, true, false);
394
395         // combined gain section (channels, mute, dim)
396         VBox* lower_packer = manage (new VBox);
397         lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
398         lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
399         lower_packer->pack_start (*mono_dim_box,        false, false, PX_SCALE(2));
400         lower_packer->pack_start (cut_all_button,       false, false, PX_SCALE(2));
401
402         // calc height of mixer scrollbar
403         int scrollbar_height = 0;
404         {
405                 Gtk::Window window (WINDOW_TOPLEVEL);
406                 HScrollbar scrollbar;
407                 window.add (scrollbar);
408                 scrollbar.set_name ("MixerWindow");
409                 scrollbar.ensure_style();
410                 Gtk::Requisition requisition(scrollbar.size_request ());
411                 scrollbar_height = requisition.height;
412         }
413
414         // output port select
415         VBox* out_packer = manage (new VBox);
416         out_packer->set_spacing (PX_SCALE(2));
417         out_packer->pack_start (*output_label, false, false);
418         out_packer->pack_start (*output_button, false, false);
419
420         /****************************************************************************
421          * TOP LEVEL LAYOUT
422          */
423         vpacker.set_border_width (PX_SCALE(3));
424         vpacker.pack_start (*rude_box,            false, false, PX_SCALE(3));
425         vpacker.pack_start (rude_audition_button, false, false, 0);
426         vpacker.pack_start (*solo_tbl,            false, false, PX_SCALE(8));
427         vpacker.pack_start (*insert_box,          true,  true,  PX_SCALE(8));
428         vpacker.pack_start (*level_tbl,           false, false, PX_SCALE(8));
429         vpacker.pack_start (*lower_packer,        false, false, PX_SCALE(8));
430         vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
431         vpacker.pack_end   (*out_packer,          false, false,
432 #ifdef MIXBUS
433                         scrollbar_height - 2 /* no outer sample */
434 #else
435                         scrollbar_height + 2 /* sample borders */
436 #endif
437                         );
438
439         hpacker.set_spacing (0);
440         hpacker.pack_start (vpacker, true, true);
441
442         add (hpacker);
443
444         gain_control->show_all ();
445         gain_display->show_all ();
446         dim_control->show_all ();
447         dim_display->show_all();
448         solo_boost_control->show_all ();
449         solo_boost_display->show_all();
450
451         mono_dim_box->show ();
452         spin_packer->show ();
453         master_packer.show ();
454
455         rude_box->show();
456         solo_tbl->show_all();
457         level_tbl->show();
458         lower_packer->show ();
459         out_packer->show ();
460
461         vpacker.show ();
462         hpacker.show ();
463
464         map_state ();
465         assign_controllables ();
466
467         output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
468         output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
469
470         signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
471         signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
472         set_flags (CAN_FOCUS);
473
474         _tearoff = new TearOff (*this);
475
476         if (!UIConfiguration::instance().get_floating_monitor_section()) {
477                 /* if torn off, make this a normal window
478                  * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
479                  */
480                 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
481         }
482         _tearoff->tearoff_window().set_title (X_("Monitor"));
483         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
484
485         update_output_display ();
486         update_processor_box ();
487         _ui_initialized = true;
488
489         /* catch changes that affect us */
490         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
491                 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
492                 );
493         Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
494 }
495
496 MonitorSection::~MonitorSection ()
497 {
498         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
499                 delete *i;
500         }
501
502         _channel_buttons.clear ();
503         output_changed_connections.drop_connections ();
504
505         delete insert_box; insert_box = 0;
506         delete output_button; output_button = 0;
507         delete gain_control; gain_control = 0;
508         delete gain_display; gain_display = 0;
509         delete dim_control; dim_control = 0;
510         delete dim_display; dim_display = 0;
511         delete solo_boost_control; solo_boost_control = 0;
512         delete solo_boost_display; solo_boost_display = 0;
513         delete solo_cut_control; solo_cut_control = 0;
514         delete solo_cut_display; solo_cut_display = 0;
515         delete _tearoff; _tearoff = 0;
516         delete _output_selector; _output_selector = 0;
517         delete channel_table; channel_table = 0;
518 }
519
520 bool
521 MonitorSection::enter_handler (GdkEventCrossing* ev)
522 {
523         grab_focus ();
524         return false;
525 }
526
527 bool
528 MonitorSection::leave_handler (GdkEventCrossing* ev)
529 {
530         switch (ev->detail) {
531         case GDK_NOTIFY_INFERIOR:
532                 return false;
533         default:
534                 break;
535         }
536
537         /* cancel focus if we're not torn off. With X11 WM's that do
538          * focus-follows-mouse, focus will be taken from us anyway.
539          */
540
541         Widget* top = get_toplevel();
542
543         if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
544                 Window* win = dynamic_cast<Window*> (top);
545                 gtk_window_set_focus (win->gobj(), 0);
546         }
547
548         return false;
549 }
550
551 void
552 MonitorSection::update_processor_box ()
553 {
554         bool show_processor_box = proctoggle->get_active ();
555
556         if (count_processors () > 0 && !show_processor_box) {
557                 toggle_processorbox_button.set_name (X_("monitor section processors present"));
558         } else {
559                 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
560         }
561
562         if (insert_box->is_visible() == show_processor_box) {
563                 return;
564         }
565
566         if (show_processor_box) {
567                 if (master_packer.get_parent()) {
568                         master_packer.get_parent()->remove (master_packer);
569                 }
570                 insert_box->show();
571                 vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
572         } else {
573                 if (master_packer.get_parent()) {
574                         master_packer.get_parent()->remove (master_packer);
575                 }
576                 insert_box->hide();
577                 vpacker.pack_start (master_packer,        true,  false, PX_SCALE(10));
578         }
579 }
580
581 void
582 MonitorSection::set_session (Session* s)
583 {
584         RouteUI::set_session (s);
585         _plugin_selector->set_session (_session);
586
587         if (_session) {
588
589                 /* These are not actually dependent on the Session, but they
590                  * need to be set after construction, not during, and
591                  * this is as good a place as any.
592                  */
593
594                 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
595                 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
596
597                 _route = _session->monitor_out ();
598
599                 if (_route) {
600                         /* session with monitor section */
601                         _monitor = _route->monitor_control ();
602                         assign_controllables ();
603                         _route->output()->changed.connect (output_changed_connections, invalidator (*this),
604                                                                                         boost::bind (&MonitorSection::update_output_display, this),
605                                                                                         gui_context());
606                         insert_box->set_route (_route);
607                         _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
608                         _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
609                         _route->DropReferences.connect (*this, invalidator (*this), boost::bind (&MonitorSection::drop_route, this), gui_context());
610
611                         if (_ui_initialized) {
612                                 update_processor_box ();
613                         }
614
615                         ActionManager::set_sensitive (monitor_actions, true);
616                         ActionManager::set_sensitive (solo_actions, true);
617
618                 } else {
619                         /* session with no monitor section */
620                         output_changed_connections.drop_connections();
621                         _monitor.reset ();
622                         _route.reset ();
623                         delete _output_selector;
624                         _output_selector = 0;
625
626                         ActionManager::set_sensitive (monitor_actions, false);
627                         /* this action needs to always be true in this * scenaro, so that we can turn it back on*/
628                         ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_sensitive (true);
629                         ActionManager::set_sensitive (solo_actions, true);
630                 }
631
632                 /* make sure the state of this action reflects reality */
633                 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_active (_route != 0);
634
635                 populate_buttons ();
636
637
638         } else {
639
640                 /* no session */
641
642                 drop_route ();
643                 assign_controllables ();
644
645                 ActionManager::set_sensitive (monitor_actions, false);
646                 ActionManager::set_sensitive (solo_actions, false);
647         }
648 }
649
650 void
651 MonitorSection::drop_route ()
652 {
653         output_changed_connections.drop_connections();
654         _monitor.reset ();
655         _route.reset ();
656         control_connections.drop_connections ();
657         rude_iso_button.unset_active_state ();
658         rude_solo_button.unset_active_state ();
659         delete _output_selector;
660         _output_selector = 0;
661 }
662
663 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
664 {
665         cut.set_name (X_("mute button"));
666         dim.set_name (X_("monitor section dim"));
667         solo.set_name (X_("solo button"));
668         invert.set_name (X_("invert button"));
669
670         cut.unset_flags (Gtk::CAN_FOCUS);
671         dim.unset_flags (Gtk::CAN_FOCUS);
672         solo.unset_flags (Gtk::CAN_FOCUS);
673         invert.unset_flags (Gtk::CAN_FOCUS);
674 }
675
676 void
677 MonitorSection::populate_buttons ()
678 {
679         if (!_monitor) {
680                 return;
681         }
682
683         if (channel_table) {
684                 channel_size_group->remove_widget (*channel_table);
685                 delete channel_table;
686         }
687
688         channel_table = new Gtk::Table();
689
690         channel_table->set_col_spacings (6);
691         channel_table->set_row_spacings (6);
692         channel_table->set_homogeneous (true);
693
694         channel_size_group->add_widget (*channel_table);
695         channel_table->show ();
696         table_hpacker.pack_start (*channel_table, true, true);
697
698         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
699                 delete *i;
700         }
701         _channel_buttons.clear ();
702
703         Glib::RefPtr<Action> act;
704         uint32_t nchans = _monitor->output_streams().n_audio();
705
706         channel_table->resize (nchans, 5);
707
708         const uint32_t row_offset = 0;
709
710         for (uint32_t i = 0; i < nchans; ++i) {
711
712                 string l;
713                 char buf[64];
714
715                 if (nchans == 2) {
716                         if (i == 0) {
717                                 l = "L";
718                         } else {
719                                 l = "R";
720                         }
721                 } else {
722                         char buf[32];
723                         snprintf (buf, sizeof (buf), "%d", i+1);
724                         l = buf;
725                 }
726
727                 Label* label = manage (new Label (l));
728                 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
729
730                 ChannelButtonSet* cbs = new ChannelButtonSet;
731
732                 _channel_buttons.push_back (cbs);
733
734                 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
735                 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
736                 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
737                 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
738
739                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
740                 act = ActionManager::get_action (X_("Monitor"), buf);
741                 if (act) {
742                         cbs->cut.set_related_action (act);
743                 }
744
745                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
746                 act = ActionManager::get_action (X_("Monitor"), buf);
747                 if (act) {
748                         cbs->dim.set_related_action (act);
749                 }
750
751                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
752                 act = ActionManager::get_action (X_("Monitor"), buf);
753                 if (act) {
754                         cbs->solo.set_related_action (act);
755                 }
756
757                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
758                 act = ActionManager::get_action (X_("Monitor"), buf);
759                 if (act) {
760                         cbs->invert.set_related_action (act);
761                 }
762         }
763
764         channel_table->show_all ();
765
766         if (channel_table_scroller.get_parent()) {
767                 /* scroller is packed, so remove it */
768                 channel_table_packer.remove (channel_table_scroller);
769         }
770
771         if (table_hpacker.get_parent () == &channel_table_packer) {
772                 /* this occurs when the table hpacker is directly
773                          packed, so remove it.
774                          */
775                 channel_table_packer.remove (table_hpacker);
776         } else if (table_hpacker.get_parent()) {
777                 channel_table_viewport.remove ();
778         }
779
780         if (nchans > 7) {
781                 /* put the table into a scrolled window, and then put
782                  * that into the channel vpacker, after the table header
783                  */
784                 channel_table_viewport.add (table_hpacker);
785                 channel_table_packer.pack_start (channel_table_scroller, true, true);
786                 channel_table_viewport.show ();
787                 channel_table_scroller.show ();
788
789         } else {
790                 /* just put the channel table itself into the channel
791                  * vpacker, after the table header
792                  */
793                 channel_table_packer.pack_start (table_hpacker, true, true);
794                 channel_table_scroller.hide ();
795         }
796         table_hpacker.show ();
797         channel_table->show ();
798 }
799
800 void
801 MonitorSection::toggle_exclusive_solo ()
802 {
803         if (!_monitor) {
804                 return;
805         }
806
807         Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
808 }
809
810 void
811 MonitorSection::toggle_mute_overrides_solo ()
812 {
813         if (!_monitor) {
814                 return;
815         }
816
817         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo");
818         Config->set_solo_mute_override (tact->get_active());
819 }
820
821 void
822 MonitorSection::dim_all ()
823 {
824         if (!_monitor) {
825                 return;
826         }
827
828         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
829         _monitor->set_dim_all (tact->get_active());
830 }
831
832 void
833 MonitorSection::cut_all ()
834 {
835         if (!_monitor) {
836                 return;
837         }
838
839         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
840         _monitor->set_cut_all (tact->get_active());
841 }
842
843 void
844 MonitorSection::mono ()
845 {
846         if (!_monitor) {
847                 return;
848         }
849
850         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
851         _monitor->set_mono (tact->get_active());
852 }
853
854 void
855 MonitorSection::cut_channel (uint32_t chn)
856 {
857         if (!_monitor) {
858                 return;
859         }
860
861         char buf[64];
862         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
863
864         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
865         _monitor->set_cut (chn, tact->get_active());
866 }
867
868 void
869 MonitorSection::dim_channel (uint32_t chn)
870 {
871         if (!_monitor) {
872                 return;
873         }
874
875         char buf[64];
876         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
877
878         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
879         _monitor->set_dim (chn, tact->get_active());
880 }
881
882 void
883 MonitorSection::solo_channel (uint32_t chn)
884 {
885         if (!_monitor) {
886                 return;
887         }
888
889         char buf[64];
890         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
891
892         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
893         _monitor->set_solo (chn, tact->get_active());
894
895 }
896
897 void
898 MonitorSection::invert_channel (uint32_t chn)
899 {
900         if (!_monitor) {
901                 return;
902         }
903
904         char buf[64];
905         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
906
907         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
908         _monitor->set_polarity (chn, tact->get_active());
909 }
910
911 void
912 MonitorSection::register_actions ()
913 {
914         string action_name;
915         string action_descr;
916         Glib::RefPtr<Action> act;
917
918         /* ...will get sensitized if a mon-session is added */
919
920         monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
921         solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
922
923         ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
924         ActionManager::register_toggle_action (monitor_actions, "monitor-mono", _("Monitor Section: Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
925         ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", _("Monitor Section: Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
926         ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", _("Monitor Section: Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
927
928         ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
929                                                sigc::mem_fun (*this, &MonitorSection::update_processor_box));
930
931
932         for (uint32_t chn = 0; chn < 16; ++chn) {
933
934                 action_name = string_compose (X_("monitor-cut-%1"), chn);
935                 action_descr = string_compose (_("Cut monitor channel %1"), chn);
936                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
937                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
938
939                 action_name = string_compose (X_("monitor-dim-%1"), chn);
940                 action_descr = string_compose (_("Dim monitor channel %1"), chn);
941                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
942                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
943
944                 action_name = string_compose (X_("monitor-solo-%1"), chn);
945                 action_descr = string_compose (_("Solo monitor channel %1"), chn);
946                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
947                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
948
949                 action_name = string_compose (X_("monitor-invert-%1"), chn);
950                 action_descr = string_compose (_("Invert monitor channel %1"), chn);
951                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
952                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
953
954         }
955
956         solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
957         RadioAction::Group solo_group;
958
959         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
960                                               sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
961         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
962                                               sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
963         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
964                                               sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
965
966         ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
967                                                sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
968         ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
969                                                sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
970 }
971
972 void
973 MonitorSection::solo_use_in_place ()
974 {
975         /* this is driven by a toggle on a radio group, and so is invoked twice,
976                  once for the item that became inactive and once for the one that became
977                  active.
978                  */
979
980         Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-in-place"));
981         if (!ract->get_active ()) {
982                 /* We are turning SiP off, which means that AFL or PFL will be turned on
983                    shortly; don't update the solo model in the mean time, as if the currently
984                    configured listen position is not the one that is about to be turned on,
985                    things will go wrong.
986                 */
987                 _inhibit_solo_model_update = true;
988         }
989         Config->set_solo_control_is_listen_control (!ract->get_active());
990         _inhibit_solo_model_update = false;
991 }
992
993 void
994 MonitorSection::solo_use_afl ()
995 {
996         /* this is driven by a toggle on a radio group, and so is invoked twice,
997                  once for the item that became inactive and once for the one that became
998                  active.
999                  */
1000
1001         Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-afl"));
1002         if (ract->get_active()) {
1003                 Config->set_solo_control_is_listen_control (true);
1004                 Config->set_listen_position (AfterFaderListen);
1005         }
1006 }
1007
1008 void
1009 MonitorSection::solo_use_pfl ()
1010 {
1011         /* this is driven by a toggle on a radio group, and so is invoked twice,
1012            once for the item that became inactive and once for the one that became
1013            active.
1014         */
1015
1016         Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-pfl"));
1017         if (ract->get_active()) {
1018                 Config->set_solo_control_is_listen_control (true);
1019                 Config->set_listen_position (PreFaderListen);
1020         }
1021 }
1022
1023 void
1024 MonitorSection::update_solo_model ()
1025 {
1026         if (_inhibit_solo_model_update) {
1027                 return;
1028         }
1029
1030         const char* action_name = 0;
1031         Glib::RefPtr<RadioAction> ract;
1032
1033         if (Config->get_solo_control_is_listen_control()) {
1034                 switch (Config->get_listen_position()) {
1035                         case AfterFaderListen:
1036                                 action_name = X_("solo-use-afl");
1037                                 break;
1038                         case PreFaderListen:
1039                                 action_name = X_("solo-use-pfl");
1040                                 break;
1041                 }
1042         } else {
1043                 action_name = X_("solo-use-in-place");
1044         }
1045
1046         ract = ActionManager::get_radio_action (X_("Solo"), action_name);
1047
1048         /* because these are radio buttons, one of them will be
1049            active no matter what. to trigger a change in the
1050            action so that the view picks it up, toggle it.
1051         */
1052
1053         if (ract->get_active()) {
1054                 ract->set_active (false);
1055         }
1056
1057         ract->set_active (true);
1058 }
1059
1060 void
1061 MonitorSection::map_state ()
1062 {
1063         if (!_route || !_monitor) {
1064                 return;
1065         }
1066
1067         update_solo_model ();
1068
1069         Glib::RefPtr<Action> act;
1070         Glib::RefPtr<ToggleAction> tact;
1071
1072         tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
1073         tact->set_active (_monitor->cut_all());
1074
1075         tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
1076         tact->set_active (_monitor->dim_all());
1077
1078         tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
1079         tact->set_active (_monitor->mono());
1080
1081         uint32_t nchans = _monitor->output_streams().n_audio();
1082
1083         assert (nchans == _channel_buttons.size ());
1084
1085         for (uint32_t n = 0; n < nchans; ++n) {
1086
1087                 char action_name[32];
1088
1089                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1090                 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1091                 tact->set_active (_monitor->cut (n));
1092
1093                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1094                 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1095                 tact->set_active (_monitor->dimmed (n));
1096
1097                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1098                 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1099                 tact->set_active (_monitor->soloed (n));
1100
1101                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1102                 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1103                 tact->set_active (_monitor->inverted (n));
1104         }
1105 }
1106
1107 void
1108 MonitorSection::do_blink (bool onoff)
1109 {
1110         if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1111                 onoff = true;
1112         }
1113
1114         solo_blink (onoff);
1115         audition_blink (onoff);
1116 }
1117
1118 void
1119 MonitorSection::audition_blink (bool onoff)
1120 {
1121         if (_session == 0) {
1122                 return;
1123         }
1124
1125         if (_session->is_auditioning()) {
1126                 rude_audition_button.set_active (onoff);
1127         } else {
1128                 rude_audition_button.set_active (false);
1129         }
1130 }
1131
1132 void
1133 MonitorSection::solo_blink (bool onoff)
1134 {
1135         if (_session == 0) {
1136                 return;
1137         }
1138
1139         if (_session->soloing() || _session->listening()) {
1140                 rude_solo_button.set_active (onoff);
1141
1142                 if (_session->soloing()) {
1143                         if (_session->solo_isolated()) {
1144                                 rude_iso_button.set_active (onoff);
1145                         } else {
1146                                 rude_iso_button.set_active (false);
1147                         }
1148                 }
1149
1150         } else {
1151                 rude_solo_button.set_active (false);
1152                 rude_iso_button.set_active (false);
1153         }
1154 }
1155
1156 bool
1157 MonitorSection::cancel_isolate (GdkEventButton*)
1158 {
1159         if (_session) {
1160                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1161                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1162         }
1163
1164         return true;
1165 }
1166
1167 bool
1168 MonitorSection::cancel_audition (GdkEventButton*)
1169 {
1170         if (_session) {
1171                 _session->cancel_audition();
1172         }
1173         return true;
1174 }
1175
1176 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1177         if (action && action->get_active() != value) { \
1178                 action->set_active(value); \
1179         } \
1180
1181 void
1182 MonitorSection::parameter_changed (std::string name)
1183 {
1184         if (name == "solo-control-is-listen-control") {
1185                 update_solo_model ();
1186         } else if (name == "listen-position") {
1187                 update_solo_model ();
1188         } else if (name == "solo-mute-override") {
1189                 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1190         } else if (name == "exclusive-solo") {
1191                 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1192         } else if (name == "use-monitor-bus") {
1193                 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), Config->get_use_monitor_bus ());
1194         }
1195 }
1196
1197 void
1198 MonitorSection::assign_controllables ()
1199 {
1200         boost::shared_ptr<Controllable> none;
1201
1202         if (!gain_control) {
1203                 /* too early - GUI controls not set up yet */
1204                 return;
1205         }
1206
1207         if (_session) {
1208                 solo_cut_control->set_controllable (_session->solo_cut_control());
1209                 solo_cut_display->set_controllable (_session->solo_cut_control());
1210         } else {
1211                 solo_cut_control->set_controllable (none);
1212                 solo_cut_display->set_controllable (none);
1213         }
1214
1215         if (_route) {
1216                 gain_control->set_controllable (_route->gain_control());
1217                 gain_display->set_controllable (_route->gain_control());
1218         } else {
1219                 gain_control->set_controllable (none);
1220         }
1221
1222         if (_monitor) {
1223
1224                 cut_all_button.set_controllable (_monitor->cut_control());
1225                 cut_all_button.watch ();
1226                 dim_all_button.set_controllable (_monitor->dim_control());
1227                 dim_all_button.watch ();
1228                 mono_button.set_controllable (_monitor->mono_control());
1229                 mono_button.watch ();
1230
1231                 dim_control->set_controllable (_monitor->dim_level_control ());
1232                 dim_display->set_controllable (_monitor->dim_level_control ());
1233                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1234                 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1235
1236         } else {
1237
1238                 cut_all_button.set_controllable (none);
1239                 dim_all_button.set_controllable (none);
1240                 mono_button.set_controllable (none);
1241
1242                 dim_control->set_controllable (none);
1243                 dim_display->set_controllable (none);
1244                 solo_boost_control->set_controllable (none);
1245                 solo_boost_display->set_controllable (none);
1246         }
1247 }
1248
1249 string
1250 MonitorSection::state_id() const
1251 {
1252         return "monitor-section";
1253 }
1254
1255 void
1256 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1257 {
1258         using namespace Menu_Helpers;
1259
1260         if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1261                 return;
1262         }
1263
1264         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1265         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1266                 ++i;
1267         }
1268
1269         if (i != output_menu_bundles.end()) {
1270                 return;
1271         }
1272
1273         output_menu_bundles.push_back (b);
1274
1275         MenuList& citems = output_menu.items();
1276
1277         std::string n = b->name ();
1278         replace_all (n, "_", " ");
1279
1280         citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1281 }
1282
1283 void
1284 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1285 {
1286
1287         ARDOUR::BundleList current = _route->output()->bundles_connected ();
1288
1289         if (std::find (current.begin(), current.end(), c) == current.end()) {
1290                 _route->output()->connect_ports_to_bundle (c, true, this);
1291         } else {
1292                 _route->output()->disconnect_ports_from_bundle (c, this);
1293         }
1294 }
1295
1296 gint
1297 MonitorSection::output_release (GdkEventButton *ev)
1298 {
1299         switch (ev->button) {
1300         case 3:
1301                 edit_output_configuration ();
1302                 break;
1303         }
1304
1305         return false;
1306 }
1307
1308 struct RouteCompareByName {
1309         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1310                 return a->name().compare (b->name()) < 0;
1311         }
1312 };
1313
1314 gint
1315 MonitorSection::output_press (GdkEventButton *ev)
1316 {
1317         using namespace Menu_Helpers;
1318         if (!_session) {
1319                 MessageDialog msg (_("No session - no I/O changes are possible"));
1320                 msg.run ();
1321                 return true;
1322         }
1323
1324         MenuList& citems = output_menu.items();
1325         switch (ev->button) {
1326
1327         case 3:
1328                 return false;  //wait for the mouse-up to pop the dialog
1329
1330         case 1:
1331         {
1332                 output_menu.set_name ("ArdourContextMenu");
1333                 citems.clear ();
1334                 output_menu_bundles.clear ();
1335
1336                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1337
1338                 citems.push_back (SeparatorElem());
1339                 uint32_t const n_with_separator = citems.size ();
1340
1341                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1342
1343                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1344
1345                 /* give user bundles first chance at being in the menu */
1346
1347                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1348                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1349                                 maybe_add_bundle_to_output_menu (*i, current);
1350                         }
1351                 }
1352
1353                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1354                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1355                                 maybe_add_bundle_to_output_menu (*i, current);
1356                         }
1357                 }
1358
1359                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1360                 RouteList copy = *routes;
1361                 copy.sort (RouteCompareByName ());
1362                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1363                         maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1364                 }
1365
1366                 if (citems.size() == n_with_separator) {
1367                         /* no routes added; remove the separator */
1368                         citems.pop_back ();
1369                 }
1370
1371                 citems.push_back (SeparatorElem());
1372                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1373
1374                 output_menu.popup (1, ev->time);
1375                 break;
1376         }
1377
1378         default:
1379                 break;
1380         }
1381         return TRUE;
1382 }
1383
1384 void
1385 MonitorSection::update_output_display ()
1386 {
1387         if (!_route || !_monitor || _session->deletion_in_progress()) {
1388                 return;
1389         }
1390
1391         uint32_t io_count;
1392         uint32_t io_index;
1393         boost::shared_ptr<Port> port;
1394         vector<string> port_connections;
1395
1396         uint32_t total_connection_count = 0;
1397         uint32_t io_connection_count = 0;
1398         uint32_t ardour_connection_count = 0;
1399         uint32_t system_connection_count = 0;
1400         uint32_t other_connection_count = 0;
1401
1402         ostringstream label;
1403
1404         bool have_label = false;
1405         bool each_io_has_one_connection = true;
1406
1407         string connection_name;
1408         string ardour_track_name;
1409         string other_connection_type;
1410         string system_ports;
1411         string system_port;
1412
1413         ostringstream tooltip;
1414         char * tooltip_cstr;
1415
1416         io_count = _route->n_outputs().n_total();
1417         tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1418
1419
1420         for (io_index = 0; io_index < io_count; ++io_index) {
1421
1422                 port = _route->output()->nth (io_index);
1423
1424                 //ignore any port connections that don't match our DataType
1425                 if (port->type() != DataType::AUDIO) {
1426                         continue;
1427                 }
1428
1429                 port_connections.clear ();
1430                 port->get_connections(port_connections);
1431                 io_connection_count = 0;
1432
1433                 if (!port_connections.empty()) {
1434                         for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1435                                 string pn = "";
1436                                 string& connection_name (*i);
1437
1438                                 if (connection_name.find("system:") == 0) {
1439                                         pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1440                                 }
1441
1442                                 if (io_connection_count == 0) {
1443                                         tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1444                                                 << " -> "
1445                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1446                                 } else {
1447                                         tooltip << ", "
1448                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1449                                 }
1450
1451                                 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1452                                         if (ardour_track_name.empty()) {
1453                                                 // "ardour:Master/in 1" -> "ardour:Master/"
1454                                                 string::size_type slash = connection_name.find("/");
1455                                                 if (slash != string::npos) {
1456                                                         ardour_track_name = connection_name.substr(0, slash + 1);
1457                                                 }
1458                                         }
1459
1460                                         if (connection_name.find(ardour_track_name) == 0) {
1461                                                 ++ardour_connection_count;
1462                                         }
1463                                 } else if (!pn.empty()) {
1464                                         if (system_ports.empty()) {
1465                                                 system_ports += pn;
1466                                         } else {
1467                                                 system_ports += "/" + pn;
1468                                         }
1469                                         if (connection_name.find("system:") == 0) {
1470                                                 ++system_connection_count;
1471                                         }
1472                                 } else if (connection_name.find("system:") == 0) {
1473                                         // "system:playback_123" -> "123"
1474                                         system_port = connection_name.substr(16);
1475                                         if (system_ports.empty()) {
1476                                                 system_ports += system_port;
1477                                         } else {
1478                                                 system_ports += "/" + system_port;
1479                                         }
1480
1481                                         ++system_connection_count;
1482                                 } else {
1483                                         if (other_connection_type.empty()) {
1484                                                 // "jamin:in 1" -> "jamin:"
1485                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1486                                         }
1487
1488                                         if (connection_name.find(other_connection_type) == 0) {
1489                                                 ++other_connection_count;
1490                                         }
1491                                 }
1492
1493                                 ++total_connection_count;
1494                                 ++io_connection_count;
1495                         }
1496                 }
1497
1498                 if (io_connection_count != 1) {
1499                         each_io_has_one_connection = false;
1500                 }
1501         }
1502
1503         if (total_connection_count == 0) {
1504                 tooltip << endl << _("Disconnected");
1505         }
1506
1507         tooltip_cstr = new char[tooltip.str().size() + 1];
1508         strcpy(tooltip_cstr, tooltip.str().c_str());
1509
1510         set_tooltip (output_button, tooltip_cstr, "");
1511
1512         if (each_io_has_one_connection) {
1513                 if (total_connection_count == ardour_connection_count) {
1514                         // all connections are to the same track in ardour
1515                         // "ardour:Master/" -> "Master"
1516                         string::size_type slash = ardour_track_name.find("/");
1517                         if (slash != string::npos) {
1518                                 label << ardour_track_name.substr(7, slash - 7);
1519                                 have_label = true;
1520                         }
1521                 } else if (total_connection_count == system_connection_count) {
1522                         // all connections are to system ports
1523                         label << system_ports;
1524                         have_label = true;
1525                 } else if (total_connection_count == other_connection_count) {
1526                         // all connections are to the same external program eg jamin
1527                         // "jamin:" -> "jamin"
1528                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1529                         have_label = true;
1530                 }
1531         }
1532
1533         if (!have_label) {
1534                 if (total_connection_count == 0) {
1535                         // Disconnected
1536                         label << "-";
1537                 } else {
1538                         // Odd configuration
1539                         label << "*" << total_connection_count << "*";
1540                 }
1541         }
1542
1543         output_button->set_text (label.str());
1544 }
1545
1546 void
1547 MonitorSection::disconnect_output ()
1548 {
1549         if (_route) {
1550                 _route->output()->disconnect(this);
1551         }
1552 }
1553
1554 void
1555 MonitorSection::edit_output_configuration ()
1556 {
1557         if (_output_selector == 0) {
1558                 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1559         }
1560         _output_selector->present ();
1561 }
1562
1563 void
1564 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1565 {
1566         if (!_route) {
1567                 return;
1568         }
1569         boost::shared_ptr<Port> a = wa.lock ();
1570         boost::shared_ptr<Port> b = wb.lock ();
1571         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1572                 update_output_display ();
1573         }
1574 }
1575
1576 void
1577 MonitorSection::load_bindings ()
1578 {
1579         bindings = Bindings::get_bindings (X_("Monitor Section"));
1580 }
1581
1582 void
1583 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1584 {
1585         boost::shared_ptr<Processor> processor (p.lock ());
1586         if (!processor || !processor->display_to_user()) {
1587                 return;
1588         }
1589         if (boost::dynamic_pointer_cast<Amp>(processor)) {
1590                 return;
1591         }
1592         ++(*cnt);
1593 }
1594
1595 uint32_t
1596 MonitorSection::count_processors ()
1597 {
1598         uint32_t processor_count = 0;
1599         if (_route) {
1600                 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1601         }
1602         return processor_count;
1603 }
1604
1605 void
1606 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1607 {
1608         update_processor_box ();
1609 }
1610
1611 void
1612 MonitorSection::use_others_actions ()
1613 {
1614         rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1615 }
1616
1617 void
1618 MonitorSection::toggle_use_monitor_section ()
1619 {
1620         if (!_session) {
1621                 return;
1622         }
1623
1624         Config->set_use_monitor_bus (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active());
1625 }