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