no longer delete and recreate MonitorSection when it is removed/added to a Session
[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 (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
967         Glib::RefPtr<ActionGroup> solo_actions = ActionManager::create_action_group (X_("Solo"));
968         RadioAction::Group solo_group;
969
970         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
971                                               sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
972         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
973                                               sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
974         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
975                                               sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
976
977         ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
978                                                sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
979
980 }
981
982 void
983 MonitorSection::solo_use_in_place ()
984 {
985         /* this is driven by a toggle on a radio group, and so is invoked twice,
986                  once for the item that became inactive and once for the one that became
987                  active.
988                  */
989
990         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
991
992         if (act) {
993                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
994                 if (ract) {
995                         if (!ract->get_active ()) {
996                                 /* We are turning SiP off, which means that AFL or PFL will be turned on
997                                          shortly; don't update the solo model in the mean time, as if the currently
998                                          configured listen position is not the one that is about to be turned on,
999                                          things will go wrong.
1000                                          */
1001                                 _inhibit_solo_model_update = true;
1002                         }
1003                         Config->set_solo_control_is_listen_control (!ract->get_active());
1004                         _inhibit_solo_model_update = false;
1005                 }
1006         }
1007 }
1008
1009 void
1010 MonitorSection::solo_use_afl ()
1011 {
1012         /* this is driven by a toggle on a radio group, and so is invoked twice,
1013                  once for the item that became inactive and once for the one that became
1014                  active.
1015                  */
1016
1017         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1018         if (act) {
1019                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1020                 if (ract) {
1021                         if (ract->get_active()) {
1022                                 Config->set_solo_control_is_listen_control (true);
1023                                 Config->set_listen_position (AfterFaderListen);
1024                         }
1025                 }
1026         }
1027 }
1028
1029 void
1030 MonitorSection::solo_use_pfl ()
1031 {
1032         /* this is driven by a toggle on a radio group, and so is invoked twice,
1033            once for the item that became inactive and once for the one that became
1034            active.
1035         */
1036
1037         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1038         if (act) {
1039                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1040                 if (ract) {
1041                         if (ract->get_active()) {
1042                                 Config->set_solo_control_is_listen_control (true);
1043                                 Config->set_listen_position (PreFaderListen);
1044                         }
1045                 }
1046         }
1047 }
1048
1049 void
1050 MonitorSection::update_solo_model ()
1051 {
1052         if (_inhibit_solo_model_update) {
1053                 return;
1054         }
1055
1056         const char* action_name = 0;
1057         Glib::RefPtr<Action> act;
1058
1059         if (Config->get_solo_control_is_listen_control()) {
1060                 switch (Config->get_listen_position()) {
1061                         case AfterFaderListen:
1062                                 action_name = X_("solo-use-afl");
1063                                 break;
1064                         case PreFaderListen:
1065                                 action_name = X_("solo-use-pfl");
1066                                 break;
1067                 }
1068         } else {
1069                 action_name = X_("solo-use-in-place");
1070         }
1071
1072         act = ActionManager::get_action (X_("Solo"), action_name);
1073         if (act) {
1074
1075                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1076                 if (ract) {
1077                         /* because these are radio buttons, one of them will be
1078                                  active no matter what. to trigger a change in the
1079                                  action so that the view picks it up, toggle it.
1080                                  */
1081                         if (ract->get_active()) {
1082                                 ract->set_active (false);
1083                         }
1084                         ract->set_active (true);
1085                 }
1086
1087         }
1088 }
1089
1090 void
1091 MonitorSection::map_state ()
1092 {
1093         if (!_route || !_monitor) {
1094                 return;
1095         }
1096
1097         update_solo_model ();
1098
1099         Glib::RefPtr<Action> act;
1100         Glib::RefPtr<ToggleAction> tact;
1101
1102         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1103         if (act) {
1104                 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1105                 if (tact) {
1106                         tact->set_active (_monitor->cut_all());
1107                 }
1108         }
1109
1110         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1111         if (act) {
1112                 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1113                 if (tact) {
1114                         tact->set_active (_monitor->dim_all());
1115                 }
1116         }
1117
1118         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1119         if (act) {
1120                 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1121                 if (tact) {
1122                         tact->set_active (_monitor->mono());
1123                 }
1124         }
1125
1126         uint32_t nchans = _monitor->output_streams().n_audio();
1127
1128         assert (nchans == _channel_buttons.size ());
1129
1130         for (uint32_t n = 0; n < nchans; ++n) {
1131
1132                 char action_name[32];
1133
1134                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1135                 act = ActionManager::get_action (X_("Monitor"), action_name);
1136                 if (act) {
1137                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1138                         if (tact) {
1139                                 tact->set_active (_monitor->cut (n));
1140                         }
1141                 }
1142
1143                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1144                 act = ActionManager::get_action (X_("Monitor"), action_name);
1145                 if (act) {
1146                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1147                         if (tact) {
1148                                 tact->set_active (_monitor->dimmed (n));
1149                         }
1150                 }
1151
1152                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1153                 act = ActionManager::get_action (X_("Monitor"), action_name);
1154                 if (act) {
1155                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1156                         if (tact) {
1157                                 tact->set_active (_monitor->soloed (n));
1158                         }
1159                 }
1160
1161                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1162                 act = ActionManager::get_action (X_("Monitor"), action_name);
1163                 if (act) {
1164                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1165                         if (tact) {
1166                                 tact->set_active (_monitor->inverted (n));
1167                         }
1168                 }
1169         }
1170 }
1171
1172 void
1173 MonitorSection::do_blink (bool onoff)
1174 {
1175         if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1176                 onoff = true;
1177         }
1178
1179         solo_blink (onoff);
1180         audition_blink (onoff);
1181 }
1182
1183 void
1184 MonitorSection::audition_blink (bool onoff)
1185 {
1186         if (_session == 0) {
1187                 return;
1188         }
1189
1190         if (_session->is_auditioning()) {
1191                 rude_audition_button.set_active (onoff);
1192         } else {
1193                 rude_audition_button.set_active (false);
1194         }
1195 }
1196
1197 void
1198 MonitorSection::solo_blink (bool onoff)
1199 {
1200         if (_session == 0) {
1201                 return;
1202         }
1203
1204         if (_session->soloing() || _session->listening()) {
1205                 rude_solo_button.set_active (onoff);
1206
1207                 if (_session->soloing()) {
1208                         if (_session->solo_isolated()) {
1209                                 rude_iso_button.set_active (onoff);
1210                         } else {
1211                                 rude_iso_button.set_active (false);
1212                         }
1213                 }
1214
1215         } else {
1216                 rude_solo_button.set_active (false);
1217                 rude_iso_button.set_active (false);
1218         }
1219 }
1220
1221 bool
1222 MonitorSection::cancel_isolate (GdkEventButton*)
1223 {
1224         if (_session) {
1225                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1226                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1227         }
1228
1229         return true;
1230 }
1231
1232 bool
1233 MonitorSection::cancel_audition (GdkEventButton*)
1234 {
1235         if (_session) {
1236                 _session->cancel_audition();
1237         }
1238         return true;
1239 }
1240
1241 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1242         if (action) { \
1243                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1244                 if (tact && tact->get_active() != value) { \
1245                         tact->set_active(value); \
1246                 } \
1247         }
1248
1249 void
1250 MonitorSection::parameter_changed (std::string name)
1251 {
1252         if (name == "solo-control-is-listen-control") {
1253                 update_solo_model ();
1254         } else if (name == "listen-position") {
1255                 update_solo_model ();
1256         } else if (name == "solo-mute-override") {
1257                 SYNCHRONIZE_TOGGLE_ACTION(
1258                                 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1259                                 Config->get_solo_mute_override ())
1260         } else if (name == "exclusive-solo") {
1261                 SYNCHRONIZE_TOGGLE_ACTION(
1262                                 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1263                                 Config->get_exclusive_solo ())
1264         }
1265 }
1266
1267 void
1268 MonitorSection::assign_controllables ()
1269 {
1270         boost::shared_ptr<Controllable> none;
1271
1272         if (!gain_control) {
1273                 /* too early - GUI controls not set up yet */
1274                 return;
1275         }
1276
1277         if (_session) {
1278                 solo_cut_control->set_controllable (_session->solo_cut_control());
1279                 solo_cut_display->set_controllable (_session->solo_cut_control());
1280         } else {
1281                 solo_cut_control->set_controllable (none);
1282                 solo_cut_display->set_controllable (none);
1283         }
1284
1285         if (_route) {
1286                 gain_control->set_controllable (_route->gain_control());
1287                 gain_display->set_controllable (_route->gain_control());
1288         } else {
1289                 gain_control->set_controllable (none);
1290         }
1291
1292         if (_monitor) {
1293
1294                 cut_all_button.set_controllable (_monitor->cut_control());
1295                 cut_all_button.watch ();
1296                 dim_all_button.set_controllable (_monitor->dim_control());
1297                 dim_all_button.watch ();
1298                 mono_button.set_controllable (_monitor->mono_control());
1299                 mono_button.watch ();
1300
1301                 dim_control->set_controllable (_monitor->dim_level_control ());
1302                 dim_display->set_controllable (_monitor->dim_level_control ());
1303                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1304                 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1305
1306         } else {
1307
1308                 cut_all_button.set_controllable (none);
1309                 dim_all_button.set_controllable (none);
1310                 mono_button.set_controllable (none);
1311
1312                 dim_control->set_controllable (none);
1313                 dim_display->set_controllable (none);
1314                 solo_boost_control->set_controllable (none);
1315                 solo_boost_display->set_controllable (none);
1316         }
1317 }
1318
1319 string
1320 MonitorSection::state_id() const
1321 {
1322         return "monitor-section";
1323 }
1324
1325 void
1326 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1327 {
1328         using namespace Menu_Helpers;
1329
1330         if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1331                 return;
1332         }
1333
1334         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1335         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1336                 ++i;
1337         }
1338
1339         if (i != output_menu_bundles.end()) {
1340                 return;
1341         }
1342
1343         output_menu_bundles.push_back (b);
1344
1345         MenuList& citems = output_menu.items();
1346
1347         std::string n = b->name ();
1348         replace_all (n, "_", " ");
1349
1350         citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1351 }
1352
1353 void
1354 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1355 {
1356
1357         ARDOUR::BundleList current = _route->output()->bundles_connected ();
1358
1359         if (std::find (current.begin(), current.end(), c) == current.end()) {
1360                 _route->output()->connect_ports_to_bundle (c, true, this);
1361         } else {
1362                 _route->output()->disconnect_ports_from_bundle (c, this);
1363         }
1364 }
1365
1366 gint
1367 MonitorSection::output_release (GdkEventButton *ev)
1368 {
1369         switch (ev->button) {
1370         case 3:
1371                 edit_output_configuration ();
1372                 break;
1373         }
1374
1375         return false;
1376 }
1377
1378 struct RouteCompareByName {
1379         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1380                 return a->name().compare (b->name()) < 0;
1381         }
1382 };
1383
1384 gint
1385 MonitorSection::output_press (GdkEventButton *ev)
1386 {
1387         using namespace Menu_Helpers;
1388         if (!_session) {
1389                 MessageDialog msg (_("No session - no I/O changes are possible"));
1390                 msg.run ();
1391                 return true;
1392         }
1393
1394         MenuList& citems = output_menu.items();
1395         switch (ev->button) {
1396
1397         case 3:
1398                 return false;  //wait for the mouse-up to pop the dialog
1399
1400         case 1:
1401         {
1402                 output_menu.set_name ("ArdourContextMenu");
1403                 citems.clear ();
1404                 output_menu_bundles.clear ();
1405
1406                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1407
1408                 citems.push_back (SeparatorElem());
1409                 uint32_t const n_with_separator = citems.size ();
1410
1411                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1412
1413                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1414
1415                 /* give user bundles first chance at being in the menu */
1416
1417                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1418                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1419                                 maybe_add_bundle_to_output_menu (*i, current);
1420                         }
1421                 }
1422
1423                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1424                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1425                                 maybe_add_bundle_to_output_menu (*i, current);
1426                         }
1427                 }
1428
1429                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1430                 RouteList copy = *routes;
1431                 copy.sort (RouteCompareByName ());
1432                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1433                         maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1434                 }
1435
1436                 if (citems.size() == n_with_separator) {
1437                         /* no routes added; remove the separator */
1438                         citems.pop_back ();
1439                 }
1440
1441                 citems.push_back (SeparatorElem());
1442                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1443
1444                 output_menu.popup (1, ev->time);
1445                 break;
1446         }
1447
1448         default:
1449                 break;
1450         }
1451         return TRUE;
1452 }
1453
1454 void
1455 MonitorSection::update_output_display ()
1456 {
1457         if (!_route || !_monitor || _session->deletion_in_progress()) {
1458                 return;
1459         }
1460
1461         uint32_t io_count;
1462         uint32_t io_index;
1463         boost::shared_ptr<Port> port;
1464         vector<string> port_connections;
1465
1466         uint32_t total_connection_count = 0;
1467         uint32_t io_connection_count = 0;
1468         uint32_t ardour_connection_count = 0;
1469         uint32_t system_connection_count = 0;
1470         uint32_t other_connection_count = 0;
1471
1472         ostringstream label;
1473
1474         bool have_label = false;
1475         bool each_io_has_one_connection = true;
1476
1477         string connection_name;
1478         string ardour_track_name;
1479         string other_connection_type;
1480         string system_ports;
1481         string system_port;
1482
1483         ostringstream tooltip;
1484         char * tooltip_cstr;
1485
1486         io_count = _route->n_outputs().n_total();
1487         tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1488
1489
1490         for (io_index = 0; io_index < io_count; ++io_index) {
1491
1492                 port = _route->output()->nth (io_index);
1493
1494                 //ignore any port connections that don't match our DataType
1495                 if (port->type() != DataType::AUDIO) {
1496                         continue;
1497                 }
1498
1499                 port_connections.clear ();
1500                 port->get_connections(port_connections);
1501                 io_connection_count = 0;
1502
1503                 if (!port_connections.empty()) {
1504                         for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1505                                 string pn = "";
1506                                 string& connection_name (*i);
1507
1508                                 if (connection_name.find("system:") == 0) {
1509                                         pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1510                                 }
1511
1512                                 if (io_connection_count == 0) {
1513                                         tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1514                                                 << " -> "
1515                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1516                                 } else {
1517                                         tooltip << ", "
1518                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1519                                 }
1520
1521                                 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1522                                         if (ardour_track_name.empty()) {
1523                                                 // "ardour:Master/in 1" -> "ardour:Master/"
1524                                                 string::size_type slash = connection_name.find("/");
1525                                                 if (slash != string::npos) {
1526                                                         ardour_track_name = connection_name.substr(0, slash + 1);
1527                                                 }
1528                                         }
1529
1530                                         if (connection_name.find(ardour_track_name) == 0) {
1531                                                 ++ardour_connection_count;
1532                                         }
1533                                 } else if (!pn.empty()) {
1534                                         if (system_ports.empty()) {
1535                                                 system_ports += pn;
1536                                         } else {
1537                                                 system_ports += "/" + pn;
1538                                         }
1539                                         if (connection_name.find("system:") == 0) {
1540                                                 ++system_connection_count;
1541                                         }
1542                                 } else if (connection_name.find("system:") == 0) {
1543                                         // "system:playback_123" -> "123"
1544                                         system_port = connection_name.substr(16);
1545                                         if (system_ports.empty()) {
1546                                                 system_ports += system_port;
1547                                         } else {
1548                                                 system_ports += "/" + system_port;
1549                                         }
1550
1551                                         ++system_connection_count;
1552                                 } else {
1553                                         if (other_connection_type.empty()) {
1554                                                 // "jamin:in 1" -> "jamin:"
1555                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1556                                         }
1557
1558                                         if (connection_name.find(other_connection_type) == 0) {
1559                                                 ++other_connection_count;
1560                                         }
1561                                 }
1562
1563                                 ++total_connection_count;
1564                                 ++io_connection_count;
1565                         }
1566                 }
1567
1568                 if (io_connection_count != 1) {
1569                         each_io_has_one_connection = false;
1570                 }
1571         }
1572
1573         if (total_connection_count == 0) {
1574                 tooltip << endl << _("Disconnected");
1575         }
1576
1577         tooltip_cstr = new char[tooltip.str().size() + 1];
1578         strcpy(tooltip_cstr, tooltip.str().c_str());
1579
1580         set_tooltip (output_button, tooltip_cstr, "");
1581
1582         if (each_io_has_one_connection) {
1583                 if (total_connection_count == ardour_connection_count) {
1584                         // all connections are to the same track in ardour
1585                         // "ardour:Master/" -> "Master"
1586                         string::size_type slash = ardour_track_name.find("/");
1587                         if (slash != string::npos) {
1588                                 label << ardour_track_name.substr(7, slash - 7);
1589                                 have_label = true;
1590                         }
1591                 } else if (total_connection_count == system_connection_count) {
1592                         // all connections are to system ports
1593                         label << system_ports;
1594                         have_label = true;
1595                 } else if (total_connection_count == other_connection_count) {
1596                         // all connections are to the same external program eg jamin
1597                         // "jamin:" -> "jamin"
1598                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1599                         have_label = true;
1600                 }
1601         }
1602
1603         if (!have_label) {
1604                 if (total_connection_count == 0) {
1605                         // Disconnected
1606                         label << "-";
1607                 } else {
1608                         // Odd configuration
1609                         label << "*" << total_connection_count << "*";
1610                 }
1611         }
1612
1613         output_button->set_text (label.str());
1614 }
1615
1616 void
1617 MonitorSection::disconnect_output ()
1618 {
1619         if (_route) {
1620                 _route->output()->disconnect(this);
1621         }
1622 }
1623
1624 void
1625 MonitorSection::edit_output_configuration ()
1626 {
1627         if (_output_selector == 0) {
1628                 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1629         }
1630         _output_selector->present ();
1631 }
1632
1633 void
1634 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1635 {
1636         if (!_route) {
1637                 return;
1638         }
1639         boost::shared_ptr<Port> a = wa.lock ();
1640         boost::shared_ptr<Port> b = wb.lock ();
1641         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1642                 update_output_display ();
1643         }
1644 }
1645
1646 void
1647 MonitorSection::load_bindings ()
1648 {
1649         bindings = Bindings::get_bindings (X_("Monitor Section"));
1650 }
1651
1652 void
1653 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1654 {
1655         boost::shared_ptr<Processor> processor (p.lock ());
1656         if (!processor || !processor->display_to_user()) {
1657                 return;
1658         }
1659         if (boost::dynamic_pointer_cast<Amp>(processor)) {
1660                 return;
1661         }
1662         ++(*cnt);
1663 }
1664
1665 uint32_t
1666 MonitorSection::count_processors ()
1667 {
1668         uint32_t processor_count = 0;
1669         if (_route) {
1670                 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1671         }
1672         return processor_count;
1673 }
1674
1675 void
1676 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1677 {
1678         update_processor_box ();
1679 }
1680
1681 void
1682 MonitorSection::action_proxy0 (enum MonitorActions action)
1683 {
1684         MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1685         if (!ms) {
1686                 return;
1687         }
1688         switch (action) {
1689                 case MonitorMono:
1690                         ms->mono ();
1691                         break;
1692                 case MonitorCutAll:
1693                         ms->cut_all ();
1694                         break;
1695                 case MonitorDimAll:
1696                         ms->dim_all ();
1697                         break;
1698                 case ToggleExclusiveSolo:
1699                         ms->toggle_exclusive_solo ();
1700                         break;
1701                 case ToggleMuteOverridesSolo:
1702                         ms->toggle_mute_overrides_solo ();
1703                         break;
1704                 case SoloUseInPlace:
1705                         ms->solo_use_in_place ();
1706                         break;
1707                 case SoloUseAFL:
1708                         ms->solo_use_afl ();
1709                         break;
1710                 case SoloUsePFL:
1711                         ms->solo_use_pfl ();
1712                         break;
1713                 case ToggleMonitorProcessorBox:
1714                         ms->update_processor_box ();
1715                         break;
1716         }
1717 }
1718
1719 void
1720 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1721 {
1722         MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1723         if (!ms) {
1724                 return;
1725         }
1726         switch (action) {
1727                 case CutChannel:
1728                         ms->cut_channel (chn);
1729                         break;
1730                 case DimChannel:
1731                         ms->dim_channel (chn);
1732                         break;
1733                 case SoloChannel:
1734                         ms->solo_channel (chn);
1735                         break;
1736                 case InvertChannel:
1737                         ms->invert_channel (chn);
1738                         break;
1739         }
1740 }