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