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