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