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