eb5e4eff977061f80e8ca05dfbea0e8a5c8b60b4
[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 (Session* s)
66         : SessionHandlePtr (s)
67         , RouteUI (s)
68         , _tearoff (0)
69         , channel_table (0)
70         , channel_table_viewport (*channel_table_scroller.get_hadjustment()
71                                   , *channel_table_scroller.get_vadjustment ())
72         , gain_control (0)
73         , dim_control (0)
74         , solo_boost_control (0)
75         , solo_cut_control (0)
76         , gain_display (0)
77         , dim_display (0)
78         , solo_boost_display (0)
79         , solo_cut_display (0)
80         , _output_selector (0)
81         , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
82         , afl_button (_("AFL"), ArdourButton::led_default_elements)
83         , pfl_button (_("PFL"), ArdourButton::led_default_elements)
84         , exclusive_solo_button (ArdourButton::led_default_elements)
85         , solo_mute_override_button (ArdourButton::led_default_elements)
86         , toggle_processorbox_button (ArdourButton::default_elements)
87         , _inhibit_solo_model_update (false)
88         , _rr_selection ()
89         , _ui_initialized (false)
90 {
91
92         using namespace Menu_Helpers;
93
94         Glib::RefPtr<Action> act;
95
96         load_bindings ();
97         register_actions ();
98         set_data ("ardour-bindings", bindings);
99         bindings->associate ();
100
101         channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
102
103         _plugin_selector = new PluginSelector (PluginManager::instance());
104         insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
105         insert_box->set_no_show_all ();
106         insert_box->show ();
107         // TODO allow keyboard shortcuts in ProcessorBox
108
109         set_session (s);
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         act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
127         rude_solo_button.set_related_action (act);
128         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
129
130         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
131         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
132
133         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
134         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
135
136         /* SIP, AFL, PFL radio */
137
138         solo_in_place_button.set_name ("monitor section solo model");
139         afl_button.set_name ("monitor section solo model");
140         pfl_button.set_name ("monitor section solo model");
141
142         solo_in_place_button.set_led_left (true);
143         afl_button.set_led_left (true);
144         pfl_button.set_led_left (true);
145
146         solo_in_place_button.show ();
147         afl_button.show ();
148         pfl_button.show ();
149
150         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
151         set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
152         if (act) {
153                 solo_in_place_button.set_related_action (act);
154         }
155
156         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
157         set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
158         if (act) {
159                 afl_button.set_related_action (act);
160         }
161
162         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
163         set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
164         if (act) {
165                 pfl_button.set_related_action (act);
166         }
167
168         /* Solo option buttons */
169         exclusive_solo_button.set_text (_("Excl. Solo"));
170         exclusive_solo_button.set_name (X_("monitor section solo option"));
171         set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
172
173         act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
174         if (act) {
175                 exclusive_solo_button.set_related_action (act);
176         }
177
178         solo_mute_override_button.set_text (_("Solo ยป Mute"));
179         solo_mute_override_button.set_name (X_("monitor section solo option"));
180         set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
181
182         act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
183         if (act) {
184                 solo_mute_override_button.set_related_action (act);
185         }
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_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"), 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"), 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"), 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 - 2 /* no outer sample */
439 #else
440                         scrollbar_height + 2 /* sample 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         assign_controllables ();
471
472         output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
473         output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
474
475         signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
476         signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
477         set_flags (CAN_FOCUS);
478
479         _tearoff = new TearOff (*this);
480
481         if (!UIConfiguration::instance().get_floating_monitor_section()) {
482                 /* if torn off, make this a normal window
483                  * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
484                  */
485                 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
486         }
487         _tearoff->tearoff_window().set_title (X_("Monitor"));
488         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
489
490         update_output_display ();
491         update_processor_box ();
492         _ui_initialized = true;
493
494         /* catch changes that affect us */
495         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
496                 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
497                 );
498         Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
499 }
500
501 MonitorSection::~MonitorSection ()
502 {
503         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
504                 delete *i;
505         }
506
507         _channel_buttons.clear ();
508         output_changed_connections.drop_connections ();
509
510         delete insert_box; insert_box = 0;
511         delete output_button; output_button = 0;
512         delete gain_control; gain_control = 0;
513         delete gain_display; gain_display = 0;
514         delete dim_control; dim_control = 0;
515         delete dim_display; dim_display = 0;
516         delete solo_boost_control; solo_boost_control = 0;
517         delete solo_boost_display; solo_boost_display = 0;
518         delete solo_cut_control; solo_cut_control = 0;
519         delete solo_cut_display; solo_cut_display = 0;
520         delete _tearoff; _tearoff = 0;
521         delete _output_selector; _output_selector = 0;
522         delete channel_table; channel_table = 0;
523 }
524
525 bool
526 MonitorSection::enter_handler (GdkEventCrossing* ev)
527 {
528         grab_focus ();
529         return false;
530 }
531
532 bool
533 MonitorSection::leave_handler (GdkEventCrossing* ev)
534 {
535         switch (ev->detail) {
536         case GDK_NOTIFY_INFERIOR:
537                 return false;
538         default:
539                 break;
540         }
541
542         /* cancel focus if we're not torn off. With X11 WM's that do
543          * focus-follows-mouse, focus will be taken from us anyway.
544          */
545
546         Widget* top = get_toplevel();
547
548         if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
549                 Window* win = dynamic_cast<Window*> (top);
550                 gtk_window_set_focus (win->gobj(), 0);
551         }
552
553         return false;
554 }
555
556 void
557 MonitorSection::update_processor_box ()
558 {
559         bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
560
561         if (count_processors () > 0 && !show_processor_box) {
562                 toggle_processorbox_button.set_name (X_("monitor section processors present"));
563         } else {
564                 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
565         }
566
567         if (insert_box->is_visible() == show_processor_box) {
568                 return;
569         }
570
571         if (show_processor_box) {
572                 if (master_packer.get_parent()) {
573                         master_packer.get_parent()->remove (master_packer);
574                 }
575                 insert_box->show();
576                 vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
577         } else {
578                 if (master_packer.get_parent()) {
579                         master_packer.get_parent()->remove (master_packer);
580                 }
581                 insert_box->hide();
582                 vpacker.pack_start (master_packer,        true,  false, PX_SCALE(10));
583         }
584 }
585
586 void
587 MonitorSection::set_session (Session* s)
588 {
589         RouteUI::set_session (s);
590         _plugin_selector->set_session (_session);
591
592         if (_session) {
593
594                 _route = _session->monitor_out ();
595
596                 if (_route) {
597                         /* session with monitor section */
598                         _monitor = _route->monitor_control ();
599                         assign_controllables ();
600                         _route->output()->changed.connect (output_changed_connections, invalidator (*this),
601                                                                                         boost::bind (&MonitorSection::update_output_display, this),
602                                                                                         gui_context());
603                         insert_box->set_route (_route);
604                         _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
605                         _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
606                         if (_ui_initialized) {
607                                 update_processor_box ();
608                         }
609                 } else {
610                         /* session with no monitor section */
611                         output_changed_connections.drop_connections();
612                         _monitor.reset ();
613                         _route.reset ();
614                         delete _output_selector;
615                         _output_selector = 0;
616                 }
617
618                 populate_buttons ();
619
620                 /* some actions may have been left in the wrong state from a
621                  * previous monitor route that was then deleted
622                  */
623                 ActionManager::set_sensitive (monitor_actions, true);
624                 ActionManager::set_sensitive (solo_actions, true);
625
626         } else {
627                 /* no session */
628
629                 output_changed_connections.drop_connections();
630                 _monitor.reset ();
631                 _route.reset ();
632                 control_connections.drop_connections ();
633                 rude_iso_button.unset_active_state ();
634                 rude_solo_button.unset_active_state ();
635                 delete _output_selector;
636                 _output_selector = 0;
637
638                 assign_controllables ();
639         }
640 }
641
642 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
643 {
644         cut.set_name (X_("mute button"));
645         dim.set_name (X_("monitor section dim"));
646         solo.set_name (X_("solo button"));
647         invert.set_name (X_("invert button"));
648
649         cut.unset_flags (Gtk::CAN_FOCUS);
650         dim.unset_flags (Gtk::CAN_FOCUS);
651         solo.unset_flags (Gtk::CAN_FOCUS);
652         invert.unset_flags (Gtk::CAN_FOCUS);
653 }
654
655 void
656 MonitorSection::populate_buttons ()
657 {
658         if (!_monitor) {
659                 return;
660         }
661
662         if (channel_table) {
663                 channel_size_group->remove_widget (*channel_table);
664                 delete channel_table;
665         }
666
667         channel_table = new Gtk::Table();
668
669         channel_table->set_col_spacings (6);
670         channel_table->set_row_spacings (6);
671         channel_table->set_homogeneous (true);
672
673         channel_size_group->add_widget (*channel_table);
674         channel_table->show ();
675         table_hpacker.pack_start (*channel_table, true, true);
676
677         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
678                 delete *i;
679         }
680         _channel_buttons.clear ();
681
682         Glib::RefPtr<Action> act;
683         uint32_t nchans = _monitor->output_streams().n_audio();
684
685         channel_table->resize (nchans, 5);
686
687         const uint32_t row_offset = 0;
688
689         for (uint32_t i = 0; i < nchans; ++i) {
690
691                 string l;
692                 char buf[64];
693
694                 if (nchans == 2) {
695                         if (i == 0) {
696                                 l = "L";
697                         } else {
698                                 l = "R";
699                         }
700                 } else {
701                         char buf[32];
702                         snprintf (buf, sizeof (buf), "%d", i+1);
703                         l = buf;
704                 }
705
706                 Label* label = manage (new Label (l));
707                 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
708
709                 ChannelButtonSet* cbs = new ChannelButtonSet;
710
711                 _channel_buttons.push_back (cbs);
712
713                 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
714                 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
715                 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
716                 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
717
718                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
719                 act = ActionManager::get_action (X_("Monitor"), buf);
720                 if (act) {
721                         cbs->cut.set_related_action (act);
722                 }
723
724                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
725                 act = ActionManager::get_action (X_("Monitor"), buf);
726                 if (act) {
727                         cbs->dim.set_related_action (act);
728                 }
729
730                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
731                 act = ActionManager::get_action (X_("Monitor"), buf);
732                 if (act) {
733                         cbs->solo.set_related_action (act);
734                 }
735
736                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
737                 act = ActionManager::get_action (X_("Monitor"), buf);
738                 if (act) {
739                         cbs->invert.set_related_action (act);
740                 }
741         }
742
743         channel_table->show_all ();
744
745         if (channel_table_scroller.get_parent()) {
746                 /* scroller is packed, so remove it */
747                 channel_table_packer.remove (channel_table_scroller);
748         }
749
750         if (table_hpacker.get_parent () == &channel_table_packer) {
751                 /* this occurs when the table hpacker is directly
752                          packed, so remove it.
753                          */
754                 channel_table_packer.remove (table_hpacker);
755         } else if (table_hpacker.get_parent()) {
756                 channel_table_viewport.remove ();
757         }
758
759         if (nchans > 7) {
760                 /* put the table into a scrolled window, and then put
761                  * that into the channel vpacker, after the table header
762                  */
763                 channel_table_viewport.add (table_hpacker);
764                 channel_table_packer.pack_start (channel_table_scroller, true, true);
765                 channel_table_viewport.show ();
766                 channel_table_scroller.show ();
767
768         } else {
769                 /* just put the channel table itself into the channel
770                  * vpacker, after the table header
771                  */
772                 channel_table_packer.pack_start (table_hpacker, true, true);
773                 channel_table_scroller.hide ();
774         }
775         table_hpacker.show ();
776         channel_table->show ();
777 }
778
779 void
780 MonitorSection::toggle_exclusive_solo ()
781 {
782         if (!_monitor) {
783                 return;
784         }
785
786         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
787         if (act) {
788                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
789                 Config->set_exclusive_solo (tact->get_active());
790         }
791
792 }
793
794 void
795 MonitorSection::toggle_mute_overrides_solo ()
796 {
797         if (!_monitor) {
798                 return;
799         }
800
801         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
802         if (act) {
803                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
804                 Config->set_solo_mute_override (tact->get_active());
805         }
806 }
807
808 void
809 MonitorSection::dim_all ()
810 {
811         if (!_monitor) {
812                 return;
813         }
814
815         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
816         if (act) {
817                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
818                 _monitor->set_dim_all (tact->get_active());
819         }
820
821 }
822
823 void
824 MonitorSection::cut_all ()
825 {
826         if (!_monitor) {
827                 return;
828         }
829
830         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
831         if (act) {
832                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
833                 _monitor->set_cut_all (tact->get_active());
834         }
835 }
836
837 void
838 MonitorSection::mono ()
839 {
840         if (!_monitor) {
841                 return;
842         }
843
844         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
845         if (act) {
846                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
847                 _monitor->set_mono (tact->get_active());
848         }
849 }
850
851 void
852 MonitorSection::cut_channel (uint32_t chn)
853 {
854         if (!_monitor) {
855                 return;
856         }
857
858         char buf[64];
859         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
860
861         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
862         if (act) {
863                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
864                 _monitor->set_cut (chn, tact->get_active());
865         }
866 }
867
868 void
869 MonitorSection::dim_channel (uint32_t chn)
870 {
871         if (!_monitor) {
872                 return;
873         }
874
875         char buf[64];
876         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
877
878         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
879         if (act) {
880                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
881                 _monitor->set_dim (chn, tact->get_active());
882         }
883
884 }
885
886 void
887 MonitorSection::solo_channel (uint32_t chn)
888 {
889         if (!_monitor) {
890                 return;
891         }
892
893         char buf[64];
894         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
895
896         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
897         if (act) {
898                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
899                 _monitor->set_solo (chn, tact->get_active());
900         }
901
902 }
903
904 void
905 MonitorSection::invert_channel (uint32_t chn)
906 {
907         if (!_monitor) {
908                 return;
909         }
910
911         char buf[64];
912         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
913
914         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
915         if (act) {
916                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
917                 _monitor->set_polarity (chn, tact->get_active());
918         }
919 }
920
921 void
922 MonitorSection::register_actions ()
923 {
924         string action_name;
925         string action_descr;
926         Glib::RefPtr<Action> act;
927
928         monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
929
930         act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
931                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
932
933         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
934         tact->set_active (Config->get_exclusive_solo());
935
936         act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
937                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
938
939         tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
940         tact->set_active (Config->get_solo_mute_override());
941
942         for (uint32_t chn = 0; chn < 16; ++chn) {
943
944                 action_name = string_compose (X_("monitor-cut-%1"), chn);
945                 action_descr = string_compose (_("Cut monitor channel %1"), chn);
946                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
947                                 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
948
949                 action_name = string_compose (X_("monitor-dim-%1"), chn);
950                 action_descr = string_compose (_("Dim monitor channel %1"), chn);
951                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
952                                 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
953
954                 action_name = string_compose (X_("monitor-solo-%1"), chn);
955                 action_descr = string_compose (_("Solo monitor channel %1"), chn);
956                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
957                                 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
958
959                 action_name = string_compose (X_("monitor-invert-%1"), chn);
960                 action_descr = string_compose (_("Invert monitor channel %1"), chn);
961                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
962                                 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
963
964         }
965
966         solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
967         RadioAction::Group solo_group;
968
969         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
970                                               sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
971         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
972                                               sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
973         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
974                                               sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
975
976         ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
977                                                sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
978
979 }
980
981 void
982 MonitorSection::solo_use_in_place ()
983 {
984         /* this is driven by a toggle on a radio group, and so is invoked twice,
985                  once for the item that became inactive and once for the one that became
986                  active.
987                  */
988
989         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
990
991         if (act) {
992                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
993                 if (ract) {
994                         if (!ract->get_active ()) {
995                                 /* We are turning SiP off, which means that AFL or PFL will be turned on
996                                          shortly; don't update the solo model in the mean time, as if the currently
997                                          configured listen position is not the one that is about to be turned on,
998                                          things will go wrong.
999                                          */
1000                                 _inhibit_solo_model_update = true;
1001                         }
1002                         Config->set_solo_control_is_listen_control (!ract->get_active());
1003                         _inhibit_solo_model_update = false;
1004                 }
1005         }
1006 }
1007
1008 void
1009 MonitorSection::solo_use_afl ()
1010 {
1011         /* this is driven by a toggle on a radio group, and so is invoked twice,
1012                  once for the item that became inactive and once for the one that became
1013                  active.
1014                  */
1015
1016         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1017         if (act) {
1018                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1019                 if (ract) {
1020                         if (ract->get_active()) {
1021                                 Config->set_solo_control_is_listen_control (true);
1022                                 Config->set_listen_position (AfterFaderListen);
1023                         }
1024                 }
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<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1037         if (act) {
1038                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1039                 if (ract) {
1040                         if (ract->get_active()) {
1041                                 Config->set_solo_control_is_listen_control (true);
1042                                 Config->set_listen_position (PreFaderListen);
1043                         }
1044                 }
1045         }
1046 }
1047
1048 void
1049 MonitorSection::update_solo_model ()
1050 {
1051         if (_inhibit_solo_model_update) {
1052                 return;
1053         }
1054
1055         const char* action_name = 0;
1056         Glib::RefPtr<Action> act;
1057
1058         if (Config->get_solo_control_is_listen_control()) {
1059                 switch (Config->get_listen_position()) {
1060                         case AfterFaderListen:
1061                                 action_name = X_("solo-use-afl");
1062                                 break;
1063                         case PreFaderListen:
1064                                 action_name = X_("solo-use-pfl");
1065                                 break;
1066                 }
1067         } else {
1068                 action_name = X_("solo-use-in-place");
1069         }
1070
1071         act = ActionManager::get_action (X_("Solo"), action_name);
1072         if (act) {
1073
1074                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1075                 if (ract) {
1076                         /* because these are radio buttons, one of them will be
1077                                  active no matter what. to trigger a change in the
1078                                  action so that the view picks it up, toggle it.
1079                                  */
1080                         if (ract->get_active()) {
1081                                 ract->set_active (false);
1082                         }
1083                         ract->set_active (true);
1084                 }
1085
1086         }
1087 }
1088
1089 void
1090 MonitorSection::map_state ()
1091 {
1092         if (!_route || !_monitor) {
1093                 return;
1094         }
1095
1096         update_solo_model ();
1097
1098         Glib::RefPtr<Action> act;
1099         Glib::RefPtr<ToggleAction> tact;
1100
1101         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1102         if (act) {
1103                 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1104                 if (tact) {
1105                         tact->set_active (_monitor->cut_all());
1106                 }
1107         }
1108
1109         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1110         if (act) {
1111                 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1112                 if (tact) {
1113                         tact->set_active (_monitor->dim_all());
1114                 }
1115         }
1116
1117         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1118         if (act) {
1119                 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1120                 if (tact) {
1121                         tact->set_active (_monitor->mono());
1122                 }
1123         }
1124
1125         uint32_t nchans = _monitor->output_streams().n_audio();
1126
1127         assert (nchans == _channel_buttons.size ());
1128
1129         for (uint32_t n = 0; n < nchans; ++n) {
1130
1131                 char action_name[32];
1132
1133                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1134                 act = ActionManager::get_action (X_("Monitor"), action_name);
1135                 if (act) {
1136                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1137                         if (tact) {
1138                                 tact->set_active (_monitor->cut (n));
1139                         }
1140                 }
1141
1142                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1143                 act = ActionManager::get_action (X_("Monitor"), action_name);
1144                 if (act) {
1145                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1146                         if (tact) {
1147                                 tact->set_active (_monitor->dimmed (n));
1148                         }
1149                 }
1150
1151                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1152                 act = ActionManager::get_action (X_("Monitor"), action_name);
1153                 if (act) {
1154                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1155                         if (tact) {
1156                                 tact->set_active (_monitor->soloed (n));
1157                         }
1158                 }
1159
1160                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1161                 act = ActionManager::get_action (X_("Monitor"), action_name);
1162                 if (act) {
1163                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1164                         if (tact) {
1165                                 tact->set_active (_monitor->inverted (n));
1166                         }
1167                 }
1168         }
1169 }
1170
1171 void
1172 MonitorSection::do_blink (bool onoff)
1173 {
1174         if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1175                 onoff = true;
1176         }
1177
1178         solo_blink (onoff);
1179         audition_blink (onoff);
1180 }
1181
1182 void
1183 MonitorSection::audition_blink (bool onoff)
1184 {
1185         if (_session == 0) {
1186                 return;
1187         }
1188
1189         if (_session->is_auditioning()) {
1190                 rude_audition_button.set_active (onoff);
1191         } else {
1192                 rude_audition_button.set_active (false);
1193         }
1194 }
1195
1196 void
1197 MonitorSection::solo_blink (bool onoff)
1198 {
1199         if (_session == 0) {
1200                 return;
1201         }
1202
1203         if (_session->soloing() || _session->listening()) {
1204                 rude_solo_button.set_active (onoff);
1205
1206                 if (_session->soloing()) {
1207                         if (_session->solo_isolated()) {
1208                                 rude_iso_button.set_active (onoff);
1209                         } else {
1210                                 rude_iso_button.set_active (false);
1211                         }
1212                 }
1213
1214         } else {
1215                 rude_solo_button.set_active (false);
1216                 rude_iso_button.set_active (false);
1217         }
1218 }
1219
1220 bool
1221 MonitorSection::cancel_isolate (GdkEventButton*)
1222 {
1223         if (_session) {
1224                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1225                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1226         }
1227
1228         return true;
1229 }
1230
1231 bool
1232 MonitorSection::cancel_audition (GdkEventButton*)
1233 {
1234         if (_session) {
1235                 _session->cancel_audition();
1236         }
1237         return true;
1238 }
1239
1240 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1241         if (action) { \
1242                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1243                 if (tact && tact->get_active() != value) { \
1244                         tact->set_active(value); \
1245                 } \
1246         }
1247
1248 void
1249 MonitorSection::parameter_changed (std::string name)
1250 {
1251         if (name == "solo-control-is-listen-control") {
1252                 update_solo_model ();
1253         } else if (name == "listen-position") {
1254                 update_solo_model ();
1255         } else if (name == "solo-mute-override") {
1256                 SYNCHRONIZE_TOGGLE_ACTION(
1257                                 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1258                                 Config->get_solo_mute_override ())
1259         } else if (name == "exclusive-solo") {
1260                 SYNCHRONIZE_TOGGLE_ACTION(
1261                                 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1262                                 Config->get_exclusive_solo ())
1263         }
1264 }
1265
1266 void
1267 MonitorSection::assign_controllables ()
1268 {
1269         boost::shared_ptr<Controllable> none;
1270
1271         if (!gain_control) {
1272                 /* too early - GUI controls not set up yet */
1273                 return;
1274         }
1275
1276         if (_session) {
1277                 solo_cut_control->set_controllable (_session->solo_cut_control());
1278                 solo_cut_display->set_controllable (_session->solo_cut_control());
1279         } else {
1280                 solo_cut_control->set_controllable (none);
1281                 solo_cut_display->set_controllable (none);
1282         }
1283
1284         if (_route) {
1285                 gain_control->set_controllable (_route->gain_control());
1286                 gain_display->set_controllable (_route->gain_control());
1287         } else {
1288                 gain_control->set_controllable (none);
1289         }
1290
1291         if (_monitor) {
1292
1293                 cut_all_button.set_controllable (_monitor->cut_control());
1294                 cut_all_button.watch ();
1295                 dim_all_button.set_controllable (_monitor->dim_control());
1296                 dim_all_button.watch ();
1297                 mono_button.set_controllable (_monitor->mono_control());
1298                 mono_button.watch ();
1299
1300                 dim_control->set_controllable (_monitor->dim_level_control ());
1301                 dim_display->set_controllable (_monitor->dim_level_control ());
1302                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1303                 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1304
1305         } else {
1306
1307                 cut_all_button.set_controllable (none);
1308                 dim_all_button.set_controllable (none);
1309                 mono_button.set_controllable (none);
1310
1311                 dim_control->set_controllable (none);
1312                 dim_display->set_controllable (none);
1313                 solo_boost_control->set_controllable (none);
1314                 solo_boost_display->set_controllable (none);
1315         }
1316 }
1317
1318 string
1319 MonitorSection::state_id() const
1320 {
1321         return "monitor-section";
1322 }
1323
1324 void
1325 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1326 {
1327         using namespace Menu_Helpers;
1328
1329         if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1330                 return;
1331         }
1332
1333         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1334         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1335                 ++i;
1336         }
1337
1338         if (i != output_menu_bundles.end()) {
1339                 return;
1340         }
1341
1342         output_menu_bundles.push_back (b);
1343
1344         MenuList& citems = output_menu.items();
1345
1346         std::string n = b->name ();
1347         replace_all (n, "_", " ");
1348
1349         citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1350 }
1351
1352 void
1353 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1354 {
1355
1356         ARDOUR::BundleList current = _route->output()->bundles_connected ();
1357
1358         if (std::find (current.begin(), current.end(), c) == current.end()) {
1359                 _route->output()->connect_ports_to_bundle (c, true, this);
1360         } else {
1361                 _route->output()->disconnect_ports_from_bundle (c, this);
1362         }
1363 }
1364
1365 gint
1366 MonitorSection::output_release (GdkEventButton *ev)
1367 {
1368         switch (ev->button) {
1369         case 3:
1370                 edit_output_configuration ();
1371                 break;
1372         }
1373
1374         return false;
1375 }
1376
1377 struct RouteCompareByName {
1378         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1379                 return a->name().compare (b->name()) < 0;
1380         }
1381 };
1382
1383 gint
1384 MonitorSection::output_press (GdkEventButton *ev)
1385 {
1386         using namespace Menu_Helpers;
1387         if (!_session) {
1388                 MessageDialog msg (_("No session - no I/O changes are possible"));
1389                 msg.run ();
1390                 return true;
1391         }
1392
1393         MenuList& citems = output_menu.items();
1394         switch (ev->button) {
1395
1396         case 3:
1397                 return false;  //wait for the mouse-up to pop the dialog
1398
1399         case 1:
1400         {
1401                 output_menu.set_name ("ArdourContextMenu");
1402                 citems.clear ();
1403                 output_menu_bundles.clear ();
1404
1405                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1406
1407                 citems.push_back (SeparatorElem());
1408                 uint32_t const n_with_separator = citems.size ();
1409
1410                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1411
1412                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1413
1414                 /* give user bundles first chance at being in the menu */
1415
1416                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1417                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1418                                 maybe_add_bundle_to_output_menu (*i, current);
1419                         }
1420                 }
1421
1422                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1423                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1424                                 maybe_add_bundle_to_output_menu (*i, current);
1425                         }
1426                 }
1427
1428                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1429                 RouteList copy = *routes;
1430                 copy.sort (RouteCompareByName ());
1431                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1432                         maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1433                 }
1434
1435                 if (citems.size() == n_with_separator) {
1436                         /* no routes added; remove the separator */
1437                         citems.pop_back ();
1438                 }
1439
1440                 citems.push_back (SeparatorElem());
1441                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1442
1443                 output_menu.popup (1, ev->time);
1444                 break;
1445         }
1446
1447         default:
1448                 break;
1449         }
1450         return TRUE;
1451 }
1452
1453 void
1454 MonitorSection::update_output_display ()
1455 {
1456         if (!_route || !_monitor || _session->deletion_in_progress()) {
1457                 return;
1458         }
1459
1460         uint32_t io_count;
1461         uint32_t io_index;
1462         boost::shared_ptr<Port> port;
1463         vector<string> port_connections;
1464
1465         uint32_t total_connection_count = 0;
1466         uint32_t io_connection_count = 0;
1467         uint32_t ardour_connection_count = 0;
1468         uint32_t system_connection_count = 0;
1469         uint32_t other_connection_count = 0;
1470
1471         ostringstream label;
1472
1473         bool have_label = false;
1474         bool each_io_has_one_connection = true;
1475
1476         string connection_name;
1477         string ardour_track_name;
1478         string other_connection_type;
1479         string system_ports;
1480         string system_port;
1481
1482         ostringstream tooltip;
1483         char * tooltip_cstr;
1484
1485         io_count = _route->n_outputs().n_total();
1486         tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1487
1488
1489         for (io_index = 0; io_index < io_count; ++io_index) {
1490
1491                 port = _route->output()->nth (io_index);
1492
1493                 //ignore any port connections that don't match our DataType
1494                 if (port->type() != DataType::AUDIO) {
1495                         continue;
1496                 }
1497
1498                 port_connections.clear ();
1499                 port->get_connections(port_connections);
1500                 io_connection_count = 0;
1501
1502                 if (!port_connections.empty()) {
1503                         for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1504                                 string pn = "";
1505                                 string& connection_name (*i);
1506
1507                                 if (connection_name.find("system:") == 0) {
1508                                         pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1509                                 }
1510
1511                                 if (io_connection_count == 0) {
1512                                         tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1513                                                 << " -> "
1514                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1515                                 } else {
1516                                         tooltip << ", "
1517                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1518                                 }
1519
1520                                 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1521                                         if (ardour_track_name.empty()) {
1522                                                 // "ardour:Master/in 1" -> "ardour:Master/"
1523                                                 string::size_type slash = connection_name.find("/");
1524                                                 if (slash != string::npos) {
1525                                                         ardour_track_name = connection_name.substr(0, slash + 1);
1526                                                 }
1527                                         }
1528
1529                                         if (connection_name.find(ardour_track_name) == 0) {
1530                                                 ++ardour_connection_count;
1531                                         }
1532                                 } else if (!pn.empty()) {
1533                                         if (system_ports.empty()) {
1534                                                 system_ports += pn;
1535                                         } else {
1536                                                 system_ports += "/" + pn;
1537                                         }
1538                                         if (connection_name.find("system:") == 0) {
1539                                                 ++system_connection_count;
1540                                         }
1541                                 } else if (connection_name.find("system:") == 0) {
1542                                         // "system:playback_123" -> "123"
1543                                         system_port = connection_name.substr(16);
1544                                         if (system_ports.empty()) {
1545                                                 system_ports += system_port;
1546                                         } else {
1547                                                 system_ports += "/" + system_port;
1548                                         }
1549
1550                                         ++system_connection_count;
1551                                 } else {
1552                                         if (other_connection_type.empty()) {
1553                                                 // "jamin:in 1" -> "jamin:"
1554                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1555                                         }
1556
1557                                         if (connection_name.find(other_connection_type) == 0) {
1558                                                 ++other_connection_count;
1559                                         }
1560                                 }
1561
1562                                 ++total_connection_count;
1563                                 ++io_connection_count;
1564                         }
1565                 }
1566
1567                 if (io_connection_count != 1) {
1568                         each_io_has_one_connection = false;
1569                 }
1570         }
1571
1572         if (total_connection_count == 0) {
1573                 tooltip << endl << _("Disconnected");
1574         }
1575
1576         tooltip_cstr = new char[tooltip.str().size() + 1];
1577         strcpy(tooltip_cstr, tooltip.str().c_str());
1578
1579         set_tooltip (output_button, tooltip_cstr, "");
1580
1581         if (each_io_has_one_connection) {
1582                 if (total_connection_count == ardour_connection_count) {
1583                         // all connections are to the same track in ardour
1584                         // "ardour:Master/" -> "Master"
1585                         string::size_type slash = ardour_track_name.find("/");
1586                         if (slash != string::npos) {
1587                                 label << ardour_track_name.substr(7, slash - 7);
1588                                 have_label = true;
1589                         }
1590                 } else if (total_connection_count == system_connection_count) {
1591                         // all connections are to system ports
1592                         label << system_ports;
1593                         have_label = true;
1594                 } else if (total_connection_count == other_connection_count) {
1595                         // all connections are to the same external program eg jamin
1596                         // "jamin:" -> "jamin"
1597                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1598                         have_label = true;
1599                 }
1600         }
1601
1602         if (!have_label) {
1603                 if (total_connection_count == 0) {
1604                         // Disconnected
1605                         label << "-";
1606                 } else {
1607                         // Odd configuration
1608                         label << "*" << total_connection_count << "*";
1609                 }
1610         }
1611
1612         output_button->set_text (label.str());
1613 }
1614
1615 void
1616 MonitorSection::disconnect_output ()
1617 {
1618         if (_route) {
1619                 _route->output()->disconnect(this);
1620         }
1621 }
1622
1623 void
1624 MonitorSection::edit_output_configuration ()
1625 {
1626         if (_output_selector == 0) {
1627                 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1628         }
1629         _output_selector->present ();
1630 }
1631
1632 void
1633 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1634 {
1635         if (!_route) {
1636                 return;
1637         }
1638         boost::shared_ptr<Port> a = wa.lock ();
1639         boost::shared_ptr<Port> b = wb.lock ();
1640         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1641                 update_output_display ();
1642         }
1643 }
1644
1645 void
1646 MonitorSection::load_bindings ()
1647 {
1648         bindings = Bindings::get_bindings (X_("Monitor Section"));
1649 }
1650
1651 void
1652 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1653 {
1654         boost::shared_ptr<Processor> processor (p.lock ());
1655         if (!processor || !processor->display_to_user()) {
1656                 return;
1657         }
1658         if (boost::dynamic_pointer_cast<Amp>(processor)) {
1659                 return;
1660         }
1661         ++(*cnt);
1662 }
1663
1664 uint32_t
1665 MonitorSection::count_processors ()
1666 {
1667         uint32_t processor_count = 0;
1668         if (_route) {
1669                 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1670         }
1671         return processor_count;
1672 }
1673
1674 void
1675 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1676 {
1677         update_processor_box ();
1678 }
1679
1680 void
1681 MonitorSection::action_proxy0 (enum MonitorActions action)
1682 {
1683         MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1684         if (!ms) {
1685                 return;
1686         }
1687         switch (action) {
1688                 case MonitorMono:
1689                         ms->mono ();
1690                         break;
1691                 case MonitorCutAll:
1692                         ms->cut_all ();
1693                         break;
1694                 case MonitorDimAll:
1695                         ms->dim_all ();
1696                         break;
1697                 case ToggleExclusiveSolo:
1698                         ms->toggle_exclusive_solo ();
1699                         break;
1700                 case ToggleMuteOverridesSolo:
1701                         ms->toggle_mute_overrides_solo ();
1702                         break;
1703                 case SoloUseInPlace:
1704                         ms->solo_use_in_place ();
1705                         break;
1706                 case SoloUseAFL:
1707                         ms->solo_use_afl ();
1708                         break;
1709                 case SoloUsePFL:
1710                         ms->solo_use_pfl ();
1711                         break;
1712                 case ToggleMonitorProcessorBox:
1713                         ms->update_processor_box ();
1714                         break;
1715         }
1716 }
1717
1718 void
1719 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1720 {
1721         MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1722         if (!ms) {
1723                 return;
1724         }
1725         switch (action) {
1726                 case CutChannel:
1727                         ms->cut_channel (chn);
1728                         break;
1729                 case DimChannel:
1730                         ms->dim_channel (chn);
1731                         break;
1732                 case SoloChannel:
1733                         ms->solo_channel (chn);
1734                         break;
1735                 case InvertChannel:
1736                         ms->invert_channel (chn);
1737                         break;
1738         }
1739 }