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