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