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