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