2 Copyright (C) 2006 Paul Davis
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.
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.
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.
29 #include <sigc++/bind.h>
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"
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>
45 #include "ardour/amp.h"
46 #include "ardour/meter.h"
47 #include "ardour/event_type_map.h"
48 #include "ardour/pannable.h"
49 #include "ardour/panner.h"
50 #include "ardour/processor.h"
51 #include "ardour/profile.h"
52 #include "ardour/route_group.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
56 #include "evoral/Parameter.hpp"
58 #include "canvas/debug.h"
60 #include "ardour_ui.h"
61 #include "ardour_button.h"
62 #include "audio_streamview.h"
64 #include "route_time_axis.h"
65 #include "automation_time_axis.h"
67 #include "gui_thread.h"
68 #include "item_counts.h"
70 #include "paste_context.h"
71 #include "playlist_selector.h"
72 #include "point_selection.h"
74 #include "public_editor.h"
75 #include "region_view.h"
76 #include "rgb_macros.h"
77 #include "selection.h"
78 #include "streamview.h"
80 #include "ui_config.h"
82 #include "route_group_menu.h"
84 #include "ardour/track.h"
88 using namespace ARDOUR;
89 using namespace ARDOUR_UI_UTILS;
91 using namespace Gtkmm2ext;
93 using namespace Editing;
97 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
100 , TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas)
102 , parent_canvas (canvas)
104 , button_table (3, 3)
105 , route_group_button (S_("RTAV|G"))
106 , playlist_button (S_("RTAV|P"))
107 , automation_button (S_("RTAV|A"))
108 , automation_action_menu (0)
109 , plugins_submenu_item (0)
110 , route_group_menu (0)
111 , playlist_action_menu (0)
113 , color_mode_menu (0)
114 , gm (sess, true, 75, 14)
115 , _ignore_set_layer_display (false)
116 , gain_automation_item(NULL)
117 , trim_automation_item(NULL)
118 , mute_automation_item(NULL)
119 , pan_automation_item(NULL)
121 number_label.set_name("tracknumber label");
122 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
123 number_label.set_alignment(.5, .5);
124 number_label.set_fallthrough_to_parent (true);
126 sess->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::parameter_changed, this, _1), gui_context());
130 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
132 RouteUI::set_route (rt);
134 CANVAS_DEBUG_NAME (_canvas_display, string_compose ("main for %1", rt->name()));
135 CANVAS_DEBUG_NAME (selection_group, string_compose ("selections for %1", rt->name()));
136 CANVAS_DEBUG_NAME (_ghost_group, string_compose ("ghosts for %1", rt->name()));
139 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
142 gm.set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
143 gm.get_level_meter().set_no_show_all();
144 gm.get_level_meter().setup_meters(50, meter_width);
145 gm.update_gain_sensitive ();
147 string str = gui_property ("height");
149 set_height (atoi (str));
151 set_height (preset_height (HeightNormal));
154 if (!_route->is_auditioner()) {
155 if (gui_property ("visible").empty()) {
156 set_gui_property ("visible", true);
159 set_gui_property ("visible", false);
162 timestretch_rect = 0;
165 ignore_toggle = false;
167 route_group_button.set_name ("route button");
168 playlist_button.set_name ("route button");
169 automation_button.set_name ("route button");
171 route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
172 playlist_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click));
173 automation_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click));
177 if (ARDOUR::Profile->get_mixbus()) {
178 controls_table.attach (*rec_enable_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
180 controls_table.attach (*rec_enable_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
183 if (is_midi_track()) {
184 set_tooltip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
185 gm.set_fader_name ("MidiTrackFader");
187 set_tooltip(*rec_enable_button, _("Record"));
188 gm.set_fader_name ("AudioTrackFader");
191 rec_enable_button->set_sensitive (_session->writable());
193 /* set playlist button tip to the current playlist, and make it update when it changes */
194 update_playlist_tip ();
195 track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
198 gm.set_fader_name ("AudioBusFader");
199 Gtk::Fixed *blank = manage(new Gtk::Fixed());
200 controls_button_size_group->add_widget(*blank);
201 if (ARDOUR::Profile->get_mixbus() ) {
202 controls_table.attach (*blank, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
204 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
209 top_hbox.pack_end(gm.get_level_meter(), false, false, 2);
211 if (!ARDOUR::Profile->get_mixbus()) {
212 controls_meters_size_group->add_widget (gm.get_level_meter());
215 _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
216 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
217 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
218 _route->track_number_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::label_view, this), gui_context());
220 if (ARDOUR::Profile->get_mixbus()) {
221 controls_table.attach (*mute_button, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
223 controls_table.attach (*mute_button, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
225 // mute button is always present, it is used to
226 // force the 'blank' placeholders to the proper size
227 controls_button_size_group->add_widget(*mute_button);
229 if (!_route->is_master()) {
230 if (ARDOUR::Profile->get_mixbus()) {
231 controls_table.attach (*solo_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
233 controls_table.attach (*solo_button, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
236 Gtk::Fixed *blank = manage(new Gtk::Fixed());
237 controls_button_size_group->add_widget(*blank);
238 if (ARDOUR::Profile->get_mixbus()) {
239 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
241 controls_table.attach (*blank, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
246 if (ARDOUR::Profile->get_mixbus()) {
247 controls_table.attach (route_group_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
248 controls_table.attach (gm.get_gain_slider(), 3, 5, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
250 else if (!ARDOUR::Profile->get_trx()) {
251 controls_table.attach (route_group_button, 4, 5, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
252 controls_table.attach (gm.get_gain_slider(), 0, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
255 set_tooltip(*solo_button,_("Solo"));
256 set_tooltip(*mute_button,_("Mute"));
257 set_tooltip(route_group_button, _("Route Group"));
259 mute_button->set_tweaks(ArdourButton::TrackHeader);
260 solo_button->set_tweaks(ArdourButton::TrackHeader);
261 rec_enable_button->set_tweaks(ArdourButton::TrackHeader);
262 playlist_button.set_tweaks(ArdourButton::TrackHeader);
263 automation_button.set_tweaks(ArdourButton::TrackHeader);
264 route_group_button.set_tweaks(ArdourButton::TrackHeader);
266 if (is_midi_track()) {
267 set_tooltip(automation_button, _("MIDI Controllers and Automation"));
269 set_tooltip(automation_button, _("Automation"));
272 update_track_number_visibility();
275 if (ARDOUR::Profile->get_mixbus()) {
276 controls_table.attach (automation_button, 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
278 else if (!ARDOUR::Profile->get_trx()) {
279 controls_table.attach (automation_button, 3, 4, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
282 if (is_track() && track()->mode() == ARDOUR::Normal) {
283 if (ARDOUR::Profile->get_mixbus()) {
284 controls_table.attach (playlist_button, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
286 else if (!ARDOUR::Profile->get_trx()) {
287 controls_table.attach (playlist_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
293 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
294 _route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::route_property_changed, this, _1), gui_context());
298 str = gui_property ("layer-display");
300 set_layer_display (LayerDisplay (string_2_enum (str, _view->layer_display ())));
303 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
304 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
306 /* pick up the correct freeze state */
311 _editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_pixel));
312 UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler));
314 PropertyList* plist = new PropertyList();
316 plist->add (ARDOUR::Properties::mute, true);
317 plist->add (ARDOUR::Properties::solo, true);
319 route_group_menu = new RouteGroupMenu (_session, plist);
321 gm.get_level_meter().signal_scroll_event().connect (sigc::mem_fun (*this, &RouteTimeAxisView::controls_ebox_scroll), false);
324 RouteTimeAxisView::~RouteTimeAxisView ()
326 cleanup_gui_properties ();
328 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
332 delete playlist_action_menu;
333 playlist_action_menu = 0;
338 _automation_tracks.clear ();
340 delete route_group_menu;
341 CatchDeletion (this);
345 RouteTimeAxisView::post_construct ()
347 /* map current state of the route */
349 update_diskstream_display ();
350 setup_processor_menu_and_curves ();
351 reset_processor_automation_curves ();
354 /** Set up the processor menu for the current set of processors, and
355 * display automation curves for any parameters which have data.
358 RouteTimeAxisView::setup_processor_menu_and_curves ()
360 _subplugin_menu_map.clear ();
361 subplugin_menu.items().clear ();
362 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
363 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
367 RouteTimeAxisView::route_group_click (GdkEventButton *ev)
369 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
370 if (_route->route_group()) {
371 _route->route_group()->remove (_route);
377 r.push_back (route ());
379 route_group_menu->build (r);
380 route_group_menu->menu()->popup (ev->button, ev->time);
386 RouteTimeAxisView::playlist_changed ()
392 RouteTimeAxisView::label_view ()
394 string x = _route->name ();
395 if (x != name_label.get_text ()) {
396 name_label.set_text (x);
398 const int64_t track_number = _route->track_number ();
399 if (track_number == 0) {
400 number_label.set_text ("");
402 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
407 RouteTimeAxisView::update_track_number_visibility ()
410 bool show_label = _session->config.get_track_name_number();
412 if (_route && _route->is_master()) {
416 if (number_label.get_parent()) {
417 controls_table.remove (number_label);
420 if (ARDOUR::Profile->get_mixbus()) {
421 controls_table.attach (number_label, 3, 4, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
423 controls_table.attach (number_label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
425 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
426 // except the width of the number label is subtracted from the name-hbox, so we
427 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
428 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
430 number_label.set_size_request(tnw, -1);
431 number_label.show ();
432 name_hbox.set_size_request(TimeAxisView::name_width_px - 2 - tnw, -1); // -2 = cellspacing
434 number_label.hide ();
435 name_hbox.set_size_request(TimeAxisView::name_width_px, -1);
440 RouteTimeAxisView::parameter_changed (string const & p)
442 if (p == "track-name-number") {
443 update_track_number_visibility();
448 RouteTimeAxisView::route_property_changed (const PropertyChange& what_changed)
450 if (what_changed.contains (ARDOUR::Properties::name)) {
456 RouteTimeAxisView::take_name_changed (void *src)
464 RouteTimeAxisView::playlist_click ()
466 build_playlist_menu ();
467 conditionally_add_to_selection ();
468 playlist_action_menu->popup (1, gtk_get_current_event_time());
472 RouteTimeAxisView::automation_click ()
474 conditionally_add_to_selection ();
475 build_automation_action_menu (false);
476 automation_action_menu->popup (1, gtk_get_current_event_time());
480 RouteTimeAxisView::build_automation_action_menu (bool for_selection)
482 using namespace Menu_Helpers;
484 /* detach subplugin_menu from automation_action_menu before we delete automation_action_menu,
485 otherwise bad things happen (see comment for similar case in MidiTimeAxisView::build_automation_action_menu)
488 detach_menu (subplugin_menu);
490 _main_automation_menu_map.clear ();
491 delete automation_action_menu;
492 automation_action_menu = new Menu;
494 MenuList& items = automation_action_menu->items();
496 automation_action_menu->set_name ("ArdourContextMenu");
498 items.push_back (MenuElem (_("Show All Automation"),
499 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_all_automation), for_selection)));
501 items.push_back (MenuElem (_("Show Existing Automation"),
502 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_existing_automation), for_selection)));
504 items.push_back (MenuElem (_("Hide All Automation"),
505 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::hide_all_automation), for_selection)));
507 /* Attach the plugin submenu. It may have previously been used elsewhere,
508 so it was detached above
511 if (!subplugin_menu.items().empty()) {
512 items.push_back (SeparatorElem ());
513 items.push_back (MenuElem (_("Processor automation"), subplugin_menu));
514 items.back().set_sensitive (!for_selection || _editor.get_selection().tracks.size() == 1);;
517 /* Add any route automation */
520 items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility)));
521 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
522 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
523 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
525 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
529 items.push_back (CheckMenuElem (_("Trim"), sigc::mem_fun (*this, &RouteTimeAxisView::update_trim_track_visibility)));
530 trim_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
531 trim_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
532 (trim_track && string_is_affirmative (trim_track->gui_property ("visible"))));
534 _main_automation_menu_map[Evoral::Parameter(TrimAutomation)] = trim_automation_item;
538 items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility)));
539 mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
540 mute_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
541 (mute_track && string_is_affirmative (mute_track->gui_property ("visible"))));
543 _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
546 if (!pan_tracks.empty()) {
547 items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility)));
548 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
549 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
550 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
552 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
553 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
554 _main_automation_menu_map[*p] = pan_automation_item;
560 RouteTimeAxisView::build_display_menu ()
562 using namespace Menu_Helpers;
566 TimeAxisView::build_display_menu ();
568 /* now fill it with our stuff */
570 MenuList& items = display_menu->items();
571 display_menu->set_name ("ArdourContextMenu");
573 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
575 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
577 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
579 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
581 items.push_back (SeparatorElem());
584 detach_menu (*_size_menu);
587 items.push_back (MenuElem (_("Height"), *_size_menu));
589 items.push_back (SeparatorElem());
591 items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
592 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
593 items.push_back (SeparatorElem());
595 // Hook for derived classes to add type specific stuff
596 append_extra_display_menu_items ();
600 Menu* layers_menu = manage (new Menu);
601 MenuList &layers_items = layers_menu->items();
602 layers_menu->set_name("ArdourContextMenu");
604 RadioMenuItem::Group layers_group;
606 /* Find out how many overlaid/stacked tracks we have in the selection */
610 TrackSelection const & s = _editor.get_selection().tracks;
611 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
612 StreamView* v = (*i)->view ();
617 switch (v->layer_display ()) {
628 /* We're not connecting to signal_toggled() here; in the case where these two items are
629 set to be in the `inconsistent' state, it seems that one or other will end up active
630 as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you
631 select the active one, no toggled signal is emitted so nothing happens.
634 _ignore_set_layer_display = true;
636 layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
637 RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
638 i->set_active (overlaid != 0 && stacked == 0);
639 i->set_inconsistent (overlaid != 0 && stacked != 0);
640 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
642 layers_items.push_back (RadioMenuElem (layers_group, _("Stacked")));
643 i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
644 i->set_active (overlaid == 0 && stacked != 0);
645 i->set_inconsistent (overlaid != 0 && stacked != 0);
646 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
648 _ignore_set_layer_display = false;
650 items.push_back (MenuElem (_("Layers"), *layers_menu));
652 Menu* alignment_menu = manage (new Menu);
653 MenuList& alignment_items = alignment_menu->items();
654 alignment_menu->set_name ("ArdourContextMenu");
656 RadioMenuItem::Group align_group;
658 /* Same verbose hacks as for the layering options above */
664 boost::shared_ptr<Track> first_track;
666 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
667 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
668 if (!r || !r->is_track ()) {
673 first_track = r->track();
676 switch (r->track()->alignment_choice()) {
680 switch (r->track()->alignment_style()) {
681 case ExistingMaterial:
689 case UseExistingMaterial:
705 inconsistent = false;
714 if (!inconsistent && first_track) {
716 alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
717 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
718 i->set_active (automatic != 0 && existing == 0 && capture == 0);
719 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
721 switch (first_track->alignment_choice()) {
723 switch (first_track->alignment_style()) {
724 case ExistingMaterial:
725 alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
728 alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
736 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
737 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
738 i->set_active (existing != 0 && capture == 0 && automatic == 0);
739 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
741 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
742 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
743 i->set_active (existing == 0 && capture != 0 && automatic == 0);
744 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
746 items.push_back (MenuElem (_("Alignment"), *alignment_menu));
752 Menu* mode_menu = manage (new Menu);
753 MenuList& mode_items = mode_menu->items ();
754 mode_menu->set_name ("ArdourContextMenu");
756 RadioMenuItem::Group mode_group;
762 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
763 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
764 if (!r || !r->is_track ()) {
768 switch (r->track()->mode()) {
781 mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode")));
782 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
783 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal, true));
784 i->set_active (normal != 0 && tape == 0 && non_layered == 0);
785 i->set_inconsistent (normal != 0 && (tape != 0 || non_layered != 0));
787 mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode")));
788 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
789 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive, true));
790 i->set_active (normal == 0 && tape != 0 && non_layered == 0);
791 i->set_inconsistent (tape != 0 && (normal != 0 || non_layered != 0));
793 mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode")));
794 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
795 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered, true));
796 i->set_active (normal == 0 && tape == 0 && non_layered != 0);
797 i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0));
799 items.push_back (MenuElem (_("Record Mode"), *mode_menu));
801 items.push_back (SeparatorElem());
803 build_playlist_menu ();
804 items.push_back (MenuElem (_("Playlist"), *playlist_action_menu));
805 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
808 route_group_menu->detach ();
811 for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
812 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
814 r.push_back (rtv->route ());
819 r.push_back (route ());
822 route_group_menu->build (r);
823 items.push_back (MenuElem (_("Group"), *route_group_menu->menu ()));
825 build_automation_action_menu (true);
826 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
828 items.push_back (SeparatorElem());
832 TrackSelection const & s = _editor.get_selection().tracks;
833 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
834 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
839 if (r->route()->active()) {
846 items.push_back (CheckMenuElem (_("Active")));
847 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
848 bool click_sets_active = true;
849 if (active > 0 && inactive == 0) {
850 i->set_active (true);
851 click_sets_active = false;
852 } else if (active > 0 && inactive > 0) {
853 i->set_inconsistent (true);
855 i->set_sensitive(! _session->transport_rolling());
856 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true));
858 items.push_back (SeparatorElem());
859 items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
860 if (_route && !_route->is_master()) {
861 items.push_back (SeparatorElem());
862 items.push_back (MenuElem (_("Duplicate..."), boost::bind (&ARDOUR_UI::start_duplicate_routes, ARDOUR_UI::instance())));
864 items.push_back (SeparatorElem());
865 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(_editor, &PublicEditor::remove_tracks)));
869 RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection)
871 if (apply_to_selection) {
872 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false));
875 bool needs_bounce = false;
877 if (!track()->can_use_mode (mode, needs_bounce)) {
883 cerr << "would bounce this one\n";
888 track()->set_mode (mode);
893 RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer)
895 TimeAxisView::show_timestretch (start, end, layers, layer);
905 /* check that the time selection was made in our route, or our route group.
906 remember that route_group() == 0 implies the route is *not* in a edit group.
909 if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
910 /* this doesn't apply to us */
914 /* ignore it if our edit group is not active */
916 if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
921 if (timestretch_rect == 0) {
922 timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ());
923 timestretch_rect->set_fill_color (ArdourCanvas::HSV (UIConfiguration::instance().color ("time stretch fill")).mod (UIConfiguration::instance().modifier ("time stretch fill")).color());
924 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
927 timestretch_rect->show ();
928 timestretch_rect->raise_to_top ();
930 double const x1 = start / _editor.get_current_zoom();
931 double const x2 = (end - 1) / _editor.get_current_zoom();
933 timestretch_rect->set (ArdourCanvas::Rect (x1, current_height() * (layers - layer - 1) / layers,
934 x2, current_height() * (layers - layer) / layers));
938 RouteTimeAxisView::hide_timestretch ()
940 TimeAxisView::hide_timestretch ();
942 if (timestretch_rect) {
943 timestretch_rect->hide ();
948 RouteTimeAxisView::show_selection (TimeSelection& ts)
952 /* ignore it if our edit group is not active or if the selection was started
953 in some other track or route group (remember that route_group() == 0 means
954 that the track is not in an route group).
957 if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
958 (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
964 TimeAxisView::show_selection (ts);
968 RouteTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
971 bool height_changed = (height == 0) || (h != height);
974 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
977 gm.get_level_meter().setup_meters (gmlen, meter_width);
979 TimeAxisView::set_height (h, m);
982 _view->set_height ((double) current_height());
985 if (height >= preset_height (HeightNormal)) {
989 gm.get_gain_slider().show();
991 if (!_route || _route->is_monitor()) {
996 if (rec_enable_button)
997 rec_enable_button->show();
999 route_group_button.show();
1000 automation_button.show();
1002 if (is_track() && track()->mode() == ARDOUR::Normal) {
1003 playlist_button.show();
1010 gm.get_gain_slider().hide();
1011 mute_button->show();
1012 if (!_route || _route->is_monitor()) {
1013 solo_button->hide();
1015 solo_button->show();
1017 if (rec_enable_button)
1018 rec_enable_button->show();
1020 route_group_button.hide ();
1021 automation_button.hide ();
1023 if (is_track() && track()->mode() == ARDOUR::Normal) {
1024 playlist_button.hide ();
1029 if (height_changed && !no_redraw) {
1030 /* only emit the signal if the height really changed */
1036 RouteTimeAxisView::route_color_changed ()
1039 _view->apply_color (color(), StreamView::RegionColor);
1042 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1046 RouteTimeAxisView::reset_samples_per_pixel ()
1048 set_samples_per_pixel (_editor.get_current_zoom());
1052 RouteTimeAxisView::set_samples_per_pixel (double fpp)
1057 speed = track()->speed();
1061 _view->set_samples_per_pixel (fpp * speed);
1064 TimeAxisView::set_samples_per_pixel (fpp * speed);
1068 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
1070 if (!mitem->get_active()) {
1071 /* this is one of the two calls made when these radio menu items change status. this one
1072 is for the item that became inactive, and we want to ignore it.
1077 if (apply_to_selection) {
1078 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
1081 track()->set_align_choice (choice);
1087 RouteTimeAxisView::rename_current_playlist ()
1089 ArdourPrompter prompter (true);
1092 boost::shared_ptr<Track> tr = track();
1093 if (!tr || tr->destructive()) {
1097 boost::shared_ptr<Playlist> pl = tr->playlist();
1102 prompter.set_title (_("Rename Playlist"));
1103 prompter.set_prompt (_("New name for playlist:"));
1104 prompter.set_initial_text (pl->name());
1105 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1106 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1108 switch (prompter.run ()) {
1109 case Gtk::RESPONSE_ACCEPT:
1110 prompter.get_result (name);
1111 if (name.length()) {
1112 pl->set_name (name);
1122 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1124 std::string ret (basename);
1126 std::string const group_string = "." + route_group()->name() + ".";
1128 // iterate through all playlists
1130 for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1131 std::string tmp = (*i)->name();
1133 std::string::size_type idx = tmp.find(group_string);
1134 // find those which belong to this group
1135 if (idx != string::npos) {
1136 tmp = tmp.substr(idx + group_string.length());
1138 // and find the largest current number
1140 if (x > maxnumber) {
1149 snprintf (buf, sizeof(buf), "%d", maxnumber);
1151 ret = this->name() + "." + route_group()->name () + "." + buf;
1157 RouteTimeAxisView::use_copy_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1161 boost::shared_ptr<Track> tr = track ();
1162 if (!tr || tr->destructive()) {
1166 boost::shared_ptr<const Playlist> pl = tr->playlist();
1173 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1174 name = resolve_new_group_playlist_name(name, playlists_before_op);
1177 while (_session->playlists->by_name(name)) {
1178 name = Playlist::bump_name (name, *_session);
1181 // TODO: The prompter "new" button should be de-activated if the user
1182 // specifies a playlist name which already exists in the session.
1186 ArdourPrompter prompter (true);
1188 prompter.set_title (_("New Copy Playlist"));
1189 prompter.set_prompt (_("Name for new playlist:"));
1190 prompter.set_initial_text (name);
1191 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1192 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1193 prompter.show_all ();
1195 switch (prompter.run ()) {
1196 case Gtk::RESPONSE_ACCEPT:
1197 prompter.get_result (name);
1205 if (name.length()) {
1206 tr->use_copy_playlist ();
1207 tr->playlist()->set_name (name);
1212 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1216 boost::shared_ptr<Track> tr = track ();
1217 if (!tr || tr->destructive()) {
1221 boost::shared_ptr<const Playlist> pl = tr->playlist();
1228 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1229 name = resolve_new_group_playlist_name(name,playlists_before_op);
1232 while (_session->playlists->by_name(name)) {
1233 name = Playlist::bump_name (name, *_session);
1239 ArdourPrompter prompter (true);
1241 prompter.set_title (_("New Playlist"));
1242 prompter.set_prompt (_("Name for new playlist:"));
1243 prompter.set_initial_text (name);
1244 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1245 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1247 switch (prompter.run ()) {
1248 case Gtk::RESPONSE_ACCEPT:
1249 prompter.get_result (name);
1257 if (name.length()) {
1258 tr->use_new_playlist ();
1259 tr->playlist()->set_name (name);
1264 RouteTimeAxisView::clear_playlist ()
1266 boost::shared_ptr<Track> tr = track ();
1267 if (!tr || tr->destructive()) {
1271 boost::shared_ptr<Playlist> pl = tr->playlist();
1276 _editor.clear_playlist (pl);
1280 RouteTimeAxisView::speed_changed ()
1282 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_pixel, this));
1286 RouteTimeAxisView::update_diskstream_display ()
1296 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1298 if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1300 /* special case: select/deselect all tracks */
1302 _editor.begin_reversible_selection_op (X_("Selection Click"));
1304 if (_editor.get_selection().selected (this)) {
1305 _editor.get_selection().clear_tracks ();
1307 _editor.select_all_tracks ();
1310 _editor.commit_reversible_selection_op ();
1315 _editor.begin_reversible_selection_op (X_("Selection Click"));
1317 switch (ArdourKeyboard::selection_type (ev->state)) {
1318 case Selection::Toggle:
1319 _editor.get_selection().toggle (this);
1322 case Selection::Set:
1323 _editor.get_selection().set (this);
1326 case Selection::Extend:
1327 _editor.extend_selection_to_track (*this);
1330 case Selection::Add:
1331 _editor.get_selection().add (this);
1335 _editor.commit_reversible_selection_op ();
1339 RouteTimeAxisView::set_selected_points (PointSelection& points)
1341 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1342 (*i)->set_selected_points (points);
1344 AudioStreamView* asv = dynamic_cast<AudioStreamView*>(_view);
1346 asv->set_selected_points (points);
1351 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1354 _view->set_selected_regionviews (regions);
1358 /** Add the selectable things that we have to a list.
1359 * @param results List to add things to.
1362 RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results, bool within)
1367 speed = track()->speed();
1370 framepos_t const start_adjusted = session_frame_to_track_frame(start, speed);
1371 framepos_t const end_adjusted = session_frame_to_track_frame(end, speed);
1373 if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1374 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1377 /* pick up visible automation tracks */
1379 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1380 if (!(*i)->hidden()) {
1381 (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1387 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1390 _view->get_inverted_selectables (sel, results);
1393 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1394 if (!(*i)->hidden()) {
1395 (*i)->get_inverted_selectables (sel, results);
1403 RouteTimeAxisView::route_group () const
1405 return _route->route_group();
1409 RouteTimeAxisView::name() const
1411 return _route->name();
1414 boost::shared_ptr<Playlist>
1415 RouteTimeAxisView::playlist () const
1417 boost::shared_ptr<Track> tr;
1419 if ((tr = track()) != 0) {
1420 return tr->playlist();
1422 return boost::shared_ptr<Playlist> ();
1427 RouteTimeAxisView::name_entry_changed ()
1429 TimeAxisView::name_entry_changed ();
1431 string x = name_entry->get_text ();
1433 if (x == _route->name()) {
1437 strip_whitespace_edges (x);
1439 if (x.length() == 0) {
1440 name_entry->set_text (_route->name());
1444 if (_session->route_name_internal (x)) {
1445 ARDOUR_UI::instance()->popup_error (string_compose (_("You cannot create a track with that name as it is reserved for %1"),
1447 name_entry->grab_focus ();
1448 } else if (RouteUI::verify_new_route_name (x)) {
1449 _route->set_name (x);
1451 name_entry->grab_focus ();
1455 boost::shared_ptr<Region>
1456 RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir)
1458 boost::shared_ptr<Playlist> pl = playlist ();
1461 return pl->find_next_region (pos, point, dir);
1464 return boost::shared_ptr<Region> ();
1468 RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir)
1470 boost::shared_ptr<Playlist> pl = playlist ();
1473 return pl->find_next_region_boundary (pos, dir);
1480 RouteTimeAxisView::fade_range (TimeSelection& selection)
1482 boost::shared_ptr<Playlist> what_we_got;
1483 boost::shared_ptr<Track> tr = track ();
1484 boost::shared_ptr<Playlist> playlist;
1487 /* route is a bus, not a track */
1491 playlist = tr->playlist();
1493 TimeSelection time (selection);
1494 float const speed = tr->speed();
1495 if (speed != 1.0f) {
1496 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1497 (*i).start = session_frame_to_track_frame((*i).start, speed);
1498 (*i).end = session_frame_to_track_frame((*i).end, speed);
1502 playlist->clear_changes ();
1503 playlist->clear_owned_changes ();
1505 playlist->fade_range (time);
1507 vector<Command*> cmds;
1508 playlist->rdiff (cmds);
1509 _session->add_commands (cmds);
1510 _session->add_command (new StatefulDiffCommand (playlist));
1515 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1517 boost::shared_ptr<Playlist> what_we_got;
1518 boost::shared_ptr<Track> tr = track ();
1519 boost::shared_ptr<Playlist> playlist;
1522 /* route is a bus, not a track */
1526 playlist = tr->playlist();
1528 TimeSelection time (selection.time);
1529 float const speed = tr->speed();
1530 if (speed != 1.0f) {
1531 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1532 (*i).start = session_frame_to_track_frame((*i).start, speed);
1533 (*i).end = session_frame_to_track_frame((*i).end, speed);
1537 playlist->clear_changes ();
1538 playlist->clear_owned_changes ();
1542 if (playlist->cut (time) != 0) {
1543 if (Config->get_edit_mode() == Ripple)
1544 playlist->ripple(time.start(), -time.length(), NULL);
1545 // no need to exclude any regions from rippling here
1547 vector<Command*> cmds;
1548 playlist->rdiff (cmds);
1549 _session->add_commands (cmds);
1551 _session->add_command (new StatefulDiffCommand (playlist));
1556 if ((what_we_got = playlist->cut (time)) != 0) {
1557 _editor.get_cut_buffer().add (what_we_got);
1558 if (Config->get_edit_mode() == Ripple)
1559 playlist->ripple(time.start(), -time.length(), NULL);
1560 // no need to exclude any regions from rippling here
1562 vector<Command*> cmds;
1563 playlist->rdiff (cmds);
1564 _session->add_commands (cmds);
1566 _session->add_command (new StatefulDiffCommand (playlist));
1570 if ((what_we_got = playlist->copy (time)) != 0) {
1571 _editor.get_cut_buffer().add (what_we_got);
1576 if ((what_we_got = playlist->cut (time)) != 0) {
1577 if (Config->get_edit_mode() == Ripple)
1578 playlist->ripple(time.start(), -time.length(), NULL);
1579 // no need to exclude any regions from rippling here
1581 vector<Command*> cmds;
1582 playlist->rdiff (cmds);
1583 _session->add_commands (cmds);
1584 _session->add_command (new StatefulDiffCommand (playlist));
1585 what_we_got->release ();
1592 RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
1598 boost::shared_ptr<Playlist> pl = playlist ();
1599 const ARDOUR::DataType type = pl->data_type();
1600 PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, ctx.counts.n_playlists(type));
1602 if (p == selection.playlists.end()) {
1605 ctx.counts.increase_n_playlists(type);
1607 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1609 if (track()->speed() != 1.0f) {
1610 pos = session_frame_to_track_frame (pos, track()->speed());
1611 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
1614 /* add multi-paste offset if applicable */
1615 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent();
1616 const framecnt_t duration = extent.second - extent.first;
1617 pos += _editor.get_paste_offset(pos, ctx.count, duration);
1619 pl->clear_changes ();
1620 pl->clear_owned_changes ();
1621 if (Config->get_edit_mode() == Ripple) {
1622 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
1623 framecnt_t amount = extent.second - extent.first;
1624 pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
1626 pl->paste (*p, pos, ctx.times);
1628 vector<Command*> cmds;
1630 _session->add_commands (cmds);
1632 _session->add_command (new StatefulDiffCommand (pl));
1638 struct PlaylistSorter {
1639 bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1640 return a->sort_id() < b->sort_id();
1645 RouteTimeAxisView::build_playlist_menu ()
1647 using namespace Menu_Helpers;
1653 delete playlist_action_menu;
1654 playlist_action_menu = new Menu;
1655 playlist_action_menu->set_name ("ArdourContextMenu");
1657 MenuList& playlist_items = playlist_action_menu->items();
1658 playlist_action_menu->set_name ("ArdourContextMenu");
1659 playlist_items.clear();
1661 RadioMenuItem::Group playlist_group;
1662 boost::shared_ptr<Track> tr = track ();
1664 vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1666 /* sort the playlists */
1668 sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1670 /* add the playlists to the menu */
1671 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1672 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1673 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1674 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1676 if (tr->playlist()->id() == (*i)->id()) {
1682 playlist_items.push_back (SeparatorElem());
1683 playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1684 playlist_items.push_back (SeparatorElem());
1686 if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1687 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1688 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1691 // Use a label which tells the user what is happening
1692 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1693 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1697 playlist_items.push_back (SeparatorElem());
1698 playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1699 playlist_items.push_back (SeparatorElem());
1701 playlist_items.push_back (MenuElem(_("Select from All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1705 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1707 assert (is_track());
1709 // exit if we were triggered by deactivating the old playlist
1710 if (!item->get_active()) {
1714 boost::shared_ptr<Playlist> pl (wpl.lock());
1720 if (track()->playlist() == pl) {
1721 // exit when use_playlist is called by the creation of the playlist menu
1722 // or the playlist choice is unchanged
1726 track()->use_playlist (pl);
1728 RouteGroup* rg = route_group();
1730 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) {
1731 std::string group_string = "." + rg->name() + ".";
1733 std::string take_name = pl->name();
1734 std::string::size_type idx = take_name.find(group_string);
1736 if (idx == std::string::npos)
1739 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1741 boost::shared_ptr<RouteList> rl (rg->route_list());
1743 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1744 if ((*i) == this->route()) {
1748 std::string playlist_name = (*i)->name()+group_string+take_name;
1750 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1755 if (track->freeze_state() == Track::Frozen) {
1756 /* Don't change playlists of frozen tracks */
1760 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1762 // No playlist for this track for this take yet, make it
1763 track->use_new_playlist();
1764 track->playlist()->set_name(playlist_name);
1766 track->use_playlist(ipl);
1773 RouteTimeAxisView::update_playlist_tip ()
1775 RouteGroup* rg = route_group ();
1776 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) {
1777 string group_string = "." + rg->name() + ".";
1779 string take_name = track()->playlist()->name();
1780 string::size_type idx = take_name.find(group_string);
1782 if (idx != string::npos) {
1783 /* find the bit containing the take number / name */
1784 take_name = take_name.substr (idx + group_string.length());
1786 /* set the playlist button tooltip to the take name */
1789 string_compose(_("Take: %1.%2"),
1790 Gtkmm2ext::markup_escape_text (rg->name()),
1791 Gtkmm2ext::markup_escape_text (take_name))
1798 /* set the playlist button tooltip to the playlist name */
1799 set_tooltip (playlist_button, _("Playlist") + std::string(": ") + Gtkmm2ext::markup_escape_text (track()->playlist()->name()));
1804 RouteTimeAxisView::show_playlist_selector ()
1806 _editor.playlist_selector().show_for (this);
1810 RouteTimeAxisView::map_frozen ()
1816 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1818 switch (track()->freeze_state()) {
1820 playlist_button.set_sensitive (false);
1821 rec_enable_button->set_sensitive (false);
1824 playlist_button.set_sensitive (true);
1825 rec_enable_button->set_sensitive (true);
1831 RouteTimeAxisView::color_handler ()
1833 //case cTimeStretchOutline:
1834 if (timestretch_rect) {
1835 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
1837 //case cTimeStretchFill:
1838 if (timestretch_rect) {
1839 timestretch_rect->set_fill_color (UIConfiguration::instance().color ("time stretch fill"));
1845 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1846 * Will add track if necessary.
1849 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1851 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1852 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1855 /* it doesn't exist yet, so we don't care about the button state: just add it */
1856 create_automation_child (param, true);
1859 bool yn = menu->get_active();
1860 bool changed = false;
1862 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1864 /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1865 will have done that for us.
1868 if (changed && !no_redraw) {
1876 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1878 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1884 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1886 if (menu && !_hidden) {
1887 ignore_toggle = true;
1888 menu->set_active (false);
1889 ignore_toggle = false;
1892 if (_route && !no_redraw) {
1898 RouteTimeAxisView::update_gain_track_visibility ()
1900 bool const showit = gain_automation_item->get_active();
1902 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1903 gain_track->set_marked_for_display (showit);
1905 /* now trigger a redisplay */
1908 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1914 RouteTimeAxisView::update_trim_track_visibility ()
1916 bool const showit = trim_automation_item->get_active();
1918 if (showit != string_is_affirmative (trim_track->gui_property ("visible"))) {
1919 trim_track->set_marked_for_display (showit);
1921 /* now trigger a redisplay */
1924 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1930 RouteTimeAxisView::update_mute_track_visibility ()
1932 bool const showit = mute_automation_item->get_active();
1934 if (showit != string_is_affirmative (mute_track->gui_property ("visible"))) {
1935 mute_track->set_marked_for_display (showit);
1937 /* now trigger a redisplay */
1940 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1946 RouteTimeAxisView::update_pan_track_visibility ()
1948 bool const showit = pan_automation_item->get_active();
1949 bool changed = false;
1951 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1952 if ((*i)->set_marked_for_display (showit)) {
1958 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1963 RouteTimeAxisView::ensure_pan_views (bool show)
1965 bool changed = false;
1966 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1968 (*i)->set_marked_for_display (false);
1971 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1975 if (!_route->panner()) {
1979 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1980 set<Evoral::Parameter>::iterator p;
1982 for (p = params.begin(); p != params.end(); ++p) {
1983 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1985 if (pan_control->parameter().type() == NullAutomation) {
1986 error << "Pan control has NULL automation type!" << endmsg;
1990 if (automation_child (pan_control->parameter ()).get () == 0) {
1992 /* we don't already have an AutomationTimeAxisView for this parameter */
1994 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1996 boost::shared_ptr<AutomationTimeAxisView> t (
1997 new AutomationTimeAxisView (_session,
2001 pan_control->parameter (),
2009 pan_tracks.push_back (t);
2010 add_automation_child (*p, t, show);
2012 pan_tracks.push_back (automation_child (pan_control->parameter ()));
2019 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
2021 if (apply_to_selection) {
2022 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
2026 /* Show our automation */
2028 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2029 i->second->set_marked_for_display (true);
2031 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2034 menu->set_active(true);
2039 /* Show processor automation */
2041 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2042 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2043 if ((*ii)->view == 0) {
2044 add_processor_automation_curve ((*i)->processor, (*ii)->what);
2047 (*ii)->menu_item->set_active (true);
2060 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
2062 if (apply_to_selection) {
2063 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
2067 /* Show our automation */
2069 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2070 if (i->second->has_automation()) {
2071 i->second->set_marked_for_display (true);
2073 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2075 menu->set_active(true);
2080 /* Show processor automation */
2082 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2083 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2084 if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
2085 (*ii)->menu_item->set_active (true);
2097 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
2099 if (apply_to_selection) {
2100 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
2104 /* Hide our automation */
2106 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2107 i->second->set_marked_for_display (false);
2109 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2112 menu->set_active (false);
2116 /* Hide processor automation */
2118 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2119 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2120 (*ii)->menu_item->set_active (false);
2131 RouteTimeAxisView::region_view_added (RegionView* rv)
2133 /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
2134 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
2135 boost::shared_ptr<AutomationTimeAxisView> atv;
2137 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
2142 for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
2143 (*i)->add_ghost(rv);
2147 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
2149 for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
2155 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
2157 parent.remove_processor_automation_node (this);
2161 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
2164 remove_child (pan->view);
2168 RouteTimeAxisView::ProcessorAutomationNode*
2169 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2171 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2173 if ((*i)->processor == processor) {
2175 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2176 if ((*ii)->what == what) {
2186 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
2188 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2191 ProcessorAutomationNode* pan;
2193 if ((pan = find_processor_automation_node (processor, what)) == 0) {
2194 /* session state may never have been saved with new plugin */
2195 error << _("programming error: ")
2196 << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
2197 processor->name(), what.type(), (int) what.channel(), what.id() )
2199 abort(); /*NOTREACHED*/
2207 boost::shared_ptr<AutomationControl> control
2208 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2210 pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2211 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2212 _editor, *this, false, parent_canvas,
2213 processor->describe_parameter (what), processor->name()));
2215 pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2217 add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2220 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2225 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2228 pan->menu_item->set_active (false);
2237 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2239 boost::shared_ptr<Processor> processor (p.lock ());
2241 if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2242 /* The Amp processor is a special case and is dealt with separately */
2246 set<Evoral::Parameter> existing;
2248 processor->what_has_data (existing);
2250 for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2252 Evoral::Parameter param (*i);
2253 boost::shared_ptr<AutomationLine> al;
2255 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2258 add_processor_automation_curve (processor, param);
2264 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
2266 using namespace Menu_Helpers;
2270 track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
2272 _automation_tracks[param] = track;
2274 /* existing state overrides "show" argument */
2275 string s = track->gui_property ("visible");
2277 show = string_is_affirmative (s);
2280 /* this might or might not change the visibility status, so don't rely on it */
2281 track->set_marked_for_display (show);
2283 if (show && !no_redraw) {
2287 if (!ARDOUR::parameter_is_midi((AutomationType)param.type())) {
2288 /* MIDI-related parameters are always in the menu, there's no
2289 reason to rebuild the menu just because we added a automation
2290 lane for one of them. But if we add a non-MIDI automation
2291 lane, then we need to invalidate the display menu.
2293 delete display_menu;
2299 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2301 boost::shared_ptr<Processor> processor (p.lock ());
2303 if (!processor || !processor->display_to_user ()) {
2307 /* we use this override to veto the Amp processor from the plugin menu,
2308 as its automation lane can be accessed using the special "Fader" menu
2312 if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2316 using namespace Menu_Helpers;
2317 ProcessorAutomationInfo *rai;
2318 list<ProcessorAutomationInfo*>::iterator x;
2320 const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2322 if (automatable.empty()) {
2326 for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2327 if ((*x)->processor == processor) {
2332 if (x == processor_automation.end()) {
2333 rai = new ProcessorAutomationInfo (processor);
2334 processor_automation.push_back (rai);
2339 /* any older menu was deleted at the top of processors_changed()
2340 when we cleared the subplugin menu.
2343 rai->menu = manage (new Menu);
2344 MenuList& items = rai->menu->items();
2345 rai->menu->set_name ("ArdourContextMenu");
2349 std::set<Evoral::Parameter> has_visible_automation;
2350 AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2352 for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2354 ProcessorAutomationNode* pan;
2355 Gtk::CheckMenuItem* mitem;
2357 string name = processor->describe_parameter (*i);
2359 if (name == X_("hidden")) {
2363 items.push_back (CheckMenuElem (name));
2364 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2366 _subplugin_menu_map[*i] = mitem;
2368 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2369 mitem->set_active(true);
2372 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2376 pan = new ProcessorAutomationNode (*i, mitem, *this);
2378 rai->lines.push_back (pan);
2382 pan->menu_item = mitem;
2386 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2389 if (items.size() == 0) {
2393 /* add the menu for this processor, because the subplugin
2394 menu is always cleared at the top of processors_changed().
2395 this is the result of some poor design in gtkmm and/or
2399 subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2404 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2405 RouteTimeAxisView::ProcessorAutomationNode* pan)
2407 bool showit = pan->menu_item->get_active();
2408 bool redraw = false;
2410 if (pan->view == 0 && showit) {
2411 add_processor_automation_curve (rai->processor, pan->what);
2415 if (pan->view && pan->view->set_marked_for_display (showit)) {
2419 if (redraw && !no_redraw) {
2425 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2427 if (c.type == RouteProcessorChange::MeterPointChange) {
2428 /* nothing to do if only the meter point has changed */
2432 using namespace Menu_Helpers;
2434 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2435 (*i)->valid = false;
2438 setup_processor_menu_and_curves ();
2440 bool deleted_processor_automation = false;
2442 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2444 list<ProcessorAutomationInfo*>::iterator tmp;
2452 processor_automation.erase (i);
2453 deleted_processor_automation = true;
2460 if (deleted_processor_automation && !no_redraw) {
2465 boost::shared_ptr<AutomationLine>
2466 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2468 ProcessorAutomationNode* pan;
2470 if ((pan = find_processor_automation_node (processor, what)) != 0) {
2476 return boost::shared_ptr<AutomationLine>();
2480 RouteTimeAxisView::reset_processor_automation_curves ()
2482 for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2488 RouteTimeAxisView::can_edit_name () const
2490 /* we do not allow track name changes if it is record enabled
2492 return !_route->record_enabled();
2496 RouteTimeAxisView::blink_rec_display (bool onoff)
2498 RouteUI::blink_rec_display (onoff);
2502 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2504 if (_ignore_set_layer_display) {
2508 if (apply_to_selection) {
2509 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2513 _view->set_layer_display (d);
2516 set_gui_property (X_("layer-display"), enum_2_string (d));
2521 RouteTimeAxisView::layer_display () const
2524 return _view->layer_display ();
2527 /* we don't know, since we don't have a _view, so just return something */
2533 boost::shared_ptr<AutomationTimeAxisView>
2534 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2536 AutomationTracks::iterator i = _automation_tracks.find(param);
2537 if (i != _automation_tracks.end()) {
2540 return boost::shared_ptr<AutomationTimeAxisView>();
2545 RouteTimeAxisView::fast_update ()
2547 gm.get_level_meter().update_meters ();
2551 RouteTimeAxisView::hide_meter ()
2554 gm.get_level_meter().hide_meters ();
2558 RouteTimeAxisView::show_meter ()
2564 RouteTimeAxisView::reset_meter ()
2566 if (UIConfiguration::instance().get_show_track_meters()) {
2567 int meter_width = 3;
2568 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2571 gm.get_level_meter().setup_meters (height - 9, meter_width);
2578 RouteTimeAxisView::clear_meter ()
2580 gm.get_level_meter().clear_meters ();
2584 RouteTimeAxisView::meter_changed ()
2586 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2588 if (_route && !no_redraw && UIConfiguration::instance().get_show_track_meters()) {
2591 // reset peak when meter point changes
2592 gm.reset_peak_display();
2596 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2599 if (_route && !no_redraw) {
2605 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2607 using namespace Menu_Helpers;
2609 if (!_underlay_streams.empty()) {
2610 MenuList& parent_items = parent_menu->items();
2611 Menu* gs_menu = manage (new Menu);
2612 gs_menu->set_name ("ArdourContextMenu");
2613 MenuList& gs_items = gs_menu->items();
2615 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2617 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2618 gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2619 sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2625 RouteTimeAxisView::set_underlay_state()
2627 if (!underlay_xml_node) {
2631 XMLNodeList nlist = underlay_xml_node->children();
2632 XMLNodeConstIterator niter;
2633 XMLNode *child_node;
2635 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2636 child_node = *niter;
2638 if (child_node->name() != "Underlay") {
2642 XMLProperty* prop = child_node->property ("id");
2644 PBD::ID id (prop->value());
2646 RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2649 add_underlay(v->view(), false);
2658 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2664 RouteTimeAxisView& other = v->trackview();
2666 if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2667 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2668 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2669 abort(); /*NOTREACHED*/
2672 _underlay_streams.push_back(v);
2673 other._underlay_mirrors.push_back(this);
2675 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2677 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2679 if (!underlay_xml_node) {
2680 underlay_xml_node = xml_node->add_child("Underlays");
2683 XMLNode* node = underlay_xml_node->add_child("Underlay");
2684 XMLProperty* prop = node->add_property("id");
2685 prop->set_value(v->trackview().route()->id().to_s());
2692 RouteTimeAxisView::remove_underlay (StreamView* v)
2698 UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2699 RouteTimeAxisView& other = v->trackview();
2701 if (it != _underlay_streams.end()) {
2702 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2704 if (gm == other._underlay_mirrors.end()) {
2705 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2706 abort(); /*NOTREACHED*/
2709 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2711 _underlay_streams.erase(it);
2712 other._underlay_mirrors.erase(gm);
2714 if (underlay_xml_node) {
2715 underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2721 RouteTimeAxisView::set_button_names ()
2723 if (_route && _route->solo_safe()) {
2724 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2726 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2728 if (Config->get_solo_control_is_listen_control()) {
2729 switch (Config->get_listen_position()) {
2730 case AfterFaderListen:
2731 solo_button->set_text (S_("AfterFader|A"));
2732 set_tooltip (*solo_button, _("After-fade listen (AFL)"));
2734 case PreFaderListen:
2735 solo_button->set_text (S_("PreFader|P"));
2736 set_tooltip (*solo_button, _("Pre-fade listen (PFL)"));
2740 solo_button->set_text (S_("Solo|S"));
2741 set_tooltip (*solo_button, _("Solo"));
2743 mute_button->set_text (S_("Mute|M"));
2747 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2749 ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2750 if (i != _main_automation_menu_map.end()) {
2754 i = _subplugin_menu_map.find (param);
2755 if (i != _subplugin_menu_map.end()) {
2763 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2765 boost::shared_ptr<AutomationControl> c = _route->gain_control();
2767 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2771 gain_track.reset (new AutomationTimeAxisView (_session,
2772 _route, _route->amp(), c, param,
2777 _route->amp()->describe_parameter(param)));
2780 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2783 add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2787 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2789 boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2790 if (!c || ! _route->trim()->active()) {
2794 trim_track.reset (new AutomationTimeAxisView (_session,
2795 _route, _route->trim(), c, param,
2800 _route->trim()->describe_parameter(param)));
2803 _view->foreach_regionview (sigc::mem_fun (*trim_track.get(), &TimeAxisView::add_ghost));
2806 add_automation_child (Evoral::Parameter(TrimAutomation), trim_track, show);
2810 RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
2812 boost::shared_ptr<AutomationControl> c = _route->mute_control();
2814 error << "Route has no mute automation, unable to add automation track view." << endmsg;
2818 mute_track.reset (new AutomationTimeAxisView (_session,
2819 _route, _route, c, param,
2824 _route->describe_parameter(param)));
2827 _view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
2830 add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
2834 void add_region_to_list (RegionView* rv, RegionList* l)
2836 l->push_back (rv->region());
2840 RouteTimeAxisView::combine_regions ()
2842 /* as of may 2011, we do not offer uncombine for MIDI tracks
2845 if (!is_audio_track()) {
2853 RegionList selected_regions;
2854 boost::shared_ptr<Playlist> playlist = track()->playlist();
2856 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2858 if (selected_regions.size() < 2) {
2862 playlist->clear_changes ();
2863 boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2865 _session->add_command (new StatefulDiffCommand (playlist));
2866 /* make the new region be selected */
2868 return _view->find_view (compound_region);
2872 RouteTimeAxisView::uncombine_regions ()
2874 /* as of may 2011, we do not offer uncombine for MIDI tracks
2876 if (!is_audio_track()) {
2884 RegionList selected_regions;
2885 boost::shared_ptr<Playlist> playlist = track()->playlist();
2887 /* have to grab selected regions first because the uncombine is going
2888 * to change that in the middle of the list traverse
2891 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2893 playlist->clear_changes ();
2895 for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2896 playlist->uncombine (*i);
2899 _session->add_command (new StatefulDiffCommand (playlist));
2903 RouteTimeAxisView::state_id() const
2905 return string_compose ("rtav %1", _route->id().to_s());
2910 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2912 TimeAxisView::remove_child (c);
2914 boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2916 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2917 if (i->second == a) {
2918 _automation_tracks.erase (i);