Tweaks to Mixer and Monitor keybindings:
[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 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
64 Gtkmm2ext::ActionMap MonitorSection::myactions (X_("monitor section"));
65 Gtkmm2ext::Bindings* MonitorSection::bindings = 0;
66
67 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
68
69 MonitorSection::MonitorSection (Session* s)
70         : SessionHandlePtr (s)
71         , RouteUI (s)
72         , _tearoff (0)
73         , channel_table (0)
74         , channel_table_viewport (*channel_table_scroller.get_hadjustment()
75                                   , *channel_table_scroller.get_vadjustment ())
76         , gain_control (0)
77         , dim_control (0)
78         , solo_boost_control (0)
79         , solo_cut_control (0)
80         , gain_display (0)
81         , dim_display (0)
82         , solo_boost_display (0)
83         , solo_cut_display (0)
84         , _output_selector (0)
85         , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
86         , afl_button (_("AFL"), ArdourButton::led_default_elements)
87         , pfl_button (_("PFL"), ArdourButton::led_default_elements)
88         , exclusive_solo_button (ArdourButton::led_default_elements)
89         , solo_mute_override_button (ArdourButton::led_default_elements)
90         , toggle_processorbox_button (ArdourButton::default_elements)
91         , _inhibit_solo_model_update (false)
92         , _rr_selection ()
93         , _ui_initialized (false)
94 {
95
96         using namespace Menu_Helpers;
97
98         Glib::RefPtr<Action> act;
99
100         if (!monitor_actions) {
101                 register_actions ();
102                 load_bindings ();
103         }
104
105         channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
106
107         set_data ("ardour-bindings", bindings);
108
109         _plugin_selector = new PluginSelector (PluginManager::instance());
110         insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
111         insert_box->set_no_show_all ();
112         insert_box->show ();
113         // TODO allow keyboard shortcuts in ProcessorBox
114
115         set_session (s);
116
117         /* Rude Solo  & Solo Isolated */
118         rude_solo_button.set_text (_("Soloing"));
119         rude_solo_button.set_name ("rude solo");
120         rude_solo_button.show ();
121
122         rude_iso_button.set_text (_("Isolated"));
123         rude_iso_button.set_name ("rude isolate");
124         rude_iso_button.show ();
125
126         rude_audition_button.set_text (_("Auditioning"));
127         rude_audition_button.set_name ("rude audition");
128         rude_audition_button.show ();
129
130         Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
131
132         act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
133         rude_solo_button.set_related_action (act);
134         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
135
136         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
137         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
138
139         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
140         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
141
142         /* SIP, AFL, PFL radio */
143
144         solo_in_place_button.set_name ("monitor section solo model");
145         afl_button.set_name ("monitor section solo model");
146         pfl_button.set_name ("monitor section solo model");
147
148         solo_in_place_button.set_led_left (true);
149         afl_button.set_led_left (true);
150         pfl_button.set_led_left (true);
151
152         solo_in_place_button.show ();
153         afl_button.show ();
154         pfl_button.show ();
155
156         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
157         set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
158         if (act) {
159                 solo_in_place_button.set_related_action (act);
160         }
161
162         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
163         set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
164         if (act) {
165                 afl_button.set_related_action (act);
166         }
167
168         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
169         set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
170         if (act) {
171                 pfl_button.set_related_action (act);
172         }
173
174         /* Solo option buttons */
175         exclusive_solo_button.set_text (_("Excl. Solo"));
176         exclusive_solo_button.set_name (X_("monitor section solo option"));
177         set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
178
179         act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
180         if (act) {
181                 exclusive_solo_button.set_related_action (act);
182         }
183
184         solo_mute_override_button.set_text (_("Solo ยป Mute"));
185         solo_mute_override_button.set_name (X_("monitor section solo option"));
186         set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
187
188         act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
189         if (act) {
190                 solo_mute_override_button.set_related_action (act);
191         }
192
193         /* Processor Box hide/shos */
194         toggle_processorbox_button.set_text (_("Processors"));
195         toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
196         set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
197
198         proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
199         toggle_processorbox_button.set_related_action (proctoggle);
200
201         /* Knobs */
202         Label* solo_boost_label;
203         Label* solo_cut_label;
204         Label* dim_label;
205
206         /* Solo Boost Knob */
207
208         solo_boost_control = new ArdourKnob ();
209         solo_boost_control->set_name("monitor section knob");
210         solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
211         set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
212
213         solo_boost_display = new ArdourDisplay ();
214         solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
215         solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
216         solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
217         solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
218         solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
219
220         solo_boost_label = manage (new Label (_("Solo Boost")));
221
222         /* Solo (SiP) cut */
223
224         solo_cut_control = new ArdourKnob ();
225         solo_cut_control->set_name ("monitor section knob");
226         solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
227         set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
228
229         solo_cut_display = new ArdourDisplay ();
230         solo_cut_display->set_name("monitor section dropdown"); // XXX
231         solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
232         solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
233         solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
234         solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
235         solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
236         solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
237
238         solo_cut_label = manage (new Label (_("SiP Cut")));
239
240         /* Dim */
241
242         dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
243         dim_control->set_name ("monitor section knob");
244         dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
245         set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
246
247         dim_display = new ArdourDisplay ();
248         dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
249         dim_display->add_controllable_preset(_("0 dB"), 0.0);
250         dim_display->add_controllable_preset(_("-3 dB"), -3.0);
251         dim_display->add_controllable_preset(_("-6 dB"), -6.0);
252         dim_display->add_controllable_preset(_("-12 dB"), -12.0);
253         dim_display->add_controllable_preset(_("-20 dB"), -20.0);
254
255         dim_label = manage (new Label (_("Dim")));
256
257         // mute button
258         cut_all_button.set_text (_("Mute"));
259         cut_all_button.set_name ("mute button");
260         cut_all_button.set_size_request (-1, PX_SCALE(30));
261         cut_all_button.show ();
262
263         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
264         if (act) {
265                 cut_all_button.set_related_action (act);
266         }
267
268         // dim button
269         dim_all_button.set_text (_("Dim"));
270         dim_all_button.set_name ("monitor section dim");
271         dim_all_button.set_size_request (-1, PX_SCALE(25));
272         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
273         if (act) {
274                 dim_all_button.set_related_action (act);
275         }
276
277         // mono button
278         mono_button.set_text (_("Mono"));
279         mono_button.set_name ("monitor section mono");
280         mono_button.set_size_request (-1, PX_SCALE(25));
281         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
282         if (act) {
283                 mono_button.set_related_action (act);
284         }
285
286         /* Gain */
287
288         gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
289         gain_control->set_name("monitor section knob");
290         gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
291
292         gain_display = new ArdourDisplay ();
293         gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
294         gain_display->add_controllable_preset(_("0 dB"), 0.0);
295         gain_display->add_controllable_preset(_("-3 dB"), -3.0);
296         gain_display->add_controllable_preset(_("-6 dB"), -6.0);
297         gain_display->add_controllable_preset(_("-12 dB"), -12.0);
298         gain_display->add_controllable_preset(_("-20 dB"), -20.0);
299         gain_display->add_controllable_preset(_("-30 dB"), -30.0);
300
301         Label* output_label = manage (new Label (_("Output")));
302         output_label->set_name (X_("MonitorSectionLabel"));
303
304         output_button = new ArdourButton ();
305         output_button->set_text (_("Output"));
306         output_button->set_name (X_("monitor section cut")); // XXX
307         output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
308         output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
309
310         channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
311         channel_table_scroller.set_size_request (-1, PX_SCALE(150));
312         channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
313         channel_table_scroller.show ();
314         channel_table_scroller.add (channel_table_viewport);
315
316         channel_size_group->add_widget (channel_table_header);
317         channel_table_header.resize (1, 5);
318
319         Label* l1 = manage (new Label (X_("  ")));
320         l1->set_name (X_("MonitorSectionLabel"));
321         channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
322
323         l1 = manage (new Label (_("Mute")));
324         l1->set_name (X_("MonitorSectionLabel"));
325         channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
326
327         l1 = manage (new Label (_("Dim")));
328         l1->set_name (X_("MonitorSectionLabel"));
329         channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
330
331         l1 = manage (new Label (_("Solo")));
332         l1->set_name (X_("MonitorSectionLabel"));
333         channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
334
335         l1 = manage (new Label (_("Inv")));
336         l1->set_name (X_("MonitorSectionLabel"));
337         channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
338
339         channel_table_header.show ();
340
341
342         /****************************************************************************
343          * LAYOUT  top to bottom
344          */
345
346         // solo, iso information
347         HBox* rude_box = manage (new HBox);
348         rude_box->set_spacing (PX_SCALE(4));
349         rude_box->set_homogeneous (true);
350         rude_box->pack_start (rude_solo_button, true, true);
351         rude_box->pack_start (rude_iso_button, true, true);
352
353         // solo options (right align)
354         HBox* tbx1 = manage (new HBox);
355         tbx1->pack_end (exclusive_solo_button, false, false);
356
357         HBox* tbx2 = manage (new HBox);
358         tbx2->pack_end (solo_mute_override_button, false, false);
359
360         HBox* tbx3 = manage (new HBox);
361         tbx3->pack_end (toggle_processorbox_button, false, false);
362
363         HBox* tbx0 = manage (new HBox); // space
364
365         // combined solo mode (Sip, AFL, PFL) & solo options
366         Table *solo_tbl = manage (new Table);
367         solo_tbl->attach (solo_in_place_button,   0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
368         solo_tbl->attach (pfl_button,             0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
369         solo_tbl->attach (afl_button,             0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
370         solo_tbl->attach (*tbx0,                  1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
371         solo_tbl->attach (*tbx1,                  2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
372         solo_tbl->attach (*tbx2,                  2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
373         solo_tbl->attach (*tbx3,                  2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
374
375         // boost, cut, dim  volume control
376         Table *level_tbl = manage (new Table);
377         level_tbl->attach (*solo_boost_label,    0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
378         level_tbl->attach (*solo_boost_control,  0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
379         level_tbl->attach (*solo_boost_display,  0, 2, 2, 3, EXPAND     , SHRINK, 1, 2);
380
381         level_tbl->attach (*solo_cut_label,      2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
382         level_tbl->attach (*solo_cut_control,    2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
383         level_tbl->attach (*solo_cut_display,    2, 4, 2, 3, EXPAND     , SHRINK, 1, 2);
384
385         level_tbl->attach (*dim_label,           1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
386         level_tbl->attach (*dim_control,         1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
387         level_tbl->attach (*dim_display,         1, 3, 5, 6, EXPAND     , SHRINK, 1, 2);
388
389         // mono, dim
390         HBox* mono_dim_box = manage (new HBox);
391         mono_dim_box->set_spacing (PX_SCALE(4));
392         mono_dim_box->set_homogeneous (true);
393         mono_dim_box->pack_start (mono_button, true, true);
394         mono_dim_box->pack_end (dim_all_button, true, true);
395
396         // master gain
397         Label* spin_label = manage (new Label (_("Monitor")));
398         VBox* spin_packer = manage (new VBox);
399         spin_packer->set_spacing (PX_SCALE(2));
400         spin_packer->pack_start (*spin_label, false, false);
401         spin_packer->pack_start (*gain_control, false, false);
402         spin_packer->pack_start (*gain_display, false, false);
403
404         master_packer.pack_start (*spin_packer, true, false);
405
406         // combined gain section (channels, mute, dim)
407         VBox* lower_packer = manage (new VBox);
408         lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
409         lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
410         lower_packer->pack_start (*mono_dim_box,        false, false, PX_SCALE(2));
411         lower_packer->pack_start (cut_all_button,       false, false, PX_SCALE(2));
412
413         // calc height of mixer scrollbar
414         int scrollbar_height = 0;
415         {
416                 Gtk::Window window (WINDOW_TOPLEVEL);
417                 HScrollbar scrollbar;
418                 window.add (scrollbar);
419                 scrollbar.set_name ("MixerWindow");
420                 scrollbar.ensure_style();
421                 Gtk::Requisition requisition(scrollbar.size_request ());
422                 scrollbar_height = requisition.height;
423         }
424
425         // output port select
426         VBox* out_packer = manage (new VBox);
427         out_packer->set_spacing (PX_SCALE(2));
428         out_packer->pack_start (*output_label, false, false);
429         out_packer->pack_start (*output_button, false, false);
430
431         /****************************************************************************
432          * TOP LEVEL LAYOUT
433          */
434         vpacker.set_border_width (PX_SCALE(3));
435         vpacker.pack_start (*rude_box,            false, false, PX_SCALE(3));
436         vpacker.pack_start (rude_audition_button, false, false, 0);
437         vpacker.pack_start (*solo_tbl,            false, false, PX_SCALE(8));
438         vpacker.pack_start (*insert_box,          true,  true,  PX_SCALE(8));
439         vpacker.pack_start (*level_tbl,           false, false, PX_SCALE(8));
440         vpacker.pack_start (*lower_packer,        false, false, PX_SCALE(8));
441         vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
442         vpacker.pack_end   (*out_packer,          false, false,
443 #ifdef MIXBUS
444                         scrollbar_height - 2 /* no outer sample */
445 #else
446                         scrollbar_height + 2 /* sample borders */
447 #endif
448                         );
449
450         hpacker.set_spacing (0);
451         hpacker.pack_start (vpacker, true, true);
452
453         add (hpacker);
454
455         gain_control->show_all ();
456         gain_display->show_all ();
457         dim_control->show_all ();
458         dim_display->show_all();
459         solo_boost_control->show_all ();
460         solo_boost_display->show_all();
461
462         mono_dim_box->show ();
463         spin_packer->show ();
464         master_packer.show ();
465
466         rude_box->show();
467         solo_tbl->show_all();
468         level_tbl->show();
469         lower_packer->show ();
470         out_packer->show ();
471
472         vpacker.show ();
473         hpacker.show ();
474
475         map_state ();
476         assign_controllables ();
477
478         output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
479         output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
480
481         signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
482         signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
483         set_flags (CAN_FOCUS);
484
485         _tearoff = new TearOff (*this);
486
487         if (!UIConfiguration::instance().get_floating_monitor_section()) {
488                 /* if torn off, make this a normal window
489                  * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
490                  */
491                 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
492         }
493         _tearoff->tearoff_window().set_title (X_("Monitor"));
494         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
495
496         update_output_display ();
497         update_processor_box ();
498         _ui_initialized = true;
499
500         /* catch changes that affect us */
501         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
502                 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
503                 );
504         Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
505 }
506
507 MonitorSection::~MonitorSection ()
508 {
509         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
510                 delete *i;
511         }
512
513         _channel_buttons.clear ();
514         output_changed_connections.drop_connections ();
515
516         delete insert_box; insert_box = 0;
517         delete output_button; output_button = 0;
518         delete gain_control; gain_control = 0;
519         delete gain_display; gain_display = 0;
520         delete dim_control; dim_control = 0;
521         delete dim_display; dim_display = 0;
522         delete solo_boost_control; solo_boost_control = 0;
523         delete solo_boost_display; solo_boost_display = 0;
524         delete solo_cut_control; solo_cut_control = 0;
525         delete solo_cut_display; solo_cut_display = 0;
526         delete _tearoff; _tearoff = 0;
527         delete _output_selector; _output_selector = 0;
528         delete channel_table; channel_table = 0;
529 }
530
531 bool
532 MonitorSection::enter_handler (GdkEventCrossing* ev)
533 {
534         grab_focus ();
535         return false;
536 }
537
538 bool
539 MonitorSection::leave_handler (GdkEventCrossing* ev)
540 {
541         switch (ev->detail) {
542         case GDK_NOTIFY_INFERIOR:
543                 return false;
544         default:
545                 break;
546         }
547
548         /* cancel focus if we're not torn off. With X11 WM's that do
549          * focus-follows-mouse, focus will be taken from us anyway.
550          */
551
552         Widget* top = get_toplevel();
553
554         if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
555                 Window* win = dynamic_cast<Window*> (top);
556                 gtk_window_set_focus (win->gobj(), 0);
557         }
558
559         return false;
560 }
561
562 void
563 MonitorSection::update_processor_box ()
564 {
565         bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
566
567         if (count_processors () > 0 && !show_processor_box) {
568                 toggle_processorbox_button.set_name (X_("monitor section processors present"));
569         } else {
570                 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
571         }
572
573         if (insert_box->is_visible() == show_processor_box) {
574                 return;
575         }
576
577         if (show_processor_box) {
578                 if (master_packer.get_parent()) {
579                         master_packer.get_parent()->remove (master_packer);
580                 }
581                 insert_box->show();
582                 vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
583         } else {
584                 if (master_packer.get_parent()) {
585                         master_packer.get_parent()->remove (master_packer);
586                 }
587                 insert_box->hide();
588                 vpacker.pack_start (master_packer,        true,  false, PX_SCALE(10));
589         }
590 }
591
592 void
593 MonitorSection::set_session (Session* s)
594 {
595         RouteUI::set_session (s);
596         _plugin_selector->set_session (_session);
597
598         if (_session) {
599
600                 _route = _session->monitor_out ();
601
602                 if (_route) {
603                         /* session with monitor section */
604                         _monitor = _route->monitor_control ();
605                         assign_controllables ();
606                         _route->output()->changed.connect (output_changed_connections, invalidator (*this),
607                                                                                         boost::bind (&MonitorSection::update_output_display, this),
608                                                                                         gui_context());
609                         insert_box->set_route (_route);
610                         _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
611                         _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
612                         if (_ui_initialized) {
613                                 update_processor_box ();
614                         }
615                 } else {
616                         /* session with no monitor section */
617                         output_changed_connections.drop_connections();
618                         _monitor.reset ();
619                         _route.reset ();
620                         delete _output_selector;
621                         _output_selector = 0;
622                 }
623
624                 populate_buttons ();
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 = myactions.create_action_group (X_("Monitor"));
929
930         act = myactions.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 = myactions.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                 myactions.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                 myactions.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                 myactions.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                 myactions.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 = myactions.create_action_group (X_("Solo"));
968         RadioAction::Group solo_group;
969
970         myactions.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         myactions.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         myactions.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         myactions.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"), myactions);
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 }