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