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