3f37b73f12bab8f41a8d0763580642a536e836ff
[ardour.git] / gtk2_ardour / route_time_axis.cc
1 /*
2     Copyright (C) 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 #include <cstdlib>
20 #include <cmath>
21 #include <cassert>
22
23 #include <algorithm>
24 #include <string>
25 #include <vector>
26 #include <utility>
27
28 #include <sigc++/bind.h>
29
30 #include <pbd/error.h>
31 #include <pbd/stl_delete.h>
32 #include <pbd/whitespace.h>
33 #include <pbd/memento_command.h>
34
35 #include <gtkmm/menu.h>
36 #include <gtkmm/menuitem.h>
37 #include <gtkmm2ext/gtk_ui.h>
38 #include <gtkmm2ext/selector.h>
39 #include <gtkmm2ext/stop_signal.h>
40 #include <gtkmm2ext/bindable_button.h>
41 #include <gtkmm2ext/utils.h>
42
43 #include <ardour/playlist.h>
44 #include <ardour/audioplaylist.h>
45 #include <ardour/diskstream.h>
46 #include <ardour/processor.h>
47 #include <ardour/ladspa_plugin.h>
48 #include <ardour/location.h>
49 #include <ardour/panner.h>
50 #include <ardour/playlist.h>
51 #include <ardour/session.h>
52 #include <ardour/session_playlist.h>
53 #include <ardour/utils.h>
54 #include <ardour/param_id.h>
55
56 #include "ardour_ui.h"
57 #include "route_time_axis.h"
58 #include "automation_time_axis.h"
59 #include "canvas_impl.h"
60 #include "crossfade_view.h"
61 #include "enums.h"
62 #include "gui_thread.h"
63 #include "keyboard.h"
64 #include "playlist_selector.h"
65 #include "point_selection.h"
66 #include "prompter.h"
67 #include "public_editor.h"
68 #include "region_view.h"
69 #include "rgb_macros.h"
70 #include "selection.h"
71 #include "simplerect.h"
72 #include "streamview.h"
73 #include "utils.h"
74
75 #include <ardour/track.h>
76
77 #include "i18n.h"
78
79 using namespace ARDOUR;
80 using namespace PBD;
81 using namespace Gtk;
82 using namespace Editing;
83 using namespace sigc;
84
85
86 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas)
87         : AxisView(sess),
88           RouteUI(rt, sess, _("m"), _("s"), _("r")), // mute, solo, and record
89           TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas),
90           parent_canvas (canvas),
91           button_table (3, 3),
92           edit_group_button (_("g")), // group
93           playlist_button (_("p")), 
94           size_button (_("h")), // height
95           automation_button (_("a")),
96           visual_button (_("v"))
97
98 {
99         _has_state = true;
100         playlist_menu = 0;
101         playlist_action_menu = 0;
102         automation_action_menu = 0;
103         _view = 0;
104         timestretch_rect = 0;
105         no_redraw = false;
106
107         ignore_toggle = false;
108
109         edit_group_button.set_name ("TrackGroupButton");
110         playlist_button.set_name ("TrackPlaylistButton");
111         automation_button.set_name ("TrackAutomationButton");
112         size_button.set_name ("TrackSizeButton");
113         visual_button.set_name ("TrackVisualButton");
114         hide_button.set_name ("TrackRemoveButton");
115
116         hide_button.add (*(manage (new Image (::get_icon("hide")))));
117         hide_button.show_all ();
118
119         edit_group_button.signal_button_release_event().connect (mem_fun(*this, &RouteTimeAxisView::edit_click), false);
120         playlist_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::playlist_click));
121         automation_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::automation_click));
122         size_button.signal_button_release_event().connect (mem_fun(*this, &RouteTimeAxisView::size_click), false);
123         visual_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::visual_click));
124         hide_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::hide_click));
125
126         solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false);
127         solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release));
128         mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
129         mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release));
130
131         if (is_track()) {
132
133                 /* use icon */
134
135                 rec_enable_button->remove ();
136                 switch (track()->mode()) {
137                 case ARDOUR::Normal:
138                         rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
139                         break;
140                 case ARDOUR::Destructive:
141                         rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red"))))));
142                         break;
143                 }
144                 rec_enable_button->show_all ();
145
146                 rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
147                 rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
148                 controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
149                 ARDOUR_UI::instance()->tooltips().set_tip(*rec_enable_button, _("Record"));
150         }
151
152         controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
153         controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::FILL|Gtk::EXPAND, 0, 0);
154
155         controls_table.attach (edit_group_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
156
157         ARDOUR_UI::instance()->tooltips().set_tip(*solo_button,_("Solo"));
158         ARDOUR_UI::instance()->tooltips().set_tip(*mute_button,_("Mute"));
159         ARDOUR_UI::instance()->tooltips().set_tip(edit_group_button,_("Edit Group"));
160         ARDOUR_UI::instance()->tooltips().set_tip(size_button,_("Display Height"));
161         ARDOUR_UI::instance()->tooltips().set_tip(playlist_button,_("Playlist"));
162         ARDOUR_UI::instance()->tooltips().set_tip(automation_button, _("Automation"));
163         ARDOUR_UI::instance()->tooltips().set_tip(visual_button, _("Visual options"));
164         ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("Hide this track"));
165         
166         label_view ();
167
168         controls_table.attach (hide_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
169         controls_table.attach (visual_button, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
170         controls_table.attach (size_button, 2, 3, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
171         controls_table.attach (automation_button, 3, 4, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
172
173         if (is_track() && track()->mode() == ARDOUR::Normal) {
174                 controls_table.attach (playlist_button, 5, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
175         }
176
177         /* remove focus from the buttons */
178         
179         y_position = -1;
180
181         _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
182         _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
183         _route->processors_changed.connect (mem_fun(*this, &RouteTimeAxisView::processors_changed));
184         _route->NameChanged.connect (mem_fun(*this, &RouteTimeAxisView::route_name_changed));
185         _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
186
187
188         if (is_track()) {
189
190                 track()->TrackModeChanged.connect (mem_fun(*this, &RouteTimeAxisView::track_mode_changed));
191                 track()->FreezeChange.connect (mem_fun(*this, &RouteTimeAxisView::map_frozen));
192                 track()->DiskstreamChanged.connect (mem_fun(*this, &RouteTimeAxisView::diskstream_changed));
193                 get_diskstream()->SpeedChanged.connect (mem_fun(*this, &RouteTimeAxisView::speed_changed));
194
195                 /* pick up the correct freeze state */
196                 map_frozen ();
197
198         }
199
200         editor.ZoomChanged.connect (mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit));
201         ColorsChanged.connect (mem_fun (*this, &RouteTimeAxisView::color_handler));
202 }
203
204 RouteTimeAxisView::~RouteTimeAxisView ()
205 {
206         GoingAway (); /* EMIT_SIGNAL */
207
208         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
209                 delete *i;
210         }
211
212         if (playlist_menu) {
213                 delete playlist_menu;
214                 playlist_menu = 0;
215         }
216   
217         if (playlist_action_menu) {
218                 delete playlist_action_menu;
219                 playlist_action_menu = 0;
220         }
221
222         if (_view) {
223                 delete _view;
224                 _view = 0;
225         }
226 }
227
228 void
229 RouteTimeAxisView::post_construct ()
230 {
231         /* map current state of the route */
232
233         update_diskstream_display ();
234         _route->foreach_processor (this, &RouteTimeAxisView::add_processor_to_subplugin_menu);
235         _route->foreach_processor (this, &RouteTimeAxisView::add_existing_processor_automation_curves);
236         reset_processor_automation_curves ();
237 }
238
239 void
240 RouteTimeAxisView::set_playlist (boost::shared_ptr<Playlist> newplaylist)
241 {
242         boost::shared_ptr<Playlist> pl = playlist();
243         assert(pl);
244
245         modified_connection.disconnect ();
246         modified_connection = pl->Modified.connect (mem_fun(*this, &RouteTimeAxisView::playlist_modified));
247 }
248
249 void
250 RouteTimeAxisView::playlist_modified ()
251 {
252 }
253
254 void
255 RouteTimeAxisView::set_state (const XMLNode& node)
256 {
257         const XMLProperty *prop;
258         
259         TimeAxisView::set_state (node);
260         
261         if ((prop = node.property ("shown_editor")) != 0) {
262                 if (prop->value() == "no") {
263                         _marked_for_display = false;
264                 } else {
265                         _marked_for_display = true;
266                 }
267         } else {
268                 _marked_for_display = true;
269         }
270         
271         XMLNodeList nlist = node.children();
272         XMLNodeConstIterator niter;
273         XMLNode *child_node;
274         
275         _show_automation.clear();
276         
277         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
278                 child_node = *niter;
279                 
280                 ParamID param(child_node->name());
281
282                 if (param) {
283                 
284                         XMLProperty* prop = child_node->property ("shown");
285                         
286                         if (_automation_tracks.find(param) == _automation_tracks.end())
287                                 create_automation_child(param);
288
289                         if (prop != 0 && prop->value() == "yes")
290                                 _show_automation.insert(ParamID(GainAutomation));
291
292                 } else {
293                         warning << "GUI info exists, but no parameter " << child_node->name() << " found." << endmsg;
294                 }
295         }
296 }
297
298 XMLNode* 
299 RouteTimeAxisView::get_child_xml_node (const string & childname)
300 {
301         return RouteUI::get_child_xml_node (childname);
302 }
303
304 gint
305 RouteTimeAxisView::edit_click (GdkEventButton *ev)
306 {
307         if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
308                 _route->set_edit_group (0, this);
309                 return FALSE;
310         } 
311
312         using namespace Menu_Helpers;
313
314         MenuList& items = edit_group_menu.items ();
315         RadioMenuItem::Group group;
316
317         items.clear ();
318         items.push_back (RadioMenuElem (group, _("No group"), 
319                                         bind (mem_fun(*this, &RouteTimeAxisView::set_edit_group_from_menu), (RouteGroup *) 0)));
320         
321         if (_route->edit_group() == 0) {
322                 static_cast<RadioMenuItem*>(&items.back())->set_active ();
323         }
324         
325         _session.foreach_edit_group (bind (mem_fun (*this, &RouteTimeAxisView::add_edit_group_menu_item), &group));
326         edit_group_menu.popup (ev->button, ev->time);
327
328         return FALSE;
329 }
330
331 void
332 RouteTimeAxisView::add_edit_group_menu_item (RouteGroup *eg, RadioMenuItem::Group* group)
333 {
334         using namespace Menu_Helpers;
335
336         MenuList &items = edit_group_menu.items();
337
338         items.push_back (RadioMenuElem (*group, eg->name(), bind (mem_fun(*this, &RouteTimeAxisView::set_edit_group_from_menu), eg)));
339         if (_route->edit_group() == eg) {
340                 static_cast<RadioMenuItem*>(&items.back())->set_active ();
341         }
342 }
343
344 void
345 RouteTimeAxisView::set_edit_group_from_menu (RouteGroup *eg)
346 {
347         _route->set_edit_group (eg, this);
348 }
349
350 void
351 RouteTimeAxisView::playlist_changed ()
352
353 {
354         label_view ();
355
356         if (is_track()) {
357                 set_playlist (get_diskstream()->playlist());
358         }
359 }
360
361 void
362 RouteTimeAxisView::label_view ()
363 {
364         string x = _route->name();
365
366         if (x != name_entry.get_text()) {
367                 name_entry.set_text (x);
368         }
369
370         ARDOUR_UI::instance()->tooltips().set_tip (name_entry, x);
371 }
372
373 void
374 RouteTimeAxisView::route_name_changed ()
375 {
376         editor.route_name_changed (this);
377         label_view ();
378 }
379
380 void
381 RouteTimeAxisView::take_name_changed (void *src)
382
383 {
384         if (src != this) {
385                 label_view ();
386         }
387 }
388
389 void
390 RouteTimeAxisView::playlist_click ()
391 {
392         // always build a new action menu
393         
394         if (playlist_action_menu != 0) {
395                 delete playlist_action_menu;
396         } 
397
398         playlist_action_menu = new Menu;
399         playlist_action_menu->set_name ("ArdourContextMenu");
400         
401         build_playlist_menu (playlist_action_menu);
402         editor.set_selected_track (*this, Selection::Add);
403         playlist_action_menu->popup (1, gtk_get_current_event_time());
404 }
405
406 void
407 RouteTimeAxisView::automation_click ()
408 {
409         if (automation_action_menu == 0) {
410                 /* this seems odd, but the automation action
411                    menu is built as part of the display menu.
412                 */
413                 build_display_menu ();
414         }
415         editor.set_selected_track (*this, Selection::Add);
416         automation_action_menu->popup (1, gtk_get_current_event_time());
417 }
418
419 void
420 RouteTimeAxisView::build_automation_action_menu ()
421 {
422         using namespace Menu_Helpers;
423
424         automation_action_menu = manage (new Menu);
425         MenuList& automation_items = automation_action_menu->items();
426         automation_action_menu->set_name ("ArdourContextMenu");
427         
428         automation_items.push_back (MenuElem (_("Show all automation"),
429                                               mem_fun(*this, &RouteTimeAxisView::show_all_automation)));
430
431         automation_items.push_back (MenuElem (_("Show existing automation"),
432                                               mem_fun(*this, &RouteTimeAxisView::show_existing_automation)));
433
434         automation_items.push_back (MenuElem (_("Hide all automation"),
435                                               mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
436
437         automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu));
438         
439         map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i;
440         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
441
442                 automation_items.push_back (SeparatorElem());
443
444                 if ( ! i->second->menu_item) {
445                         automation_items.push_back(CheckMenuElem (_route->describe_parameter(i->second->param), 
446                                         bind (mem_fun(*this, &RouteTimeAxisView::toggle_automation_track), i->second->param)));
447
448                         i->second->menu_item = static_cast<Gtk::CheckMenuItem*>(&automation_items.back());
449
450                 } else {
451                         automation_items.push_back (*i->second->menu_item);
452                 }
453                 
454                 //i->second->menu_item->set_active(show_automation(i->second->param));
455                 i->second->menu_item->set_active(false);
456         }
457 }
458
459 void
460 RouteTimeAxisView::build_display_menu ()
461 {
462         using namespace Menu_Helpers;
463
464         /* get the size menu ready */
465
466         build_size_menu ();
467
468         /* prepare it */
469
470         TimeAxisView::build_display_menu ();
471
472         /* now fill it with our stuff */
473
474         MenuList& items = display_menu->items();
475         display_menu->set_name ("ArdourContextMenu");
476         
477         items.push_back (MenuElem (_("Height"), *size_menu));
478         items.push_back (MenuElem (_("Color"), mem_fun(*this, &RouteTimeAxisView::select_track_color)));
479
480         items.push_back (SeparatorElem());
481
482         build_remote_control_menu ();
483         items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu));
484
485         build_automation_action_menu ();
486         items.push_back (MenuElem (_("Automation"), *automation_action_menu));
487
488         // Hook for derived classes to add type specific stuff
489         items.push_back (SeparatorElem());
490         append_extra_display_menu_items ();
491         items.push_back (SeparatorElem());
492         
493         if (is_track()) {
494
495                 Menu* alignment_menu = manage (new Menu);
496                 MenuList& alignment_items = alignment_menu->items();
497                 alignment_menu->set_name ("ArdourContextMenu");
498
499                 RadioMenuItem::Group align_group;
500                 
501                 alignment_items.push_back (RadioMenuElem (align_group, _("Align with existing material"),
502                         bind (mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial)));
503                 align_existing_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
504                 if (get_diskstream()->alignment_style() == ExistingMaterial)
505                         align_existing_item->set_active();
506                 
507                 alignment_items.push_back (RadioMenuElem (align_group, _("Align with capture time"),
508                         bind (mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime)));
509                 align_capture_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
510                 if (get_diskstream()->alignment_style() == CaptureTime)
511                         align_capture_item->set_active();
512                 
513                 items.push_back (MenuElem (_("Alignment"), *alignment_menu));
514
515                 get_diskstream()->AlignmentStyleChanged.connect (
516                         mem_fun(*this, &RouteTimeAxisView::align_style_changed));
517
518                 RadioMenuItem::Group mode_group;
519                 items.push_back (RadioMenuElem (mode_group, _("Normal mode"),
520                                                 bind (mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal)));
521                 normal_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
522                 items.push_back (RadioMenuElem (mode_group, _("Tape mode"),
523                                                 bind (mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive)));
524                 destructive_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
525                                  
526                 
527                 switch (track()->mode()) {
528                 case ARDOUR::Destructive:
529                         destructive_track_mode_item->set_active ();
530                         break;
531                 case ARDOUR::Normal:
532                         normal_track_mode_item->set_active ();
533                         break;
534                 }
535         }
536
537         items.push_back (SeparatorElem());
538         items.push_back (CheckMenuElem (_("Active"), mem_fun(*this, &RouteUI::toggle_route_active)));
539         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
540         route_active_menu_item->set_active (_route->active());
541
542         items.push_back (SeparatorElem());
543         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
544 }
545
546 static bool __reset_item (RadioMenuItem* item)
547 {
548         item->set_active ();
549         return false;
550 }
551
552 void
553 RouteTimeAxisView::set_track_mode (TrackMode mode)
554 {
555         RadioMenuItem* item;
556         RadioMenuItem* other_item;
557
558         switch (mode) {
559         case ARDOUR::Normal:
560                 item = normal_track_mode_item;
561                 other_item = destructive_track_mode_item;
562                 break;
563         case ARDOUR::Destructive:
564                 item = destructive_track_mode_item;
565                 other_item = normal_track_mode_item;
566                 break;
567         default:
568                 fatal << string_compose (_("programming error: %1 %2"), "illegal track mode in RouteTimeAxisView::set_track_mode", mode) << endmsg;
569                 /*NOTREACHED*/
570                 return;
571         }
572
573         if (item->get_active () && track()->mode() != mode) {
574                 _set_track_mode (track().get(), mode, other_item);
575         }
576 }
577
578 void
579 RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem* reset_item)
580 {
581         bool needs_bounce;
582
583         if (!track->can_use_mode (mode, needs_bounce)) {
584
585                 if (!needs_bounce) {
586                         /* cannot be done */
587                         Glib::signal_idle().connect (bind (sigc::ptr_fun (__reset_item), reset_item));
588                         return;
589                 } else {
590                         cerr << "would bounce this one\n";
591                         return;
592                 }
593         }
594
595         track->set_mode (mode);
596
597         rec_enable_button->remove ();
598         switch (mode) {
599         case ARDOUR::Normal:
600                 rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
601                 break;
602         case ARDOUR::Destructive:
603                 rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red"))))));
604                 break;
605         }
606         rec_enable_button->show_all ();
607
608 }
609
610 void
611 RouteTimeAxisView::track_mode_changed ()
612 {
613         RadioMenuItem* item;
614         
615         switch (track()->mode()) {
616         case ARDOUR::Normal:
617                 item = normal_track_mode_item;
618                 break;
619         case ARDOUR::Destructive:
620                 item = destructive_track_mode_item;
621                 break;
622         default:
623                 fatal << string_compose (_("programming error: %1 %2"), "illegal track mode in RouteTimeAxisView::set_track_mode", track()->mode()) << endmsg;
624                 /*NOTREACHED*/
625                 return;
626         }
627
628         item->set_active ();
629 }
630
631 void
632 RouteTimeAxisView::show_timestretch (nframes_t start, nframes_t end)
633 {
634         double x1;
635         double x2;
636         double y2;
637         
638         TimeAxisView::show_timestretch (start, end);
639
640         hide_timestretch ();
641
642 #if 0   
643         if (ts.empty()) {
644                 return;
645         }
646
647
648         /* check that the time selection was made in our route, or our edit group.
649            remember that edit_group() == 0 implies the route is *not* in a edit group.
650         */
651
652         if (!(ts.track == this || (ts.group != 0 && ts.group == _route->edit_group()))) {
653                 /* this doesn't apply to us */
654                 return;
655         }
656
657         /* ignore it if our edit group is not active */
658         
659         if ((ts.track != this) && _route->edit_group() && !_route->edit_group()->is_active()) {
660                 return;
661         }
662 #endif
663
664         if (timestretch_rect == 0) {
665                 timestretch_rect = new SimpleRect (*canvas_display);
666                 timestretch_rect->property_x1() =  0.0;
667                 timestretch_rect->property_y1() =  0.0;
668                 timestretch_rect->property_x2() =  0.0;
669                 timestretch_rect->property_y2() =  0.0;
670                 timestretch_rect->property_fill_color_rgba() =  ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
671                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
672         }
673
674         timestretch_rect->show ();
675         timestretch_rect->raise_to_top ();
676
677         x1 = start / editor.get_current_zoom();
678         x2 = (end - 1) / editor.get_current_zoom();
679         y2 = height - 2;
680         
681         timestretch_rect->property_x1() = x1;
682         timestretch_rect->property_y1() = 1.0;
683         timestretch_rect->property_x2() = x2;
684         timestretch_rect->property_y2() = y2;
685 }
686
687 void
688 RouteTimeAxisView::hide_timestretch ()
689 {
690         TimeAxisView::hide_timestretch ();
691
692         if (timestretch_rect) {
693                 timestretch_rect->hide ();
694         }
695 }
696
697 void
698 RouteTimeAxisView::show_selection (TimeSelection& ts)
699 {
700
701 #if 0
702         /* ignore it if our edit group is not active or if the selection was started
703            in some other track or edit group (remember that edit_group() == 0 means
704            that the track is not in an edit group).
705         */
706
707         if (((ts.track != this && !is_child (ts.track)) && _route->edit_group() && !_route->edit_group()->is_active()) ||
708             (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->edit_group())))) {
709                 hide_selection ();
710                 return;
711         }
712 #endif
713
714         TimeAxisView::show_selection (ts);
715 }
716
717 void
718 RouteTimeAxisView::set_height (TrackHeight h)
719 {
720         bool height_changed = (height == 0) || (h != height_style);
721
722         TimeAxisView::set_height (h);
723
724         ensure_xml_node ();
725
726         if (_view) {
727                 _view->set_height ((double) height);
728         }
729
730         switch (height_style) {
731         case Largest:
732                 xml_node->add_property ("track_height", "largest");
733                 break;
734
735         case Large:
736                 xml_node->add_property ("track_height", "large");
737                 break;
738
739         case Larger:
740                 xml_node->add_property ("track_height", "larger");
741                 break;
742
743         case Normal:
744                 xml_node->add_property ("track_height", "normal");
745                 break;
746
747         case Smaller:
748                 xml_node->add_property ("track_height", "smaller");
749                 break;
750
751         case Small:
752                 xml_node->add_property ("track_height", "small");
753                 break;
754         }
755
756         switch (height_style) {
757         case Largest:
758         case Large:
759         case Larger:
760         case Normal:
761                 show_name_entry ();
762                 hide_name_label ();
763
764                 mute_button->show();
765                 solo_button->show();
766                 if (rec_enable_button)
767                         rec_enable_button->show();
768
769                 edit_group_button.show();
770                 hide_button.show();
771                 visual_button.show();
772                 size_button.show();
773                 automation_button.show();
774                 
775                 if (is_track() && track()->mode() == ARDOUR::Normal) {
776                         playlist_button.show();
777                 }
778                 break;
779
780         case Smaller:
781                 show_name_entry ();
782                 hide_name_label ();
783
784                 mute_button->show();
785                 solo_button->show();
786                 if (rec_enable_button)
787                         rec_enable_button->show();
788
789                 edit_group_button.hide ();
790                 hide_button.hide ();
791                 visual_button.hide ();
792                 size_button.hide ();
793                 automation_button.hide ();
794                 
795                 if (is_track() && track()->mode() == ARDOUR::Normal) {
796                         playlist_button.hide ();
797                 }
798                 break;
799
800         case Small:
801                 hide_name_entry ();
802                 show_name_label ();
803
804                 mute_button->hide();
805                 solo_button->hide();
806                 if (rec_enable_button)
807                         rec_enable_button->hide();
808
809                 edit_group_button.hide ();
810                 hide_button.hide ();
811                 visual_button.hide ();
812                 size_button.hide ();
813                 automation_button.hide ();
814                 playlist_button.hide ();
815                 name_label.set_text (_route->name());
816                 break;
817         }
818
819         if (height_changed) {
820                 /* only emit the signal if the height really changed */
821                  _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
822         }
823 }
824
825 void
826 RouteTimeAxisView::select_track_color ()
827 {
828         if (RouteUI::choose_color ()) {
829
830                 if (_view) {
831                         _view->apply_color (_color, StreamView::RegionColor);
832                 }
833         }
834 }
835
836 void
837 RouteTimeAxisView::reset_samples_per_unit ()
838 {
839         set_samples_per_unit (editor.get_current_zoom());
840 }
841
842 void
843 RouteTimeAxisView::set_samples_per_unit (double spu)
844 {
845         double speed = 1.0;
846
847         if (get_diskstream() != 0) {
848                 speed = get_diskstream()->speed();
849         }
850         
851         if (_view) {
852                 _view->set_samples_per_unit (spu * speed);
853         }
854
855         TimeAxisView::set_samples_per_unit (spu * speed);
856 }
857
858 void
859 RouteTimeAxisView::align_style_changed ()
860 {
861         switch (get_diskstream()->alignment_style()) {
862         case ExistingMaterial:
863                 if (!align_existing_item->get_active()) {
864                         align_existing_item->set_active();
865                 }
866                 break;
867         case CaptureTime:
868                 if (!align_capture_item->get_active()) {
869                         align_capture_item->set_active();
870                 }
871                 break;
872         }
873 }
874
875 void
876 RouteTimeAxisView::set_align_style (AlignStyle style)
877 {
878         RadioMenuItem* item;
879
880         switch (style) {
881         case ExistingMaterial:
882                 item = align_existing_item;
883                 break;
884         case CaptureTime:
885                 item = align_capture_item;
886                 break;
887         default:
888                 fatal << string_compose (_("programming error: %1 %2"), "illegal align style in RouteTimeAxisView::set_align_style", style) << endmsg;
889                 /*NOTREACHED*/
890                 return;
891         }
892
893         if (item->get_active()) {
894                 get_diskstream()->set_align_style (style);
895         }
896 }
897
898 void
899 RouteTimeAxisView::rename_current_playlist ()
900 {
901         ArdourPrompter prompter (true);
902         string name;
903
904         boost::shared_ptr<Diskstream> ds = get_diskstream();
905         if (!ds || ds->destructive())
906                 return;
907
908         boost::shared_ptr<Playlist> pl = ds->playlist();
909         if (!pl)
910                 return;
911
912         prompter.set_prompt (_("Name for playlist"));
913         prompter.set_initial_text (pl->name());
914         prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
915         prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
916
917         switch (prompter.run ()) {
918         case Gtk::RESPONSE_ACCEPT:
919                 prompter.get_result (name);
920                 if (name.length()) {
921                         pl->set_name (name);
922                 }
923                 break;
924
925         default:
926                 break;
927         }
928 }
929
930 void
931 RouteTimeAxisView::use_copy_playlist (bool prompt)
932 {
933         string name;
934         
935         boost::shared_ptr<Diskstream> ds = get_diskstream();
936         if (!ds || ds->destructive())
937                 return;
938
939         boost::shared_ptr<const Playlist> pl = ds->playlist();
940         if (!pl)
941                 return;
942
943         name = pl->name();
944
945         do {
946                 name = Playlist::bump_name (name, _session);
947         } while (_session.playlist_by_name(name));
948
949         // TODO: The prompter "new" button should be de-activated if the user
950         // specifies a playlist name which already exists in the session.
951
952         if (prompt) {
953
954                 ArdourPrompter prompter (true);
955                 
956                 prompter.set_prompt (_("Name for Playlist"));
957                 prompter.set_initial_text (name);
958                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
959                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
960                 prompter.show_all ();
961                 
962                 switch (prompter.run ()) {
963                 case Gtk::RESPONSE_ACCEPT:
964                         prompter.get_result (name);
965                         break;
966                         
967                 default:
968                         return;
969                 }
970         }
971
972         if (name.length()) {
973                 ds->use_copy_playlist ();
974                 ds->playlist()->set_name (name);
975         }
976 }
977
978 void
979 RouteTimeAxisView::use_new_playlist (bool prompt)
980 {
981         string name;
982         
983         boost::shared_ptr<Diskstream> ds = get_diskstream();
984         if (!ds || ds->destructive())
985                 return;
986
987         boost::shared_ptr<const Playlist> pl = ds->playlist();
988         if (!pl)
989                 return;
990
991         name = pl->name();
992
993         do {
994                 name = Playlist::bump_name (name, _session);
995         } while (_session.playlist_by_name(name));
996
997
998         if (prompt) {
999                 
1000                 ArdourPrompter prompter (true);
1001                 
1002                 prompter.set_prompt (_("Name for Playlist"));
1003                 prompter.set_initial_text (name);
1004                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1005                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1006
1007                 switch (prompter.run ()) {
1008                 case Gtk::RESPONSE_ACCEPT:
1009                         prompter.get_result (name);
1010                         break;
1011                         
1012                 default:
1013                         return;
1014                 }
1015         }
1016
1017         if (name.length()) {
1018                 ds->use_new_playlist ();
1019                 ds->playlist()->set_name (name);
1020         }
1021 }
1022
1023 void
1024 RouteTimeAxisView::clear_playlist ()
1025 {
1026         boost::shared_ptr<Diskstream> ds = get_diskstream();
1027         if (!ds || ds->destructive())
1028                 return;
1029
1030         boost::shared_ptr<Playlist> pl = ds->playlist();
1031         if (!pl)
1032                 return;
1033
1034         editor.clear_playlist (pl);
1035 }
1036
1037 void
1038 RouteTimeAxisView::speed_changed ()
1039 {
1040         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit));
1041 }
1042
1043 void
1044 RouteTimeAxisView::diskstream_changed ()
1045 {
1046         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &RouteTimeAxisView::update_diskstream_display));
1047 }       
1048
1049 void
1050 RouteTimeAxisView::update_diskstream_display ()
1051 {
1052         if (!get_diskstream()) // bus
1053                 return;
1054
1055         set_playlist (get_diskstream()->playlist());
1056         map_frozen ();
1057 }       
1058
1059 void
1060 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1061 {
1062         if (Keyboard::modifier_state_equals (ev->state, (Keyboard::Shift|Keyboard::Control))) {
1063
1064                 /* special case: select/deselect all tracks */
1065                 if (editor.get_selection().selected (this)) {
1066                         editor.get_selection().clear_tracks ();
1067                 } else {
1068                         editor.select_all_tracks ();
1069                 }
1070
1071                 return;
1072         } 
1073
1074         PublicEditor::TrackViewList* tracks = editor.get_valid_views (this, _route->edit_group());
1075
1076         switch (Keyboard::selection_type (ev->state)) {
1077         case Selection::Toggle:
1078                 editor.get_selection().toggle (*tracks);
1079                 break;
1080                 
1081         case Selection::Set:
1082                 editor.get_selection().set (*tracks);
1083                 break;
1084
1085         case Selection::Extend:
1086                 if (tracks->size() > 1) {
1087                         /* add each one, do not "extend" */
1088                         editor.get_selection().add (*tracks);
1089                 } else {
1090                         /* extend to the single track */
1091                         editor.extend_selection_to_track (*tracks->front());
1092                 }
1093                 break;
1094
1095         case Selection::Add:
1096                 editor.get_selection().add (*tracks);
1097                 break;
1098         }
1099
1100         delete tracks;
1101 }
1102
1103 void
1104 RouteTimeAxisView::set_selected_points (PointSelection& points)
1105 {
1106         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1107                 (*i)->set_selected_points (points);
1108         }
1109 }
1110
1111 void
1112 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1113 {
1114         if (_view) {
1115                 _view->set_selected_regionviews (regions);
1116         }
1117 }
1118
1119 /** Add the selectable things that we have to a list.
1120  * @param results List to add things to.
1121  */
1122 void
1123 RouteTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
1124 {
1125         double speed = 1.0;
1126         
1127         if (get_diskstream() != 0) {
1128                 speed = get_diskstream()->speed();
1129         }
1130         
1131         nframes_t start_adjusted = session_frame_to_track_frame(start, speed);
1132         nframes_t end_adjusted   = session_frame_to_track_frame(end, speed);
1133
1134         if (_view && ((top < 0.0 && bot < 0.0)) || touched (top, bot)) {
1135                 _view->get_selectables (start_adjusted, end_adjusted, results);
1136         }
1137
1138         /* pick up visible automation tracks */
1139         
1140         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1141                 if (!(*i)->hidden()) {
1142                         (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1143                 }
1144         }
1145 }
1146
1147 void
1148 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1149 {
1150         if (_view) {
1151                 _view->get_inverted_selectables (sel, results);
1152         }
1153
1154         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1155                 if (!(*i)->hidden()) {
1156                         (*i)->get_inverted_selectables (sel, results);
1157                 }
1158         }
1159
1160         return;
1161 }
1162
1163 bool
1164 RouteTimeAxisView::show_automation(ParamID param)
1165 {
1166         return (_show_automation.find(param) != _show_automation.end());
1167 }
1168
1169 /** Retuns NULL if track for \a param doesn't exist.
1170  */
1171 RouteTimeAxisView::RouteAutomationNode*
1172 RouteTimeAxisView::automation_track(ParamID param)
1173 {
1174         map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i = _automation_tracks.find(param);
1175
1176         if (i != _automation_tracks.end())
1177                 return i->second;
1178         else
1179                 return NULL;
1180 }
1181
1182 /** Shorthand for GainAutomation, etc.
1183  */     
1184 RouteTimeAxisView::RouteAutomationNode*
1185 RouteTimeAxisView::automation_track(AutomationType type)
1186 {
1187         return automation_track(ParamID(type));
1188 }
1189
1190 RouteGroup*
1191 RouteTimeAxisView::edit_group() const
1192 {
1193         return _route->edit_group();
1194 }
1195
1196 string
1197 RouteTimeAxisView::name() const
1198 {
1199         return _route->name();
1200 }
1201
1202 boost::shared_ptr<Playlist>
1203 RouteTimeAxisView::playlist () const 
1204 {
1205         boost::shared_ptr<Diskstream> ds;
1206
1207         if ((ds = get_diskstream()) != 0) {
1208                 return ds->playlist(); 
1209         } else {
1210                 return boost::shared_ptr<Playlist> ();
1211         }
1212 }
1213
1214 void
1215 RouteTimeAxisView::name_entry_changed ()
1216 {
1217         string x;
1218
1219         x = name_entry.get_text ();
1220         
1221         if (x == _route->name()) {
1222                 return;
1223         }
1224
1225         strip_whitespace_edges(x);
1226
1227         if (x.length() == 0) {
1228                 name_entry.set_text (_route->name());
1229                 return;
1230         }
1231
1232         if (_session.route_name_unique (x)) {
1233                 _route->set_name (x);
1234         } else {
1235                 ARDOUR_UI::instance()->popup_error (_("A track already exists with that name"));
1236                 name_entry.set_text (_route->name());
1237         }
1238 }
1239
1240 void
1241 RouteTimeAxisView::visual_click ()
1242 {
1243         popup_display_menu (0);
1244 }
1245
1246 void
1247 RouteTimeAxisView::hide_click ()
1248 {
1249         // LAME fix for hide_button refresh fix
1250         hide_button.set_sensitive(false);
1251         
1252         editor.hide_track_in_display (*this);
1253         
1254         hide_button.set_sensitive(true);
1255 }
1256
1257 boost::shared_ptr<Region>
1258 RouteTimeAxisView::find_next_region (nframes_t pos, RegionPoint point, int32_t dir)
1259 {
1260         boost::shared_ptr<Diskstream> stream;
1261         boost::shared_ptr<Playlist> playlist;
1262
1263         if ((stream = get_diskstream()) != 0 && (playlist = stream->playlist()) != 0) {
1264                 return playlist->find_next_region (pos, point, dir);
1265         }
1266
1267         return boost::shared_ptr<Region> ();
1268 }
1269
1270 bool
1271 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1272 {
1273         boost::shared_ptr<Playlist> what_we_got;
1274         boost::shared_ptr<Diskstream> ds = get_diskstream();
1275         boost::shared_ptr<Playlist> playlist;
1276         bool ret = false;
1277
1278         if (ds == 0) {
1279                 /* route is a bus, not a track */
1280                 return false;
1281         }
1282
1283         playlist = ds->playlist();
1284
1285         TimeSelection time (selection.time);
1286         float speed = ds->speed();
1287         if (speed != 1.0f) {
1288                 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1289                         (*i).start = session_frame_to_track_frame((*i).start, speed);
1290                         (*i).end   = session_frame_to_track_frame((*i).end,   speed);
1291                 }
1292         }
1293         
1294         XMLNode &before = playlist->get_state();
1295         switch (op) {
1296         case Cut:
1297                 if ((what_we_got = playlist->cut (time)) != 0) {
1298                         editor.get_cut_buffer().add (what_we_got);
1299                         _session.add_command( new MementoCommand<Playlist>(*playlist.get(), &before, &playlist->get_state()));
1300                         ret = true;
1301                 }
1302                 break;
1303         case Copy:
1304                 if ((what_we_got = playlist->copy (time)) != 0) {
1305                         editor.get_cut_buffer().add (what_we_got);
1306                 }
1307                 break;
1308
1309         case Clear:
1310                 if ((what_we_got = playlist->cut (time)) != 0) {
1311                         _session.add_command( new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1312                         what_we_got->release ();
1313                         ret = true;
1314                 }
1315                 break;
1316         }
1317
1318         return ret;
1319 }
1320
1321 bool
1322 RouteTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
1323 {
1324         if (!is_track()) {
1325                 return false;
1326         }
1327
1328         boost::shared_ptr<Playlist> playlist = get_diskstream()->playlist();
1329         PlaylistSelection::iterator p;
1330         
1331         for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth);
1332
1333         if (p == selection.playlists.end()) {
1334                 return false;
1335         }
1336
1337         if (get_diskstream()->speed() != 1.0f)
1338                 pos = session_frame_to_track_frame(pos, get_diskstream()->speed() );
1339         
1340         XMLNode &before = playlist->get_state();
1341         playlist->paste (*p, pos, times);
1342         _session.add_command( new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1343
1344         return true;
1345 }
1346
1347
1348 TimeAxisView::Children
1349 RouteTimeAxisView::get_child_list()
1350 {
1351         TimeAxisView::Children redirect_children;
1352         
1353         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1354                 if (!(*i)->hidden()) {
1355                         redirect_children.push_back(*i);
1356                 }
1357         }
1358         return redirect_children;
1359 }
1360
1361
1362 void
1363 RouteTimeAxisView::build_playlist_menu (Gtk::Menu * menu)
1364 {
1365         using namespace Menu_Helpers;
1366
1367         if (!menu || !is_track()) {
1368                 return;
1369         }
1370
1371         MenuList& playlist_items = menu->items();
1372         menu->set_name ("ArdourContextMenu");
1373         playlist_items.clear();
1374
1375         if (playlist_menu) {
1376                 delete playlist_menu;
1377         }
1378
1379         playlist_menu = new Menu;
1380         playlist_menu->set_name ("ArdourContextMenu");
1381
1382         vector<boost::shared_ptr<Playlist> > playlists;
1383         boost::shared_ptr<Diskstream> ds = get_diskstream();
1384         RadioMenuItem::Group playlist_group;
1385
1386         _session.get_playlists (playlists);
1387         
1388         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
1389
1390                 if ((*i)->get_orig_diskstream_id() == ds->id()) {
1391                         playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name(), bind (mem_fun (*this, &RouteTimeAxisView::use_playlist),
1392                                                                                                      boost::weak_ptr<Playlist> (*i))));
1393
1394                         if (ds->playlist()->id() == (*i)->id()) {
1395                                 static_cast<RadioMenuItem*>(&playlist_items.back())->set_active();
1396                         }
1397                 } else if (ds->playlist()->id() == (*i)->id()) {
1398                         playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name(), bind (mem_fun (*this, &RouteTimeAxisView::use_playlist), 
1399                                                                                                      boost::weak_ptr<Playlist>(*i))));
1400                         static_cast<RadioMenuItem*>(&playlist_items.back())->set_active();
1401                         
1402                 }
1403         }
1404
1405         playlist_items.push_back (SeparatorElem());
1406         playlist_items.push_back (MenuElem (_("Rename"), mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1407         playlist_items.push_back (SeparatorElem());
1408
1409         playlist_items.push_back (MenuElem (_("New"), mem_fun(editor, &PublicEditor::new_playlists)));
1410         playlist_items.push_back (MenuElem (_("New Copy"), mem_fun(editor, &PublicEditor::copy_playlists)));
1411         playlist_items.push_back (SeparatorElem());
1412         playlist_items.push_back (MenuElem (_("Clear Current"), mem_fun(editor, &PublicEditor::clear_playlists)));
1413         playlist_items.push_back (SeparatorElem());
1414
1415         playlist_items.push_back (MenuElem(_("Select from all ..."), mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1416 }
1417
1418 void
1419 RouteTimeAxisView::use_playlist (boost::weak_ptr<Playlist> wpl)
1420 {
1421         assert (is_track());
1422
1423         boost::shared_ptr<Playlist> pl (wpl.lock());
1424
1425         if (!pl) {
1426                 return;
1427         }
1428
1429         boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
1430         
1431         if (apl) {
1432                 get_diskstream()->use_playlist (apl);
1433         }
1434 }
1435
1436 void
1437 RouteTimeAxisView::show_playlist_selector ()
1438 {
1439         editor.playlist_selector().show_for (this);
1440 }
1441
1442 void
1443 RouteTimeAxisView::map_frozen ()
1444 {
1445         if (!is_track()) {
1446                 return;
1447         }
1448
1449         ENSURE_GUI_THREAD (mem_fun(*this, &RouteTimeAxisView::map_frozen));
1450
1451         switch (track()->freeze_state()) {
1452         case Track::Frozen:
1453                 playlist_button.set_sensitive (false);
1454                 rec_enable_button->set_sensitive (false);
1455                 break;
1456         default:
1457                 playlist_button.set_sensitive (true);
1458                 rec_enable_button->set_sensitive (true);
1459                 break;
1460         }
1461 }
1462
1463 void
1464 RouteTimeAxisView::color_handler ()
1465 {
1466         //case cTimeStretchOutline:
1467         if (timestretch_rect) {
1468                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
1469         }
1470         //case cTimeStretchFill:
1471         if (timestretch_rect) {
1472                 timestretch_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
1473         }
1474
1475 }
1476
1477 void
1478 RouteTimeAxisView::toggle_automation_track (ParamID param)
1479 {
1480         RouteAutomationNode* node = automation_track(param);
1481
1482         if (!node)
1483                 return;
1484
1485         bool showit = node->menu_item->get_active();
1486
1487         if (showit != node->track->marked_for_display()) {
1488                 if (showit) {
1489                         node->track->set_marked_for_display (true);
1490                         node->track->canvas_display->show();
1491                         node->track->get_state_node()->add_property ("shown", X_("yes"));
1492                 } else {
1493                         node->track->set_marked_for_display (false);
1494                         node->track->hide ();
1495                         node->track->get_state_node()->add_property ("shown", X_("no"));
1496                 }
1497
1498                 /* now trigger a redisplay */
1499                 
1500                 if (!no_redraw) {
1501                          _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
1502                 }
1503         }
1504 }
1505
1506 void
1507 RouteTimeAxisView::automation_track_hidden (ParamID param)
1508 {
1509         RouteAutomationNode* ran = automation_track(param);
1510         if (!ran)
1511                 return;
1512
1513         _show_automation.erase(param);
1514         ran->track->get_state_node()->add_property (X_("shown"), X_("no"));
1515
1516         if (ran->menu_item && !_hidden) {
1517                 ran->menu_item->set_active (false);
1518         }
1519
1520          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1521 }
1522
1523
1524 void
1525 RouteTimeAxisView::show_all_automation ()
1526 {
1527         no_redraw = true;
1528         
1529         /* Show our automation */
1530
1531         map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i;
1532         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1533                 i->second->track->set_marked_for_display (true);
1534                 i->second->track->canvas_display->show();
1535                 i->second->track->get_state_node()->add_property ("shown", X_("yes"));
1536                 i->second->menu_item->set_active(true);
1537         }
1538
1539
1540         /* Show processor automation */
1541
1542         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1543                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1544                         if ((*ii)->view == 0) {
1545                                 add_processor_automation_curve ((*i)->processor, (*ii)->what);
1546                         } 
1547
1548                         (*ii)->menu_item->set_active (true);
1549                 }
1550         }
1551
1552         no_redraw = false;
1553
1554
1555         /* Redraw */
1556
1557          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1558 }
1559
1560 void
1561 RouteTimeAxisView::show_existing_automation ()
1562 {
1563         no_redraw = true;
1564         
1565         /* Show our automation */
1566
1567         map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i;
1568         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1569                 if (i->second->track->line() && i->second->track->line()->npoints() > 0) {
1570                         i->second->track->set_marked_for_display (true);
1571                         i->second->track->canvas_display->show();
1572                         i->second->track->get_state_node()->add_property ("shown", X_("yes"));
1573                         i->second->menu_item->set_active(true);
1574                 }
1575         }
1576
1577
1578         /* Show processor automation */
1579
1580         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1581                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1582                         if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
1583                                 (*ii)->menu_item->set_active (true);
1584                         }
1585                 }
1586         }
1587
1588         no_redraw = false;
1589
1590          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1591 }
1592
1593 void
1594 RouteTimeAxisView::hide_all_automation ()
1595 {
1596         no_redraw = true;
1597
1598         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1599                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1600                         (*ii)->menu_item->set_active (false);
1601                 }
1602         }
1603
1604         _show_automation.clear();
1605
1606         no_redraw = false;
1607          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1608 }
1609
1610
1611 void
1612 RouteTimeAxisView::region_view_added (RegionView* rv)
1613 {
1614         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1615                 boost::shared_ptr<AutomationTimeAxisView> atv;
1616
1617                 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
1618                         rv->add_ghost (*atv.get());
1619                 }
1620         }
1621 }
1622
1623 void
1624 RouteTimeAxisView::add_ghost_to_processor (RegionView* rv, boost::shared_ptr<AutomationTimeAxisView> atv)
1625 {
1626         rv->add_ghost (*atv.get());
1627 }
1628
1629 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
1630 {
1631         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1632                 delete *i;
1633         }
1634 }
1635
1636
1637 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
1638 {
1639         parent.remove_processor_automation_node (this);
1640 }
1641
1642 void
1643 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
1644 {
1645         if (pan->view) {
1646                 remove_child (pan->view);
1647         }
1648 }
1649
1650 RouteTimeAxisView::ProcessorAutomationNode*
1651 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, ParamID what)
1652 {
1653         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1654
1655                 if ((*i)->processor == processor) {
1656
1657                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1658                                 if ((*ii)->what == what) {
1659                                         return *ii;
1660                                 }
1661                         }
1662                 }
1663         }
1664
1665         return 0;
1666 }
1667
1668 static string 
1669 legalize_for_xml_node (string str)
1670 {
1671         string::size_type pos;
1672         string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:";
1673         string legal;
1674
1675         legal = str;
1676         pos = 0;
1677
1678         while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
1679                 legal.replace (pos, 1, "_");
1680                 pos += 1;
1681         }
1682
1683         return legal;
1684 }
1685
1686
1687 void
1688 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, ParamID what)
1689 {
1690         string name;
1691         ProcessorAutomationNode* pan;
1692
1693         if ((pan = find_processor_automation_node (processor, what)) == 0) {
1694                 fatal << _("programming error: ")
1695                       << string_compose (X_("processor automation curve for %1:%2 not registered with track!"),
1696                                   processor->name(), what)
1697                       << endmsg;
1698                 /*NOTREACHED*/
1699                 return;
1700         }
1701
1702         if (pan->view) {
1703                 return;
1704         }
1705
1706         name = processor->describe_parameter (what);
1707
1708         /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
1709
1710         /* FIXME: ew */
1711
1712         char state_name[256];
1713         snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id());
1714
1715         boost::shared_ptr<AutomationControl> control = processor->control(what, true);
1716
1717         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
1718                         new AutomationTimeAxisView (_session, _route, processor, control,
1719                                 editor, *this, parent_canvas, name, state_name));
1720
1721         pan->view->Hiding.connect (bind (mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
1722
1723         if (!pan->view->marked_for_display()) {
1724                 pan->view->hide ();
1725         } else {
1726                 pan->menu_item->set_active (true);
1727         }
1728
1729         add_child (pan->view);
1730
1731         if (_view) {
1732                 _view->foreach_regionview (bind (mem_fun(*this, &RouteTimeAxisView::add_ghost_to_processor), pan->view));
1733         }
1734
1735         processor->mark_automation_visible (what, true);
1736 }
1737
1738 void
1739 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor> i)
1740 {
1741         if (!_hidden) {
1742                 pan->menu_item->set_active (false);
1743         }
1744
1745         i->mark_automation_visible (pan->what, false);
1746
1747          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1748 }
1749
1750 void
1751 RouteTimeAxisView::add_existing_processor_automation_curves (boost::shared_ptr<Processor> processor)
1752 {
1753         set<ParamID> s;
1754         boost::shared_ptr<AutomationLine> al;
1755
1756         processor->what_has_visible_automation (s);
1757
1758         for (set<ParamID>::iterator i = s.begin(); i != s.end(); ++i) {
1759                 
1760                 if ((al = find_processor_automation_curve (processor, *i)) != 0) {
1761                         al->queue_reset ();
1762                 } else {
1763                         add_processor_automation_curve (processor, (*i));
1764                 }
1765         }
1766 }
1767
1768 void
1769 RouteTimeAxisView::add_automation_child(ParamID param, boost::shared_ptr<AutomationTimeAxisView> track)
1770 {
1771         using namespace Menu_Helpers;
1772
1773         XMLProperty* prop;
1774
1775         add_child (track);
1776
1777         track->Hiding.connect (bind (mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
1778
1779         bool hideit = false;
1780         
1781         XMLNode* node;
1782
1783         if ((node = track->get_state_node()) != 0) {
1784                 if  ((prop = node->property ("shown")) != 0) {
1785                         if (prop->value() == "yes") {
1786                                 hideit = false;
1787                         }
1788                 } 
1789         }
1790         
1791         _automation_tracks.insert(std::make_pair(param, new RouteAutomationNode(param, NULL, track)));
1792
1793         if (hideit) {
1794                 track->hide ();
1795         } else {
1796                 _show_automation.insert(param);
1797                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1798         }
1799 }
1800
1801
1802 void
1803 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::shared_ptr<Processor> processor)
1804 {
1805         using namespace Menu_Helpers;
1806         ProcessorAutomationInfo *rai;
1807         list<ProcessorAutomationInfo*>::iterator x;
1808         
1809         const std::set<ParamID>& automatable = processor->what_can_be_automated ();
1810         std::set<ParamID> has_visible_automation;
1811
1812         processor->what_has_visible_automation(has_visible_automation);
1813
1814         if (automatable.empty()) {
1815                 return;
1816         }
1817
1818         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
1819                 if ((*x)->processor == processor) {
1820                         break;
1821                 }
1822         }
1823
1824         if (x == processor_automation.end()) {
1825
1826                 rai = new ProcessorAutomationInfo (processor);
1827                 processor_automation.push_back (rai);
1828
1829         } else {
1830
1831                 rai = *x;
1832
1833         }
1834
1835         /* any older menu was deleted at the top of processors_changed()
1836            when we cleared the subplugin menu.
1837         */
1838
1839         rai->menu = manage (new Menu);
1840         MenuList& items = rai->menu->items();
1841         rai->menu->set_name ("ArdourContextMenu");
1842
1843         items.clear ();
1844
1845         for (std::set<ParamID>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
1846
1847                 ProcessorAutomationNode* pan;
1848                 CheckMenuItem* mitem;
1849                 
1850                 string name = processor->describe_parameter (*i);
1851                 
1852                 items.push_back (CheckMenuElem (name));
1853                 mitem = dynamic_cast<CheckMenuItem*> (&items.back());
1854
1855                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
1856                         mitem->set_active(true);
1857                 }
1858
1859                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
1860
1861                         /* new item */
1862                         
1863                         pan = new ProcessorAutomationNode (*i, mitem, *this);
1864                         
1865                         rai->lines.push_back (pan);
1866
1867                 } else {
1868
1869                         pan->menu_item = mitem;
1870
1871                 }
1872
1873                 mitem->signal_toggled().connect (bind (mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
1874         }
1875
1876         /* add the menu for this processor, because the subplugin
1877            menu is always cleared at the top of processors_changed().
1878            this is the result of some poor design in gtkmm and/or
1879            GTK+.
1880         */
1881
1882         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
1883         rai->valid = true;
1884 }
1885
1886 void
1887 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
1888                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
1889 {
1890         bool showit = pan->menu_item->get_active();
1891         bool redraw = false;
1892
1893         if (pan->view == 0 && showit) {
1894                 add_processor_automation_curve (rai->processor, pan->what);
1895                 redraw = true;
1896         }
1897
1898         if (showit != pan->view->marked_for_display()) {
1899
1900                 if (showit) {
1901                         pan->view->set_marked_for_display (true);
1902                         pan->view->canvas_display->show();
1903                 } else {
1904                         rai->processor->mark_automation_visible (pan->what, true);
1905                         pan->view->set_marked_for_display (false);
1906                         pan->view->hide ();
1907                 }
1908
1909                 redraw = true;
1910
1911         }
1912
1913         if (redraw && !no_redraw) {
1914
1915                 /* now trigger a redisplay */
1916                 
1917                  _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1918
1919         }
1920 }
1921
1922 void
1923 RouteTimeAxisView::processors_changed ()
1924 {
1925         using namespace Menu_Helpers;
1926
1927         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1928                 (*i)->valid = false;
1929         }
1930
1931         subplugin_menu.items().clear ();
1932
1933         _route->foreach_processor (this, &RouteTimeAxisView::add_processor_to_subplugin_menu);
1934         _route->foreach_processor (this, &RouteTimeAxisView::add_existing_processor_automation_curves);
1935
1936         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
1937
1938                 list<ProcessorAutomationInfo*>::iterator tmp;
1939
1940                 tmp = i;
1941                 ++tmp;
1942
1943                 if (!(*i)->valid) {
1944
1945                         delete *i;
1946                         processor_automation.erase (i);
1947
1948                 } 
1949
1950                 i = tmp;
1951         }
1952
1953         /* change in visibility was possible */
1954
1955         _route->gui_changed ("track_height", this);
1956 }
1957
1958 boost::shared_ptr<AutomationLine>
1959 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, ParamID what)
1960 {
1961         ProcessorAutomationNode* pan;
1962
1963         if ((pan = find_processor_automation_node (processor, what)) != 0) {
1964                 if (pan->view) {
1965                         pan->view->line();
1966                 } 
1967         }
1968
1969         return boost::shared_ptr<AutomationLine>();
1970 }
1971
1972 void
1973 RouteTimeAxisView::reset_processor_automation_curves ()
1974 {
1975         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
1976                 (*i)->reset();
1977         }
1978 }
1979
1980 void
1981 RouteTimeAxisView::update_rec_display ()
1982 {
1983         RouteUI::update_rec_display ();
1984         name_entry.set_sensitive (!_route->record_enabled());
1985 }
1986