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