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