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