consistently use mixed-case labels
[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
25 #include "gtkmm2ext/bindable_button.h"
26 #include "gtkmm2ext/tearoff.h"
27 #include "gtkmm2ext/actions.h"
28 #include "gtkmm2ext/motionfeedback.h"
29
30 #include <gtkmm/menu.h>
31 #include <gtkmm/menuitem.h>
32
33 #include "ardour/monitor_processor.h"
34 #include "ardour/route.h"
35
36 #include "ardour_ui.h"
37 #include "gui_thread.h"
38 #include "monitor_section.h"
39 #include "public_editor.h"
40 #include "volume_controller.h"
41 #include "utils.h"
42
43 #include "i18n.h"
44
45 using namespace ARDOUR;
46 using namespace ARDOUR_UI_UTILS;
47 using namespace Gtk;
48 using namespace Gtkmm2ext;
49 using namespace PBD;
50 using namespace std;
51
52 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
53 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
54 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
55
56 MonitorSection::MonitorSection (Session* s)
57         : AxisView (s)
58         , RouteUI (s)
59         , _tearoff (0)
60         , channel_table_viewport (*channel_table_scroller.get_hadjustment(),
61                                   *channel_table_scroller.get_vadjustment ())
62         , gain_control (0)
63         , dim_control (0)
64         , solo_boost_control (0)
65         , solo_cut_control (0)
66         , gain_display (0)
67         , dim_display (0)
68         , solo_boost_display (0)
69         , solo_cut_display (0)
70         , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
71         , afl_button (_("AFL"), ArdourButton::led_default_elements)
72         , pfl_button (_("PFL"), ArdourButton::led_default_elements)
73         , exclusive_solo_button (ArdourButton::led_default_elements)
74         , solo_mute_override_button (ArdourButton::led_default_elements)
75         , _inhibit_solo_model_update (false)
76 {
77
78         using namespace Menu_Helpers;
79
80         Glib::RefPtr<Action> act;
81
82         if (!monitor_actions) {
83
84                 /* do some static stuff */
85
86                 register_actions ();
87
88         }
89
90         set_session (s);
91
92         VBox* spin_packer;
93         Label* spin_label;
94
95         /* Rude Solo */
96
97         rude_solo_button.set_text (_("Soloing"));
98         rude_solo_button.set_name ("rude solo");
99         rude_solo_button.show ();
100
101         rude_iso_button.set_text (_("Isolated"));
102         rude_iso_button.set_name ("rude isolate");
103         rude_iso_button.show ();
104
105         rude_audition_button.set_text (_("Auditioning"));
106         rude_audition_button.set_name ("rude audition");
107         rude_audition_button.show ();
108
109         ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
110
111         rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo));
112         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
113
114         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate));
115         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
116
117         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition));
118         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
119
120         solo_in_place_button.set_name ("monitor section solo model");
121         afl_button.set_name ("monitor section solo model");
122         pfl_button.set_name ("monitor section solo model");
123
124         solo_model_box.set_spacing (6);
125         solo_model_box.pack_start (solo_in_place_button, true, false);
126         solo_model_box.pack_start (afl_button, true, false);
127         solo_model_box.pack_start (pfl_button, true, false);
128
129         solo_in_place_button.show ();
130         afl_button.show ();
131         pfl_button.show ();
132         solo_model_box.show ();
133
134         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
135         ARDOUR_UI::instance()->tooltips().set_tip (solo_in_place_button, _("Solo controls affect solo-in-place"));
136         if (act) {
137                 solo_in_place_button.set_related_action (act);
138         }
139
140         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
141         ARDOUR_UI::instance()->tooltips().set_tip (afl_button, _("Solo controls toggle after-fader-listen"));
142         if (act) {
143                 afl_button.set_related_action (act);
144         }
145
146         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
147         ARDOUR_UI::instance()->tooltips().set_tip (pfl_button, _("Solo controls toggle pre-fader-listen"));
148         if (act) {
149                 pfl_button.set_related_action (act);
150         }
151
152         /* Solo Boost */
153
154         solo_boost_control = new ArdourKnob ();
155                 solo_boost_control->set_name("monitor knob");
156                 solo_boost_control->set_size_request(40,40);
157                 ARDOUR_UI::instance()->tooltips().set_tip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
158
159         solo_boost_display = new ArdourDisplay ();
160                 solo_boost_display->set_name("monitor section cut");
161                 solo_boost_display->set_size_request(80,20);
162                 solo_boost_display->add_controllable_preset("0dB", 0.0);
163                 solo_boost_display->add_controllable_preset("3 dB", 3.0);
164                 solo_boost_display->add_controllable_preset("6 dB", 6.0);
165                 solo_boost_display->add_controllable_preset("10 dB", 10.0);
166         
167         HBox* solo_packer = manage (new HBox);
168         solo_packer->set_spacing (6);
169         solo_packer->show ();
170
171         spin_label = manage (new Label (_("Solo Boost")));
172         spin_packer = manage (new VBox);
173         spin_packer->show ();
174         spin_packer->set_spacing (3);
175         spin_packer->pack_start (*spin_label, false, false);
176         spin_packer->pack_start (*solo_boost_control, false, false);
177         spin_packer->pack_start (*solo_boost_display, false, false);
178
179         solo_packer->pack_start (*spin_packer, true, false);
180
181         /* Solo (SiP) cut */
182
183         solo_cut_control = new ArdourKnob ();
184         solo_cut_control->set_name ("monitor knob");
185         solo_cut_control->set_size_request (40,40);
186                 ARDOUR_UI::instance()->tooltips().set_tip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
187
188         solo_cut_display = new ArdourDisplay ();
189                 solo_cut_display->set_name("monitor section cut");
190                 solo_cut_display->set_size_request(80,20);
191                 solo_cut_display->add_controllable_preset("0dB", 0.0);
192                 solo_cut_display->add_controllable_preset("-6 dB", -6.0);
193                 solo_cut_display->add_controllable_preset("-12 dB", -12.0);
194                 solo_cut_display->add_controllable_preset("-20 dB", -20.0);
195                 solo_cut_display->add_controllable_preset("OFF", -1200.0);
196        
197         spin_label = manage (new Label (_("SiP Cut")));
198         spin_packer = manage (new VBox);
199         spin_packer->show ();
200         spin_packer->set_spacing (3);
201         spin_packer->pack_start (*spin_label, false, false);
202         spin_packer->pack_start (*solo_cut_control, false, false);
203         spin_packer->pack_start (*solo_cut_display, false, false);
204
205         solo_packer->pack_start (*spin_packer, true, false);
206
207         /* Dim */
208
209         dim_control = new ArdourKnob ();
210         dim_control->set_name ("monitor knob");
211         dim_control->set_size_request (40,40);
212                 ARDOUR_UI::instance()->tooltips().set_tip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
213
214         dim_display = new ArdourDisplay ();
215                 dim_display->set_name("monitor section cut");
216                 dim_display->set_size_request(80,20);
217                 dim_display->add_controllable_preset("0dB", 0.0);
218                 dim_display->add_controllable_preset("-3 dB", -3.0);
219                 dim_display->add_controllable_preset("-6 dB", -6.0);
220                 dim_display->add_controllable_preset("-12 dB", -12.0);
221                 dim_display->add_controllable_preset("-20 dB", -20.0);
222         
223         HBox* dim_packer = manage (new HBox);
224         dim_packer->show ();
225
226         spin_label = manage (new Label (_("Dim")));
227         spin_packer = manage (new VBox);
228         spin_packer->show ();
229         spin_packer->set_spacing (3);
230         spin_packer->pack_start (*spin_label, false, false);
231         spin_packer->pack_start (*dim_control, false, false);
232         spin_packer->pack_start (*dim_display, false, false);
233
234         dim_packer->pack_start (*spin_packer, true, false);
235
236                 exclusive_solo_button.set_text (_("Excl. Solo"));
237         exclusive_solo_button.set_name (X_("monitor solo exclusive"));
238         ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
239
240         act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
241         if (act) {
242                 exclusive_solo_button.set_related_action (act);
243         }
244
245         solo_mute_override_button.set_text (_("Solo Â» Mute"));
246         solo_mute_override_button.set_name (X_("monitor solo override"));
247         ARDOUR_UI::instance()->set_tip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
248
249         act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
250         if (act) {
251                 solo_mute_override_button.set_related_action (act);
252         }
253
254         HBox* solo_opt_box = manage (new HBox);
255         solo_opt_box->set_spacing (12);
256         solo_opt_box->set_homogeneous (true);
257         solo_opt_box->pack_start (exclusive_solo_button);
258         solo_opt_box->pack_start (solo_mute_override_button);
259         solo_opt_box->show ();
260
261         upper_packer.set_spacing (6);
262
263         Gtk::HBox* rude_box = manage (new HBox);
264         rude_box->pack_start (rude_solo_button, true, true);
265         rude_box->pack_start (rude_iso_button, true, true);
266
267         upper_packer.pack_start (*rude_box, false, false);
268         upper_packer.pack_start (rude_audition_button, false, false);
269         upper_packer.pack_start (solo_model_box, false, false, 12);
270         upper_packer.pack_start (*solo_opt_box, false, false);
271         upper_packer.pack_start (*solo_packer, false, false, 12);
272
273         cut_all_button.set_text (_("Mute"));
274         cut_all_button.set_name ("monitor section cut");
275         cut_all_button.set_name (X_("monitor section cut"));
276         cut_all_button.set_size_request (-1,50);
277         cut_all_button.show ();
278
279         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
280         if (act) {
281                 cut_all_button.set_related_action (act);
282         }
283
284         dim_all_button.set_text (_("Dim"));
285         dim_all_button.set_name ("monitor section dim");
286         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
287         if (act) {
288                 dim_all_button.set_related_action (act);
289         }
290
291         mono_button.set_text (_("Mono"));
292         mono_button.set_name ("monitor section mono");
293         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
294         if (act) {
295                 mono_button.set_related_action (act);
296         }
297
298         HBox* bbox = manage (new HBox);
299
300         bbox->set_spacing (12);
301         bbox->pack_start (mono_button, true, true);
302         bbox->pack_start (dim_all_button, true, true);
303
304         lower_packer.set_spacing (12);
305         lower_packer.pack_start (*bbox, false, false);
306         lower_packer.pack_start (cut_all_button, false, false);
307
308         /* Gain */
309
310         gain_control = new ArdourKnob ();
311                 gain_control->set_name("monitor knob");
312                 gain_control->set_size_request(80,80);
313         
314         gain_display = new ArdourDisplay ();
315                 gain_display->set_name("monitor section cut");
316                 gain_display->set_size_request(40,20);
317                 gain_display->add_controllable_preset("0dB", 0.0);
318                 gain_display->add_controllable_preset("-3 dB", -3.0);
319                 gain_display->add_controllable_preset("-6 dB", -6.0);
320                 gain_display->add_controllable_preset("-12 dB", -12.0);
321                 gain_display->add_controllable_preset("-20 dB", -20.0);
322                 gain_display->add_controllable_preset("-30 dB", -30.0);
323         
324                 spin_label = manage (new Label (_("Monitor")));
325                 spin_packer = manage (new VBox);
326         spin_packer->show ();
327         spin_packer->set_spacing (3);
328         spin_packer->pack_start (*spin_label, false, false);
329         spin_packer->pack_start (*gain_control, false, false);
330         spin_packer->pack_start (*gain_display, false, false);
331
332         lower_packer.pack_start (*spin_packer, true, true);
333
334         channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
335         channel_table_scroller.set_size_request (-1, 150);
336         channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
337         channel_table_scroller.show ();
338         channel_table_scroller.add (channel_table_viewport);
339
340         channel_size_group  = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
341         channel_size_group->add_widget (channel_table_header);
342         channel_size_group->add_widget (channel_table);
343
344         channel_table_header.resize (1, 5);
345
346         Label* l1 = manage (new Label (X_("  ")));
347         l1->set_name (X_("MonitorSectionLabel"));
348         channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
349
350         l1 = manage (new Label (X_("Mute")));
351         l1->set_name (X_("MonitorSectionLabel"));
352         channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
353
354         l1 = manage (new Label (X_("Dim")));
355         l1->set_name (X_("MonitorSectionLabel"));
356         channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
357
358         l1 = manage (new Label (X_("Solo")));
359         l1->set_name (X_("MonitorSectionLabel"));
360         channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
361
362         l1 = manage (new Label (X_("Inv")));
363         l1->set_name (X_("MonitorSectionLabel"));
364         channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
365
366         channel_table_header.show ();
367
368         table_hpacker.pack_start (channel_table, true, true);
369
370         /* note that we don't pack the table_hpacker till later
371          */
372
373         vpacker.set_border_width (6);
374         vpacker.set_spacing (12);
375         vpacker.pack_start (upper_packer, false, false);
376         vpacker.pack_start (*dim_packer, false, false);
377         vpacker.pack_start (channel_table_header, false, false);
378         vpacker.pack_start (channel_table_packer, false, false);
379         vpacker.pack_start (lower_packer, false, false);
380
381         hpacker.pack_start (vpacker, true, true);
382
383         gain_control->show_all ();
384         gain_display->show_all ();
385         dim_control->show_all ();
386         dim_display->show_all();
387         solo_boost_control->show_all ();
388         solo_boost_display->show_all();
389
390         channel_table.show ();
391         hpacker.show ();
392         upper_packer.show ();
393         lower_packer.show ();
394         vpacker.show ();
395
396         populate_buttons ();
397         map_state ();
398         assign_controllables ();
399
400         _tearoff = new TearOff (hpacker);
401
402         /* if torn off, make this a normal window */
403         _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
404         _tearoff->tearoff_window().set_title (X_("Monitor"));
405         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
406
407         /* catch changes that affect us */
408
409         Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
410 }
411
412 MonitorSection::~MonitorSection ()
413 {
414         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
415                 delete *i;
416         }
417
418         _channel_buttons.clear ();
419
420         delete gain_control;
421         delete gain_display;
422         delete dim_control;
423         delete dim_display;
424         delete solo_boost_control;
425         delete solo_boost_display;
426         delete solo_cut_control;
427         delete solo_cut_display;
428         delete _tearoff;
429 }
430
431 void
432 MonitorSection::set_session (Session* s)
433 {
434         AxisView::set_session (s);
435
436         if (_session) {
437
438                 _route = _session->monitor_out ();
439
440                 if (_route) {
441                         /* session with monitor section */
442                         _monitor = _route->monitor_control ();
443                         assign_controllables ();
444                 } else {
445                         /* session with no monitor section */
446                         _monitor.reset ();
447                         _route.reset ();
448                 }
449
450                 if (channel_table_scroller.get_parent()) {
451                         /* scroller is packed, so remove it */
452                         channel_table_packer.remove (channel_table_scroller);
453                 } 
454
455                 if (table_hpacker.get_parent () == &channel_table_packer) {
456                         /* this occurs when the table hpacker is directly
457                            packed, so remove it.
458                         */
459                         channel_table_packer.remove (table_hpacker);
460                 } else if (table_hpacker.get_parent()) {
461                         channel_table_viewport.remove ();
462                 }
463                 
464                 if (_monitor->output_streams().n_audio() > 7) {
465                         /* put the table into a scrolled window, and then put
466                          * that into the channel vpacker, after the table header
467                          */
468                         channel_table_viewport.add (table_hpacker);
469                         channel_table_packer.pack_start (channel_table_scroller, true, true);
470                         channel_table_viewport.show ();
471                         channel_table_scroller.show ();
472
473                 } else {
474                         /* just put the channel table itself into the channel
475                          * vpacker, after the table header
476                          */
477                          
478                         channel_table_packer.pack_start (table_hpacker, true, true);
479                         channel_table_scroller.hide ();
480                 }
481
482                 table_hpacker.show ();
483                 channel_table.show ();
484
485         } else {
486                 /* no session */
487
488                 _monitor.reset ();
489                 _route.reset ();
490                 control_connections.drop_connections ();
491                 rude_iso_button.unset_active_state ();
492                 rude_solo_button.unset_active_state ();
493
494                 assign_controllables ();
495         }
496 }
497
498 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
499 {
500         cut.set_diameter (3);
501         dim.set_diameter (3);
502         solo.set_diameter (3);
503         invert.set_diameter (3);
504
505         cut.set_name (X_("monitor section cut"));
506         dim.set_name (X_("monitor section dim"));
507         solo.set_name (X_("monitor section solo"));
508         invert.set_name (X_("monitor section invert"));
509
510         cut.unset_flags (Gtk::CAN_FOCUS);
511         dim.unset_flags (Gtk::CAN_FOCUS);
512         solo.unset_flags (Gtk::CAN_FOCUS);
513         invert.unset_flags (Gtk::CAN_FOCUS);
514 }
515
516 void
517 MonitorSection::populate_buttons ()
518 {
519         if (!_monitor) {
520                 return;
521         }
522
523         Glib::RefPtr<Action> act;
524         uint32_t nchans = _monitor->output_streams().n_audio();
525
526         channel_table.resize (nchans, 5);
527         channel_table.set_col_spacings (6);
528         channel_table.set_row_spacings (6);
529         channel_table.set_homogeneous (true);
530
531         const uint32_t row_offset = 0;
532
533         for (uint32_t i = 0; i < nchans; ++i) {
534
535                 string l;
536                 char buf[64];
537
538                 if (nchans == 2) {
539                         if (i == 0) {
540                                 l = "L";
541                         } else {
542                                 l = "R";
543                         }
544                 } else {
545                         char buf[32];
546                         snprintf (buf, sizeof (buf), "%d", i+1);
547                         l = buf;
548                 }
549
550                 Label* label = manage (new Label (l));
551                 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
552
553                 ChannelButtonSet* cbs = new ChannelButtonSet;
554
555                 _channel_buttons.push_back (cbs);
556
557                 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
558                 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
559                 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
560                 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
561
562                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
563                 act = ActionManager::get_action (X_("Monitor"), buf);
564                 if (act) {
565                         cbs->cut.set_related_action (act);
566                 }
567
568                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
569                 act = ActionManager::get_action (X_("Monitor"), buf);
570                 if (act) {
571                         cbs->dim.set_related_action (act);
572                 }
573
574                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
575                 act = ActionManager::get_action (X_("Monitor"), buf);
576                 if (act) {
577                         cbs->solo.set_related_action (act);
578                 }
579
580                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
581                 act = ActionManager::get_action (X_("Monitor"), buf);
582                 if (act) {
583                         cbs->invert.set_related_action (act);
584                 }
585         }
586
587         channel_table.show_all ();
588 }
589
590 void
591 MonitorSection::toggle_exclusive_solo ()
592 {
593         if (!_monitor) {
594                 return;
595         }
596
597         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
598         if (act) {
599                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
600                 Config->set_exclusive_solo (tact->get_active());
601         }
602
603 }
604
605
606 void
607 MonitorSection::toggle_mute_overrides_solo ()
608 {
609         if (!_monitor) {
610                 return;
611         }
612
613         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
614         if (act) {
615                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
616                 Config->set_solo_mute_override (tact->get_active());
617         }
618 }
619
620 void
621 MonitorSection::dim_all ()
622 {
623         if (!_monitor) {
624                 return;
625         }
626
627         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
628         if (act) {
629                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
630                 _monitor->set_dim_all (tact->get_active());
631         }
632
633 }
634
635 void
636 MonitorSection::cut_all ()
637 {
638         if (!_monitor) {
639                 return;
640         }
641
642         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
643         if (act) {
644                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
645                 _monitor->set_cut_all (tact->get_active());
646         }
647 }
648
649 void
650 MonitorSection::mono ()
651 {
652         if (!_monitor) {
653                 return;
654         }
655
656         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
657         if (act) {
658                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
659                 _monitor->set_mono (tact->get_active());
660         }
661 }
662
663 void
664 MonitorSection::cut_channel (uint32_t chn)
665 {
666         if (!_monitor) {
667                 return;
668         }
669
670         char buf[64];
671         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
672
673         --chn; // 0-based in backend
674
675         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
676         if (act) {
677                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
678                 _monitor->set_cut (chn, tact->get_active());
679         }
680 }
681
682 void
683 MonitorSection::dim_channel (uint32_t chn)
684 {
685         if (!_monitor) {
686                 return;
687         }
688
689         char buf[64];
690         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
691
692         --chn; // 0-based in backend
693
694         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
695         if (act) {
696                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
697                 _monitor->set_dim (chn, tact->get_active());
698         }
699
700 }
701
702 void
703 MonitorSection::solo_channel (uint32_t chn)
704 {
705         if (!_monitor) {
706                 return;
707         }
708
709         char buf[64];
710         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
711
712         --chn; // 0-based in backend
713
714         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
715         if (act) {
716                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
717                 _monitor->set_solo (chn, tact->get_active());
718         }
719
720 }
721
722 void
723 MonitorSection::invert_channel (uint32_t chn)
724 {
725         if (!_monitor) {
726                 return;
727         }
728
729         char buf[64];
730         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
731
732         --chn; // 0-based in backend
733
734         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
735         if (act) {
736                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
737                 _monitor->set_polarity (chn, tact->get_active());
738         }
739 }
740
741 void
742 MonitorSection::register_actions ()
743 {
744         string action_name;
745         string action_descr;
746         Glib::RefPtr<Action> act;
747
748         monitor_actions = ActionGroup::create (X_("Monitor"));
749         ActionManager::add_action_group (monitor_actions);
750
751         ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
752                                                sigc::mem_fun (*this, &MonitorSection::mono));
753
754         ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
755                                                sigc::mem_fun (*this, &MonitorSection::cut_all));
756
757         ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
758                                                sigc::mem_fun (*this, &MonitorSection::dim_all));
759
760         act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
761                                                sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
762
763         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
764         tact->set_active (Config->get_exclusive_solo());
765
766         act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
767                                                      sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
768
769         tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
770         tact->set_active (Config->get_solo_mute_override());
771
772
773         /* note the 1-based counting (for naming - backend uses 0-based) */
774
775         for (uint32_t chn = 1; chn <= 16; ++chn) {
776
777                 action_name = string_compose (X_("monitor-cut-%1"), chn);
778                 action_descr = string_compose (_("Cut monitor channel %1"), chn);
779                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
780                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
781
782                 action_name = string_compose (X_("monitor-dim-%1"), chn);
783                 action_descr = string_compose (_("Dim monitor channel %1"), chn);
784                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
785                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
786
787                 action_name = string_compose (X_("monitor-solo-%1"), chn);
788                 action_descr = string_compose (_("Solo monitor channel %1"), chn);
789                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
790                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
791
792                 action_name = string_compose (X_("monitor-invert-%1"), chn);
793                 action_descr = string_compose (_("Invert monitor channel %1"), chn);
794                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
795                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
796
797         }
798
799
800         Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
801         RadioAction::Group solo_group;
802
803         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
804                                               sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
805         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
806                                               sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
807         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
808                                               sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
809
810         ActionManager::add_action_group (solo_actions);
811 }
812
813 void
814 MonitorSection::solo_use_in_place ()
815 {
816         /* this is driven by a toggle on a radio group, and so is invoked twice,
817            once for the item that became inactive and once for the one that became
818            active.
819         */
820
821         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
822
823         if (act) {
824                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
825                 if (ract) {
826                         if (!ract->get_active ()) {
827                                 /* We are turning SiP off, which means that AFL or PFL will be turned on
828                                    shortly; don't update the solo model in the mean time, as if the currently
829                                    configured listen position is not the one that is about to be turned on,
830                                    things will go wrong.
831                                 */
832                                 _inhibit_solo_model_update = true;
833                         }
834                         Config->set_solo_control_is_listen_control (!ract->get_active());
835                         _inhibit_solo_model_update = false;
836                 }
837         }
838 }
839
840 void
841 MonitorSection::solo_use_afl ()
842 {
843         /* this is driven by a toggle on a radio group, and so is invoked twice,
844            once for the item that became inactive and once for the one that became
845            active.
846         */
847
848         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
849         if (act) {
850                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
851                 if (ract) {
852                         if (ract->get_active()) {
853                                 Config->set_solo_control_is_listen_control (true);
854                                 Config->set_listen_position (AfterFaderListen);
855                         }
856                 }
857         }
858 }
859
860 void
861 MonitorSection::solo_use_pfl ()
862 {
863         /* this is driven by a toggle on a radio group, and so is invoked twice,
864            once for the item that became inactive and once for the one that became
865            active.
866         */
867
868         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
869         if (act) {
870                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
871                 if (ract) {
872                         if (ract->get_active()) {
873                                 Config->set_solo_control_is_listen_control (true);
874                                 Config->set_listen_position (PreFaderListen);
875                         }
876                 }
877         }
878 }
879
880 void
881 MonitorSection::setup_knob_images ()
882 {
883         
884         try {
885                 uint32_t c = ARDOUR_UI::config()->color_by_name ("monitor knob");
886                 char buf[16];
887                 snprintf (buf, 16, "#%x", (c >> 8));
888                 MotionFeedback::set_lamp_color (buf);
889                 big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
890
891         }  catch (...) {
892
893                 error << "No usable large knob image" << endmsg;
894                 throw failed_constructor ();
895         }
896
897         if (!big_knob_pixbuf) {
898                 error << "No usable large knob image" << endmsg;
899                 throw failed_constructor ();
900         }
901
902         try {
903
904                 little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
905
906         }  catch (...) {
907
908                 error << "No usable small knob image" << endmsg;
909                 throw failed_constructor ();
910         }
911
912         if (!little_knob_pixbuf) {
913                 error << "No usable small knob image" << endmsg;
914                 throw failed_constructor ();
915         }
916
917 }
918
919 void
920 MonitorSection::update_solo_model ()
921 {
922         if (_inhibit_solo_model_update) {
923                 return;
924         }
925         
926         const char* action_name = 0;
927         Glib::RefPtr<Action> act;
928
929         if (Config->get_solo_control_is_listen_control()) {
930                 switch (Config->get_listen_position()) {
931                 case AfterFaderListen:
932                         action_name = X_("solo-use-afl");
933                         break;
934                 case PreFaderListen:
935                         action_name = X_("solo-use-pfl");
936                         break;
937                 }
938         } else {
939                 action_name = X_("solo-use-in-place");
940         }
941
942         act = ActionManager::get_action (X_("Solo"), action_name);
943         if (act) {
944
945                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
946                 if (ract) {
947                         /* because these are radio buttons, one of them will be
948                            active no matter what. to trigger a change in the
949                            action so that the view picks it up, toggle it.
950                         */
951                         if (ract->get_active()) {
952                                 ract->set_active (false);
953                         }
954                         ract->set_active (true);
955                 }
956                 
957         }
958 }
959
960 void
961 MonitorSection::map_state ()
962 {
963         if (!_route || !_monitor) {
964                 return;
965         }
966
967         Glib::RefPtr<Action> act;
968
969         update_solo_model ();
970
971         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
972         if (act) {
973                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
974                 if (tact) {
975                         tact->set_active (_monitor->cut_all());
976                 }
977         }
978
979         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
980         if (act) {
981                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
982                 if (tact) {
983                         tact->set_active (_monitor->dim_all());
984                 }
985         }
986
987         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
988         if (act) {
989                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
990                 if (tact) {
991                         tact->set_active (_monitor->mono());
992                 }
993         }
994
995         uint32_t nchans = _monitor->output_streams().n_audio();
996
997         assert (nchans == _channel_buttons.size ());
998
999         for (uint32_t n = 0; n < nchans; ++n) {
1000
1001                 char action_name[32];
1002
1003                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1004                 act = ActionManager::get_action (X_("Monitor"), action_name);
1005                 if (act) {
1006                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1007                         if (tact) {
1008                                 tact->set_active (_monitor->cut (n));
1009                         }
1010                 }
1011
1012                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1013                 act = ActionManager::get_action (X_("Monitor"), action_name);
1014                 if (act) {
1015                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1016                         if (tact) {
1017                                 tact->set_active (_monitor->dimmed (n));
1018                         }
1019                 }
1020
1021                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1022                 act = ActionManager::get_action (X_("Monitor"), action_name);
1023                 if (act) {
1024                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1025                         if (tact) {
1026                                 tact->set_active (_monitor->soloed (n));
1027                         }
1028                 }
1029
1030                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1031                 act = ActionManager::get_action (X_("Monitor"), action_name);
1032                 if (act) {
1033                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1034                         if (tact) {
1035                                 tact->set_active (_monitor->inverted (n));
1036                         }
1037                 }
1038         }
1039 }
1040
1041 void
1042 MonitorSection::do_blink (bool onoff)
1043 {
1044         solo_blink (onoff);
1045         audition_blink (onoff);
1046 }
1047
1048 void
1049 MonitorSection::audition_blink (bool onoff)
1050 {
1051         if (_session == 0) {
1052                 return;
1053         }
1054
1055         if (_session->is_auditioning()) {
1056                 rude_audition_button.set_active (onoff);
1057         } else {
1058                 rude_audition_button.set_active (false);
1059         }
1060 }
1061
1062 void
1063 MonitorSection::solo_blink (bool onoff)
1064 {
1065         if (_session == 0) {
1066                 return;
1067         }
1068
1069         if (_session->soloing() || _session->listening()) {
1070                 rude_solo_button.set_active (onoff);
1071
1072                 if (_session->soloing()) {
1073                         if (_session->solo_isolated()) {
1074                                 rude_iso_button.set_active (false);
1075                         }
1076                 }
1077
1078         } else {
1079                 rude_solo_button.set_active (false);
1080                 rude_iso_button.set_active (false);
1081         }
1082 }
1083
1084 bool
1085 MonitorSection::cancel_solo (GdkEventButton*)
1086 {
1087         if (_session) {
1088                 if (_session->soloing()) {
1089                         _session->set_solo (_session->get_routes(), false);
1090                 } else if (_session->listening()) {
1091                         _session->set_listen (_session->get_routes(), false);
1092                 }
1093         }
1094
1095         return true;
1096 }
1097
1098 bool
1099 MonitorSection::cancel_isolate (GdkEventButton*)
1100 {
1101         if (_session) {
1102                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1103                 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1104         }
1105
1106         return true;
1107 }
1108
1109 bool
1110 MonitorSection::cancel_audition (GdkEventButton*)
1111 {
1112         if (_session) {
1113                 _session->cancel_audition();
1114         }
1115         return true;
1116 }
1117
1118 void
1119 MonitorSection::parameter_changed (std::string name)
1120 {
1121         if (name == "solo-control-is-listen-control") {
1122                 update_solo_model ();
1123         } else if (name == "listen-position") {
1124                 update_solo_model ();
1125         }
1126 }
1127
1128 void
1129 MonitorSection::assign_controllables ()
1130 {
1131         boost::shared_ptr<Controllable> none;
1132
1133         if (!gain_control) {
1134                 /* too early - GUI controls not set up yet */
1135                 return;
1136         }
1137
1138         if (_session) {
1139                         solo_cut_control->set_controllable (_session->solo_cut_control());
1140                         solo_cut_display->set_controllable (_session->solo_cut_control());
1141         } else {
1142             solo_cut_control->set_controllable (none);
1143                         solo_cut_display->set_controllable (none);
1144         }
1145
1146         if (_route) {
1147                 gain_control->set_controllable (_route->gain_control());
1148                 gain_display->set_controllable (_route->gain_control());
1149         } else {
1150                 gain_control->set_controllable (none);
1151         }
1152
1153         if (_monitor) {
1154
1155                 cut_all_button.set_controllable (_monitor->cut_control());
1156                 cut_all_button.watch ();
1157                 dim_all_button.set_controllable (_monitor->dim_control());
1158                 dim_all_button.watch ();
1159                 mono_button.set_controllable (_monitor->mono_control());
1160                 mono_button.watch ();
1161
1162                                 dim_control->set_controllable (_monitor->dim_level_control ());
1163                                 dim_display->set_controllable (_monitor->dim_level_control ());
1164                                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1165                                 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1166
1167         } else {
1168
1169                 cut_all_button.set_controllable (none);
1170                 dim_all_button.set_controllable (none);
1171                 mono_button.set_controllable (none);
1172
1173                 dim_control->set_controllable (none);
1174                 dim_display->set_controllable (none);
1175                 solo_boost_control->set_controllable (none);
1176                 solo_boost_display->set_controllable (none);
1177         }
1178 }
1179
1180 string
1181 MonitorSection::state_id() const
1182 {
1183         return "monitor-section";
1184 }