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