introduce GUIObjectState; massive, pervasive changes in visibility and height managem...
[ardour.git] / gtk2_ardour / monitor_section.cc
1 #include <gdkmm/pixbuf.h>
2
3 #include "pbd/compose.h"
4 #include "pbd/error.h"
5
6 #include "gtkmm2ext/bindable_button.h"
7 #include "gtkmm2ext/tearoff.h"
8 #include "gtkmm2ext/actions.h"
9 #include "gtkmm2ext/motionfeedback.h"
10
11 #include "ardour/dB.h"
12 #include "ardour/monitor_processor.h"
13 #include "ardour/route.h"
14 #include "ardour/utils.h"
15
16 #include "ardour_ui.h"
17 #include "gui_thread.h"
18 #include "monitor_section.h"
19 #include "public_editor.h"
20 #include "volume_controller.h"
21 #include "utils.h"
22
23 #include "i18n.h"
24
25 using namespace ARDOUR;
26 using namespace Gtk;
27 using namespace Gtkmm2ext;
28 using namespace PBD;
29 using namespace std;
30
31 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
32 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
33 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
34
35 MonitorSection::MonitorSection (Session* s)
36         : AxisView (s)
37         , RouteUI (s)
38         , main_table (2, 3)
39         , _tearoff (0)
40         , gain_control (0)
41         , dim_control (0)
42         , solo_boost_control (0)
43         , solo_cut_control (0)
44         , solo_in_place_button (solo_model_group, _("SiP"))
45         , afl_button (solo_model_group, _("AFL"))
46         , pfl_button (solo_model_group, _("PFL"))
47         , cut_all_button (_("MUTE"))
48         , dim_all_button (_("dim"))
49         , mono_button (_("mono"))
50         , rude_solo_button (_("soloing"))
51         , rude_iso_button (_("isolated"))
52         , rude_audition_button (_("auditioning"))
53         , exclusive_solo_button (_("Exclusive"))
54         , solo_mute_override_button (_("Solo/Mute"))
55 {
56         Glib::RefPtr<Action> act;
57
58         if (!monitor_actions) {
59
60                 /* do some static stuff */
61
62                 register_actions ();
63
64         }
65
66         set_session (s);
67
68         VBox* spin_packer;
69         Label* spin_label;
70
71         /* Dim */
72
73         dim_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.01, 0.1, true, 30, 30, true);
74
75         HBox* dim_packer = manage (new HBox);
76         dim_packer->show ();
77
78         spin_label = manage (new Label (_("Dim")));
79         spin_packer = manage (new VBox);
80         spin_packer->show ();
81         spin_packer->set_spacing (6);
82         spin_packer->pack_start (*dim_control, false, false);
83         spin_packer->pack_start (*spin_label, false, false);
84
85         dim_packer->set_spacing (12);
86         dim_packer->pack_start (*spin_packer, true, false);
87
88         /* Rude Solo */
89
90         rude_solo_button.set_name ("TransportSoloAlert");
91         rude_solo_button.show ();
92
93         rude_iso_button.set_name ("MonitorIsoAlert");
94         rude_iso_button.show ();
95
96         rude_audition_button.set_name ("TransportAuditioningAlert");
97         rude_audition_button.show ();
98
99         ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
100
101         rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo), false);
102         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
103
104         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
105         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
106
107         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
108         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
109
110         solo_model_box.set_spacing (6);
111         solo_model_box.pack_start (solo_in_place_button, false, false);
112         solo_model_box.pack_start (afl_button, false, false);
113         solo_model_box.pack_start (pfl_button, false, false);
114
115         solo_in_place_button.show ();
116         afl_button.show ();
117         pfl_button.show ();
118         solo_model_box.show ();
119
120         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
121         if (act) {
122                 act->connect_proxy (solo_in_place_button);
123         }
124
125         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
126         if (act) {
127                 act->connect_proxy (afl_button);
128         }
129
130         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
131         if (act) {
132                 act->connect_proxy (pfl_button);
133         }
134
135         /* Solo Boost */
136
137         solo_boost_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.01, 0.1, true, 30, 30, true);
138
139         HBox* solo_packer = manage (new HBox);
140         solo_packer->set_spacing (12);
141         solo_packer->show ();
142
143         spin_label = manage (new Label (_("Solo Boost")));
144         spin_packer = manage (new VBox);
145         spin_packer->show ();
146         spin_packer->set_spacing (6);
147         spin_packer->pack_start (*solo_boost_control, false, false);
148         spin_packer->pack_start (*spin_label, false, false);
149
150         solo_packer->pack_start (*spin_packer, false, true);
151
152         /* Solo (SiP) cut */
153
154         solo_cut_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.1, 0.5, true, 30, 30, true);
155
156         spin_label = manage (new Label (_("SiP Cut")));
157         spin_packer = manage (new VBox);
158         spin_packer->show ();
159         spin_packer->set_spacing (6);
160         spin_packer->pack_start (*solo_cut_control, false, false);
161         spin_packer->pack_start (*spin_label, false, false);
162
163         solo_packer->pack_start (*spin_packer, false, true);
164
165         exclusive_solo_button.set_name (X_("MonitorOptButton"));
166         ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
167
168         act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
169         if (act) {
170                 act->connect_proxy (exclusive_solo_button);
171         }
172
173         solo_mute_override_button.set_name (X_("MonitorOptButton"));
174         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)"));
175
176         act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
177         if (act) {
178                 act->connect_proxy (solo_mute_override_button);
179         }
180
181         HBox* solo_opt_box = manage (new HBox);
182         solo_opt_box->set_spacing (12);
183         solo_opt_box->set_homogeneous (true);
184         solo_opt_box->pack_start (exclusive_solo_button);
185         solo_opt_box->pack_start (solo_mute_override_button);
186         solo_opt_box->show ();
187
188         upper_packer.set_spacing (12);
189
190         Gtk::HBox* rude_box = manage (new HBox);
191         rude_box->pack_start (rude_solo_button, true, true);
192         rude_box->pack_start (rude_iso_button, true, true);
193
194         upper_packer.pack_start (*rude_box, false, false);
195         upper_packer.pack_start (rude_audition_button, false, false);
196         upper_packer.pack_start (solo_model_box, false, false);
197         upper_packer.pack_start (*solo_opt_box, false, false);
198         upper_packer.pack_start (*solo_packer, false, false);
199
200         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
201         if (act) {
202                 act->connect_proxy (cut_all_button);
203         }
204
205         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
206         if (act) {
207                 act->connect_proxy (dim_all_button);
208         }
209
210         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
211         if (act) {
212                 act->connect_proxy (mono_button);
213         }
214
215         cut_all_button.set_name (X_("MonitorMuteButton"));
216         cut_all_button.unset_flags (Gtk::CAN_FOCUS);
217         cut_all_button.set_size_request (50,50);
218         cut_all_button.show ();
219
220         HBox* bbox = manage (new HBox);
221
222         bbox->set_spacing (12);
223         bbox->pack_start (mono_button, true, true);
224         bbox->pack_start (dim_all_button, true, true);
225
226         dim_all_button.set_name (X_("MonitorDimButton"));
227         dim_all_button.unset_flags (Gtk::CAN_FOCUS);
228         mono_button.set_name (X_("MonitorMonoButton"));
229         mono_button.unset_flags (Gtk::CAN_FOCUS);
230
231         lower_packer.set_spacing (12);
232         lower_packer.pack_start (*bbox, false, false);
233         lower_packer.pack_start (cut_all_button, false, false);
234
235         /* Gain */
236
237         gain_control = new VolumeController (big_knob_pixbuf, boost::shared_ptr<Controllable>(), 1.0, 0.01, 0.1, true, 80, 80, false);
238
239         spin_label = manage (new Label (_("Monitor")));
240         spin_packer = manage (new VBox);
241         spin_packer->show ();
242         spin_packer->set_spacing (6);
243         spin_packer->pack_start (*gain_control, false, false);
244         spin_packer->pack_start (*spin_label, false, false);
245
246         lower_packer.pack_start (*spin_packer, true, true);
247
248         vpacker.set_border_width (12);
249         vpacker.set_spacing (12);
250         vpacker.pack_start (upper_packer, false, false);
251         vpacker.pack_start (*dim_packer, false, false);
252         vpacker.pack_start (main_table, false, false);
253         vpacker.pack_start (lower_packer, false, false);
254
255         hpacker.set_border_width (12);
256         hpacker.set_spacing (12);
257         hpacker.pack_start (vpacker, true, true);
258
259         gain_control->show_all ();
260         dim_control->show_all ();
261         solo_boost_control->show_all ();
262
263         main_table.show ();
264         hpacker.show ();
265         upper_packer.show ();
266         lower_packer.show ();
267         vpacker.show ();
268
269         populate_buttons ();
270         map_state ();
271         assign_controllables ();
272
273         _tearoff = new TearOff (hpacker);
274
275         /* if torn off, make this a normal window */
276         _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
277         _tearoff->tearoff_window().set_title (X_("Monitor"));
278         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
279
280         /* catch changes that affect us */
281
282         Config->ParameterChanged.connect (config_connection, invalidator (*this), ui_bind (&MonitorSection::parameter_changed, this, _1), gui_context());
283 }
284
285 MonitorSection::~MonitorSection ()
286 {
287         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
288                 delete *i;
289         }
290
291         _channel_buttons.clear ();
292
293         delete gain_control;
294         delete dim_control;
295         delete solo_boost_control;
296         delete _tearoff;
297 }
298
299 void
300 MonitorSection::set_session (Session* s)
301 {
302         AxisView::set_session (s);
303
304         if (_session) {
305
306                 _route = _session->monitor_out ();
307
308                 if (_route) {
309                         /* session with monitor section */
310                         _monitor = _route->monitor_control ();
311                         assign_controllables ();
312                 } else {
313                         /* session with no monitor section */
314                         _monitor.reset ();
315                         _route.reset ();
316                 }
317
318         } else {
319                 /* no session */
320
321                 _monitor.reset ();
322                 _route.reset ();
323                 control_connections.drop_connections ();
324                 rude_iso_button.set_active (false);
325                 rude_solo_button.set_active (false);
326
327                 assign_controllables ();
328         }
329 }
330
331 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
332         : cut (X_(""))
333         , dim (X_(""))
334         , solo (X_(""))
335         , invert (X_(""))
336 {
337         cut.set_name (X_("MonitorMuteButton"));
338         dim.set_name (X_("MonitorDimButton"));
339         solo.set_name (X_("MixerSoloButton"));
340         invert.set_name (X_("MonitorInvertButton"));
341
342         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (cut.gobj()), false);
343         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (dim.gobj()), false);
344         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (invert.gobj()), false);
345         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (solo.gobj()), false);
346
347         cut.unset_flags (Gtk::CAN_FOCUS);
348         dim.unset_flags (Gtk::CAN_FOCUS);
349         solo.unset_flags (Gtk::CAN_FOCUS);
350         invert.unset_flags (Gtk::CAN_FOCUS);
351 }
352
353 void
354 MonitorSection::populate_buttons ()
355 {
356         if (!_monitor) {
357                 return;
358         }
359
360         Glib::RefPtr<Action> act;
361         uint32_t nchans = _monitor->output_streams().n_audio();
362
363         main_table.resize (nchans+1, 5);
364         main_table.set_col_spacings (6);
365         main_table.set_row_spacings (6);
366         main_table.set_homogeneous (true);
367
368         Label* l1 = manage (new Label (X_("out")));
369         main_table.attach (*l1, 0, 1, 0, 1, SHRINK|FILL, SHRINK|FILL);
370         l1 = manage (new Label (X_("cut")));
371         main_table.attach (*l1, 1, 2, 0, 1, SHRINK|FILL, SHRINK|FILL);
372         l1 = manage (new Label (X_("dim")));
373         main_table.attach (*l1, 2, 3, 0, 1, SHRINK|FILL, SHRINK|FILL);
374         l1 = manage (new Label (X_("solo")));
375         main_table.attach (*l1, 3, 4, 0, 1, SHRINK|FILL, SHRINK|FILL);
376         l1 = manage (new Label (X_("inv")));
377         main_table.attach (*l1, 4, 5, 0, 1, SHRINK|FILL, SHRINK|FILL);
378
379         const uint32_t row_offset = 1;
380
381         for (uint32_t i = 0; i < nchans; ++i) {
382
383                 string l;
384                 char buf[64];
385
386                 if (nchans == 2) {
387                         if (i == 0) {
388                                 l = "L";
389                         } else {
390                                 l = "R";
391                         }
392                 } else {
393                         char buf[32];
394                         snprintf (buf, sizeof (buf), "%d", i+1);
395                         l = buf;
396                 }
397
398                 Label* label = manage (new Label (l));
399                 main_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
400
401                 ChannelButtonSet* cbs = new ChannelButtonSet;
402
403                 _channel_buttons.push_back (cbs);
404
405                 main_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
406                 main_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
407                 main_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
408                 main_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
409
410                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
411                 act = ActionManager::get_action (X_("Monitor"), buf);
412                 if (act) {
413                         act->connect_proxy (cbs->cut);
414                 }
415
416                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
417                 act = ActionManager::get_action (X_("Monitor"), buf);
418                 if (act) {
419                         act->connect_proxy (cbs->dim);
420                 }
421
422                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
423                 act = ActionManager::get_action (X_("Monitor"), buf);
424                 if (act) {
425                         act->connect_proxy (cbs->solo);
426                 }
427
428                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
429                 act = ActionManager::get_action (X_("Monitor"), buf);
430                 if (act) {
431                         act->connect_proxy (cbs->invert);
432                 }
433         }
434
435         main_table.show_all ();
436 }
437
438 void
439 MonitorSection::set_button_names ()
440 {
441         rec_enable_button_label.set_text ("rec");
442         mute_button_label.set_text ("rec");
443         solo_button_label.set_text ("rec");
444 }
445
446 void
447 MonitorSection::toggle_exclusive_solo ()
448 {
449         if (!_monitor) {
450                 return;
451         }
452
453         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
454         if (act) {
455                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
456                 Config->set_exclusive_solo (tact->get_active());
457         }
458
459 }
460
461
462 void
463 MonitorSection::toggle_mute_overrides_solo ()
464 {
465         if (!_monitor) {
466                 return;
467         }
468
469         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
470         if (act) {
471                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
472                 Config->set_solo_mute_override (tact->get_active());
473         }
474 }
475
476 void
477 MonitorSection::dim_all ()
478 {
479         if (!_monitor) {
480                 return;
481         }
482
483         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
484         if (act) {
485                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
486                 _monitor->set_dim_all (tact->get_active());
487         }
488
489 }
490
491 void
492 MonitorSection::cut_all ()
493 {
494         if (!_monitor) {
495                 return;
496         }
497
498         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
499         if (act) {
500                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
501                 _monitor->set_cut_all (tact->get_active());
502         }
503 }
504
505 void
506 MonitorSection::mono ()
507 {
508         if (!_monitor) {
509                 return;
510         }
511
512         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
513         if (act) {
514                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
515                 _monitor->set_mono (tact->get_active());
516         }
517 }
518
519 void
520 MonitorSection::cut_channel (uint32_t chn)
521 {
522         if (!_monitor) {
523                 return;
524         }
525
526         char buf[64];
527         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
528
529         --chn; // 0-based in backend
530
531         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
532         if (act) {
533                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
534                 _monitor->set_cut (chn, tact->get_active());
535         }
536 }
537
538 void
539 MonitorSection::dim_channel (uint32_t chn)
540 {
541         if (!_monitor) {
542                 return;
543         }
544
545         char buf[64];
546         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
547
548         --chn; // 0-based in backend
549
550         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
551         if (act) {
552                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
553                 _monitor->set_dim (chn, tact->get_active());
554         }
555
556 }
557
558 void
559 MonitorSection::solo_channel (uint32_t chn)
560 {
561         if (!_monitor) {
562                 return;
563         }
564
565         char buf[64];
566         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
567
568         --chn; // 0-based in backend
569
570         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
571         if (act) {
572                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
573                 _monitor->set_solo (chn, tact->get_active());
574         }
575
576 }
577
578 void
579 MonitorSection::invert_channel (uint32_t chn)
580 {
581         if (!_monitor) {
582                 return;
583         }
584
585         char buf[64];
586         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
587
588         --chn; // 0-based in backend
589
590         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
591         if (act) {
592                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
593                 _monitor->set_polarity (chn, tact->get_active());
594         }
595 }
596
597 void
598 MonitorSection::register_actions ()
599 {
600         string action_name;
601         string action_descr;
602         Glib::RefPtr<Action> act;
603
604         monitor_actions = ActionGroup::create (X_("Monitor"));
605         ActionManager::add_action_group (monitor_actions);
606
607         ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", "Switch monitor to mono",
608                                                sigc::mem_fun (*this, &MonitorSection::mono));
609
610         ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", "Cut monitor",
611                                                sigc::mem_fun (*this, &MonitorSection::cut_all));
612
613         ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", "Dim monitor",
614                                                sigc::mem_fun (*this, &MonitorSection::dim_all));
615
616         act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", "Toggle exclusive solo mode",
617                                                sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
618
619         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
620         tact->set_active (Config->get_exclusive_solo());
621
622         act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", "Toggle mute overrides solo mode",
623                                                      sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
624
625         tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
626         tact->set_active (Config->get_solo_mute_override());
627
628
629         /* note the 1-based counting (for naming - backend uses 0-based) */
630
631         for (uint32_t chn = 1; chn <= 16; ++chn) {
632
633                 action_name = string_compose (X_("monitor-cut-%1"), chn);
634                 action_descr = string_compose (_("Cut monitor channel %1"), chn);
635                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
636                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
637
638                 action_name = string_compose (X_("monitor-dim-%1"), chn);
639                 action_descr = string_compose (_("Dim monitor channel %1"), chn+1);
640                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
641                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
642
643                 action_name = string_compose (X_("monitor-solo-%1"), chn);
644                 action_descr = string_compose (_("Solo monitor channel %1"), chn+1);
645                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
646                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
647
648                 action_name = string_compose (X_("monitor-invert-%1"), chn);
649                 action_descr = string_compose (_("Invert monitor channel %1"), chn+1);
650                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
651                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
652
653         }
654
655
656         Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
657         RadioAction::Group solo_group;
658
659         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", "In-place solo",
660                                               sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
661         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", "After Fade Listen (AFL) solo",
662                                               sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
663         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", "Pre Fade Listen (PFL) solo",
664                                               sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
665
666         ActionManager::add_action_group (solo_actions);
667 }
668
669 void
670 MonitorSection::solo_use_in_place ()
671 {
672         /* this is driven by a toggle on a radio group, and so is invoked twice,
673            once for the item that became inactive and once for the one that became
674            active.
675         */
676
677         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
678
679         if (act) {
680                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
681                 if (ract) {
682                         Config->set_solo_control_is_listen_control (!ract->get_active());
683                 }
684         }
685 }
686
687 void
688 MonitorSection::solo_use_afl ()
689 {
690         /* this is driven by a toggle on a radio group, and so is invoked twice,
691            once for the item that became inactive and once for the one that became
692            active.
693         */
694
695         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
696         if (act) {
697                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
698                 if (ract) {
699                         if (ract->get_active()) {
700                                 Config->set_listen_position (AfterFaderListen);
701                                 Config->set_solo_control_is_listen_control (true);
702                         }
703                 }
704         }
705 }
706
707 void
708 MonitorSection::solo_use_pfl ()
709 {
710         /* this is driven by a toggle on a radio group, and so is invoked twice,
711            once for the item that became inactive and once for the one that became
712            active.
713         */
714
715         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
716         if (act) {
717                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
718                 if (ract) {
719                         if (ract->get_active()) {
720                                 Config->set_listen_position (PreFaderListen);
721                                 Config->set_solo_control_is_listen_control (true);
722                         }
723                 }
724         }
725 }
726
727 void
728 MonitorSection::setup_knob_images ()
729 {
730         try {
731
732                 big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
733
734         }  catch (...) {
735
736                 error << "No usable large knob image" << endmsg;
737                 throw failed_constructor ();
738         }
739
740         if (!big_knob_pixbuf) {
741                 error << "No usable large knob image" << endmsg;
742                 throw failed_constructor ();
743         }
744
745         try {
746
747                 little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
748
749         }  catch (...) {
750
751                 error << "No usable small knob image" << endmsg;
752                 throw failed_constructor ();
753         }
754
755         if (!little_knob_pixbuf) {
756                 error << "No usable small knob image" << endmsg;
757                 throw failed_constructor ();
758         }
759
760 }
761
762 void
763 MonitorSection::update_solo_model ()
764 {
765         const char* action_name;
766         Glib::RefPtr<Action> act;
767
768         if (Config->get_solo_control_is_listen_control()) {
769                 switch (Config->get_listen_position()) {
770                 case AfterFaderListen:
771                         action_name = X_("solo-use-afl");
772                         break;
773                 case PreFaderListen:
774                         action_name = X_("solo-use-pfl");
775                         break;
776                 }
777         } else {
778                 action_name = X_("solo-use-in-place");
779         }
780
781         act = ActionManager::get_action (X_("Solo"), action_name);
782         if (act) {
783                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
784                 if (ract) {
785                         ract->set_active (true);
786                 }
787         }
788 }
789
790 void
791 MonitorSection::map_state ()
792 {
793         if (!_route || !_monitor) {
794                 return;
795         }
796
797         Glib::RefPtr<Action> act;
798
799         update_solo_model ();
800
801         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
802         if (act) {
803                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
804                 if (tact) {
805                         tact->set_active (_monitor->cut_all());
806                 }
807         }
808
809         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
810         if (act) {
811                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
812                 if (tact) {
813                         tact->set_active (_monitor->dim_all());
814                 }
815         }
816
817         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
818         if (act) {
819                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
820                 if (tact) {
821                         tact->set_active (_monitor->mono());
822                 }
823         }
824
825         uint32_t nchans = _monitor->output_streams().n_audio();
826
827         assert (nchans == _channel_buttons.size ());
828
829         for (uint32_t n = 0; n < nchans; ++n) {
830
831                 char action_name[32];
832
833                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n+1);
834                 act = ActionManager::get_action (X_("Monitor"), action_name);
835                 if (act) {
836                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
837                         if (tact) {
838                                 tact->set_active (_monitor->cut (n));
839                         }
840                 }
841
842                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n+1);
843                 act = ActionManager::get_action (X_("Monitor"), action_name);
844                 if (act) {
845                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
846                         if (tact) {
847                                 tact->set_active (_monitor->dimmed (n));
848                         }
849                 }
850
851                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n+1);
852                 act = ActionManager::get_action (X_("Monitor"), action_name);
853                 if (act) {
854                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
855                         if (tact) {
856                                 tact->set_active (_monitor->soloed (n));
857                         }
858                 }
859
860                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n+1);
861                 act = ActionManager::get_action (X_("Monitor"), action_name);
862                 if (act) {
863                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
864                         if (tact) {
865                                 tact->set_active (_monitor->inverted (n));
866                         }
867                 }
868         }
869 }
870
871 void
872 MonitorSection::do_blink (bool onoff)
873 {
874         solo_blink (onoff);
875         audition_blink (onoff);
876 }
877
878 void
879 MonitorSection::audition_blink (bool onoff)
880 {
881         if (_session == 0) {
882                 return;
883         }
884
885         if (_session->is_auditioning()) {
886                 if (onoff) {
887                         rude_audition_button.set_state (STATE_ACTIVE);
888                 } else {
889                         rude_audition_button.set_state (STATE_NORMAL);
890                 }
891         } else {
892                 rude_audition_button.set_active (false);
893                 rude_audition_button.set_state (STATE_NORMAL);
894         }
895 }
896
897 void
898 MonitorSection::solo_blink (bool onoff)
899 {
900         if (_session == 0) {
901                 return;
902         }
903
904         if (_session->soloing() || _session->listening()) {
905                 if (onoff) {
906                         rude_solo_button.set_state (STATE_ACTIVE);
907                 } else {
908                         rude_solo_button.set_state (STATE_NORMAL);
909                 }
910
911                 if (_session->soloing()) {
912                         rude_iso_button.set_active (_session->solo_isolated());
913                 }
914
915         } else {
916                 // rude_solo_button.set_active (false);
917                 rude_solo_button.set_state (STATE_NORMAL);
918                 rude_iso_button.set_active (false);
919         }
920 }
921
922 bool
923 MonitorSection::cancel_solo (GdkEventButton*)
924 {
925         if (_session) {
926                 if (_session->soloing()) {
927                         _session->set_solo (_session->get_routes(), false);
928                 } else if (_session->listening()) {
929                         _session->set_listen (_session->get_routes(), false);
930                 }
931         }
932
933         return true;
934 }
935
936 bool
937 MonitorSection::cancel_isolate (GdkEventButton*)
938 {
939         if (_session) {
940                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
941                 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
942         }
943
944         return true;
945 }
946
947 bool
948 MonitorSection::cancel_audition (GdkEventButton*)
949 {
950         if (_session) {
951                 _session->cancel_audition();
952         }
953         return true;
954 }
955
956 void
957 MonitorSection::parameter_changed (std::string name)
958 {
959         if (name == "solo-control-is-listen-control" ||
960             name == "listen-position") {
961                 update_solo_model ();
962         }
963 }
964
965 void
966 MonitorSection::assign_controllables ()
967 {
968         boost::shared_ptr<Controllable> none;
969
970         if (!gain_control) {
971                 /* too early - GUI controls not set up yet */
972                 return;
973         }
974
975         if (_session) {
976                 solo_cut_control->set_controllable (_session->solo_cut_control());
977         } else {
978                 solo_cut_control->set_controllable (none);
979         }
980
981         if (_route) {
982                 gain_control->set_controllable (_route->gain_control());
983         } else {
984                 gain_control->set_controllable (none);
985         }
986
987         if (_monitor) {
988
989                 cut_all_button.set_controllable (_monitor->cut_control());
990                 cut_all_button.watch ();
991                 dim_all_button.set_controllable (_monitor->dim_control());
992                 dim_all_button.watch ();
993                 mono_button.set_controllable (_monitor->mono_control());
994                 mono_button.watch ();
995
996                 dim_control->set_controllable (_monitor->dim_level_control ());
997                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
998
999         } else {
1000
1001                 cut_all_button.set_controllable (none);
1002                 dim_all_button.set_controllable (none);
1003                 mono_button.set_controllable (none);
1004
1005                 dim_control->set_controllable (none);
1006                 solo_boost_control->set_controllable (none);
1007         }
1008 }
1009
1010 string
1011 MonitorSection::state_id() const
1012 {
1013         return "monitor-section";
1014 }