Don't report an error when the user cancels a time stretch operation.
[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  <map>
27 #include <utility>
28
29 #include <sigc++/bind.h>
30
31 #include "pbd/error.h"
32 #include "pbd/stl_delete.h"
33 #include "pbd/whitespace.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/enumwriter.h"
36 #include "pbd/stateful_diff_command.h"
37
38 #include <gtkmm/menu.h>
39 #include <gtkmm/menuitem.h>
40 #include <gtkmm2ext/gtk_ui.h>
41 #include <gtkmm2ext/selector.h>
42 #include <gtkmm2ext/stop_signal.h>
43 #include <gtkmm2ext/bindable_button.h>
44 #include <gtkmm2ext/utils.h>
45
46 #include "ardour/amp.h"
47 #include "ardour/audioplaylist.h"
48 #include "ardour/diskstream.h"
49 #include "ardour/event_type_map.h"
50 #include "ardour/ladspa_plugin.h"
51 #include "ardour/location.h"
52 #include "ardour/panner.h"
53 #include "ardour/playlist.h"
54 #include "ardour/playlist.h"
55 #include "ardour/processor.h"
56 #include "ardour/profile.h"
57 #include "ardour/route_group.h"
58 #include "ardour/session.h"
59 #include "ardour/session_playlist.h"
60 #include "ardour/debug.h"
61 #include "ardour/utils.h"
62 #include "evoral/Parameter.hpp"
63
64 #include "ardour_ui.h"
65 #include "route_time_axis.h"
66 #include "automation_time_axis.h"
67 #include "canvas_impl.h"
68 #include "crossfade_view.h"
69 #include "enums.h"
70 #include "gui_thread.h"
71 #include "keyboard.h"
72 #include "playlist_selector.h"
73 #include "point_selection.h"
74 #include "prompter.h"
75 #include "public_editor.h"
76 #include "region_view.h"
77 #include "rgb_macros.h"
78 #include "selection.h"
79 #include "simplerect.h"
80 #include "streamview.h"
81 #include "utils.h"
82 #include "route_group_menu.h"
83
84 #include "ardour/track.h"
85
86 #include "i18n.h"
87
88 using namespace ARDOUR;
89 using namespace PBD;
90 using namespace Gtkmm2ext;
91 using namespace Gtk;
92 using namespace Editing;
93 using namespace std;
94
95 Glib::RefPtr<Gdk::Pixbuf> RouteTimeAxisView::slider;
96
97 void
98 RouteTimeAxisView::setup_slider_pix ()
99 {
100         if ((slider = ::get_icon ("fader_belt_h")) == 0) {
101                 throw failed_constructor ();
102         }
103 }
104
105 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::shared_ptr<Route> rt, Canvas& canvas)
106         : AxisView(sess)
107         , RouteUI(rt, sess)
108         , TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas)
109         , parent_canvas (canvas)
110         , button_table (3, 3)
111         , route_group_button (_("g"))
112         , playlist_button (_("p"))
113         , size_button (_("h"))
114         , automation_button (_("a"))
115         , visual_button (_("v"))
116         , gm (sess, slider, true, 115)
117         , _ignore_track_mode_change (false)
118 {
119         gm.set_controls (_route, _route->shared_peak_meter(), _route->amp());
120         gm.get_level_meter().set_no_show_all();
121         gm.get_level_meter().setup_meters(50);
122
123         _has_state = true;
124         playlist_menu = 0;
125         playlist_action_menu = 0;
126         automation_action_menu = 0;
127         plugins_submenu_item = 0;
128         mode_menu = 0;
129         _view = 0;
130
131         if (!_route->is_hidden()) {
132                 _marked_for_display = true;
133         }
134
135         mute_changed (0);
136         update_solo_display ();
137
138         timestretch_rect = 0;
139         no_redraw = false;
140         destructive_track_mode_item = 0;
141         normal_track_mode_item = 0;
142         non_layered_track_mode_item = 0;
143
144         ignore_toggle = false;
145
146         route_group_button.set_name ("TrackGroupButton");
147         playlist_button.set_name ("TrackPlaylistButton");
148         automation_button.set_name ("TrackAutomationButton");
149         size_button.set_name ("TrackSizeButton");
150         visual_button.set_name ("TrackVisualButton");
151         hide_button.set_name ("TrackRemoveButton");
152
153         route_group_button.unset_flags (Gtk::CAN_FOCUS);
154         playlist_button.unset_flags (Gtk::CAN_FOCUS);
155         automation_button.unset_flags (Gtk::CAN_FOCUS);
156         size_button.unset_flags (Gtk::CAN_FOCUS);
157         visual_button.unset_flags (Gtk::CAN_FOCUS);
158         hide_button.unset_flags (Gtk::CAN_FOCUS);
159
160         hide_button.add (*(manage (new Image (::get_icon("hide")))));
161         hide_button.show_all ();
162
163         route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::edit_click), false);
164         playlist_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click));
165         automation_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click));
166         size_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::size_click), false);
167         visual_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::visual_click));
168         hide_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::hide_click));
169
170         if (is_track()) {
171
172                 /* use icon */
173
174                 rec_enable_button->remove ();
175
176                 switch (track()->mode()) {
177                 case ARDOUR::Normal:
178                 case ARDOUR::NonLayered:
179                         rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
180                         break;
181                 case ARDOUR::Destructive:
182                         rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red"))))));
183                         break;
184                 }
185                 rec_enable_button->show_all ();
186
187                 controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
188                 ARDOUR_UI::instance()->set_tip(*rec_enable_button, _("Record"));
189
190                 rec_enable_button->set_sensitive (_session->writable());
191         }
192
193         controls_hbox.pack_start(gm.get_level_meter(), false, false);
194         _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
195         _route->input()->changed.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
196         _route->output()->changed.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
197
198         controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
199
200         if (!_route->is_master()) {
201                 controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
202         }
203
204         controls_table.attach (route_group_button, 7, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
205         controls_table.attach (gm.get_gain_slider(), 0, 5, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
206
207         ARDOUR_UI::instance()->set_tip(*solo_button,_("Solo"));
208         ARDOUR_UI::instance()->set_tip(*mute_button,_("Mute"));
209         ARDOUR_UI::instance()->set_tip(route_group_button, _("Route Group"));
210         ARDOUR_UI::instance()->set_tip(size_button,_("Display Height"));
211         ARDOUR_UI::instance()->set_tip(playlist_button,_("Playlist"));
212         ARDOUR_UI::instance()->set_tip(automation_button, _("Automation"));
213         ARDOUR_UI::instance()->set_tip(visual_button, _("Visual options"));
214         ARDOUR_UI::instance()->set_tip(hide_button, _("Hide this track"));
215
216         label_view ();
217
218         if (0) {
219
220                 /* old school - when we used to put an extra row of buttons in place */
221
222                 controls_table.attach (hide_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
223                 controls_table.attach (visual_button, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
224                 controls_table.attach (size_button, 2, 3, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
225                 controls_table.attach (automation_button, 3, 4, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
226
227         } else {
228
229                 controls_table.attach (automation_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
230         }
231
232         if (is_track() && track()->mode() == ARDOUR::Normal) {
233                 controls_table.attach (playlist_button, 5, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
234         }
235
236         _y_position = -1;
237
238         _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
239         _route->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::route_property_changed, this, _1), gui_context());
240
241         if (is_track()) {
242
243                 track()->TrackModeChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::track_mode_changed, this), gui_context());
244                 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
245                 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
246
247                 /* pick up the correct freeze state */
248                 map_frozen ();
249
250         }
251
252         _editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit));
253         ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler));
254
255         PropertyList* plist = new PropertyList();
256         
257         plist->add (ARDOUR::Properties::edit, true);
258         plist->add (ARDOUR::Properties::mute, true);
259         plist->add (ARDOUR::Properties::solo, true);
260         
261         route_group_menu = new RouteGroupMenu (_session, plist);
262         route_group_menu->GroupSelected.connect (sigc::mem_fun (*this, &RouteTimeAxisView::set_route_group_from_menu));
263
264         gm.get_gain_slider().signal_scroll_event().connect(sigc::mem_fun(*this, &RouteTimeAxisView::controls_ebox_scroll), false);
265         gm.get_gain_slider().set_name ("TrackGainFader");
266 }
267
268 RouteTimeAxisView::~RouteTimeAxisView ()
269 {
270         CatchDeletion (this);
271
272         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
273                 delete *i;
274         }
275
276         delete playlist_menu;
277         playlist_menu = 0;
278
279         delete playlist_action_menu;
280         playlist_action_menu = 0;
281
282         delete _view;
283         _view = 0;
284
285         for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
286                 delete i->second;
287         }
288
289         _automation_tracks.clear ();
290
291         delete route_group_menu;
292 }
293
294 void
295 RouteTimeAxisView::post_construct ()
296 {
297         /* map current state of the route */
298
299         update_diskstream_display ();
300
301         subplugin_menu.items().clear ();
302         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
303         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
304         reset_processor_automation_curves ();
305 }
306
307 gint
308 RouteTimeAxisView::edit_click (GdkEventButton *ev)
309 {
310         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
311                 if (_route->route_group()) {
312                         _route->route_group()->remove (_route);
313                 }
314                 return false;
315         }
316
317         route_group_menu->rebuild (_route->route_group ());
318         route_group_menu->popup (ev->button, ev->time);
319
320         return false;
321 }
322
323 void
324 RouteTimeAxisView::set_route_group_from_menu (RouteGroup *eg)
325 {
326         if (eg) {
327                 eg->add (_route);
328         } else {
329                 if (_route->route_group()) {
330                         _route->route_group()->remove (_route);
331                 }
332         }
333 }
334
335 void
336 RouteTimeAxisView::playlist_changed ()
337 {
338         label_view ();
339 }
340
341 void
342 RouteTimeAxisView::label_view ()
343 {
344         string x = _route->name();
345
346         if (x != name_entry.get_text()) {
347                 name_entry.set_text (x);
348         }
349
350         ARDOUR_UI::instance()->set_tip (name_entry, x);
351 }
352
353 void
354 RouteTimeAxisView::route_property_changed (const PropertyChange& what_changed)
355 {
356         if (what_changed.contains (ARDOUR::Properties::name)) {
357                 label_view ();
358         }
359 }
360
361 void
362 RouteTimeAxisView::take_name_changed (void *src)
363
364 {
365         if (src != this) {
366                 label_view ();
367         }
368 }
369
370 void
371 RouteTimeAxisView::playlist_click ()
372 {
373         // always build a new action menu
374
375         delete playlist_action_menu;
376
377         playlist_action_menu = new Menu;
378         playlist_action_menu->set_name ("ArdourContextMenu");
379
380         build_playlist_menu (playlist_action_menu);
381
382         conditionally_add_to_selection ();
383         playlist_action_menu->popup (1, gtk_get_current_event_time());
384 }
385
386 void
387 RouteTimeAxisView::automation_click ()
388 {
389         conditionally_add_to_selection ();
390         build_automation_action_menu ();
391         automation_action_menu->popup (1, gtk_get_current_event_time());
392 }
393
394 int
395 RouteTimeAxisView::set_state (const XMLNode& node, int version)
396 {
397         TimeAxisView::set_state (node, version);
398
399         XMLNodeList kids = node.children();
400         XMLNodeConstIterator iter;
401         const XMLProperty* prop;
402
403         if (_view && (prop = node.property ("layer-display"))) {
404                 set_layer_display (LayerDisplay (string_2_enum (prop->value(), _view->layer_display ())));
405         }
406
407         for (iter = kids.begin(); iter != kids.end(); ++iter) {
408                 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
409                         if ((prop = (*iter)->property ("automation-id")) != 0) {
410
411                                 Evoral::Parameter param = ARDOUR::EventTypeMap::instance().new_parameter(prop->value());
412                                 bool show = ((prop = (*iter)->property ("shown")) != 0) && string_is_affirmative (prop->value());
413                                 create_automation_child(param, show);
414                         } else {
415                                 warning << "Automation child has no ID" << endmsg;
416                         }
417                 }
418         }
419
420         return 0;
421 }
422
423 void
424 RouteTimeAxisView::build_automation_action_menu ()
425 {
426         using namespace Menu_Helpers;
427
428         delete automation_action_menu;
429         automation_action_menu = new Menu;
430
431         MenuList& items = automation_action_menu->items();
432
433         automation_action_menu->set_name ("ArdourContextMenu");
434         
435         items.push_back (MenuElem (_("Show All Automation"),
436                                    sigc::mem_fun(*this, &RouteTimeAxisView::show_all_automation)));
437         
438         items.push_back (MenuElem (_("Show Existing Automation"),
439                                    sigc::mem_fun(*this, &RouteTimeAxisView::show_existing_automation)));
440         
441         items.push_back (MenuElem (_("Hide All Automation"),
442                                    sigc::mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
443         
444         /* attach the plugin submenu. It may have previously been used elsewhere, so we detach it first. */
445
446         detach_menu (subplugin_menu);
447         items.push_back (MenuElem (_("Plugins"),  subplugin_menu));
448         items.back().set_sensitive (!subplugin_menu.items().empty());
449 }
450
451 void
452 RouteTimeAxisView::build_display_menu ()
453 {
454         using namespace Menu_Helpers;
455
456         /* get the size menu ready */
457
458         build_size_menu ();
459
460         /* prepare it */
461
462         TimeAxisView::build_display_menu ();
463
464         /* now fill it with our stuff */
465
466         MenuList& items = display_menu->items();
467         display_menu->set_name ("ArdourContextMenu");
468
469         items.push_back (MenuElem (_("Height"), *size_menu));
470         items.push_back (MenuElem (_("Color"), sigc::mem_fun(*this, &RouteTimeAxisView::select_track_color)));
471
472         items.push_back (SeparatorElem());
473
474         if (!Profile->get_sae()) {
475                 items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
476                 /* rebuild this every time */
477                 build_automation_action_menu ();
478                 detach_menu (*automation_action_menu);
479                 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
480                 items.push_back (SeparatorElem());
481         }
482
483         // Hook for derived classes to add type specific stuff
484         append_extra_display_menu_items ();
485         items.push_back (SeparatorElem());
486
487         if (is_track()) {
488
489                 Menu *layers_menu = manage(new Menu);
490                 MenuList &layers_items = layers_menu->items();
491                 layers_menu->set_name("ArdourContextMenu");
492
493                 RadioMenuItem::Group layers_group;
494
495                 layers_items.push_back(RadioMenuElem (layers_group, _("Overlaid"),
496                                 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid)));
497                 layers_items.push_back(RadioMenuElem (layers_group, _("Stacked"),
498                                 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked)));
499
500                 items.push_back (MenuElem (_("Layers"), *layers_menu));
501
502                 Menu* alignment_menu = manage (new Menu);
503                 MenuList& alignment_items = alignment_menu->items();
504                 alignment_menu->set_name ("ArdourContextMenu");
505
506                 RadioMenuItem::Group align_group;
507
508                 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material"),
509                                         sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial)));
510                 align_existing_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
511                 if (track()->alignment_style() == ExistingMaterial) {
512                         align_existing_item->set_active();
513                 }
514
515                 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time"),
516                                         sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime)));
517                 align_capture_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
518                 if (track()->alignment_style() == CaptureTime) {
519                         align_capture_item->set_active();
520                 }
521
522                 if (!Profile->get_sae()) {
523
524                         items.push_back (MenuElem (_("Alignment"), *alignment_menu));
525                         track()->AlignmentStyleChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteTimeAxisView::align_style_changed, this), gui_context());
526
527                         RadioMenuItem::Group mode_group;
528                         items.push_back (RadioMenuElem (mode_group, _("Normal Mode"), sigc::bind (
529                                         sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode),
530                                         ARDOUR::Normal)));
531                         normal_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
532
533                         items.push_back (RadioMenuElem (mode_group, _("Tape Mode"), sigc::bind (
534                                         sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode),
535                                         ARDOUR::Destructive)));
536                         destructive_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
537
538                         items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode"),
539                                                         sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered)));
540                         non_layered_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
541
542
543                         _ignore_track_mode_change = true;
544                         
545                         switch (track()->mode()) {
546                         case ARDOUR::Destructive:
547                                 destructive_track_mode_item->set_active ();
548                                 break;
549                         case ARDOUR::Normal:
550                                 normal_track_mode_item->set_active ();
551                                 break;
552                         case ARDOUR::NonLayered:
553                                 non_layered_track_mode_item->set_active ();
554                                 break;
555                         }
556                         
557                         _ignore_track_mode_change = false;
558                 }
559
560                 track()->AlignmentStyleChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteTimeAxisView::align_style_changed, this), gui_context());
561
562                 color_mode_menu = build_color_mode_menu();
563                 if (color_mode_menu) {
564                         items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
565                 }
566
567                 items.push_back (SeparatorElem());
568         }
569
570         items.push_back (CheckMenuElem (_("Active"), sigc::mem_fun(*this, &RouteUI::toggle_route_active)));
571         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
572         route_active_menu_item->set_active (_route->active());
573
574         items.push_back (SeparatorElem());
575         items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &RouteTimeAxisView::hide_click)));
576         if (!Profile->get_sae()) {
577                 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &RouteUI::remove_this_route)));
578         } else {
579                 items.push_front (SeparatorElem());
580                 items.push_front (MenuElem (_("Delete"), sigc::mem_fun(*this, &RouteUI::remove_this_route)));
581         }
582 }
583
584 static bool __reset_item (RadioMenuItem* item, RadioMenuItem* item_2)
585 {
586         item->set_active ();
587         item_2->set_active ();
588         return false;
589 }
590
591 void
592 RouteTimeAxisView::set_track_mode (TrackMode mode)
593 {
594         if (_ignore_track_mode_change) {
595                 return;
596         }
597         
598         RadioMenuItem* item;
599         RadioMenuItem* other_item;
600         RadioMenuItem* other_item_2;
601
602         switch (mode) {
603         case ARDOUR::Normal:
604                 item = normal_track_mode_item;
605                 other_item = non_layered_track_mode_item;
606                 other_item_2 = destructive_track_mode_item;
607                 break;
608         case ARDOUR::NonLayered:
609                 item = non_layered_track_mode_item;
610                 other_item = normal_track_mode_item;
611                 other_item_2 = destructive_track_mode_item;
612                 break;
613         case ARDOUR::Destructive:
614                 item = destructive_track_mode_item;
615                 other_item = normal_track_mode_item;
616                 other_item_2 = non_layered_track_mode_item;
617                 break;
618         default:
619                 fatal << string_compose (_("programming error: %1 %2"), "illegal track mode in RouteTimeAxisView::set_track_mode", mode) << endmsg;
620                 /*NOTREACHED*/
621                 return;
622         }
623
624         if (item && other_item && other_item_2 && track()->mode() != mode) {
625                 _set_track_mode (track().get(), mode, other_item, other_item_2);
626         }
627 }
628
629 void
630 RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem* reset_item, RadioMenuItem* reset_item_2)
631 {
632         bool needs_bounce;
633
634         if (!track->can_use_mode (mode, needs_bounce)) {
635
636                 if (!needs_bounce) {
637                         /* cannot be done */
638                         Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (__reset_item), reset_item, reset_item_2));
639                         return;
640                 } else {
641                         cerr << "would bounce this one\n";
642                         /* XXX: radio menu item becomes inconsistent with track state in this case */
643                         return;
644                 }
645         }
646
647         track->set_mode (mode);
648
649         rec_enable_button->remove ();
650
651         switch (mode) {
652         case ARDOUR::NonLayered:
653         case ARDOUR::Normal:
654                 rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
655                 break;
656         case ARDOUR::Destructive:
657                 rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red"))))));
658                 break;
659         }
660
661         rec_enable_button->show_all ();
662 }
663
664 void
665 RouteTimeAxisView::track_mode_changed ()
666 {
667         RadioMenuItem* item;
668
669         switch (track()->mode()) {
670         case ARDOUR::Normal:
671                 item = normal_track_mode_item;
672                 break;
673         case ARDOUR::NonLayered:
674                 item = non_layered_track_mode_item;
675                 break;
676         case ARDOUR::Destructive:
677                 item = destructive_track_mode_item;
678                 break;
679         default:
680                 fatal << string_compose (_("programming error: %1 %2"), "illegal track mode in RouteTimeAxisView::set_track_mode", track()->mode()) << endmsg;
681                 /*NOTREACHED*/
682                 return;
683         }
684
685         item->set_active ();
686 }
687
688 void
689 RouteTimeAxisView::show_timestretch (nframes_t start, nframes_t end)
690 {
691         double x1;
692         double x2;
693         double y2;
694
695         TimeAxisView::show_timestretch (start, end);
696
697         hide_timestretch ();
698
699 #if 0
700         if (ts.empty()) {
701                 return;
702         }
703
704
705         /* check that the time selection was made in our route, or our route group.
706            remember that route_group() == 0 implies the route is *not* in a edit group.
707         */
708
709         if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
710                 /* this doesn't apply to us */
711                 return;
712         }
713
714         /* ignore it if our edit group is not active */
715
716         if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
717                 return;
718         }
719 #endif
720
721         if (timestretch_rect == 0) {
722                 timestretch_rect = new SimpleRect (*canvas_display ());
723                 timestretch_rect->property_x1() =  0.0;
724                 timestretch_rect->property_y1() =  0.0;
725                 timestretch_rect->property_x2() =  0.0;
726                 timestretch_rect->property_y2() =  0.0;
727                 timestretch_rect->property_fill_color_rgba() =  ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
728                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
729         }
730
731         timestretch_rect->show ();
732         timestretch_rect->raise_to_top ();
733
734         x1 = start / _editor.get_current_zoom();
735         x2 = (end - 1) / _editor.get_current_zoom();
736         y2 = current_height() - 2;
737
738         timestretch_rect->property_x1() = x1;
739         timestretch_rect->property_y1() = 1.0;
740         timestretch_rect->property_x2() = x2;
741         timestretch_rect->property_y2() = y2;
742 }
743
744 void
745 RouteTimeAxisView::hide_timestretch ()
746 {
747         TimeAxisView::hide_timestretch ();
748
749         if (timestretch_rect) {
750                 timestretch_rect->hide ();
751         }
752 }
753
754 void
755 RouteTimeAxisView::show_selection (TimeSelection& ts)
756 {
757
758 #if 0
759         /* ignore it if our edit group is not active or if the selection was started
760            in some other track or route group (remember that route_group() == 0 means
761            that the track is not in an route group).
762         */
763
764         if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
765             (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
766                 hide_selection ();
767                 return;
768         }
769 #endif
770
771         TimeAxisView::show_selection (ts);
772 }
773
774 void
775 RouteTimeAxisView::set_height (uint32_t h)
776 {
777         int gmlen = h - 5;
778         bool height_changed = (height == 0) || (h != height);
779         gm.get_level_meter().setup_meters (gmlen);
780
781         TimeAxisView::set_height (h);
782
783         ensure_xml_node ();
784
785         if (_view) {
786                 _view->set_height ((double) current_height());
787         }
788
789         char buf[32];
790         snprintf (buf, sizeof (buf), "%u", height);
791         xml_node->add_property ("height", buf);
792
793         if (height >= hNormal) {
794                 reset_meter();
795                 show_name_entry ();
796                 hide_name_label ();
797
798                 gm.get_gain_slider().show();
799                 mute_button->show();
800                 if (!_route || _route->is_monitor()) {
801                         solo_button->hide();
802                 } else {
803                         solo_button->show();
804                 }
805                 if (rec_enable_button)
806                         rec_enable_button->show();
807
808                 route_group_button.show();
809                 hide_button.show();
810                 visual_button.show();
811                 size_button.show();
812                 automation_button.show();
813
814                 if (is_track() && track()->mode() == ARDOUR::Normal) {
815                         playlist_button.show();
816                 }
817
818         } else if (height >= hSmaller) {
819
820                 reset_meter();
821                 show_name_entry ();
822                 hide_name_label ();
823
824                 gm.get_gain_slider().hide();
825                 mute_button->show();
826                 if (!_route || _route->is_monitor()) {
827                         solo_button->hide();
828                 } else {
829                         solo_button->show();
830                 }
831                 if (rec_enable_button)
832                         rec_enable_button->show();
833
834                 route_group_button.hide ();
835                 hide_button.hide ();
836                 visual_button.hide ();
837                 size_button.hide ();
838                 automation_button.hide ();
839
840                 if (is_track() && track()->mode() == ARDOUR::Normal) {
841                         playlist_button.hide ();
842                 }
843
844         } else {
845
846
847                 /* don't allow name_entry to be hidden while
848                    it has focus, otherwise the GUI becomes unusable.
849                 */
850
851                 if (name_entry.has_focus()) {
852                         if (name_entry.get_text() != _route->name()) {
853                                 name_entry_changed ();
854                         }
855                         controls_ebox.grab_focus ();
856                 }
857
858                 hide_name_entry ();
859                 show_name_label ();
860
861                 gm.get_gain_slider().hide();
862                 mute_button->hide();
863                 solo_button->hide();
864                 if (rec_enable_button)
865                         rec_enable_button->hide();
866
867                 route_group_button.hide ();
868                 hide_button.hide ();
869                 visual_button.hide ();
870                 size_button.hide ();
871                 automation_button.hide ();
872                 playlist_button.hide ();
873                 name_label.set_text (_route->name());
874         }
875
876         if (height_changed && !no_redraw) {
877                 /* only emit the signal if the height really changed */
878                  _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
879         }
880 }
881
882 void
883 RouteTimeAxisView::select_track_color ()
884 {
885         if (RouteUI::choose_color ()) {
886
887                 if (_view) {
888                         _view->apply_color (_color, StreamView::RegionColor);
889                 }
890         }
891 }
892
893 void
894 RouteTimeAxisView::reset_samples_per_unit ()
895 {
896         set_samples_per_unit (_editor.get_current_zoom());
897 }
898
899 void
900 RouteTimeAxisView::set_samples_per_unit (double spu)
901 {
902         double speed = 1.0;
903
904         if (track()) {
905                 speed = track()->speed();
906         }
907
908         if (_view) {
909                 _view->set_samples_per_unit (spu * speed);
910         }
911
912         TimeAxisView::set_samples_per_unit (spu * speed);
913 }
914
915 void
916 RouteTimeAxisView::align_style_changed ()
917 {
918         switch (track()->alignment_style()) {
919         case ExistingMaterial:
920                 if (!align_existing_item->get_active()) {
921                         align_existing_item->set_active();
922                 }
923                 break;
924         case CaptureTime:
925                 if (!align_capture_item->get_active()) {
926                         align_capture_item->set_active();
927                 }
928                 break;
929         }
930 }
931
932 void
933 RouteTimeAxisView::set_align_style (AlignStyle style)
934 {
935         RadioMenuItem* item;
936
937         switch (style) {
938         case ExistingMaterial:
939                 item = align_existing_item;
940                 break;
941         case CaptureTime:
942                 item = align_capture_item;
943                 break;
944         default:
945                 fatal << string_compose (_("programming error: %1 %2"), "illegal align style in RouteTimeAxisView::set_align_style", style) << endmsg;
946                 /*NOTREACHED*/
947                 return;
948         }
949
950         if (item->get_active()) {
951                 track()->set_align_style (style);
952         }
953 }
954
955 void
956 RouteTimeAxisView::rename_current_playlist ()
957 {
958         ArdourPrompter prompter (true);
959         string name;
960
961         boost::shared_ptr<Track> tr = track();
962         if (!tr || tr->destructive()) {
963                 return;
964         }
965
966         boost::shared_ptr<Playlist> pl = tr->playlist();
967         if (!pl) {
968                 return;
969         }
970
971         prompter.set_title (_("Rename Playlist"));
972         prompter.set_prompt (_("New name for playlist:"));
973         prompter.set_initial_text (pl->name());
974         prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
975         prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
976
977         switch (prompter.run ()) {
978         case Gtk::RESPONSE_ACCEPT:
979                 prompter.get_result (name);
980                 if (name.length()) {
981                         pl->set_name (name);
982                 }
983                 break;
984
985         default:
986                 break;
987         }
988 }
989
990 std::string
991 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
992 {
993         std::string ret (basename);
994
995         std::string const group_string = "." + route_group()->name() + ".";
996
997         // iterate through all playlists
998         int maxnumber = 0;
999         for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1000                 std::string tmp = (*i)->name();
1001
1002                 std::string::size_type idx = tmp.find(group_string);
1003                 // find those which belong to this group
1004                 if (idx != string::npos) {
1005                         tmp = tmp.substr(idx + group_string.length());
1006
1007                         // and find the largest current number
1008                         int x = atoi(tmp.c_str());
1009                         if (x > maxnumber) {
1010                                 maxnumber = x;
1011                         }
1012                 }
1013         }
1014
1015         maxnumber++;
1016
1017         char buf[32];
1018         snprintf (buf, sizeof(buf), "%d", maxnumber);
1019
1020         ret = this->name() + "." + route_group()->name () + "." + buf;
1021
1022         return ret;
1023 }
1024
1025 void
1026 RouteTimeAxisView::use_copy_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1027 {
1028         string name;
1029
1030         boost::shared_ptr<Track> tr = track ();
1031         if (!tr || tr->destructive()) {
1032                 return;
1033         }
1034
1035         boost::shared_ptr<const Playlist> pl = tr->playlist();
1036         if (!pl) {
1037                 return;
1038         }
1039
1040         name = pl->name();
1041
1042         if (route_group() && route_group()->is_active()) {
1043                 name = resolve_new_group_playlist_name(name, playlists_before_op);
1044         }
1045
1046         while (_session->playlists->by_name(name)) {
1047                 name = Playlist::bump_name (name, *_session);
1048         }
1049
1050         // TODO: The prompter "new" button should be de-activated if the user
1051         // specifies a playlist name which already exists in the session.
1052
1053         if (prompt) {
1054
1055                 ArdourPrompter prompter (true);
1056
1057                 prompter.set_title (_("New Copy Playlist"));
1058                 prompter.set_prompt (_("Name for new playlist:"));
1059                 prompter.set_initial_text (name);
1060                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1061                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1062                 prompter.show_all ();
1063
1064                 switch (prompter.run ()) {
1065                 case Gtk::RESPONSE_ACCEPT:
1066                         prompter.get_result (name);
1067                         break;
1068
1069                 default:
1070                         return;
1071                 }
1072         }
1073
1074         if (name.length()) {
1075                 tr->use_copy_playlist ();
1076                 tr->playlist()->set_name (name);
1077         }
1078 }
1079
1080 void
1081 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1082 {
1083         string name;
1084
1085         boost::shared_ptr<Track> tr = track ();
1086         if (!tr || tr->destructive()) {
1087                 return;
1088         }
1089
1090         boost::shared_ptr<const Playlist> pl = tr->playlist();
1091         if (!pl) {
1092                 return;
1093         }
1094
1095         name = pl->name();
1096
1097         if (route_group() && route_group()->is_active()) {
1098                 name = resolve_new_group_playlist_name(name,playlists_before_op);
1099         }
1100
1101         while (_session->playlists->by_name(name)) {
1102                 name = Playlist::bump_name (name, *_session);
1103         }
1104
1105
1106         if (prompt) {
1107
1108                 ArdourPrompter prompter (true);
1109
1110                 prompter.set_title (_("New Playlist"));
1111                 prompter.set_prompt (_("Name for new playlist:"));
1112                 prompter.set_initial_text (name);
1113                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1114                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1115
1116                 switch (prompter.run ()) {
1117                 case Gtk::RESPONSE_ACCEPT:
1118                         prompter.get_result (name);
1119                         break;
1120
1121                 default:
1122                         return;
1123                 }
1124         }
1125
1126         if (name.length()) {
1127                 tr->use_new_playlist ();
1128                 tr->playlist()->set_name (name);
1129         }
1130 }
1131
1132 void
1133 RouteTimeAxisView::clear_playlist ()
1134 {
1135         boost::shared_ptr<Track> tr = track ();
1136         if (!tr || tr->destructive()) {
1137                 return;
1138         }
1139
1140         boost::shared_ptr<Playlist> pl = tr->playlist();
1141         if (!pl) {
1142                 return;
1143         }
1144
1145         _editor.clear_playlist (pl);
1146 }
1147
1148 void
1149 RouteTimeAxisView::speed_changed ()
1150 {
1151         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_unit, this));
1152 }
1153
1154 void
1155 RouteTimeAxisView::update_diskstream_display ()
1156 {
1157         if (!track()) {
1158                 return;
1159         }
1160
1161         map_frozen ();
1162 }
1163
1164 void
1165 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1166 {
1167         if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1168
1169                 /* special case: select/deselect all tracks */
1170                 if (_editor.get_selection().selected (this)) {
1171                         _editor.get_selection().clear_tracks ();
1172                 } else {
1173                         _editor.select_all_tracks ();
1174                 }
1175
1176                 return;
1177         }
1178
1179         switch (ArdourKeyboard::selection_type (ev->state)) {
1180         case Selection::Toggle:
1181                 _editor.get_selection().toggle (this);
1182                 break;
1183
1184         case Selection::Set:
1185                 _editor.get_selection().set (this);
1186                 break;
1187
1188         case Selection::Extend:
1189                 _editor.extend_selection_to_track (*this);
1190                 break;
1191
1192         case Selection::Add:
1193                 _editor.get_selection().add (this);
1194                 break;
1195         }
1196 }
1197
1198 void
1199 RouteTimeAxisView::set_selected_points (PointSelection& points)
1200 {
1201         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1202                 (*i)->set_selected_points (points);
1203         }
1204 }
1205
1206 void
1207 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1208 {
1209         if (_view) {
1210                 _view->set_selected_regionviews (regions);
1211         }
1212 }
1213
1214 /** Add the selectable things that we have to a list.
1215  * @param results List to add things to.
1216  */
1217 void
1218 RouteTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
1219 {
1220         double speed = 1.0;
1221
1222         if (track() != 0) {
1223                 speed = track()->speed();
1224         }
1225
1226         nframes_t start_adjusted = session_frame_to_track_frame(start, speed);
1227         nframes_t end_adjusted   = session_frame_to_track_frame(end, speed);
1228
1229         if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1230                 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1231         }
1232
1233         /* pick up visible automation tracks */
1234
1235         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1236                 if (!(*i)->hidden()) {
1237                         (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1238                 }
1239         }
1240 }
1241
1242 void
1243 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1244 {
1245         if (_view) {
1246                 _view->get_inverted_selectables (sel, results);
1247         }
1248
1249         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1250                 if (!(*i)->hidden()) {
1251                         (*i)->get_inverted_selectables (sel, results);
1252                 }
1253         }
1254
1255         return;
1256 }
1257
1258 bool
1259 RouteTimeAxisView::show_automation(Evoral::Parameter param)
1260 {
1261         return (_show_automation.find(param) != _show_automation.end());
1262 }
1263
1264 /** Retuns 0 if track for \a param doesn't exist.
1265  */
1266 RouteTimeAxisView::RouteAutomationNode*
1267 RouteTimeAxisView::automation_track (Evoral::Parameter param)
1268 {
1269         map<Evoral::Parameter, RouteAutomationNode*>::iterator i = _automation_tracks.find (param);
1270
1271         if (i != _automation_tracks.end()) {
1272                 return i->second;
1273         } else {
1274                 return 0;
1275         }
1276 }
1277
1278 /** Shorthand for GainAutomation, etc.
1279  */
1280 RouteTimeAxisView::RouteAutomationNode*
1281 RouteTimeAxisView::automation_track (AutomationType type)
1282 {
1283         return automation_track (Evoral::Parameter(type));
1284 }
1285
1286 RouteGroup*
1287 RouteTimeAxisView::route_group () const
1288 {
1289         return _route->route_group();
1290 }
1291
1292 string
1293 RouteTimeAxisView::name() const
1294 {
1295         return _route->name();
1296 }
1297
1298 boost::shared_ptr<Playlist>
1299 RouteTimeAxisView::playlist () const
1300 {
1301         boost::shared_ptr<Track> tr;
1302
1303         if ((tr = track()) != 0) {
1304                 return tr->playlist();
1305         } else {
1306                 return boost::shared_ptr<Playlist> ();
1307         }
1308 }
1309
1310 void
1311 RouteTimeAxisView::name_entry_changed ()
1312 {
1313         string x;
1314
1315         x = name_entry.get_text ();
1316
1317         if (x == _route->name()) {
1318                 return;
1319         }
1320
1321         strip_whitespace_edges(x);
1322
1323         if (x.length() == 0) {
1324                 name_entry.set_text (_route->name());
1325                 return;
1326         }
1327
1328         if (!_session->route_name_unique (x)) {
1329                 ARDOUR_UI::instance()->popup_error (_("A track already exists with that name"));
1330                 name_entry.set_text (_route->name());
1331         } else if (_session->route_name_internal (x)) {
1332                 ARDOUR_UI::instance()->popup_error (_("You cannot create a track with that name as it is reserved for Ardour"));
1333                 name_entry.set_text (_route->name());
1334         } else {
1335                 _route->set_name (x);
1336         }
1337 }
1338
1339 void
1340 RouteTimeAxisView::visual_click ()
1341 {
1342         popup_display_menu (0);
1343 }
1344
1345 void
1346 RouteTimeAxisView::hide_click ()
1347 {
1348         // LAME fix for hide_button refresh fix
1349         hide_button.set_sensitive(false);
1350
1351         _editor.hide_track_in_display (*this);
1352
1353         hide_button.set_sensitive(true);
1354 }
1355
1356 boost::shared_ptr<Region>
1357 RouteTimeAxisView::find_next_region (nframes_t pos, RegionPoint point, int32_t dir)
1358 {
1359         boost::shared_ptr<Playlist> pl = playlist ();
1360
1361         if (pl) {
1362                 return pl->find_next_region (pos, point, dir);
1363         }
1364
1365         return boost::shared_ptr<Region> ();
1366 }
1367
1368 nframes64_t
1369 RouteTimeAxisView::find_next_region_boundary (nframes64_t pos, int32_t dir)
1370 {
1371         boost::shared_ptr<Playlist> pl = playlist ();
1372
1373         if (pl) {
1374                 return pl->find_next_region_boundary (pos, dir);
1375         }
1376
1377         return -1;
1378 }
1379
1380 bool
1381 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1382 {
1383         boost::shared_ptr<Playlist> what_we_got;
1384         boost::shared_ptr<Track> tr = track ();
1385         boost::shared_ptr<Playlist> playlist;
1386         bool ret = false;
1387
1388         if (tr == 0) {
1389                 /* route is a bus, not a track */
1390                 return false;
1391         }
1392
1393         playlist = tr->playlist();
1394
1395         TimeSelection time (selection.time);
1396         float const speed = tr->speed();
1397         if (speed != 1.0f) {
1398                 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1399                         (*i).start = session_frame_to_track_frame((*i).start, speed);
1400                         (*i).end   = session_frame_to_track_frame((*i).end,   speed);
1401                 }
1402         }
1403
1404         playlist->clear_history ();
1405         playlist->clear_owned_history ();
1406
1407         switch (op) {
1408         case Cut:
1409                 if ((what_we_got = playlist->cut (time)) != 0) {
1410                         _editor.get_cut_buffer().add (what_we_got);
1411
1412                         vector<StatefulDiffCommand*> cmds;
1413                         
1414                         playlist->rdiff (cmds);
1415                         
1416                         for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
1417                                 _session->add_command (*c);
1418                         }
1419                         _session->add_command (new StatefulDiffCommand (playlist));
1420                         ret = true;
1421                 }
1422                 break;
1423         case Copy:
1424                 if ((what_we_got = playlist->copy (time)) != 0) {
1425                         _editor.get_cut_buffer().add (what_we_got);
1426                 }
1427                 break;
1428
1429         case Clear:
1430                 if ((what_we_got = playlist->cut (time)) != 0) {
1431                         vector<StatefulDiffCommand*> cmds;
1432                         
1433                         playlist->rdiff (cmds);
1434                         
1435                         for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
1436                                 _session->add_command (*c);
1437                         }
1438                         _session->add_command (new StatefulDiffCommand (playlist));
1439                         what_we_got->release ();
1440                         ret = true;
1441                 }
1442                 break;
1443         }
1444
1445         return ret;
1446 }
1447
1448 bool
1449 RouteTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
1450 {
1451         if (!is_track()) {
1452                 return false;
1453         }
1454
1455         boost::shared_ptr<Playlist> pl = playlist ();
1456         PlaylistSelection::iterator p;
1457
1458         for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth) {}
1459
1460         if (p == selection.playlists.end()) {
1461                 return false;
1462         }
1463
1464         if (track()->speed() != 1.0f) {
1465                 pos = session_frame_to_track_frame (pos, track()->speed());
1466         }
1467
1468         pl->clear_history ();
1469         pl->paste (*p, pos, times);
1470         _session->add_command (new StatefulDiffCommand (pl));
1471
1472         return true;
1473 }
1474
1475
1476 TimeAxisView::Children
1477 RouteTimeAxisView::get_child_list()
1478 {
1479         TimeAxisView::Children redirect_children;
1480
1481         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1482                 if (!(*i)->hidden()) {
1483                         redirect_children.push_back(*i);
1484                 }
1485         }
1486         return redirect_children;
1487 }
1488
1489
1490 struct PlaylistSorter {
1491     bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1492             return a->sort_id() < b->sort_id();
1493     }
1494 };
1495
1496 void
1497 RouteTimeAxisView::build_playlist_menu (Gtk::Menu * menu)
1498 {
1499         using namespace Menu_Helpers;
1500
1501         if (!menu || !is_track()) {
1502                 return;
1503         }
1504
1505         MenuList& playlist_items = menu->items();
1506         menu->set_name ("ArdourContextMenu");
1507         playlist_items.clear();
1508
1509         delete playlist_menu;
1510
1511
1512         vector<boost::shared_ptr<Playlist> > playlists, playlists_tr;
1513         boost::shared_ptr<Track> tr = track();
1514         RadioMenuItem::Group playlist_group;
1515
1516         _session->playlists->get (playlists);
1517
1518         /* find the playlists for this diskstream */
1519         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
1520                 if (((*i)->get_orig_diskstream_id() == tr->diskstream_id()) || (tr->playlist()->id() == (*i)->id())) {
1521                         playlists_tr.push_back(*i);
1522                 }
1523         }
1524
1525         /* sort the playlists */
1526         PlaylistSorter cmp;
1527         sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1528         
1529         /* add the playlists to the menu */
1530         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1531                 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1532                 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1533                 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1534                 
1535                 if (tr->playlist()->id() == (*i)->id()) {
1536                         item->set_active();
1537                         
1538                 }
1539         }
1540         
1541         playlist_items.push_back (SeparatorElem());
1542         playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1543         playlist_items.push_back (SeparatorElem());
1544
1545         if (!route_group() || !route_group()->is_active()) {
1546                 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1547                 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1548
1549         } else {
1550                 // Use a label which tells the user what is happening
1551                 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1552                 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1553
1554         }
1555
1556         playlist_items.push_back (SeparatorElem());
1557         playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1558         playlist_items.push_back (SeparatorElem());
1559
1560         playlist_items.push_back (MenuElem(_("Select from all..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1561 }
1562
1563 void
1564 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1565 {
1566         assert (is_track());
1567
1568         // exit if we were triggered by deactivating the old playlist
1569         if (!item->get_active()) {
1570                 return;
1571         }
1572
1573         boost::shared_ptr<Playlist> pl (wpl.lock());
1574
1575         if (!pl) {
1576                 return;
1577         }
1578
1579         boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
1580
1581         if (apl) {
1582                 if (track()->playlist() == apl) {
1583                         // exit when use_playlist is called by the creation of the playlist menu
1584                         // or the playlist choice is unchanged
1585                         return;
1586                 }
1587                 track()->use_playlist (apl);
1588
1589                 if (route_group() && route_group()->is_active()) {
1590                         std::string group_string = "."+route_group()->name()+".";
1591
1592                         std::string take_name = apl->name();
1593                         std::string::size_type idx = take_name.find(group_string);
1594
1595                         if (idx == std::string::npos)
1596                                 return;
1597
1598                         take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1599
1600                         boost::shared_ptr<RouteList> rl (route_group()->route_list());
1601
1602                         for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1603                                 if ( (*i) == this->route()) {
1604                                         continue;
1605                                 }
1606
1607                                 std::string playlist_name = (*i)->name()+group_string+take_name;
1608
1609                                 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1610                                 if (!track) {
1611                                         std::cerr << "route " << (*i)->name() << " is not a Track" << std::endl;
1612                                         continue;
1613                                 }
1614
1615                                 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1616                                 if (!ipl) {
1617                                         // No playlist for this track for this take yet, make it
1618                                         track->use_new_playlist();
1619                                         track->playlist()->set_name(playlist_name);
1620                                 } else {
1621                                         track->use_playlist(ipl);
1622                                 }
1623                         }
1624                 }
1625         }
1626 }
1627
1628 void
1629 RouteTimeAxisView::show_playlist_selector ()
1630 {
1631         _editor.playlist_selector().show_for (this);
1632 }
1633
1634 void
1635 RouteTimeAxisView::map_frozen ()
1636 {
1637         if (!is_track()) {
1638                 return;
1639         }
1640
1641         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1642
1643         switch (track()->freeze_state()) {
1644         case Track::Frozen:
1645                 playlist_button.set_sensitive (false);
1646                 rec_enable_button->set_sensitive (false);
1647                 break;
1648         default:
1649                 playlist_button.set_sensitive (true);
1650                 rec_enable_button->set_sensitive (true);
1651                 break;
1652         }
1653 }
1654
1655 void
1656 RouteTimeAxisView::color_handler ()
1657 {
1658         //case cTimeStretchOutline:
1659         if (timestretch_rect) {
1660                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
1661         }
1662         //case cTimeStretchFill:
1663         if (timestretch_rect) {
1664                 timestretch_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
1665         }
1666
1667         reset_meter();
1668 }
1669
1670 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1671  *  Will add track if necessary.
1672  */
1673 void
1674 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1675 {
1676         RouteAutomationNode* node = automation_track(param);
1677         
1678         if (!node) {
1679                 /* it doesn't exist yet, so we don't care about the button state: just add it */
1680                 create_automation_child (param, true);
1681         } else {
1682                 bool yn = node->menu_item->get_active();
1683                 if (node->track->set_visibility (node->menu_item->get_active()) && yn) {
1684                         
1685                         /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1686                            will have done that for us.
1687                         */
1688                         
1689                         if (!no_redraw) {
1690                                 _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
1691                         } 
1692                 }
1693         }
1694 }
1695
1696 void
1697 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1698 {
1699         RouteAutomationNode* ran = automation_track(param);
1700
1701         if (!ran) {
1702                 return;
1703         }
1704
1705         // if Evoral::Parameter::operator< doesn't obey strict weak ordering, we may crash here....
1706         _show_automation.erase (param);
1707         ran->track->get_state_node()->add_property (X_("shown"), X_("no"));
1708
1709         if (ran->menu_item && !_hidden) {
1710                 ignore_toggle = true;
1711                 ran->menu_item->set_active (false);
1712                 ignore_toggle = false;
1713         }
1714
1715         if (_route && !no_redraw) {
1716                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1717         }
1718 }
1719
1720
1721 void
1722 RouteTimeAxisView::show_all_automation ()
1723 {
1724         no_redraw = true;
1725
1726         /* Show our automation */
1727
1728         map<Evoral::Parameter, RouteAutomationNode*>::iterator i;
1729         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1730                 i->second->track->set_marked_for_display (true);
1731                 i->second->track->canvas_display()->show();
1732                 i->second->track->get_state_node()->add_property ("shown", X_("yes"));
1733                 if (i->second->menu_item) {
1734                         i->second->menu_item->set_active(true);
1735                 }
1736         }
1737
1738
1739         /* Show processor automation */
1740
1741         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1742                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1743                         if ((*ii)->view == 0) {
1744                                 add_processor_automation_curve ((*i)->processor, (*ii)->what);
1745                         }
1746
1747                         (*ii)->menu_item->set_active (true);
1748                 }
1749         }
1750
1751         no_redraw = false;
1752
1753         /* Redraw */
1754
1755          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1756 }
1757
1758 void
1759 RouteTimeAxisView::show_existing_automation ()
1760 {
1761         no_redraw = true;
1762
1763         /* Show our automation */
1764
1765         map<Evoral::Parameter, RouteAutomationNode*>::iterator i;
1766         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1767                 if (i->second->track->line() && i->second->track->line()->npoints() > 0) {
1768                         i->second->track->set_marked_for_display (true);
1769                         i->second->track->canvas_display()->show();
1770                         i->second->track->get_state_node()->add_property ("shown", X_("yes"));
1771                         i->second->menu_item->set_active(true);
1772                 }
1773         }
1774
1775
1776         /* Show processor automation */
1777
1778         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1779                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1780                         if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
1781                                 (*ii)->menu_item->set_active (true);
1782                         }
1783                 }
1784         }
1785
1786         no_redraw = false;
1787
1788         _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1789 }
1790
1791 void
1792 RouteTimeAxisView::hide_all_automation ()
1793 {
1794         no_redraw = true;
1795
1796         /* Hide our automation */
1797
1798         for (map<Evoral::Parameter, RouteAutomationNode*>::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1799                 i->second->track->set_marked_for_display (false);
1800                 i->second->track->hide ();
1801                 i->second->track->get_state_node()->add_property ("shown", X_("no"));
1802                 if (i->second->menu_item) {
1803                         i->second->menu_item->set_active (false);
1804                 }
1805         }
1806
1807         /* Hide processor automation */
1808
1809         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1810                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1811                         (*ii)->menu_item->set_active (false);
1812                 }
1813         }
1814
1815         _show_automation.clear();
1816
1817         no_redraw = false;
1818          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1819 }
1820
1821
1822 void
1823 RouteTimeAxisView::region_view_added (RegionView* rv)
1824 {
1825         /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
1826         if (is_audio_track()) {
1827                 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1828                         boost::shared_ptr<AutomationTimeAxisView> atv;
1829
1830                         if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
1831                                 atv->add_ghost(rv);
1832                         }
1833                 }
1834         }
1835
1836         for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
1837                 (*i)->add_ghost(rv);
1838         }
1839 }
1840
1841 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
1842 {
1843         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1844                 delete *i;
1845         }
1846 }
1847
1848
1849 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
1850 {
1851         parent.remove_processor_automation_node (this);
1852 }
1853
1854 void
1855 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
1856 {
1857         if (pan->view) {
1858                 remove_child (pan->view);
1859         }
1860 }
1861
1862 RouteTimeAxisView::ProcessorAutomationNode*
1863 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1864 {
1865         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1866
1867                 if ((*i)->processor == processor) {
1868
1869                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1870                                 if ((*ii)->what == what) {
1871                                         return *ii;
1872                                 }
1873                         }
1874                 }
1875         }
1876
1877         return 0;
1878 }
1879
1880 static string
1881 legalize_for_xml_node (string str)
1882 {
1883         string::size_type pos;
1884         string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_=:";
1885         string legal;
1886
1887         legal = str;
1888         pos = 0;
1889
1890         while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
1891                 legal.replace (pos, 1, "_");
1892                 pos += 1;
1893         }
1894
1895         return legal;
1896 }
1897
1898
1899 void
1900 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1901 {
1902         string name;
1903         ProcessorAutomationNode* pan;
1904
1905         if ((pan = find_processor_automation_node (processor, what)) == 0) {
1906                 error << _("programming error: ")
1907                       << string_compose (X_("processor automation curve for %1:%2 not registered with track!"),
1908                                   processor->name(), what)
1909                       << endmsg;
1910                 /*NOTREACHED*/
1911                 return;
1912         }
1913
1914         if (pan->view) {
1915                 return;
1916         }
1917
1918         name = processor->describe_parameter (what);
1919
1920         /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
1921
1922         /* FIXME: ew */
1923
1924         char state_name[256];
1925         snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id());
1926
1927         boost::shared_ptr<AutomationControl> control
1928                         = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
1929
1930         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
1931                         new AutomationTimeAxisView (_session, _route, processor, control,
1932                                 _editor, *this, false, parent_canvas, name, state_name));
1933
1934         pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
1935
1936         if (!pan->view->marked_for_display()) {
1937                 pan->view->hide ();
1938         } else {
1939                 pan->menu_item->set_active (true);
1940         }
1941
1942         add_child (pan->view);
1943
1944         if (_view) {
1945                 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
1946         }
1947
1948         processor->mark_automation_visible (what, true);
1949 }
1950
1951 void
1952 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor> i)
1953 {
1954         if (!_hidden) {
1955                 pan->menu_item->set_active (false);
1956         }
1957
1958         i->mark_automation_visible (pan->what, false);
1959
1960         if (!no_redraw) {
1961                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1962         }
1963 }
1964
1965 void
1966 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
1967 {
1968         boost::shared_ptr<Processor> processor (p.lock ());
1969         if (!processor) {
1970                 return;
1971         }
1972
1973         set<Evoral::Parameter> s;
1974         boost::shared_ptr<AutomationLine> al;
1975
1976         processor->what_has_visible_data (s);
1977
1978         for (set<Evoral::Parameter>::iterator i = s.begin(); i != s.end(); ++i) {
1979
1980                 if ((al = find_processor_automation_curve (processor, *i)) != 0) {
1981                         al->queue_reset ();
1982                 } else {
1983                         add_processor_automation_curve (processor, (*i));
1984                 }
1985         }
1986 }
1987
1988 void
1989 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
1990 {
1991         using namespace Menu_Helpers;
1992
1993         XMLProperty* prop;
1994         XMLNode* node;
1995
1996         add_child (track);
1997
1998         track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
1999
2000         bool hideit = (!show);
2001
2002         if ((node = track->get_state_node()) != 0) {
2003                 if  ((prop = node->property ("shown")) != 0) {
2004                         if (string_is_affirmative (prop->value())) {
2005                                 hideit = false;
2006                         }
2007                 }
2008         }
2009
2010         _automation_tracks.insert (std::make_pair (param, new RouteAutomationNode(param, NULL, track)));
2011
2012         track->set_visibility (!hideit);
2013
2014         if (!hideit) {
2015                 _show_automation.insert (param);
2016         }
2017         
2018         if (!no_redraw) {
2019                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2020         }
2021
2022         if (!EventTypeMap::instance().is_midi_parameter(param)) {
2023                 /* MIDI-related parameters are always in the menu, there's no
2024                    reason to rebuild the menu just because we added a automation
2025                    lane for one of them. But if we add a non-MIDI automation
2026                    lane, then we need to invalidate the display menu.
2027                 */
2028                 delete display_menu;
2029                 display_menu = 0;
2030         }
2031 }
2032
2033 void
2034 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2035 {
2036         boost::shared_ptr<Processor> processor (p.lock ());
2037
2038         if (!processor || !processor->display_to_user ()) {
2039                 return;
2040         }
2041
2042         using namespace Menu_Helpers;
2043         ProcessorAutomationInfo *rai;
2044         list<ProcessorAutomationInfo*>::iterator x;
2045
2046         const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2047         std::set<Evoral::Parameter> has_visible_automation;
2048
2049         processor->what_has_visible_data(has_visible_automation);
2050
2051         if (automatable.empty()) {
2052                 return;
2053         }
2054
2055         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2056                 if ((*x)->processor == processor) {
2057                         break;
2058                 }
2059         }
2060
2061         if (x == processor_automation.end()) {
2062
2063                 rai = new ProcessorAutomationInfo (processor);
2064                 processor_automation.push_back (rai);
2065
2066         } else {
2067
2068                 rai = *x;
2069
2070         }
2071
2072         /* any older menu was deleted at the top of processors_changed()
2073            when we cleared the subplugin menu.
2074         */
2075
2076         rai->menu = manage (new Menu);
2077         MenuList& items = rai->menu->items();
2078         rai->menu->set_name ("ArdourContextMenu");
2079
2080         items.clear ();
2081
2082         for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2083
2084                 ProcessorAutomationNode* pan;
2085                 CheckMenuItem* mitem;
2086
2087                 string name = processor->describe_parameter (*i);
2088
2089                 items.push_back (CheckMenuElem (name));
2090                 mitem = dynamic_cast<CheckMenuItem*> (&items.back());
2091
2092                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2093                         mitem->set_active(true);
2094                 }
2095
2096                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2097
2098                         /* new item */
2099
2100                         pan = new ProcessorAutomationNode (*i, mitem, *this);
2101
2102                         rai->lines.push_back (pan);
2103
2104                 } else {
2105
2106                         pan->menu_item = mitem;
2107
2108                 }
2109
2110                 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2111         }
2112
2113         /* add the menu for this processor, because the subplugin
2114            menu is always cleared at the top of processors_changed().
2115            this is the result of some poor design in gtkmm and/or
2116            GTK+.
2117         */
2118
2119         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2120         rai->valid = true;
2121 }
2122
2123 void
2124 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2125                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
2126 {
2127         bool showit = pan->menu_item->get_active();
2128         bool redraw = false;
2129
2130         if (pan->view == 0 && showit) {
2131                 add_processor_automation_curve (rai->processor, pan->what);
2132                 redraw = true;
2133         }
2134
2135         if (pan->view && showit != pan->view->marked_for_display()) {
2136
2137                 if (showit) {
2138                         pan->view->set_marked_for_display (true);
2139                         pan->view->canvas_display()->show();
2140                         pan->view->canvas_background()->show();
2141                 } else {
2142                         rai->processor->mark_automation_visible (pan->what, true);
2143                         pan->view->set_marked_for_display (false);
2144                         pan->view->hide ();
2145                 }
2146
2147                 redraw = true;
2148
2149         }
2150
2151         if (redraw && !no_redraw) {
2152                  _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2153
2154         }
2155 }
2156
2157 void
2158 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2159 {
2160         if (c.type == RouteProcessorChange::MeterPointChange) {
2161                 /* nothing to do if only the meter point has changed */
2162                 return;
2163         }
2164
2165         using namespace Menu_Helpers;
2166
2167         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2168                 (*i)->valid = false;
2169         }
2170
2171         subplugin_menu.items().clear ();
2172
2173         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
2174         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
2175
2176         bool deleted_processor_automation = false;
2177
2178         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2179
2180                 list<ProcessorAutomationInfo*>::iterator tmp;
2181
2182                 tmp = i;
2183                 ++tmp;
2184
2185                 if (!(*i)->valid) {
2186
2187                         delete *i;
2188                         processor_automation.erase (i);
2189                         deleted_processor_automation = true;
2190
2191                 }
2192
2193                 i = tmp;
2194         }
2195
2196         if (deleted_processor_automation && !no_redraw) {
2197                 _route->gui_changed ("track_height", this);
2198         }
2199 }
2200
2201 boost::shared_ptr<AutomationLine>
2202 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2203 {
2204         ProcessorAutomationNode* pan;
2205
2206         if ((pan = find_processor_automation_node (processor, what)) != 0) {
2207                 if (pan->view) {
2208                         pan->view->line();
2209                 }
2210         }
2211
2212         return boost::shared_ptr<AutomationLine>();
2213 }
2214
2215 void
2216 RouteTimeAxisView::reset_processor_automation_curves ()
2217 {
2218         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2219                 (*i)->reset();
2220         }
2221 }
2222
2223 void
2224 RouteTimeAxisView::update_rec_display ()
2225 {
2226         RouteUI::update_rec_display ();
2227         name_entry.set_sensitive (!_route->record_enabled());
2228 }
2229
2230 void
2231 RouteTimeAxisView::set_layer_display (LayerDisplay d)
2232 {
2233         if (_view) {
2234                 _view->set_layer_display (d);
2235         }
2236
2237         ensure_xml_node ();
2238         xml_node->add_property (N_("layer-display"), enum_2_string (d));
2239 }
2240
2241 LayerDisplay
2242 RouteTimeAxisView::layer_display () const
2243 {
2244         if (_view) {
2245                 return _view->layer_display ();
2246         }
2247
2248         /* we don't know, since we don't have a _view, so just return something */
2249         return Overlaid;
2250 }
2251
2252
2253
2254 boost::shared_ptr<AutomationTimeAxisView>
2255 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2256 {
2257         AutomationTracks::iterator i = _automation_tracks.find(param);
2258         if (i != _automation_tracks.end()) {
2259                 return i->second->track;
2260         } else {
2261                 return boost::shared_ptr<AutomationTimeAxisView>();
2262         }
2263 }
2264
2265 void
2266 RouteTimeAxisView::fast_update ()
2267 {
2268         gm.get_level_meter().update_meters ();
2269 }
2270
2271 void
2272 RouteTimeAxisView::hide_meter ()
2273 {
2274         clear_meter ();
2275         gm.get_level_meter().hide_meters ();
2276 }
2277
2278 void
2279 RouteTimeAxisView::show_meter ()
2280 {
2281         reset_meter ();
2282 }
2283
2284 void
2285 RouteTimeAxisView::reset_meter ()
2286 {
2287         if (Config->get_show_track_meters()) {
2288                 gm.get_level_meter().setup_meters (height-5);
2289         } else {
2290                 hide_meter ();
2291         }
2292 }
2293
2294 void
2295 RouteTimeAxisView::clear_meter ()
2296 {
2297         gm.get_level_meter().clear_meters ();
2298 }
2299
2300 void
2301 RouteTimeAxisView::meter_changed ()
2302 {
2303         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2304         reset_meter();
2305 }
2306
2307 void
2308 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2309 {
2310         reset_meter ();
2311 }
2312
2313 void
2314 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2315 {
2316         using namespace Menu_Helpers;
2317
2318         if (!_underlay_streams.empty()) {
2319                 MenuList& parent_items = parent_menu->items();
2320                 Menu* gs_menu = manage (new Menu);
2321                 gs_menu->set_name ("ArdourContextMenu");
2322                 MenuList& gs_items = gs_menu->items();
2323
2324                 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2325
2326                 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2327                         gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2328                                                     sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2329                 }
2330         }
2331 }
2332
2333 bool
2334 RouteTimeAxisView::set_underlay_state()
2335 {
2336         if (!underlay_xml_node) {
2337                 return false;
2338         }
2339
2340         XMLNodeList nlist = underlay_xml_node->children();
2341         XMLNodeConstIterator niter;
2342         XMLNode *child_node;
2343
2344         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2345                 child_node = *niter;
2346
2347                 if (child_node->name() != "Underlay") {
2348                         continue;
2349                 }
2350
2351                 XMLProperty* prop = child_node->property ("id");
2352                 if (prop) {
2353                         PBD::ID id (prop->value());
2354
2355                         RouteTimeAxisView* v = _editor.get_route_view_by_id (id);
2356
2357                         if (v) {
2358                                 add_underlay(v->view(), false);
2359                         }
2360                 }
2361         }
2362
2363         return false;
2364 }
2365
2366 void
2367 RouteTimeAxisView::add_underlay (StreamView* v, bool update_xml)
2368 {
2369         if (!v) {
2370                 return;
2371         }
2372
2373         RouteTimeAxisView& other = v->trackview();
2374
2375         if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2376                 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2377                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2378                         /*NOTREACHED*/
2379                 }
2380
2381                 _underlay_streams.push_back(v);
2382                 other._underlay_mirrors.push_back(this);
2383
2384                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2385
2386                 if (update_xml) {
2387                         if (!underlay_xml_node) {
2388                                 ensure_xml_node();
2389                                 underlay_xml_node = xml_node->add_child("Underlays");
2390                         }
2391
2392                         XMLNode* node = underlay_xml_node->add_child("Underlay");
2393                         XMLProperty* prop = node->add_property("id");
2394                         prop->set_value(v->trackview().route()->id().to_s());
2395                 }
2396         }
2397 }
2398
2399 void
2400 RouteTimeAxisView::remove_underlay (StreamView* v)
2401 {
2402         if (!v) {
2403                 return;
2404         }
2405
2406         UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2407         RouteTimeAxisView& other = v->trackview();
2408
2409         if (it != _underlay_streams.end()) {
2410                 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2411
2412                 if (gm == other._underlay_mirrors.end()) {
2413                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2414                         /*NOTREACHED*/
2415                 }
2416
2417                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2418
2419                 _underlay_streams.erase(it);
2420                 other._underlay_mirrors.erase(gm);
2421
2422                 if (underlay_xml_node) {
2423                         underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2424                 }
2425         }
2426 }
2427
2428 void
2429 RouteTimeAxisView::set_button_names ()
2430 {
2431         rec_enable_button_label.set_text (_("r"));
2432
2433         if (_route && _route->solo_safe()) {
2434                 solo_button_label.set_text (X_("!"));
2435         } else {
2436                 if (Config->get_solo_control_is_listen_control()) {
2437                         switch (Config->get_listen_position()) {
2438                         case AfterFaderListen:
2439                                 solo_button_label.set_text (_("A"));
2440                                 break;
2441                         case PreFaderListen:
2442                                 solo_button_label.set_text (_("P"));
2443                                 break;
2444                         }
2445                 } else {
2446                         solo_button_label.set_text (_("s"));
2447                 }
2448         }
2449         mute_button_label.set_text (_("m"));
2450 }