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