Move Diskstream ownership to Track, so that Session no longer holds lists of Diskstre...
[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         solo_changed (0);
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_prompt (_("Name for playlist"));
972         prompter.set_initial_text (pl->name());
973         prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
974         prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
975
976         switch (prompter.run ()) {
977         case Gtk::RESPONSE_ACCEPT:
978                 prompter.get_result (name);
979                 if (name.length()) {
980                         pl->set_name (name);
981                 }
982                 break;
983
984         default:
985                 break;
986         }
987 }
988
989 std::string
990 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
991 {
992         std::string ret (basename);
993
994         std::string const group_string = "." + route_group()->name() + ".";
995
996         // iterate through all playlists
997         int maxnumber = 0;
998         for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
999                 std::string tmp = (*i)->name();
1000
1001                 std::string::size_type idx = tmp.find(group_string);
1002                 // find those which belong to this group
1003                 if (idx != string::npos) {
1004                         tmp = tmp.substr(idx + group_string.length());
1005
1006                         // and find the largest current number
1007                         int x = atoi(tmp.c_str());
1008                         if (x > maxnumber) {
1009                                 maxnumber = x;
1010                         }
1011                 }
1012         }
1013
1014         maxnumber++;
1015
1016         char buf[32];
1017         snprintf (buf, sizeof(buf), "%d", maxnumber);
1018
1019         ret = this->name() + "." + route_group()->name () + "." + buf;
1020
1021         return ret;
1022 }
1023
1024 void
1025 RouteTimeAxisView::use_copy_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1026 {
1027         string name;
1028
1029         boost::shared_ptr<Track> tr = track ();
1030         if (!tr || tr->destructive()) {
1031                 return;
1032         }
1033
1034         boost::shared_ptr<const Playlist> pl = tr->playlist();
1035         if (!pl) {
1036                 return;
1037         }
1038
1039         name = pl->name();
1040
1041         if (route_group() && route_group()->is_active()) {
1042                 name = resolve_new_group_playlist_name(name, playlists_before_op);
1043         }
1044
1045         while (_session->playlists->by_name(name)) {
1046                 name = Playlist::bump_name (name, *_session);
1047         }
1048
1049         // TODO: The prompter "new" button should be de-activated if the user
1050         // specifies a playlist name which already exists in the session.
1051
1052         if (prompt) {
1053
1054                 ArdourPrompter prompter (true);
1055
1056                 prompter.set_prompt (_("Name for Playlist"));
1057                 prompter.set_initial_text (name);
1058                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1059                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1060                 prompter.show_all ();
1061
1062                 switch (prompter.run ()) {
1063                 case Gtk::RESPONSE_ACCEPT:
1064                         prompter.get_result (name);
1065                         break;
1066
1067                 default:
1068                         return;
1069                 }
1070         }
1071
1072         if (name.length()) {
1073                 tr->use_copy_playlist ();
1074                 tr->playlist()->set_name (name);
1075         }
1076 }
1077
1078 void
1079 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1080 {
1081         string name;
1082
1083         boost::shared_ptr<Track> tr = track ();
1084         if (!tr || tr->destructive()) {
1085                 return;
1086         }
1087
1088         boost::shared_ptr<const Playlist> pl = tr->playlist();
1089         if (!pl) {
1090                 return;
1091         }
1092
1093         name = pl->name();
1094
1095         if (route_group() && route_group()->is_active()) {
1096                 name = resolve_new_group_playlist_name(name,playlists_before_op);
1097         }
1098
1099         while (_session->playlists->by_name(name)) {
1100                 name = Playlist::bump_name (name, *_session);
1101         }
1102
1103
1104         if (prompt) {
1105
1106                 ArdourPrompter prompter (true);
1107
1108                 prompter.set_prompt (_("Name for Playlist"));
1109                 prompter.set_initial_text (name);
1110                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1111                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1112
1113                 switch (prompter.run ()) {
1114                 case Gtk::RESPONSE_ACCEPT:
1115                         prompter.get_result (name);
1116                         break;
1117
1118                 default:
1119                         return;
1120                 }
1121         }
1122
1123         if (name.length()) {
1124                 tr->use_new_playlist ();
1125                 tr->playlist()->set_name (name);
1126         }
1127 }
1128
1129 void
1130 RouteTimeAxisView::clear_playlist ()
1131 {
1132         boost::shared_ptr<Track> tr = track ();
1133         if (!tr || tr->destructive()) {
1134                 return;
1135         }
1136
1137         boost::shared_ptr<Playlist> pl = tr->playlist();
1138         if (!pl) {
1139                 return;
1140         }
1141
1142         _editor.clear_playlist (pl);
1143 }
1144
1145 void
1146 RouteTimeAxisView::speed_changed ()
1147 {
1148         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_unit, this));
1149 }
1150
1151 void
1152 RouteTimeAxisView::update_diskstream_display ()
1153 {
1154         if (!track()) {
1155                 return;
1156         }
1157
1158         map_frozen ();
1159 }
1160
1161 void
1162 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1163 {
1164         if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1165
1166                 /* special case: select/deselect all tracks */
1167                 if (_editor.get_selection().selected (this)) {
1168                         _editor.get_selection().clear_tracks ();
1169                 } else {
1170                         _editor.select_all_tracks ();
1171                 }
1172
1173                 return;
1174         }
1175
1176         switch (ArdourKeyboard::selection_type (ev->state)) {
1177         case Selection::Toggle:
1178                 _editor.get_selection().toggle (this);
1179                 break;
1180
1181         case Selection::Set:
1182                 _editor.get_selection().set (this);
1183                 break;
1184
1185         case Selection::Extend:
1186                 _editor.extend_selection_to_track (*this);
1187                 break;
1188
1189         case Selection::Add:
1190                 _editor.get_selection().add (this);
1191                 break;
1192         }
1193 }
1194
1195 void
1196 RouteTimeAxisView::set_selected_points (PointSelection& points)
1197 {
1198         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1199                 (*i)->set_selected_points (points);
1200         }
1201 }
1202
1203 void
1204 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1205 {
1206         if (_view) {
1207                 _view->set_selected_regionviews (regions);
1208         }
1209 }
1210
1211 /** Add the selectable things that we have to a list.
1212  * @param results List to add things to.
1213  */
1214 void
1215 RouteTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
1216 {
1217         double speed = 1.0;
1218
1219         if (track() != 0) {
1220                 speed = track()->speed();
1221         }
1222
1223         nframes_t start_adjusted = session_frame_to_track_frame(start, speed);
1224         nframes_t end_adjusted   = session_frame_to_track_frame(end, speed);
1225
1226         if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1227                 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1228         }
1229
1230         /* pick up visible automation tracks */
1231
1232         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1233                 if (!(*i)->hidden()) {
1234                         (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1235                 }
1236         }
1237 }
1238
1239 void
1240 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1241 {
1242         if (_view) {
1243                 _view->get_inverted_selectables (sel, results);
1244         }
1245
1246         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1247                 if (!(*i)->hidden()) {
1248                         (*i)->get_inverted_selectables (sel, results);
1249                 }
1250         }
1251
1252         return;
1253 }
1254
1255 bool
1256 RouteTimeAxisView::show_automation(Evoral::Parameter param)
1257 {
1258         return (_show_automation.find(param) != _show_automation.end());
1259 }
1260
1261 /** Retuns 0 if track for \a param doesn't exist.
1262  */
1263 RouteTimeAxisView::RouteAutomationNode*
1264 RouteTimeAxisView::automation_track (Evoral::Parameter param)
1265 {
1266         map<Evoral::Parameter, RouteAutomationNode*>::iterator i = _automation_tracks.find (param);
1267
1268         if (i != _automation_tracks.end()) {
1269                 return i->second;
1270         } else {
1271                 return 0;
1272         }
1273 }
1274
1275 /** Shorthand for GainAutomation, etc.
1276  */
1277 RouteTimeAxisView::RouteAutomationNode*
1278 RouteTimeAxisView::automation_track (AutomationType type)
1279 {
1280         return automation_track (Evoral::Parameter(type));
1281 }
1282
1283 RouteGroup*
1284 RouteTimeAxisView::route_group () const
1285 {
1286         return _route->route_group();
1287 }
1288
1289 string
1290 RouteTimeAxisView::name() const
1291 {
1292         return _route->name();
1293 }
1294
1295 boost::shared_ptr<Playlist>
1296 RouteTimeAxisView::playlist () const
1297 {
1298         boost::shared_ptr<Track> tr;
1299
1300         if ((tr = track()) != 0) {
1301                 return tr->playlist();
1302         } else {
1303                 return boost::shared_ptr<Playlist> ();
1304         }
1305 }
1306
1307 void
1308 RouteTimeAxisView::name_entry_changed ()
1309 {
1310         string x;
1311
1312         x = name_entry.get_text ();
1313
1314         if (x == _route->name()) {
1315                 return;
1316         }
1317
1318         strip_whitespace_edges(x);
1319
1320         if (x.length() == 0) {
1321                 name_entry.set_text (_route->name());
1322                 return;
1323         }
1324
1325         if (!_session->route_name_unique (x)) {
1326                 ARDOUR_UI::instance()->popup_error (_("A track already exists with that name"));
1327                 name_entry.set_text (_route->name());
1328         } else if (_session->route_name_internal (x)) {
1329                 ARDOUR_UI::instance()->popup_error (_("You cannot create a track with that name as it is reserved for Ardour"));
1330                 name_entry.set_text (_route->name());
1331         } else {
1332                 _route->set_name (x);
1333         }
1334 }
1335
1336 void
1337 RouteTimeAxisView::visual_click ()
1338 {
1339         popup_display_menu (0);
1340 }
1341
1342 void
1343 RouteTimeAxisView::hide_click ()
1344 {
1345         // LAME fix for hide_button refresh fix
1346         hide_button.set_sensitive(false);
1347
1348         _editor.hide_track_in_display (*this);
1349
1350         hide_button.set_sensitive(true);
1351 }
1352
1353 boost::shared_ptr<Region>
1354 RouteTimeAxisView::find_next_region (nframes_t pos, RegionPoint point, int32_t dir)
1355 {
1356         boost::shared_ptr<Playlist> pl = playlist ();
1357
1358         if (pl) {
1359                 return pl->find_next_region (pos, point, dir);
1360         }
1361
1362         return boost::shared_ptr<Region> ();
1363 }
1364
1365 nframes64_t
1366 RouteTimeAxisView::find_next_region_boundary (nframes64_t pos, int32_t dir)
1367 {
1368         boost::shared_ptr<Playlist> pl = playlist ();
1369
1370         if (pl) {
1371                 return pl->find_next_region_boundary (pos, dir);
1372         }
1373
1374         return -1;
1375 }
1376
1377 bool
1378 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1379 {
1380         boost::shared_ptr<Playlist> what_we_got;
1381         boost::shared_ptr<Track> tr = track ();
1382         boost::shared_ptr<Playlist> playlist;
1383         bool ret = false;
1384
1385         if (tr == 0) {
1386                 /* route is a bus, not a track */
1387                 return false;
1388         }
1389
1390         playlist = tr->playlist();
1391
1392         TimeSelection time (selection.time);
1393         float const speed = tr->speed();
1394         if (speed != 1.0f) {
1395                 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1396                         (*i).start = session_frame_to_track_frame((*i).start, speed);
1397                         (*i).end   = session_frame_to_track_frame((*i).end,   speed);
1398                 }
1399         }
1400
1401         playlist->clear_history ();
1402         playlist->clear_owned_history ();
1403
1404         switch (op) {
1405         case Cut:
1406                 if ((what_we_got = playlist->cut (time)) != 0) {
1407                         _editor.get_cut_buffer().add (what_we_got);
1408
1409                         vector<StatefulDiffCommand*> cmds;
1410                         
1411                         playlist->rdiff (cmds);
1412                         
1413                         for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
1414                                 _session->add_command (*c);
1415                         }
1416                         _session->add_command (new StatefulDiffCommand (playlist));
1417                         ret = true;
1418                 }
1419                 break;
1420         case Copy:
1421                 if ((what_we_got = playlist->copy (time)) != 0) {
1422                         _editor.get_cut_buffer().add (what_we_got);
1423                 }
1424                 break;
1425
1426         case Clear:
1427                 if ((what_we_got = playlist->cut (time)) != 0) {
1428                         vector<StatefulDiffCommand*> cmds;
1429                         
1430                         playlist->rdiff (cmds);
1431                         
1432                         for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
1433                                 _session->add_command (*c);
1434                         }
1435                         _session->add_command (new StatefulDiffCommand (playlist));
1436                         what_we_got->release ();
1437                         ret = true;
1438                 }
1439                 break;
1440         }
1441
1442         return ret;
1443 }
1444
1445 bool
1446 RouteTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
1447 {
1448         if (!is_track()) {
1449                 return false;
1450         }
1451
1452         boost::shared_ptr<Playlist> pl = playlist ();
1453         PlaylistSelection::iterator p;
1454
1455         for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth) {}
1456
1457         if (p == selection.playlists.end()) {
1458                 return false;
1459         }
1460
1461         if (track()->speed() != 1.0f) {
1462                 pos = session_frame_to_track_frame (pos, track()->speed());
1463         }
1464
1465         pl->clear_history ();
1466         pl->paste (*p, pos, times);
1467         _session->add_command (new StatefulDiffCommand (pl));
1468
1469         return true;
1470 }
1471
1472
1473 TimeAxisView::Children
1474 RouteTimeAxisView::get_child_list()
1475 {
1476         TimeAxisView::Children redirect_children;
1477
1478         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1479                 if (!(*i)->hidden()) {
1480                         redirect_children.push_back(*i);
1481                 }
1482         }
1483         return redirect_children;
1484 }
1485
1486
1487 struct PlaylistSorter {
1488     bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1489             return a->sort_id() < b->sort_id();
1490     }
1491 };
1492
1493 void
1494 RouteTimeAxisView::build_playlist_menu (Gtk::Menu * menu)
1495 {
1496         using namespace Menu_Helpers;
1497
1498         if (!menu || !is_track()) {
1499                 return;
1500         }
1501
1502         MenuList& playlist_items = menu->items();
1503         menu->set_name ("ArdourContextMenu");
1504         playlist_items.clear();
1505
1506         delete playlist_menu;
1507
1508
1509         vector<boost::shared_ptr<Playlist> > playlists, playlists_tr;
1510         boost::shared_ptr<Track> tr = track();
1511         RadioMenuItem::Group playlist_group;
1512
1513         _session->playlists->get (playlists);
1514
1515         /* find the playlists for this diskstream */
1516         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
1517                 if (((*i)->get_orig_diskstream_id() == tr->diskstream_id()) || (tr->playlist()->id() == (*i)->id())) {
1518                         playlists_tr.push_back(*i);
1519                 }
1520         }
1521
1522         /* sort the playlists */
1523         PlaylistSorter cmp;
1524         sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1525         
1526         /* add the playlists to the menu */
1527         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1528                 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1529                 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1530                 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1531                 
1532                 if (tr->playlist()->id() == (*i)->id()) {
1533                         item->set_active();
1534                         
1535                 }
1536         }
1537         
1538         playlist_items.push_back (SeparatorElem());
1539         playlist_items.push_back (MenuElem (_("Rename"), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1540         playlist_items.push_back (SeparatorElem());
1541
1542         if (!route_group() || !route_group()->is_active()) {
1543                 playlist_items.push_back (MenuElem (_("New"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1544                 playlist_items.push_back (MenuElem (_("New Copy"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1545
1546         } else {
1547                 // Use a label which tells the user what is happening
1548                 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1549                 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1550
1551         }
1552
1553         playlist_items.push_back (SeparatorElem());
1554         playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1555         playlist_items.push_back (SeparatorElem());
1556
1557         playlist_items.push_back (MenuElem(_("Select from all ..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1558 }
1559
1560 void
1561 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1562 {
1563         assert (is_track());
1564
1565         // exit if we were triggered by deactivating the old playlist
1566         if (!item->get_active()) {
1567                 return;
1568         }
1569
1570         boost::shared_ptr<Playlist> pl (wpl.lock());
1571
1572         if (!pl) {
1573                 return;
1574         }
1575
1576         boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
1577
1578         if (apl) {
1579                 if (track()->playlist() == apl) {
1580                         // exit when use_playlist is called by the creation of the playlist menu
1581                         // or the playlist choice is unchanged
1582                         return;
1583                 }
1584                 track()->use_playlist (apl);
1585
1586                 if (route_group() && route_group()->is_active()) {
1587                         std::string group_string = "."+route_group()->name()+".";
1588
1589                         std::string take_name = apl->name();
1590                         std::string::size_type idx = take_name.find(group_string);
1591
1592                         if (idx == std::string::npos)
1593                                 return;
1594
1595                         take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1596
1597                         boost::shared_ptr<RouteList> rl (route_group()->route_list());
1598
1599                         for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1600                                 if ( (*i) == this->route()) {
1601                                         continue;
1602                                 }
1603
1604                                 std::string playlist_name = (*i)->name()+group_string+take_name;
1605
1606                                 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1607                                 if (!track) {
1608                                         std::cerr << "route " << (*i)->name() << " is not a Track" << std::endl;
1609                                         continue;
1610                                 }
1611
1612                                 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1613                                 if (!ipl) {
1614                                         // No playlist for this track for this take yet, make it
1615                                         track->use_new_playlist();
1616                                         track->playlist()->set_name(playlist_name);
1617                                 } else {
1618                                         track->use_playlist(ipl);
1619                                 }
1620                         }
1621                 }
1622         }
1623 }
1624
1625 void
1626 RouteTimeAxisView::show_playlist_selector ()
1627 {
1628         _editor.playlist_selector().show_for (this);
1629 }
1630
1631 void
1632 RouteTimeAxisView::map_frozen ()
1633 {
1634         if (!is_track()) {
1635                 return;
1636         }
1637
1638         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1639
1640         switch (track()->freeze_state()) {
1641         case Track::Frozen:
1642                 playlist_button.set_sensitive (false);
1643                 rec_enable_button->set_sensitive (false);
1644                 break;
1645         default:
1646                 playlist_button.set_sensitive (true);
1647                 rec_enable_button->set_sensitive (true);
1648                 break;
1649         }
1650 }
1651
1652 void
1653 RouteTimeAxisView::color_handler ()
1654 {
1655         //case cTimeStretchOutline:
1656         if (timestretch_rect) {
1657                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
1658         }
1659         //case cTimeStretchFill:
1660         if (timestretch_rect) {
1661                 timestretch_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
1662         }
1663
1664         reset_meter();
1665 }
1666
1667 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1668  *  Will add track if necessary.
1669  */
1670 void
1671 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1672 {
1673         RouteAutomationNode* node = automation_track(param);
1674         
1675         if (!node) {
1676                 /* it doesn't exist yet, so we don't care about the button state: just add it */
1677                 create_automation_child (param, true);
1678         } else {
1679                 bool yn = node->menu_item->get_active();
1680                 if (node->track->set_visibility (node->menu_item->get_active()) && yn) {
1681                         
1682                         /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1683                            will have done that for us.
1684                         */
1685                         
1686                         if (!no_redraw) {
1687                                 _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
1688                         } 
1689                 }
1690         }
1691 }
1692
1693 void
1694 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1695 {
1696         RouteAutomationNode* ran = automation_track(param);
1697
1698         if (!ran) {
1699                 return;
1700         }
1701
1702         // if Evoral::Parameter::operator< doesn't obey strict weak ordering, we may crash here....
1703         _show_automation.erase (param);
1704         ran->track->get_state_node()->add_property (X_("shown"), X_("no"));
1705
1706         if (ran->menu_item && !_hidden) {
1707                 ignore_toggle = true;
1708                 ran->menu_item->set_active (false);
1709                 ignore_toggle = false;
1710         }
1711
1712         if (_route && !no_redraw) {
1713                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1714         }
1715 }
1716
1717
1718 void
1719 RouteTimeAxisView::show_all_automation ()
1720 {
1721         no_redraw = true;
1722
1723         /* Show our automation */
1724
1725         map<Evoral::Parameter, RouteAutomationNode*>::iterator i;
1726         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1727                 i->second->track->set_marked_for_display (true);
1728                 i->second->track->canvas_display()->show();
1729                 i->second->track->get_state_node()->add_property ("shown", X_("yes"));
1730                 if (i->second->menu_item) {
1731                         i->second->menu_item->set_active(true);
1732                 }
1733         }
1734
1735
1736         /* Show processor automation */
1737
1738         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1739                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1740                         if ((*ii)->view == 0) {
1741                                 add_processor_automation_curve ((*i)->processor, (*ii)->what);
1742                         }
1743
1744                         (*ii)->menu_item->set_active (true);
1745                 }
1746         }
1747
1748         no_redraw = false;
1749
1750         /* Redraw */
1751
1752          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1753 }
1754
1755 void
1756 RouteTimeAxisView::show_existing_automation ()
1757 {
1758         no_redraw = true;
1759
1760         /* Show our automation */
1761
1762         map<Evoral::Parameter, RouteAutomationNode*>::iterator i;
1763         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1764                 if (i->second->track->line() && i->second->track->line()->npoints() > 0) {
1765                         i->second->track->set_marked_for_display (true);
1766                         i->second->track->canvas_display()->show();
1767                         i->second->track->get_state_node()->add_property ("shown", X_("yes"));
1768                         i->second->menu_item->set_active(true);
1769                 }
1770         }
1771
1772
1773         /* Show processor automation */
1774
1775         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1776                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1777                         if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
1778                                 (*ii)->menu_item->set_active (true);
1779                         }
1780                 }
1781         }
1782
1783         no_redraw = false;
1784
1785         _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1786 }
1787
1788 void
1789 RouteTimeAxisView::hide_all_automation ()
1790 {
1791         no_redraw = true;
1792
1793         /* Hide our automation */
1794
1795         for (map<Evoral::Parameter, RouteAutomationNode*>::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1796                 i->second->track->set_marked_for_display (false);
1797                 i->second->track->hide ();
1798                 i->second->track->get_state_node()->add_property ("shown", X_("no"));
1799                 if (i->second->menu_item) {
1800                         i->second->menu_item->set_active (false);
1801                 }
1802         }
1803
1804         /* Hide processor automation */
1805
1806         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1807                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1808                         (*ii)->menu_item->set_active (false);
1809                 }
1810         }
1811
1812         _show_automation.clear();
1813
1814         no_redraw = false;
1815          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1816 }
1817
1818
1819 void
1820 RouteTimeAxisView::region_view_added (RegionView* rv)
1821 {
1822         /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
1823         if (is_audio_track()) {
1824                 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1825                         boost::shared_ptr<AutomationTimeAxisView> atv;
1826
1827                         if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
1828                                 atv->add_ghost(rv);
1829                         }
1830                 }
1831         }
1832
1833         for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
1834                 (*i)->add_ghost(rv);
1835         }
1836 }
1837
1838 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
1839 {
1840         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1841                 delete *i;
1842         }
1843 }
1844
1845
1846 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
1847 {
1848         parent.remove_processor_automation_node (this);
1849 }
1850
1851 void
1852 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
1853 {
1854         if (pan->view) {
1855                 remove_child (pan->view);
1856         }
1857 }
1858
1859 RouteTimeAxisView::ProcessorAutomationNode*
1860 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1861 {
1862         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1863
1864                 if ((*i)->processor == processor) {
1865
1866                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1867                                 if ((*ii)->what == what) {
1868                                         return *ii;
1869                                 }
1870                         }
1871                 }
1872         }
1873
1874         return 0;
1875 }
1876
1877 static string
1878 legalize_for_xml_node (string str)
1879 {
1880         string::size_type pos;
1881         string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_=:";
1882         string legal;
1883
1884         legal = str;
1885         pos = 0;
1886
1887         while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
1888                 legal.replace (pos, 1, "_");
1889                 pos += 1;
1890         }
1891
1892         return legal;
1893 }
1894
1895
1896 void
1897 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1898 {
1899         string name;
1900         ProcessorAutomationNode* pan;
1901
1902         if ((pan = find_processor_automation_node (processor, what)) == 0) {
1903                 error << _("programming error: ")
1904                       << string_compose (X_("processor automation curve for %1:%2 not registered with track!"),
1905                                   processor->name(), what)
1906                       << endmsg;
1907                 /*NOTREACHED*/
1908                 return;
1909         }
1910
1911         if (pan->view) {
1912                 return;
1913         }
1914
1915         name = processor->describe_parameter (what);
1916
1917         /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
1918
1919         /* FIXME: ew */
1920
1921         char state_name[256];
1922         snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id());
1923
1924         boost::shared_ptr<AutomationControl> control
1925                         = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
1926
1927         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
1928                         new AutomationTimeAxisView (_session, _route, processor, control,
1929                                 _editor, *this, false, parent_canvas, name, state_name));
1930
1931         pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
1932
1933         if (!pan->view->marked_for_display()) {
1934                 pan->view->hide ();
1935         } else {
1936                 pan->menu_item->set_active (true);
1937         }
1938
1939         add_child (pan->view);
1940
1941         if (_view) {
1942                 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
1943         }
1944
1945         processor->mark_automation_visible (what, true);
1946 }
1947
1948 void
1949 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor> i)
1950 {
1951         if (!_hidden) {
1952                 pan->menu_item->set_active (false);
1953         }
1954
1955         i->mark_automation_visible (pan->what, false);
1956
1957         if (!no_redraw) {
1958                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1959         }
1960 }
1961
1962 void
1963 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
1964 {
1965         boost::shared_ptr<Processor> processor (p.lock ());
1966         if (!processor) {
1967                 return;
1968         }
1969
1970         set<Evoral::Parameter> s;
1971         boost::shared_ptr<AutomationLine> al;
1972
1973         processor->what_has_visible_data (s);
1974
1975         for (set<Evoral::Parameter>::iterator i = s.begin(); i != s.end(); ++i) {
1976
1977                 if ((al = find_processor_automation_curve (processor, *i)) != 0) {
1978                         al->queue_reset ();
1979                 } else {
1980                         add_processor_automation_curve (processor, (*i));
1981                 }
1982         }
1983 }
1984
1985 void
1986 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
1987 {
1988         using namespace Menu_Helpers;
1989
1990         XMLProperty* prop;
1991         XMLNode* node;
1992
1993         add_child (track);
1994
1995         track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
1996
1997         bool hideit = (!show);
1998
1999         if ((node = track->get_state_node()) != 0) {
2000                 if  ((prop = node->property ("shown")) != 0) {
2001                         if (string_is_affirmative (prop->value())) {
2002                                 hideit = false;
2003                         }
2004                 }
2005         }
2006
2007         _automation_tracks.insert (std::make_pair (param, new RouteAutomationNode(param, NULL, track)));
2008
2009         track->set_visibility (!hideit);
2010
2011         if (!hideit) {
2012                 _show_automation.insert (param);
2013         }
2014         
2015         if (!no_redraw) {
2016                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2017         }
2018
2019         if (!EventTypeMap::instance().is_midi_parameter(param)) {
2020                 /* MIDI-related parameters are always in the menu, there's no
2021                    reason to rebuild the menu just because we added a automation
2022                    lane for one of them. But if we add a non-MIDI automation
2023                    lane, then we need to invalidate the display menu.
2024                 */
2025                 delete display_menu;
2026                 display_menu = 0;
2027         }
2028 }
2029
2030 void
2031 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2032 {
2033         boost::shared_ptr<Processor> processor (p.lock ());
2034
2035         if (!processor || !processor->display_to_user ()) {
2036                 return;
2037         }
2038
2039         using namespace Menu_Helpers;
2040         ProcessorAutomationInfo *rai;
2041         list<ProcessorAutomationInfo*>::iterator x;
2042
2043         const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2044         std::set<Evoral::Parameter> has_visible_automation;
2045
2046         processor->what_has_visible_data(has_visible_automation);
2047
2048         if (automatable.empty()) {
2049                 return;
2050         }
2051
2052         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2053                 if ((*x)->processor == processor) {
2054                         break;
2055                 }
2056         }
2057
2058         if (x == processor_automation.end()) {
2059
2060                 rai = new ProcessorAutomationInfo (processor);
2061                 processor_automation.push_back (rai);
2062
2063         } else {
2064
2065                 rai = *x;
2066
2067         }
2068
2069         /* any older menu was deleted at the top of processors_changed()
2070            when we cleared the subplugin menu.
2071         */
2072
2073         rai->menu = manage (new Menu);
2074         MenuList& items = rai->menu->items();
2075         rai->menu->set_name ("ArdourContextMenu");
2076
2077         items.clear ();
2078
2079         for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2080
2081                 ProcessorAutomationNode* pan;
2082                 CheckMenuItem* mitem;
2083
2084                 string name = processor->describe_parameter (*i);
2085
2086                 items.push_back (CheckMenuElem (name));
2087                 mitem = dynamic_cast<CheckMenuItem*> (&items.back());
2088
2089                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2090                         mitem->set_active(true);
2091                 }
2092
2093                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2094
2095                         /* new item */
2096
2097                         pan = new ProcessorAutomationNode (*i, mitem, *this);
2098
2099                         rai->lines.push_back (pan);
2100
2101                 } else {
2102
2103                         pan->menu_item = mitem;
2104
2105                 }
2106
2107                 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2108         }
2109
2110         /* add the menu for this processor, because the subplugin
2111            menu is always cleared at the top of processors_changed().
2112            this is the result of some poor design in gtkmm and/or
2113            GTK+.
2114         */
2115
2116         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2117         rai->valid = true;
2118 }
2119
2120 void
2121 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2122                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
2123 {
2124         bool showit = pan->menu_item->get_active();
2125         bool redraw = false;
2126
2127         if (pan->view == 0 && showit) {
2128                 add_processor_automation_curve (rai->processor, pan->what);
2129                 redraw = true;
2130         }
2131
2132         if (pan->view && showit != pan->view->marked_for_display()) {
2133
2134                 if (showit) {
2135                         pan->view->set_marked_for_display (true);
2136                         pan->view->canvas_display()->show();
2137                         pan->view->canvas_background()->show();
2138                 } else {
2139                         rai->processor->mark_automation_visible (pan->what, true);
2140                         pan->view->set_marked_for_display (false);
2141                         pan->view->hide ();
2142                 }
2143
2144                 redraw = true;
2145
2146         }
2147
2148         if (redraw && !no_redraw) {
2149                  _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2150
2151         }
2152 }
2153
2154 void
2155 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2156 {
2157         if (c.type == RouteProcessorChange::MeterPointChange) {
2158                 /* nothing to do if only the meter point has changed */
2159                 return;
2160         }
2161
2162         using namespace Menu_Helpers;
2163
2164         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2165                 (*i)->valid = false;
2166         }
2167
2168         subplugin_menu.items().clear ();
2169
2170         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
2171         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
2172
2173         bool deleted_processor_automation = false;
2174
2175         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2176
2177                 list<ProcessorAutomationInfo*>::iterator tmp;
2178
2179                 tmp = i;
2180                 ++tmp;
2181
2182                 if (!(*i)->valid) {
2183
2184                         delete *i;
2185                         processor_automation.erase (i);
2186                         deleted_processor_automation = true;
2187
2188                 }
2189
2190                 i = tmp;
2191         }
2192
2193         if (deleted_processor_automation && !no_redraw) {
2194                 _route->gui_changed ("track_height", this);
2195         }
2196 }
2197
2198 boost::shared_ptr<AutomationLine>
2199 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2200 {
2201         ProcessorAutomationNode* pan;
2202
2203         if ((pan = find_processor_automation_node (processor, what)) != 0) {
2204                 if (pan->view) {
2205                         pan->view->line();
2206                 }
2207         }
2208
2209         return boost::shared_ptr<AutomationLine>();
2210 }
2211
2212 void
2213 RouteTimeAxisView::reset_processor_automation_curves ()
2214 {
2215         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2216                 (*i)->reset();
2217         }
2218 }
2219
2220 void
2221 RouteTimeAxisView::update_rec_display ()
2222 {
2223         RouteUI::update_rec_display ();
2224         name_entry.set_sensitive (!_route->record_enabled());
2225 }
2226
2227 void
2228 RouteTimeAxisView::set_layer_display (LayerDisplay d)
2229 {
2230         if (_view) {
2231                 _view->set_layer_display (d);
2232         }
2233
2234         ensure_xml_node ();
2235         xml_node->add_property (N_("layer-display"), enum_2_string (d));
2236 }
2237
2238 LayerDisplay
2239 RouteTimeAxisView::layer_display () const
2240 {
2241         if (_view) {
2242                 return _view->layer_display ();
2243         }
2244
2245         /* we don't know, since we don't have a _view, so just return something */
2246         return Overlaid;
2247 }
2248
2249
2250
2251 boost::shared_ptr<AutomationTimeAxisView>
2252 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2253 {
2254         AutomationTracks::iterator i = _automation_tracks.find(param);
2255         if (i != _automation_tracks.end()) {
2256                 return i->second->track;
2257         } else {
2258                 return boost::shared_ptr<AutomationTimeAxisView>();
2259         }
2260 }
2261
2262 void
2263 RouteTimeAxisView::fast_update ()
2264 {
2265         gm.get_level_meter().update_meters ();
2266 }
2267
2268 void
2269 RouteTimeAxisView::hide_meter ()
2270 {
2271         clear_meter ();
2272         gm.get_level_meter().hide_meters ();
2273 }
2274
2275 void
2276 RouteTimeAxisView::show_meter ()
2277 {
2278         reset_meter ();
2279 }
2280
2281 void
2282 RouteTimeAxisView::reset_meter ()
2283 {
2284         if (Config->get_show_track_meters()) {
2285                 gm.get_level_meter().setup_meters (height-5);
2286         } else {
2287                 hide_meter ();
2288         }
2289 }
2290
2291 void
2292 RouteTimeAxisView::clear_meter ()
2293 {
2294         gm.get_level_meter().clear_meters ();
2295 }
2296
2297 void
2298 RouteTimeAxisView::meter_changed ()
2299 {
2300         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2301         reset_meter();
2302 }
2303
2304 void
2305 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2306 {
2307         reset_meter ();
2308 }
2309
2310 void
2311 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2312 {
2313         using namespace Menu_Helpers;
2314
2315         if (!_underlay_streams.empty()) {
2316                 MenuList& parent_items = parent_menu->items();
2317                 Menu* gs_menu = manage (new Menu);
2318                 gs_menu->set_name ("ArdourContextMenu");
2319                 MenuList& gs_items = gs_menu->items();
2320
2321                 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2322
2323                 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2324                         gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2325                                                     sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2326                 }
2327         }
2328 }
2329
2330 bool
2331 RouteTimeAxisView::set_underlay_state()
2332 {
2333         if (!underlay_xml_node) {
2334                 return false;
2335         }
2336
2337         XMLNodeList nlist = underlay_xml_node->children();
2338         XMLNodeConstIterator niter;
2339         XMLNode *child_node;
2340
2341         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2342                 child_node = *niter;
2343
2344                 if (child_node->name() != "Underlay") {
2345                         continue;
2346                 }
2347
2348                 XMLProperty* prop = child_node->property ("id");
2349                 if (prop) {
2350                         PBD::ID id (prop->value());
2351
2352                         RouteTimeAxisView* v = _editor.get_route_view_by_id (id);
2353
2354                         if (v) {
2355                                 add_underlay(v->view(), false);
2356                         }
2357                 }
2358         }
2359
2360         return false;
2361 }
2362
2363 void
2364 RouteTimeAxisView::add_underlay (StreamView* v, bool update_xml)
2365 {
2366         if (!v) {
2367                 return;
2368         }
2369
2370         RouteTimeAxisView& other = v->trackview();
2371
2372         if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2373                 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2374                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2375                         /*NOTREACHED*/
2376                 }
2377
2378                 _underlay_streams.push_back(v);
2379                 other._underlay_mirrors.push_back(this);
2380
2381                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2382
2383                 if (update_xml) {
2384                         if (!underlay_xml_node) {
2385                                 ensure_xml_node();
2386                                 underlay_xml_node = xml_node->add_child("Underlays");
2387                         }
2388
2389                         XMLNode* node = underlay_xml_node->add_child("Underlay");
2390                         XMLProperty* prop = node->add_property("id");
2391                         prop->set_value(v->trackview().route()->id().to_s());
2392                 }
2393         }
2394 }
2395
2396 void
2397 RouteTimeAxisView::remove_underlay (StreamView* v)
2398 {
2399         if (!v) {
2400                 return;
2401         }
2402
2403         UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2404         RouteTimeAxisView& other = v->trackview();
2405
2406         if (it != _underlay_streams.end()) {
2407                 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2408
2409                 if (gm == other._underlay_mirrors.end()) {
2410                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2411                         /*NOTREACHED*/
2412                 }
2413
2414                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2415
2416                 _underlay_streams.erase(it);
2417                 other._underlay_mirrors.erase(gm);
2418
2419                 if (underlay_xml_node) {
2420                         underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2421                 }
2422         }
2423 }
2424
2425 void
2426 RouteTimeAxisView::set_button_names ()
2427 {
2428         rec_enable_button_label.set_text (_("r"));
2429
2430         if (_route && _route->solo_safe()) {
2431                 solo_button_label.set_text (X_("!"));
2432         } else {
2433                 if (Config->get_solo_control_is_listen_control()) {
2434                         switch (Config->get_listen_position()) {
2435                         case AfterFaderListen:
2436                                 solo_button_label.set_text (_("A"));
2437                                 break;
2438                         case PreFaderListen:
2439                                 solo_button_label.set_text (_("P"));
2440                                 break;
2441                         }
2442                 } else {
2443                         solo_button_label.set_text (_("s"));
2444                 }
2445         }
2446         mute_button_label.set_text (_("m"));
2447 }