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