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