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