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