rec-safe GUI
[ardour.git] / gtk2_ardour / route_ui.cc
1 /*
2     Copyright (C) 2002-2006 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 <boost/algorithm/string.hpp>
21
22 #include <gtkmm2ext/gtk_ui.h>
23 #include <gtkmm2ext/choice.h>
24 #include <gtkmm2ext/doi.h>
25 #include <gtkmm2ext/bindable_button.h>
26 #include <gtkmm2ext/barcontroller.h>
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
29
30 #include "ardour/route_group.h"
31 #include "ardour/dB.h"
32 #include "pbd/memento_command.h"
33 #include "pbd/stacktrace.h"
34 #include "pbd/controllable.h"
35 #include "pbd/enumwriter.h"
36
37 #include "ardour_ui.h"
38 #include "editor.h"
39 #include "route_ui.h"
40 #include "ardour_button.h"
41 #include "keyboard.h"
42 #include "utils.h"
43 #include "plugin_pin_dialog.h"
44 #include "prompter.h"
45 #include "gui_thread.h"
46 #include "ardour_dialog.h"
47 #include "latency_gui.h"
48 #include "mixer_strip.h"
49 #include "automation_time_axis.h"
50 #include "route_time_axis.h"
51 #include "group_tabs.h"
52 #include "timers.h"
53 #include "ui_config.h"
54
55 #include "ardour/audio_track.h"
56 #include "ardour/audioengine.h"
57 #include "ardour/filename_extensions.h"
58 #include "ardour/midi_track.h"
59 #include "ardour/internal_send.h"
60 #include "ardour/profile.h"
61 #include "ardour/send.h"
62 #include "ardour/route.h"
63 #include "ardour/session.h"
64 #include "ardour/template_utils.h"
65
66 #include "i18n.h"
67 using namespace Gtk;
68 using namespace Gtkmm2ext;
69 using namespace ARDOUR;
70 using namespace ARDOUR_UI_UTILS;
71 using namespace PBD;
72 using namespace std;
73
74 uint32_t RouteUI::_max_invert_buttons = 3;
75 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
76 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
77 std::string RouteUI::program_port_prefix;
78
79 RouteUI::RouteUI (ARDOUR::Session* sess)
80         : AxisView(sess)
81         , mute_menu(0)
82         , solo_menu(0)
83         , sends_menu(0)
84         , record_menu(0)
85         , comment_window(0)
86         , comment_area(0)
87         , input_selector (0)
88         , output_selector (0)
89         , _invert_menu(0)
90 {
91         if (program_port_prefix.empty()) {
92                 // compare to gtk2_ardour/port_group.cc
93                 string lpn (PROGRAM_NAME);
94                 boost::to_lower (lpn);
95                 program_port_prefix = lpn + ":"; // e.g. "ardour:"
96         }
97         if (sess) init ();
98 }
99
100 RouteUI::~RouteUI()
101 {
102         if (_route) {
103                 gui_object_state().remove_node (route_state_id());
104         }
105
106         _route.reset (); /* drop reference to route, so that it can be cleaned up */
107         route_connections.drop_connections ();
108
109         delete solo_menu;
110         delete mute_menu;
111         delete sends_menu;
112         delete record_menu;
113         delete comment_window;
114         delete input_selector;
115         delete output_selector;
116         delete _invert_menu;
117
118         send_blink_connection.disconnect ();
119         rec_blink_connection.disconnect ();
120 }
121
122 void
123 RouteUI::init ()
124 {
125         self_destruct = true;
126         mute_menu = 0;
127         solo_menu = 0;
128         sends_menu = 0;
129         record_menu = 0;
130         _invert_menu = 0;
131         pre_fader_mute_check = 0;
132         post_fader_mute_check = 0;
133         listen_mute_check = 0;
134         main_mute_check = 0;
135         solo_safe_check = 0;
136         solo_isolated_check = 0;
137         solo_isolated_led = 0;
138         solo_safe_led = 0;
139         _solo_release = 0;
140         _mute_release = 0;
141         denormal_menu_item = 0;
142         step_edit_item = 0;
143         rec_safe_item = 0;
144         multiple_mute_change = false;
145         multiple_solo_change = false;
146         _i_am_the_modifier = 0;
147
148         input_selector = 0;
149         output_selector = 0;
150
151         setup_invert_buttons ();
152
153         mute_button = manage (new ArdourButton);
154         mute_button->set_name ("mute button");
155         UI::instance()->set_tip (mute_button, _("Mute this track"), "");
156
157         solo_button = manage (new ArdourButton);
158         solo_button->set_name ("solo button");
159         UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
160         solo_button->set_no_show_all (true);
161
162         rec_enable_button = manage (new ArdourButton);
163         rec_enable_button->set_name ("record enable button");
164         rec_enable_button->set_icon (ArdourIcon::RecButton);
165         UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
166
167         if (UIConfiguration::instance().get_blink_rec_arm()) {
168                 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
169         }
170
171         show_sends_button = manage (new ArdourButton);
172         show_sends_button->set_name ("send alert button");
173         UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
174
175         monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
176         monitor_input_button->set_name ("monitor button");
177         monitor_input_button->set_text (_("In"));
178         UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
179         monitor_input_button->set_no_show_all (true);
180
181         monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
182         monitor_disk_button->set_name ("monitor button");
183         monitor_disk_button->set_text (_("Disk"));
184         UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
185         monitor_disk_button->set_no_show_all (true);
186
187         _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
188         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
189         _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
190
191         _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
192         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
193
194         rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
195         rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
196
197         show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
198         show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
199
200         solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
201         solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
202         mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
203         mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
204
205         monitor_input_button->set_distinct_led_click (false);
206         monitor_disk_button->set_distinct_led_click (false);
207
208         monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
209         monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
210
211         monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
212         monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
213
214         BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
215 }
216
217 void
218 RouteUI::reset ()
219 {
220         route_connections.drop_connections ();
221
222         delete solo_menu;
223         solo_menu = 0;
224
225         delete mute_menu;
226         mute_menu = 0;
227
228         denormal_menu_item = 0;
229 }
230
231 void
232 RouteUI::self_delete ()
233 {
234         delete this;
235 }
236
237 void
238 RouteUI::set_route (boost::shared_ptr<Route> rp)
239 {
240         reset ();
241
242         _route = rp;
243
244         if (set_color_from_route()) {
245                 set_color (unique_random_color());
246         }
247
248         if (self_destruct) {
249                 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
250         }
251
252         delete input_selector;
253         input_selector = 0;
254
255         delete output_selector;
256         output_selector = 0;
257
258         mute_button->set_controllable (_route->mute_control());
259         solo_button->set_controllable (_route->solo_control());
260
261         _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
262         _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
263
264         _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
265
266         _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
267         _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
268         _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
269         _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
270         if (is_track()) {
271                 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
272                 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
273                 track_mode_changed();
274         }
275
276         _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
277         _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
278
279         _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
280         _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
281
282         if (_session->writable() && is_track()) {
283                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
284
285                 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
286                 t->RecordSafeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
287
288                 rec_enable_button->show();
289                 rec_enable_button->set_controllable (t->rec_enable_control());
290
291                 if (is_midi_track()) {
292                         midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
293                                                                     boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
294                 }
295
296         }
297
298         /* this will work for busses and tracks, and needs to be called to
299            set up the name entry/name label display.
300         */
301
302         if (is_track()) {
303                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
304                 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
305
306                 update_monitoring_display ();
307         }
308
309         mute_button->unset_flags (Gtk::CAN_FOCUS);
310         solo_button->unset_flags (Gtk::CAN_FOCUS);
311
312         mute_button->show();
313
314         if (_route->is_monitor() || _route->is_master()) {
315                 solo_button->hide ();
316         } else {
317                 solo_button->show();
318         }
319
320         map_frozen ();
321
322         setup_invert_buttons ();
323         set_invert_button_state ();
324
325         boost::shared_ptr<Route> s = _showing_sends_to.lock ();
326         bus_send_display_changed (s);
327
328         update_mute_display ();
329         update_solo_display ();
330
331         if (!UIConfiguration::instance().get_blink_rec_arm()) {
332                 blink_rec_display(true); // set initial rec-en button state
333         }
334
335         check_rec_enable_sensitivity ();
336         maybe_add_route_print_mgr ();
337         route_color_changed();
338 }
339
340 void
341 RouteUI::polarity_changed ()
342 {
343         if (!_route) {
344                 return;
345         }
346
347         set_invert_button_state ();
348 }
349
350 bool
351 RouteUI::mute_press (GdkEventButton* ev)
352 {
353         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
354                 return true;
355         }
356
357         //if this is a binding action, let the ArdourButton handle it
358         if ( BindingProxy::is_bind_action(ev) )
359                 return false;
360
361         multiple_mute_change = false;
362
363         if (Keyboard::is_context_menu_event (ev)) {
364
365                 if (mute_menu == 0){
366                         build_mute_menu();
367                 }
368
369                 mute_menu->popup(0,ev->time);
370
371                 return true;
372
373         } else {
374
375                 if (Keyboard::is_button2_event (ev)) {
376                         // button2-click is "momentary"
377
378                         _mute_release = new SoloMuteRelease (_route->muted ());
379                 }
380
381                 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
382
383                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
384
385                                 /* toggle mute on everything (but
386                                  * exclude the master and monitor)
387                                  *
388                                  * because we are going to erase
389                                  * elements of the list we need to work
390                                  * on a copy.
391                                  */
392
393                                 boost::shared_ptr<RouteList> copy (new RouteList);
394
395                                 *copy = *_session->get_routes ();
396
397                                 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
398                                         if ((*i)->is_master() || (*i)->is_monitor()) {
399                                                 i = copy->erase (i);
400                                         } else {
401                                                 ++i;
402                                         }
403                                 }
404
405                                 if (_mute_release) {
406                                         _mute_release->routes = copy;
407                                 }
408
409                                 DisplaySuspender ds;
410                                 _session->set_mute (copy, !_route->muted());
411
412                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
413
414                                 /* Primary-button1 inverts the implication of
415                                    the group being active. If the group is
416                                    active (for mute), then this modifier means
417                                    "do not apply to mute". If the group is
418                                    inactive (for mute), then this modifier
419                                    means "apply to route". This is all
420                                    accomplished by passing just the actual
421                                    route, along with the InverseGroup group
422                                    control disposition.
423
424                                    NOTE: Primary-button2 is MIDI learn.
425                                 */
426
427                                 boost::shared_ptr<RouteList> rl;
428
429                                 if (ev->button == 1) {
430
431                                         rl.reset (new RouteList);
432                                         rl->push_back (_route);
433
434                                         if (_mute_release) {
435                                                 _mute_release->routes = rl;
436                                         }
437
438                                         DisplaySuspender ds;
439                                         _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
440                                 }
441
442                         } else {
443
444                                 /* plain click applies change to this route */
445
446                                 boost::shared_ptr<RouteList> rl (new RouteList);
447                                 rl->push_back (_route);
448
449                                 if (_mute_release) {
450                                         _mute_release->routes = rl;
451                                 }
452
453                                 _session->set_mute (rl, !_route->muted());
454
455                         }
456                 }
457         }
458
459         return false;
460 }
461
462 bool
463 RouteUI::mute_release (GdkEventButton* /*ev*/)
464 {
465         if (_mute_release){
466                 DisplaySuspender ds;
467                 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
468                 delete _mute_release;
469                 _mute_release = 0;
470         }
471
472         return false;
473 }
474
475 void
476 RouteUI::edit_output_configuration ()
477 {
478         if (output_selector == 0) {
479
480                 boost::shared_ptr<Send> send;
481                 boost::shared_ptr<IO> output;
482
483                 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
484                         if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
485                                 output = send->output();
486                         } else {
487                                 output = _route->output ();
488                         }
489                 } else {
490                         output = _route->output ();
491                 }
492
493                 output_selector = new IOSelectorWindow (_session, output);
494         }
495
496         if (output_selector->is_visible()) {
497                 output_selector->get_toplevel()->get_window()->raise();
498         } else {
499                 output_selector->present ();
500         }
501
502         //output_selector->set_keep_above (true);
503 }
504
505 void
506 RouteUI::edit_input_configuration ()
507 {
508         if (input_selector == 0) {
509                 input_selector = new IOSelectorWindow (_session, _route->input());
510         }
511
512         if (input_selector->is_visible()) {
513                 input_selector->get_toplevel()->get_window()->raise();
514         } else {
515                 input_selector->present ();
516         }
517
518         //input_selector->set_keep_above (true);
519 }
520
521 bool
522 RouteUI::solo_press(GdkEventButton* ev)
523 {
524         /* ignore double/triple clicks */
525
526         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
527                 return true;
528         }
529
530         //if this is a binding action, let the ArdourButton handle it
531         if ( BindingProxy::is_bind_action(ev) )
532                 return false;
533
534         multiple_solo_change = false;
535
536         if (Keyboard::is_context_menu_event (ev)) {
537
538                 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
539                     ! (solo_safe_led && solo_safe_led->is_visible())) {
540
541                         if (solo_menu == 0) {
542                                 build_solo_menu ();
543                         }
544
545                         solo_menu->popup (1, ev->time);
546                 }
547
548         } else {
549
550                 if (Keyboard::is_button2_event (ev)) {
551
552                         // button2-click is "momentary"
553                         _solo_release = new SoloMuteRelease (_route->self_soloed());
554                 }
555
556                 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
557
558                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
559
560                                 /* Primary-Tertiary-click applies change to all routes */
561
562                                 if (_solo_release) {
563                                         _solo_release->routes = _session->get_routes ();
564                                 }
565
566                                 DisplaySuspender ds;
567                                 if (Config->get_solo_control_is_listen_control()) {
568                                         _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(),  Session::rt_cleanup, Controllable::UseGroup);
569                                 } else {
570                                         _session->set_solo (_session->get_routes(), !_route->self_soloed(),  Session::rt_cleanup, Controllable::UseGroup);
571                                 }
572
573                         } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
574
575                                 // Primary-Secondary-click: exclusively solo this track
576
577                                 if (_solo_release) {
578                                         _solo_release->exclusive = true;
579
580                                         boost::shared_ptr<RouteList> routes = _session->get_routes();
581
582                                         for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
583                                                 if ((*i)->soloed ()) {
584                                                         _solo_release->routes_on->push_back (*i);
585                                                 } else {
586                                                         _solo_release->routes_off->push_back (*i);
587                                                 }
588                                         }
589                                 }
590
591                                 if (Config->get_solo_control_is_listen_control()) {
592                                         /* ??? we need a just_one_listen() method */
593                                 } else {
594                                         DisplaySuspender ds;
595                                         _session->set_just_one_solo (_route, true);
596                                 }
597
598                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
599
600                                 // shift-click: toggle solo isolated status
601
602                                 _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
603                                 delete _solo_release;
604                                 _solo_release = 0;
605
606                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
607
608                                 /* Primary-button1: solo mix group.
609                                    NOTE: Primary-button2 is MIDI learn.
610                                 */
611
612                                 /* Primary-button1 applies change to the mix group even if it is not active
613                                    NOTE: Primary-button2 is MIDI learn.
614                                 */
615
616                                 boost::shared_ptr<RouteList> rl;
617
618                                 if (ev->button == 1) {
619
620                                         /* Primary-button1 inverts the implication of
621                                            the group being active. If the group is
622                                            active (for solo), then this modifier means
623                                            "do not apply to solo". If the group is
624                                            inactive (for mute), then this modifier
625                                            means "apply to route". This is all
626                                            accomplished by passing just the actual
627                                            route, along with the InverseGroup group
628                                            control disposition.
629
630                                            NOTE: Primary-button2 is MIDI learn.
631                                         */
632
633                                         rl.reset (new RouteList);
634                                         rl->push_back (_route);
635
636                                         if (_solo_release) {
637                                                 _solo_release->routes = rl;
638                                         }
639
640                                         DisplaySuspender ds;
641
642                                         if (Config->get_solo_control_is_listen_control()) {
643                                                 _session->set_listen (rl, !_route->listening_via_monitor(),  Session::rt_cleanup, Controllable::InverseGroup);
644                                         } else {
645                                                 _session->set_solo (rl, !_route->self_soloed(),  Session::rt_cleanup, Controllable::InverseGroup);
646                                         }
647                                 }
648
649                                 delete _solo_release;
650                                 _solo_release = 0;
651
652                         } else {
653
654                                 /* click: solo this route */
655
656                                 boost::shared_ptr<RouteList> rl (new RouteList);
657                                 rl->push_back (route());
658
659                                 if (_solo_release) {
660                                         _solo_release->routes = rl;
661                                 }
662
663                                 DisplaySuspender ds;
664                                 if (Config->get_solo_control_is_listen_control()) {
665                                         _session->set_listen (rl, !_route->listening_via_monitor());
666                                 } else {
667                                         _session->set_solo (rl, !_route->self_soloed());
668                                 }
669                         }
670                 }
671         }
672
673         return false;
674 }
675
676 bool
677 RouteUI::solo_release (GdkEventButton* /*ev*/)
678 {
679         if (_solo_release) {
680
681                 if (_solo_release->exclusive) {
682
683                 } else {
684                         DisplaySuspender ds;
685                         if (Config->get_solo_control_is_listen_control()) {
686                                 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
687                         } else {
688                                 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
689                         }
690                 }
691
692                 delete _solo_release;
693                 _solo_release = 0;
694         }
695
696         return false;
697 }
698
699 bool
700 RouteUI::rec_enable_press(GdkEventButton* ev)
701 {
702         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
703                 return true;
704         }
705
706         //if this is a binding action, let the ArdourButton handle it
707         if ( BindingProxy::is_bind_action(ev) )
708                 return false;
709
710         if (!_session->engine().connected()) {
711                 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
712                 msg.run ();
713                 return false;
714         }
715
716         if (is_midi_track()) {
717
718                 /* rec-enable button exits from step editing */
719
720                 if (midi_track()->step_editing()) {
721                         midi_track()->set_step_editing (false);
722                         return false;
723                 }
724         }
725
726         if (is_track() && rec_enable_button) {
727
728                 if (Keyboard::is_button2_event (ev)) {
729
730                         //rec arm does not have a momentary mode
731                         return false;
732
733                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
734
735                         DisplaySuspender ds;
736                         _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
737
738                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
739
740                         /* Primary-button1 applies change to the route group (even if it is not active)
741                            NOTE: Primary-button2 is MIDI learn.
742                         */
743
744                         if (ev->button == 1) {
745
746                                 boost::shared_ptr<RouteList> rl;
747
748                                 rl.reset (new RouteList);
749                                 rl->push_back (_route);
750
751                                 DisplaySuspender ds;
752                                 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
753                         }
754
755                 } else if (Keyboard::is_context_menu_event (ev)) {
756
757                         /* do this on release */
758
759                 } else {
760
761                         boost::shared_ptr<RouteList> rl (new RouteList);
762                         rl->push_back (route());
763                         DisplaySuspender ds;
764                         _session->set_record_enabled (rl, !_route->record_enabled());
765                 }
766         }
767
768         return false;
769 }
770
771 void
772 RouteUI::monitoring_changed ()
773 {
774         update_monitoring_display ();
775 }
776
777 void
778 RouteUI::update_monitoring_display ()
779 {
780         if (!_route) {
781                 return;
782         }
783
784         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
785
786         if (!t) {
787                 return;
788         }
789
790         MonitorState ms = t->monitoring_state();
791
792         if (t->monitoring_choice() & MonitorInput) {
793                 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
794         } else {
795                 if (ms & MonitoringInput) {
796                         monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
797                 } else {
798                         monitor_input_button->unset_active_state ();
799                 }
800         }
801
802         if (t->monitoring_choice() & MonitorDisk) {
803                 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
804         } else {
805                 if (ms & MonitoringDisk) {
806                         monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
807                 } else {
808                         monitor_disk_button->unset_active_state ();
809                 }
810         }
811 }
812
813 bool
814 RouteUI::monitor_input_press(GdkEventButton*)
815 {
816         return false;
817 }
818
819 bool
820 RouteUI::monitor_input_release(GdkEventButton* ev)
821 {
822         return monitor_release (ev, MonitorInput);
823 }
824
825 bool
826 RouteUI::monitor_disk_press (GdkEventButton*)
827 {
828         return false;
829 }
830
831 bool
832 RouteUI::monitor_disk_release (GdkEventButton* ev)
833 {
834         return monitor_release (ev, MonitorDisk);
835 }
836
837 bool
838 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
839 {
840         if (ev->button != 1) {
841                 return false;
842         }
843
844         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
845
846         if (!t) {
847                 return true;
848         }
849
850         MonitorChoice mc;
851         boost::shared_ptr<RouteList> rl;
852
853         /* XXX for now, monitoring choices are orthogonal. cue monitoring
854            will follow in 3.X but requires mixing the input and playback (disk)
855            signal together, which requires yet more buffers.
856         */
857
858         if (t->monitoring_choice() & monitor_choice) {
859                 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
860         } else {
861                 /* this line will change when the options are non-orthogonal */
862                 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
863                 mc = monitor_choice;
864         }
865
866         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
867                 rl = _session->get_routes ();
868
869         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
870                 if (_route->route_group() && _route->route_group()->is_monitoring()) {
871                         rl = _route->route_group()->route_list();
872                 } else {
873                         rl.reset (new RouteList);
874                         rl->push_back (route());
875                 }
876         } else {
877                 rl.reset (new RouteList);
878                 rl->push_back (route());
879         }
880
881         DisplaySuspender ds;
882         _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
883
884         return false;
885 }
886
887 void
888 RouteUI::build_record_menu ()
889 {
890         if (!record_menu) {
891                 record_menu = new Menu;
892                 record_menu->set_name ("ArdourContextMenu");
893                 using namespace Menu_Helpers;
894                 MenuList& items = record_menu->items();
895
896                 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
897                 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
898
899                 if (is_midi_track()) {
900                         items.push_back (SeparatorElem());
901                         items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
902                         step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
903                 }
904         }
905
906         if (step_edit_item) {
907                 step_edit_item->set_sensitive (!_route->record_enabled());
908                 step_edit_item->set_active (midi_track()->step_editing());
909         }
910         if (rec_safe_item) {
911                 rec_safe_item->set_sensitive (!_route->record_enabled());
912                 rec_safe_item->set_active (_route->record_safe());
913         }
914 }
915
916 void
917 RouteUI::toggle_step_edit ()
918 {
919         if (!is_midi_track() || _route->record_enabled()) {
920                 return;
921         }
922
923         midi_track()->set_step_editing (step_edit_item->get_active());
924 }
925
926 void
927 RouteUI::toggle_rec_safe ()
928 {
929         if (_route->record_enabled()) {
930                 return;
931         }
932         DisplaySuspender ds;
933         boost::shared_ptr<RouteList> rl (new RouteList);
934         rl->push_back (_route);
935         _session->set_record_safe (rl, rec_safe_item->get_active (), Session::rt_cleanup);
936 }
937
938 void
939 RouteUI::step_edit_changed (bool yn)
940 {
941         if (yn) {
942                 if (rec_enable_button) {
943                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
944                 }
945
946                 start_step_editing ();
947
948                 if (step_edit_item) {
949                         step_edit_item->set_active (true);
950                 }
951
952         } else {
953
954                 if (rec_enable_button) {
955                         rec_enable_button->unset_active_state ();
956                 }
957
958                 stop_step_editing ();
959
960                 if (step_edit_item) {
961                         step_edit_item->set_active (false);
962                 }
963         }
964 }
965
966 bool
967 RouteUI::rec_enable_release (GdkEventButton* ev)
968 {
969         if (Keyboard::is_context_menu_event (ev)) {
970                 build_record_menu ();
971                 if (record_menu) {
972                         record_menu->popup (1, ev->time);
973                 }
974                 return false;
975         }
976
977         return false;
978 }
979
980 void
981 RouteUI::build_sends_menu ()
982 {
983         using namespace Menu_Helpers;
984
985         sends_menu = new Menu;
986         sends_menu->set_name ("ArdourContextMenu");
987         MenuList& items = sends_menu->items();
988
989         items.push_back (
990                 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
991                 );
992
993         items.push_back (
994                 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
995                 );
996
997         items.push_back (
998                 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
999                 );
1000
1001         items.push_back (
1002                 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1003                 );
1004
1005         items.push_back (
1006                 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1007                 );
1008
1009         items.push_back (
1010                 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1011
1012         items.push_back (
1013                 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1014                 );
1015
1016         items.push_back (
1017                 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1018                 );
1019
1020         items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1021         items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1022         items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1023
1024 }
1025
1026 void
1027 RouteUI::create_sends (Placement p, bool include_buses)
1028 {
1029         _session->globally_add_internal_sends (_route, p, include_buses);
1030 }
1031
1032 void
1033 RouteUI::create_selected_sends (Placement p, bool include_buses)
1034 {
1035         boost::shared_ptr<RouteList> rlist (new RouteList);
1036         TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1037
1038         for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1039                 RouteTimeAxisView* rtv;
1040                 RouteUI* rui;
1041                 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1042                         if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1043                                 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1044                                         rlist->push_back (rui->route());
1045                                 }
1046                         }
1047                 }
1048         }
1049
1050         _session->add_internal_sends (_route, p, rlist);
1051 }
1052
1053 void
1054 RouteUI::set_sends_gain_from_track ()
1055 {
1056         _session->globally_set_send_gains_from_track (_route);
1057 }
1058
1059 void
1060 RouteUI::set_sends_gain_to_zero ()
1061 {
1062         _session->globally_set_send_gains_to_zero (_route);
1063 }
1064
1065 void
1066 RouteUI::set_sends_gain_to_unity ()
1067 {
1068         _session->globally_set_send_gains_to_unity (_route);
1069 }
1070
1071 bool
1072 RouteUI::show_sends_press(GdkEventButton* ev)
1073 {
1074         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1075                 return true;
1076         }
1077
1078         if (!is_track() && show_sends_button) {
1079
1080                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1081
1082                         // do nothing on midi sigc::bind event
1083                         return false;
1084
1085                 } else if (Keyboard::is_context_menu_event (ev)) {
1086
1087                         if (sends_menu == 0) {
1088                                 build_sends_menu ();
1089                         }
1090
1091                         sends_menu->popup (0, ev->time);
1092
1093                 } else {
1094
1095                         boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1096
1097                         if (s == _route) {
1098                                 set_showing_sends_to (boost::shared_ptr<Route> ());
1099                         } else {
1100                                 set_showing_sends_to (_route);
1101                         }
1102                 }
1103         }
1104
1105         return true;
1106 }
1107
1108 bool
1109 RouteUI::show_sends_release (GdkEventButton*)
1110 {
1111         return true;
1112 }
1113
1114 void
1115 RouteUI::send_blink (bool onoff)
1116 {
1117         if (!show_sends_button) {
1118                 return;
1119         }
1120
1121         if (onoff) {
1122                 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1123         } else {
1124                 show_sends_button->unset_active_state ();
1125         }
1126 }
1127
1128 Gtkmm2ext::ActiveState
1129 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1130 {
1131         if (r->is_master() || r->is_monitor()) {
1132                 return Gtkmm2ext::Off;
1133         }
1134
1135         if (Config->get_solo_control_is_listen_control()) {
1136
1137                 if (r->listening_via_monitor()) {
1138                         return Gtkmm2ext::ExplicitActive;
1139                 } else {
1140                         return Gtkmm2ext::Off;
1141                 }
1142
1143         }
1144
1145         if (r->soloed()) {
1146                 if (!r->self_soloed()) {
1147                         return Gtkmm2ext::ImplicitActive;
1148                 } else {
1149                         return Gtkmm2ext::ExplicitActive;
1150                 }
1151         } else {
1152                 return Gtkmm2ext::Off;
1153         }
1154 }
1155
1156 Gtkmm2ext::ActiveState
1157 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1158 {
1159         if (r->is_master() || r->is_monitor()) {
1160                 return Gtkmm2ext::Off;
1161         }
1162
1163         if (r->solo_isolated()) {
1164                 return Gtkmm2ext::ExplicitActive;
1165         } else {
1166                 return Gtkmm2ext::Off;
1167         }
1168 }
1169
1170 Gtkmm2ext::ActiveState
1171 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1172 {
1173         if (r->is_master() || r->is_monitor()) {
1174                 return Gtkmm2ext::Off;
1175         }
1176
1177         if (r->solo_safe()) {
1178                 return Gtkmm2ext::ExplicitActive;
1179         } else {
1180                 return Gtkmm2ext::Off;
1181         }
1182 }
1183
1184 void
1185 RouteUI::update_solo_display ()
1186 {
1187         bool yn = _route->solo_safe ();
1188
1189         if (solo_safe_check && solo_safe_check->get_active() != yn) {
1190                 solo_safe_check->set_active (yn);
1191         }
1192
1193         yn = _route->solo_isolated ();
1194
1195         if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1196                 solo_isolated_check->set_active (yn);
1197         }
1198
1199         set_button_names ();
1200
1201         if (solo_isolated_led) {
1202                 if (_route->solo_isolated()) {
1203                         solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1204                 } else {
1205                         solo_isolated_led->unset_active_state ();
1206                 }
1207         }
1208
1209         if (solo_safe_led) {
1210                 if (_route->solo_safe()) {
1211                         solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1212                 } else {
1213                         solo_safe_led->unset_active_state ();
1214                 }
1215         }
1216
1217         solo_button->set_active_state (solo_active_state (_route));
1218
1219         /* some changes to solo status can affect mute display, so catch up
1220          */
1221
1222         update_mute_display ();
1223 }
1224
1225 void
1226 RouteUI::solo_changed_so_update_mute ()
1227 {
1228         update_mute_display ();
1229 }
1230
1231 ActiveState
1232 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1233 {
1234         if (r->is_monitor()) {
1235                 return ActiveState(0);
1236         }
1237
1238
1239         if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1240
1241                 if (r->muted ()) {
1242                         /* full mute */
1243                         return Gtkmm2ext::ExplicitActive;
1244                 } else if (r->muted_by_others()) {
1245                         return Gtkmm2ext::ImplicitActive;
1246                 } else {
1247                         /* no mute at all */
1248                         return Gtkmm2ext::Off;
1249                 }
1250
1251         } else {
1252
1253                 if (r->muted()) {
1254                         /* full mute */
1255                         return Gtkmm2ext::ExplicitActive;
1256                 } else {
1257                         /* no mute at all */
1258                         return Gtkmm2ext::Off;
1259                 }
1260         }
1261
1262         return ActiveState(0);
1263 }
1264
1265 void
1266 RouteUI::update_mute_display ()
1267 {
1268         if (!_route) {
1269                 return;
1270         }
1271
1272         mute_button->set_active_state (mute_active_state (_session, _route));
1273 }
1274
1275 void
1276 RouteUI::route_rec_enable_changed ()
1277 {
1278         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1279         update_monitoring_display ();
1280 }
1281
1282 void
1283 RouteUI::session_rec_enable_changed ()
1284 {
1285         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1286         update_monitoring_display ();
1287 }
1288
1289 void
1290 RouteUI::blink_rec_display (bool blinkOn)
1291 {
1292         if (!rec_enable_button || !_route) {
1293                 return;
1294         }
1295         if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1296                 return;
1297         }
1298
1299         if (_route->record_enabled()) {
1300                 switch (_session->record_status ()) {
1301                 case Session::Recording:
1302                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1303                         break;
1304
1305                 case Session::Disabled:
1306                 case Session::Enabled:
1307                         if ( UIConfiguration::instance().get_blink_rec_arm() )
1308                                                         rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1309                                                 else
1310                                                         rec_enable_button->set_active_state ( ImplicitActive );
1311                         break;
1312
1313                 }
1314
1315                 if (step_edit_item) {
1316                         step_edit_item->set_sensitive (false);
1317                 }
1318
1319         } else {
1320                 rec_enable_button->unset_active_state ();
1321
1322                 if (step_edit_item) {
1323                         step_edit_item->set_sensitive (true);
1324                 }
1325         }
1326
1327         check_rec_enable_sensitivity ();
1328 }
1329
1330 void
1331 RouteUI::build_solo_menu (void)
1332 {
1333         using namespace Menu_Helpers;
1334
1335         solo_menu = new Menu;
1336         solo_menu->set_name ("ArdourContextMenu");
1337         MenuList& items = solo_menu->items();
1338         Gtk::CheckMenuItem* check;
1339
1340         check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1341         check->set_active (_route->solo_isolated());
1342         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1343         items.push_back (CheckMenuElem(*check));
1344         solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1345         check->show_all();
1346
1347         check = new Gtk::CheckMenuItem(_("Solo Safe"));
1348         check->set_active (_route->solo_safe());
1349         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1350         items.push_back (CheckMenuElem(*check));
1351         solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1352         check->show_all();
1353
1354         //items.push_back (SeparatorElem());
1355         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1356
1357 }
1358
1359 void
1360 RouteUI::build_mute_menu(void)
1361 {
1362         using namespace Menu_Helpers;
1363
1364         mute_menu = new Menu;
1365         mute_menu->set_name ("ArdourContextMenu");
1366
1367         MenuList& items = mute_menu->items();
1368
1369         pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1370         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1371         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1372         items.push_back (CheckMenuElem(*pre_fader_mute_check));
1373         pre_fader_mute_check->show_all();
1374
1375         post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1376         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1377         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1378         items.push_back (CheckMenuElem(*post_fader_mute_check));
1379         post_fader_mute_check->show_all();
1380
1381         listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1382         init_mute_menu(MuteMaster::Listen, listen_mute_check);
1383         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1384         items.push_back (CheckMenuElem(*listen_mute_check));
1385         listen_mute_check->show_all();
1386
1387         main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1388         init_mute_menu(MuteMaster::Main, main_mute_check);
1389         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1390         items.push_back (CheckMenuElem(*main_mute_check));
1391         main_mute_check->show_all();
1392
1393         //items.push_back (SeparatorElem());
1394         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1395
1396         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1397 }
1398
1399 void
1400 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1401 {
1402         check->set_active (_route->mute_points() & mp);
1403 }
1404
1405 void
1406 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1407 {
1408         if (check->get_active()) {
1409                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1410         } else {
1411                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1412         }
1413 }
1414
1415 void
1416 RouteUI::muting_change ()
1417 {
1418         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1419
1420         bool yn;
1421         MuteMaster::MutePoint current = _route->mute_points ();
1422
1423         yn = (current & MuteMaster::PreFader);
1424
1425         if (pre_fader_mute_check->get_active() != yn) {
1426                 pre_fader_mute_check->set_active (yn);
1427         }
1428
1429         yn = (current & MuteMaster::PostFader);
1430
1431         if (post_fader_mute_check->get_active() != yn) {
1432                 post_fader_mute_check->set_active (yn);
1433         }
1434
1435         yn = (current & MuteMaster::Listen);
1436
1437         if (listen_mute_check->get_active() != yn) {
1438                 listen_mute_check->set_active (yn);
1439         }
1440
1441         yn = (current & MuteMaster::Main);
1442
1443         if (main_mute_check->get_active() != yn) {
1444                 main_mute_check->set_active (yn);
1445         }
1446 }
1447
1448 bool
1449 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1450 {
1451         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1452                 return true;
1453         }
1454
1455         bool view = solo_isolated_led->active_state();
1456         bool model = _route->solo_isolated();
1457
1458         /* called BEFORE the view has changed */
1459
1460         if (ev->button == 1) {
1461                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1462
1463                         if (model) {
1464                                 /* disable isolate for all routes */
1465                                 DisplaySuspender ds;
1466                                 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1467                         } else {
1468                                 /* enable isolate for all routes */
1469                                 DisplaySuspender ds;
1470                                 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1471                         }
1472
1473                 } else {
1474
1475                         if (model == view) {
1476
1477                                 /* flip just this route */
1478
1479                                 boost::shared_ptr<RouteList> rl (new RouteList);
1480                                 rl->push_back (_route);
1481                                 DisplaySuspender ds;
1482                                 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1483                         }
1484                 }
1485         }
1486
1487         return false;
1488 }
1489
1490 bool
1491 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1492 {
1493         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1494                 return true;
1495         }
1496
1497         bool view = solo_safe_led->active_state();
1498         bool model = _route->solo_safe();
1499
1500         if (ev->button == 1) {
1501                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1502                         boost::shared_ptr<RouteList> rl (_session->get_routes());
1503                         if (model) {
1504                                 /* disable solo safe for all routes */
1505                                 DisplaySuspender ds;
1506                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1507                                         (*i)->set_solo_safe (false, Controllable::NoGroup);
1508                                 }
1509                         } else {
1510                                 /* enable solo safe for all routes */
1511                                 DisplaySuspender ds;
1512                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1513                                         (*i)->set_solo_safe (true, Controllable::NoGroup);
1514                                 }
1515                         }
1516                 }
1517                 else {
1518                         if (model == view) {
1519                                 /* flip just this route */
1520                                 _route->set_solo_safe (!view, Controllable::NoGroup);
1521                         }
1522                 }
1523         }
1524
1525         return false;
1526 }
1527
1528 void
1529 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1530 {
1531         bool view = check->get_active();
1532         bool model = _route->solo_isolated();
1533
1534         /* called AFTER the view has changed */
1535
1536         if (model != view) {
1537                 _route->set_solo_isolated (view, Controllable::UseGroup);
1538         }
1539 }
1540
1541 void
1542 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1543 {
1544         _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1545 }
1546
1547 /** Ask the user to choose a colour, and then apply that color to my route
1548  */
1549 void
1550 RouteUI::choose_color ()
1551 {
1552         bool picked;
1553         Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1554
1555         if (picked) {
1556                 set_color(color);
1557         }
1558 }
1559
1560 /** Set the route's own color.  This may not be used for display if
1561  *  the route is in a group which shares its color with its routes.
1562  */
1563 void
1564 RouteUI::set_color (const Gdk::Color & c)
1565 {
1566         /* leave _color alone in the group case so that tracks can retain their
1567          * own pre-group colors.
1568          */
1569
1570         char buf[64];
1571         _color = c;
1572         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1573
1574         /* note: we use the route state ID here so that color is the same for both
1575            the time axis view and the mixer strip
1576         */
1577
1578         gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1579         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1580 }
1581
1582 /** @return GUI state ID for things that are common to the route in all its representations */
1583 string
1584 RouteUI::route_state_id () const
1585 {
1586         return string_compose (X_("route %1"), _route->id().to_s());
1587 }
1588
1589 int
1590 RouteUI::set_color_from_route ()
1591 {
1592         const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1593
1594         if (str.empty()) {
1595                 return 1;
1596         }
1597
1598         int r, g, b;
1599
1600         sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1601
1602         _color.set_red (r);
1603         _color.set_green (g);
1604         _color.set_blue (b);
1605
1606         return 0;
1607 }
1608
1609 /** @return true if this name should be used for the route, otherwise false */
1610 bool
1611 RouteUI::verify_new_route_name (const std::string& name)
1612 {
1613         if (name.find (':') == string::npos) {
1614                 return true;
1615         }
1616
1617         MessageDialog colon_msg (
1618                 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1619                 false, MESSAGE_QUESTION, BUTTONS_NONE
1620                 );
1621
1622         colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1623         colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1624
1625         return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1626 }
1627
1628 void
1629 RouteUI::route_rename ()
1630 {
1631         ArdourPrompter name_prompter (true);
1632         string result;
1633         bool done = false;
1634
1635         if (is_track()) {
1636                 name_prompter.set_title (_("Rename Track"));
1637         } else {
1638                 name_prompter.set_title (_("Rename Bus"));
1639         }
1640         name_prompter.set_prompt (_("New name:"));
1641         name_prompter.set_initial_text (_route->name());
1642         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1643         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1644         name_prompter.show_all ();
1645
1646         while (!done) {
1647                 switch (name_prompter.run ()) {
1648                 case Gtk::RESPONSE_ACCEPT:
1649                         name_prompter.get_result (result);
1650                         name_prompter.hide ();
1651                         if (result.length()) {
1652                                 if (verify_new_route_name (result)) {
1653                                         _route->set_name (result);
1654                                         done = true;
1655                                 } else {
1656                                         /* back to name prompter */
1657                                 }
1658
1659                         } else {
1660                                 /* nothing entered, just get out of here */
1661                                 done = true;
1662                         }
1663                         break;
1664                 default:
1665                         done = true;
1666                         break;
1667                 }
1668         }
1669
1670         return;
1671
1672 }
1673
1674 void
1675 RouteUI::property_changed (const PropertyChange& what_changed)
1676 {
1677         if (what_changed.contains (ARDOUR::Properties::name)) {
1678                 name_label.set_text (_route->name());
1679         }
1680 }
1681
1682 void
1683 RouteUI::toggle_comment_editor ()
1684 {
1685 //      if (ignore_toggle) {
1686 //              return;
1687 //      }
1688
1689         if (comment_window && comment_window->is_visible ()) {
1690                 comment_window->hide ();
1691         } else {
1692                 open_comment_editor ();
1693         }
1694 }
1695
1696
1697 void
1698 RouteUI::open_comment_editor ()
1699 {
1700         if (comment_window == 0) {
1701                 setup_comment_editor ();
1702         }
1703
1704         string title;
1705         title = _route->name();
1706         title += _(": comment editor");
1707
1708         comment_window->set_title (title);
1709         comment_window->present();
1710 }
1711
1712 void
1713 RouteUI::setup_comment_editor ()
1714 {
1715         comment_window = new ArdourWindow (""); // title will be reset to show route
1716         comment_window->set_skip_taskbar_hint (true);
1717         comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1718         comment_window->set_default_size (400, 200);
1719
1720         comment_area = manage (new TextView());
1721         comment_area->set_name ("MixerTrackCommentArea");
1722         comment_area->set_wrap_mode (WRAP_WORD);
1723         comment_area->set_editable (true);
1724         comment_area->get_buffer()->set_text (_route->comment());
1725         comment_area->show ();
1726
1727         comment_window->add (*comment_area);
1728 }
1729
1730 void
1731 RouteUI::comment_changed ()
1732 {
1733         ignore_comment_edit = true;
1734         if (comment_area) {
1735                 comment_area->get_buffer()->set_text (_route->comment());
1736         }
1737         ignore_comment_edit = false;
1738 }
1739
1740 void
1741 RouteUI::comment_editor_done_editing ()
1742 {
1743         ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1744
1745         string const str = comment_area->get_buffer()->get_text();
1746         if (str == _route->comment ()) {
1747                 return;
1748         }
1749
1750         _route->set_comment (str, this);
1751 }
1752
1753 void
1754 RouteUI::set_route_active (bool a, bool apply_to_selection)
1755 {
1756         if (apply_to_selection) {
1757                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1758         } else {
1759                 _route->set_active (a, this);
1760         }
1761 }
1762
1763 void
1764 RouteUI::duplicate_selected_routes ()
1765 {
1766         ARDOUR_UI::instance()->start_duplicate_routes();
1767 }
1768
1769 void
1770 RouteUI::toggle_denormal_protection ()
1771 {
1772         if (denormal_menu_item) {
1773
1774                 bool x;
1775
1776                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1777
1778                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1779                         _route->set_denormal_protection (x);
1780                 }
1781         }
1782 }
1783
1784 void
1785 RouteUI::denormal_protection_changed ()
1786 {
1787         if (denormal_menu_item) {
1788                 denormal_menu_item->set_active (_route->denormal_protection());
1789         }
1790 }
1791
1792 void
1793 RouteUI::disconnect_input ()
1794 {
1795         _route->input()->disconnect (this);
1796 }
1797
1798 void
1799 RouteUI::disconnect_output ()
1800 {
1801         _route->output()->disconnect (this);
1802 }
1803
1804 bool
1805 RouteUI::is_track () const
1806 {
1807         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1808 }
1809
1810 boost::shared_ptr<Track>
1811 RouteUI::track() const
1812 {
1813         return boost::dynamic_pointer_cast<Track>(_route);
1814 }
1815
1816 bool
1817 RouteUI::is_audio_track () const
1818 {
1819         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1820 }
1821
1822 boost::shared_ptr<AudioTrack>
1823 RouteUI::audio_track() const
1824 {
1825         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1826 }
1827
1828 bool
1829 RouteUI::is_midi_track () const
1830 {
1831         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1832 }
1833
1834 boost::shared_ptr<MidiTrack>
1835 RouteUI::midi_track() const
1836 {
1837         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1838 }
1839
1840 bool
1841 RouteUI::has_audio_outputs () const
1842 {
1843         return (_route->n_outputs().n_audio() > 0);
1844 }
1845
1846 string
1847 RouteUI::name() const
1848 {
1849         return _route->name();
1850 }
1851
1852 void
1853 RouteUI::map_frozen ()
1854 {
1855         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1856
1857         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1858
1859         if (at) {
1860                 check_rec_enable_sensitivity ();
1861         }
1862 }
1863
1864 void
1865 RouteUI::adjust_latency ()
1866 {
1867         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1868 }
1869
1870 bool
1871 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1872 {
1873         std::string path;
1874         std::string safe_name;
1875         std::string name;
1876
1877         prompter.get_result (name, true);
1878
1879         safe_name = legalize_for_path (name);
1880         safe_name += template_suffix;
1881
1882         path = Glib::build_filename (dir, safe_name);
1883
1884         if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1885                 bool overwrite = overwrite_file_dialog (prompter,
1886                                                         _("Confirm Template Overwrite"),
1887                                                         _("A template already exists with that name. Do you want to overwrite it?"));
1888
1889                 if (!overwrite) {
1890                         return false;
1891                 }
1892         }
1893
1894         _route->save_as_template (path, name);
1895
1896         return true;
1897 }
1898
1899 void
1900 RouteUI::save_as_template ()
1901 {
1902         std::string dir;
1903
1904         dir = ARDOUR::user_route_template_directory ();
1905
1906         if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1907                 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1908                 return;
1909         }
1910
1911         ArdourPrompter prompter (true); // modal
1912
1913         prompter.set_title (_("Save As Template"));
1914         prompter.set_prompt (_("Template name:"));
1915         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1916
1917         bool finished = false;
1918         while (!finished) {
1919                 switch (prompter.run()) {
1920                 case RESPONSE_ACCEPT:
1921                         finished = process_save_template_prompter (prompter, dir);
1922                         break;
1923                 default:
1924                         finished = true;
1925                         break;
1926                 }
1927         }
1928 }
1929
1930 void
1931 RouteUI::check_rec_enable_sensitivity ()
1932 {
1933         if (!rec_enable_button) {
1934                 assert (0); // This should not happen
1935                 return;
1936         }
1937         if (!_session->writable()) {
1938                 rec_enable_button->set_sensitive (false);
1939                 return;
1940         }
1941
1942         if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1943                 rec_enable_button->set_sensitive (false);
1944         } else if (is_audio_track ()  && track()->freeze_state() == AudioTrack::Frozen) {
1945                 rec_enable_button->set_sensitive (false);
1946         } else {
1947                 rec_enable_button->set_sensitive (true);
1948         }
1949         if (_route && _route->record_safe ()) {
1950                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1951         } else {
1952                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1953         }
1954         update_monitoring_display ();
1955 }
1956
1957 void
1958 RouteUI::parameter_changed (string const & p)
1959 {
1960         /* this handles RC and per-session parameter changes */
1961
1962         if (p == "disable-disarm-during-roll") {
1963                 check_rec_enable_sensitivity ();
1964         } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1965                 set_button_names ();
1966         } else if (p == "auto-input") {
1967                 update_monitoring_display ();
1968         } else if (p == "blink-rec-arm") {
1969                 if (UIConfiguration::instance().get_blink_rec_arm()) {
1970                         rec_blink_connection.disconnect ();
1971                         rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1972                 } else {
1973                         rec_blink_connection.disconnect ();
1974                         RouteUI::blink_rec_display(false);
1975                 }
1976         }
1977 }
1978
1979 void
1980 RouteUI::step_gain_up ()
1981 {
1982         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1983 }
1984
1985 void
1986 RouteUI::page_gain_up ()
1987 {
1988         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1989 }
1990
1991 void
1992 RouteUI::step_gain_down ()
1993 {
1994         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1995 }
1996
1997 void
1998 RouteUI::page_gain_down ()
1999 {
2000         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2001 }
2002
2003 void
2004 RouteUI::open_remote_control_id_dialog ()
2005 {
2006         ArdourDialog dialog (_("Remote Control ID"));
2007         SpinButton* spin = 0;
2008
2009         dialog.get_vbox()->set_border_width (18);
2010
2011         if (Config->get_remote_model() == UserOrdered) {
2012                 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2013
2014                 HBox* hbox = manage (new HBox);
2015                 hbox->set_spacing (6);
2016                 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2017                 spin = manage (new SpinButton);
2018                 spin->set_digits (0);
2019                 spin->set_increments (1, 10);
2020                 spin->set_range (0, limit);
2021                 spin->set_value (_route->remote_control_id());
2022                 hbox->pack_start (*spin);
2023                 dialog.get_vbox()->pack_start (*hbox);
2024
2025                 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2026                 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2027         } else {
2028                 Label* l = manage (new Label());
2029                 if (_route->is_master() || _route->is_monitor()) {
2030                         l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2031                                                          "The remote control ID of %3 cannot be changed."),
2032                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2033                                                        _route->remote_control_id(),
2034                                                        (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2035                 } else {
2036                         l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2037                                                          "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2038                                                          "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2039                                                        (is_track() ? _("track") : _("bus")),
2040                                                        _route->remote_control_id(),
2041                                                        "<span size=\"small\" style=\"italic\">",
2042                                                        "</span>",
2043                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2044                                                        PROGRAM_NAME));
2045                 }
2046                 dialog.get_vbox()->pack_start (*l);
2047                 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2048         }
2049
2050         dialog.show_all ();
2051         int const r = dialog.run ();
2052
2053         if (r == RESPONSE_ACCEPT && spin) {
2054                 _route->set_remote_control_id (spin->get_value_as_int ());
2055         }
2056 }
2057
2058 void
2059 RouteUI::setup_invert_buttons ()
2060 {
2061         /* remove old invert buttons */
2062         for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2063                 _invert_button_box.remove (**i);
2064         }
2065
2066         _invert_buttons.clear ();
2067
2068         if (!_route || !_route->input()) {
2069                 return;
2070         }
2071
2072         uint32_t const N = _route->input()->n_ports().n_audio ();
2073
2074         uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2075
2076         for (uint32_t i = 0; i < to_add; ++i) {
2077                 ArdourButton* b = manage (new ArdourButton);
2078                 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2079                 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2080
2081                 b->set_name (X_("invert button"));
2082                 if (to_add == 1) {
2083                         if (N > 1) {
2084                                 b->set_text (string_compose (X_("Ø (%1)"), N));
2085                         } else {
2086                                 b->set_text (X_("Ø"));
2087                         }
2088                 } else {
2089                         b->set_text (string_compose (X_("Ø%1"), i + 1));
2090                 }
2091
2092                 if (N <= _max_invert_buttons) {
2093                         UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) channel %1 of this track.  Right-click to show menu."), i + 1));
2094                 } else {
2095                         UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2096                 }
2097
2098                 _invert_buttons.push_back (b);
2099                 _invert_button_box.pack_start (*b);
2100         }
2101
2102         _invert_button_box.set_spacing (1);
2103         _invert_button_box.show_all ();
2104 }
2105
2106 void
2107 RouteUI::set_invert_button_state ()
2108 {
2109         uint32_t const N = _route->input()->n_ports().n_audio();
2110         if (N > _max_invert_buttons) {
2111
2112                 /* One button for many channels; explicit active if all channels are inverted,
2113                    implicit active if some are, off if none are.
2114                 */
2115
2116                 ArdourButton* b = _invert_buttons.front ();
2117
2118                 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2119                         b->set_active_state (Gtkmm2ext::ExplicitActive);
2120                 } else if (_route->phase_invert().any()) {
2121                         b->set_active_state (Gtkmm2ext::ImplicitActive);
2122                 } else {
2123                         b->set_active_state (Gtkmm2ext::Off);
2124                 }
2125
2126         } else {
2127
2128                 /* One button per channel; just set active */
2129
2130                 int j = 0;
2131                 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2132                         (*i)->set_active (_route->phase_invert (j));
2133                 }
2134
2135         }
2136 }
2137
2138 bool
2139 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2140 {
2141         if (ev->button == 1 && i < _invert_buttons.size()) {
2142                 uint32_t const N = _route->input()->n_ports().n_audio ();
2143                 if (N <= _max_invert_buttons) {
2144                         /* left-click inverts phase so long as we have a button per channel */
2145                         _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2146                         return false;
2147                 }
2148         }
2149         return false;
2150 }
2151
2152
2153 bool
2154 RouteUI::invert_press (GdkEventButton* ev)
2155 {
2156         using namespace Menu_Helpers;
2157
2158         uint32_t const N = _route->input()->n_ports().n_audio();
2159         if (N <= _max_invert_buttons && ev->button != 3) {
2160                 /* If we have an invert button per channel, we only pop
2161                    up a menu on right-click; left click is handled
2162                    on release.
2163                 */
2164                 return false;
2165         }
2166
2167         delete _invert_menu;
2168         _invert_menu = new Menu;
2169         _invert_menu->set_name ("ArdourContextMenu");
2170         MenuList& items = _invert_menu->items ();
2171
2172         for (uint32_t i = 0; i < N; ++i) {
2173                 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2174                 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2175                 ++_i_am_the_modifier;
2176                 e->set_active (_route->phase_invert (i));
2177                 --_i_am_the_modifier;
2178         }
2179
2180         _invert_menu->popup (0, ev->time);
2181
2182         return true;
2183 }
2184
2185 void
2186 RouteUI::invert_menu_toggled (uint32_t c)
2187 {
2188         if (_i_am_the_modifier) {
2189                 return;
2190         }
2191
2192         _route->set_phase_invert (c, !_route->phase_invert (c));
2193 }
2194
2195 void
2196 RouteUI::set_invert_sensitive (bool yn)
2197 {
2198         for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2199                 (*b)->set_sensitive (yn);
2200         }
2201 }
2202
2203 void
2204 RouteUI::request_redraw ()
2205 {
2206         if (_route) {
2207                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2208         }
2209 }
2210
2211 /** The Route's gui_changed signal has been emitted */
2212 void
2213 RouteUI::route_gui_changed (string what_changed)
2214 {
2215         if (what_changed == "color") {
2216                 if (set_color_from_route () == 0) {
2217                         route_color_changed ();
2218                 }
2219         }
2220 }
2221
2222 void
2223 RouteUI::track_mode_changed (void)
2224 {
2225         assert(is_track());
2226         switch (track()->mode()) {
2227                 case ARDOUR::NonLayered:
2228                 case ARDOUR::Normal:
2229                         rec_enable_button->set_icon (ArdourIcon::RecButton);
2230                         break;
2231                 case ARDOUR::Destructive:
2232                         rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2233                         break;
2234         }
2235         rec_enable_button->queue_draw();
2236 }
2237
2238 /** @return the color that this route should use; it maybe its own,
2239     or it maybe that of its route group.
2240 */
2241 Gdk::Color
2242 RouteUI::color () const
2243 {
2244         RouteGroup* g = _route->route_group ();
2245
2246         if (g && g->is_color()) {
2247                 Gdk::Color c;
2248                 set_color_from_rgba (c, GroupTabs::group_color (g));
2249                 return c;
2250         }
2251
2252         return _color;
2253 }
2254
2255 void
2256 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2257 {
2258         _showing_sends_to = send_to;
2259         BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2260 }
2261
2262 void
2263 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2264 {
2265         if (_route == send_to) {
2266                 show_sends_button->set_active (true);
2267                 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2268         } else {
2269                 show_sends_button->set_active (false);
2270                 send_blink_connection.disconnect ();
2271         }
2272 }
2273
2274 RouteGroup*
2275 RouteUI::route_group() const
2276 {
2277         return _route->route_group();
2278 }
2279
2280
2281 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2282         : WM::ProxyBase (name, string())
2283         , _route (boost::weak_ptr<Route> (route))
2284 {
2285         route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2286 }
2287
2288 RoutePinWindowProxy::~RoutePinWindowProxy()
2289 {
2290         _window = 0;
2291 }
2292
2293 ARDOUR::SessionHandlePtr*
2294 RoutePinWindowProxy::session_handle ()
2295 {
2296         ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2297         if (aw) { return aw; }
2298         return 0;
2299 }
2300
2301 Gtk::Window*
2302 RoutePinWindowProxy::get (bool create)
2303 {
2304         boost::shared_ptr<Route> r = _route.lock ();
2305         if (!r) {
2306                 return 0;
2307         }
2308
2309         if (!_window) {
2310                 if (!create) {
2311                         return 0;
2312                 }
2313                 _window = new PluginPinDialog (r);
2314                 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2315                 if (aw) {
2316                         aw->set_session (_session);
2317                 }
2318                 _window->show_all ();
2319         }
2320         return _window;
2321 }
2322
2323 void
2324 RoutePinWindowProxy::route_going_away ()
2325 {
2326         delete _window;
2327         _window = 0;
2328         WM::Manager::instance().remove (this);
2329         going_away_connection.disconnect();
2330 }
2331
2332 void
2333 RouteUI::maybe_add_route_print_mgr ()
2334 {
2335         if (_route->pinmgr_proxy ()) {
2336                 return;
2337         }
2338         RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2339                         string_compose ("RPM-%1", _route->id()), _route);
2340         wp->set_session (_session);
2341
2342         const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2343         if (ui_xml) {
2344                 wp->set_state (*ui_xml, 0);
2345         }
2346
2347 #if 0
2348         void* existing_ui = _route->pinmgr_proxy ();
2349         if (existing_ui) {
2350                 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2351         }
2352 #endif
2353         _route->set_pingmgr_proxy (wp);
2354
2355         WM::Manager::instance().register_window (wp);
2356 }
2357
2358 void
2359 RouteUI::manage_pins ()
2360 {
2361         RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2362         if (proxy) {
2363                 proxy->get (true);
2364                 proxy->present();
2365         }
2366 }