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());
127 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::parameter_changed));
129 parameter_changed ("editor-stereo-only-meters");
133 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
135 RouteUI::set_route (rt);
137 CANVAS_DEBUG_NAME (_canvas_display, string_compose ("main for %1", rt->name()));
138 CANVAS_DEBUG_NAME (selection_group, string_compose ("selections for %1", rt->name()));
139 CANVAS_DEBUG_NAME (_ghost_group, string_compose ("ghosts for %1", rt->name()));
142 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
145 gm.set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
146 gm.get_level_meter().set_no_show_all();
147 gm.get_level_meter().setup_meters(50, meter_width);
148 gm.update_gain_sensitive ();
150 string str = gui_property ("height");
152 set_height (atoi (str));
154 set_height (preset_height (HeightNormal));
157 if (!_route->is_auditioner()) {
158 if (gui_property ("visible").empty()) {
159 set_gui_property ("visible", true);
162 set_gui_property ("visible", false);
165 timestretch_rect = 0;
168 ignore_toggle = false;
170 route_group_button.set_name ("route button");
171 playlist_button.set_name ("route button");
172 automation_button.set_name ("route button");
174 route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
175 playlist_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click));
176 automation_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click));
180 if (ARDOUR::Profile->get_mixbus()) {
181 controls_table.attach (*rec_enable_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
183 controls_table.attach (*rec_enable_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
186 if (is_midi_track()) {
187 set_tooltip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
188 gm.set_fader_name ("MidiTrackFader");
190 set_tooltip(*rec_enable_button, _("Record"));
191 gm.set_fader_name ("AudioTrackFader");
194 /* set playlist button tip to the current playlist, and make it update when it changes */
195 update_playlist_tip ();
196 track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
199 gm.set_fader_name ("AudioBusFader");
200 Gtk::Fixed *blank = manage(new Gtk::Fixed());
201 controls_button_size_group->add_widget(*blank);
202 if (ARDOUR::Profile->get_mixbus() ) {
203 controls_table.attach (*blank, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
205 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
210 top_hbox.pack_end(gm.get_level_meter(), false, false, 2);
212 if (!ARDOUR::Profile->get_mixbus()) {
213 controls_meters_size_group->add_widget (gm.get_level_meter());
216 _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
217 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
218 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
219 _route->track_number_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::label_view, this), gui_context());
221 if (ARDOUR::Profile->get_mixbus()) {
222 controls_table.attach (*mute_button, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
224 controls_table.attach (*mute_button, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
226 // mute button is always present, it is used to
227 // force the 'blank' placeholders to the proper size
228 controls_button_size_group->add_widget(*mute_button);
230 if (!_route->is_master()) {
231 if (ARDOUR::Profile->get_mixbus()) {
232 controls_table.attach (*solo_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
234 controls_table.attach (*solo_button, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
237 Gtk::Fixed *blank = manage(new Gtk::Fixed());
238 controls_button_size_group->add_widget(*blank);
239 if (ARDOUR::Profile->get_mixbus()) {
240 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
242 controls_table.attach (*blank, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
247 if (ARDOUR::Profile->get_mixbus()) {
248 controls_table.attach (route_group_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
249 controls_table.attach (gm.get_gain_slider(), 3, 5, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
251 else if (!ARDOUR::Profile->get_trx()) {
252 controls_table.attach (route_group_button, 4, 5, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
253 controls_table.attach (gm.get_gain_slider(), 0, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
256 set_tooltip(*solo_button,_("Solo"));
257 set_tooltip(*mute_button,_("Mute"));
258 set_tooltip(route_group_button, _("Route Group"));
260 mute_button->set_tweaks(ArdourButton::TrackHeader);
261 solo_button->set_tweaks(ArdourButton::TrackHeader);
262 rec_enable_button->set_tweaks(ArdourButton::TrackHeader);
263 playlist_button.set_tweaks(ArdourButton::TrackHeader);
264 automation_button.set_tweaks(ArdourButton::TrackHeader);
265 route_group_button.set_tweaks(ArdourButton::TrackHeader);
267 if (is_midi_track()) {
268 set_tooltip(automation_button, _("MIDI Controllers and Automation"));
270 set_tooltip(automation_button, _("Automation"));
273 update_track_number_visibility();
276 if (ARDOUR::Profile->get_mixbus()) {
277 controls_table.attach (automation_button, 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
279 else if (!ARDOUR::Profile->get_trx()) {
280 controls_table.attach (automation_button, 3, 4, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
283 if (is_track() && track()->mode() == ARDOUR::Normal) {
284 if (ARDOUR::Profile->get_mixbus()) {
285 controls_table.attach (playlist_button, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
287 else if (!ARDOUR::Profile->get_trx()) {
288 controls_table.attach (playlist_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
294 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
295 _route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::route_property_changed, this, _1), gui_context());
299 str = gui_property ("layer-display");
301 set_layer_display (LayerDisplay (string_2_enum (str, _view->layer_display ())));
304 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
305 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
307 /* pick up the correct freeze state */
312 _editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_pixel));
313 UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler));
315 PropertyList* plist = new PropertyList();
317 plist->add (ARDOUR::Properties::mute, true);
318 plist->add (ARDOUR::Properties::solo, true);
320 route_group_menu = new RouteGroupMenu (_session, plist);
322 gm.get_level_meter().signal_scroll_event().connect (sigc::mem_fun (*this, &RouteTimeAxisView::controls_ebox_scroll), false);
325 RouteTimeAxisView::~RouteTimeAxisView ()
327 cleanup_gui_properties ();
329 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
333 delete playlist_action_menu;
334 playlist_action_menu = 0;
339 _automation_tracks.clear ();
341 delete route_group_menu;
342 CatchDeletion (this);
346 RouteTimeAxisView::post_construct ()
348 /* map current state of the route */
350 update_diskstream_display ();
351 setup_processor_menu_and_curves ();
352 reset_processor_automation_curves ();
355 /** Set up the processor menu for the current set of processors, and
356 * display automation curves for any parameters which have data.
359 RouteTimeAxisView::setup_processor_menu_and_curves ()
361 _subplugin_menu_map.clear ();
362 subplugin_menu.items().clear ();
363 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
364 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
368 RouteTimeAxisView::route_group_click (GdkEventButton *ev)
370 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
371 if (_route->route_group()) {
372 _route->route_group()->remove (_route);
378 r.push_back (route ());
380 route_group_menu->build (r);
381 route_group_menu->menu()->popup (ev->button, ev->time);
387 RouteTimeAxisView::playlist_changed ()
393 RouteTimeAxisView::label_view ()
395 string x = _route->name ();
396 if (x != name_label.get_text ()) {
397 name_label.set_text (x);
399 const int64_t track_number = _route->track_number ();
400 if (track_number == 0) {
401 number_label.set_text ("");
403 number_label.set_text (PBD::to_string (abs(_route->track_number ()), std::dec));
408 RouteTimeAxisView::update_track_number_visibility ()
411 bool show_label = _session->config.get_track_name_number();
413 if (_route && _route->is_master()) {
417 if (number_label.get_parent()) {
418 controls_table.remove (number_label);
421 if (ARDOUR::Profile->get_mixbus()) {
422 controls_table.attach (number_label, 3, 4, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
424 controls_table.attach (number_label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
426 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
427 // except the width of the number label is subtracted from the name-hbox, so we
428 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
429 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
431 number_label.set_size_request(tnw, -1);
432 number_label.show ();
434 number_label.hide ();
439 RouteTimeAxisView::parameter_changed (string const & p)
441 if (p == "track-name-number") {
442 update_track_number_visibility();
443 } else if (p == "editor-stereo-only-meters") {
444 if (UIConfiguration::instance().get_editor_stereo_only_meters()) {
445 gm.get_level_meter().set_max_audio_meter_count (2);
447 gm.get_level_meter().set_max_audio_meter_count (0);
453 RouteTimeAxisView::route_property_changed (const PropertyChange& what_changed)
455 if (what_changed.contains (ARDOUR::Properties::name)) {
461 RouteTimeAxisView::take_name_changed (void *src)
469 RouteTimeAxisView::playlist_click ()
471 build_playlist_menu ();
472 conditionally_add_to_selection ();
473 playlist_action_menu->popup (1, gtk_get_current_event_time());
477 RouteTimeAxisView::automation_click ()
479 conditionally_add_to_selection ();
480 build_automation_action_menu (false);
481 automation_action_menu->popup (1, gtk_get_current_event_time());
485 RouteTimeAxisView::build_automation_action_menu (bool for_selection)
487 using namespace Menu_Helpers;
489 /* detach subplugin_menu from automation_action_menu before we delete automation_action_menu,
490 otherwise bad things happen (see comment for similar case in MidiTimeAxisView::build_automation_action_menu)
493 detach_menu (subplugin_menu);
495 _main_automation_menu_map.clear ();
496 delete automation_action_menu;
497 automation_action_menu = new Menu;
499 MenuList& items = automation_action_menu->items();
501 automation_action_menu->set_name ("ArdourContextMenu");
503 items.push_back (MenuElem (_("Show All Automation"),
504 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_all_automation), for_selection)));
506 items.push_back (MenuElem (_("Show Existing Automation"),
507 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_existing_automation), for_selection)));
509 items.push_back (MenuElem (_("Hide All Automation"),
510 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::hide_all_automation), for_selection)));
512 /* Attach the plugin submenu. It may have previously been used elsewhere,
513 so it was detached above
516 if (!subplugin_menu.items().empty()) {
517 items.push_back (SeparatorElem ());
518 items.push_back (MenuElem (_("Processor automation"), subplugin_menu));
519 items.back().set_sensitive (!for_selection || _editor.get_selection().tracks.size() == 1);;
522 /* Add any route automation */
525 items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility)));
526 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
527 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
528 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
530 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
534 items.push_back (CheckMenuElem (_("Trim"), sigc::mem_fun (*this, &RouteTimeAxisView::update_trim_track_visibility)));
535 trim_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
536 trim_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
537 (trim_track && string_is_affirmative (trim_track->gui_property ("visible"))));
539 _main_automation_menu_map[Evoral::Parameter(TrimAutomation)] = trim_automation_item;
543 items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility)));
544 mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
545 mute_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
546 (mute_track && string_is_affirmative (mute_track->gui_property ("visible"))));
548 _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
551 if (!pan_tracks.empty()) {
552 items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility)));
553 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
554 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
555 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
557 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
558 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
559 _main_automation_menu_map[*p] = pan_automation_item;
565 RouteTimeAxisView::build_display_menu ()
567 using namespace Menu_Helpers;
571 TimeAxisView::build_display_menu ();
573 /* now fill it with our stuff */
575 MenuList& items = display_menu->items();
576 display_menu->set_name ("ArdourContextMenu");
578 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
580 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
582 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
584 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
586 items.push_back (SeparatorElem());
589 detach_menu (*_size_menu);
592 items.push_back (MenuElem (_("Height"), *_size_menu));
594 items.push_back (SeparatorElem());
596 items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
597 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
598 items.push_back (SeparatorElem());
600 // Hook for derived classes to add type specific stuff
601 append_extra_display_menu_items ();
605 Menu* layers_menu = manage (new Menu);
606 MenuList &layers_items = layers_menu->items();
607 layers_menu->set_name("ArdourContextMenu");
609 RadioMenuItem::Group layers_group;
611 /* Find out how many overlaid/stacked tracks we have in the selection */
615 TrackSelection const & s = _editor.get_selection().tracks;
616 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
617 StreamView* v = (*i)->view ();
622 switch (v->layer_display ()) {
633 /* We're not connecting to signal_toggled() here; in the case where these two items are
634 set to be in the `inconsistent' state, it seems that one or other will end up active
635 as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you
636 select the active one, no toggled signal is emitted so nothing happens.
639 _ignore_set_layer_display = true;
641 layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
642 RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
643 i->set_active (overlaid != 0 && stacked == 0);
644 i->set_inconsistent (overlaid != 0 && stacked != 0);
645 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
647 layers_items.push_back (RadioMenuElem (layers_group, _("Stacked")));
648 i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
649 i->set_active (overlaid == 0 && stacked != 0);
650 i->set_inconsistent (overlaid != 0 && stacked != 0);
651 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
653 _ignore_set_layer_display = false;
655 items.push_back (MenuElem (_("Layers"), *layers_menu));
657 Menu* alignment_menu = manage (new Menu);
658 MenuList& alignment_items = alignment_menu->items();
659 alignment_menu->set_name ("ArdourContextMenu");
661 RadioMenuItem::Group align_group;
663 /* Same verbose hacks as for the layering options above */
669 boost::shared_ptr<Track> first_track;
671 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
672 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
673 if (!r || !r->is_track ()) {
678 first_track = r->track();
681 switch (r->track()->alignment_choice()) {
685 switch (r->track()->alignment_style()) {
686 case ExistingMaterial:
694 case UseExistingMaterial:
710 inconsistent = false;
717 if (!inconsistent && first_track) {
719 alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
720 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
721 i->set_active (automatic != 0 && existing == 0 && capture == 0);
722 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
724 switch (first_track->alignment_choice()) {
726 switch (first_track->alignment_style()) {
727 case ExistingMaterial:
728 alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
731 alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
739 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
740 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
741 i->set_active (existing != 0 && capture == 0 && automatic == 0);
742 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
744 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
745 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
746 i->set_active (existing == 0 && capture != 0 && automatic == 0);
747 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
749 items.push_back (MenuElem (_("Alignment"), *alignment_menu));
755 Menu* mode_menu = manage (new Menu);
756 MenuList& mode_items = mode_menu->items ();
757 mode_menu->set_name ("ArdourContextMenu");
759 RadioMenuItem::Group mode_group;
765 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
766 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
767 if (!r || !r->is_track ()) {
771 switch (r->track()->mode()) {
784 mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode")));
785 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
786 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal, true));
787 i->set_active (normal != 0 && tape == 0 && non_layered == 0);
788 i->set_inconsistent (normal != 0 && (tape != 0 || non_layered != 0));
790 mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode")));
791 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
792 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive, true));
793 i->set_active (normal == 0 && tape != 0 && non_layered == 0);
794 i->set_inconsistent (tape != 0 && (normal != 0 || non_layered != 0));
796 mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode")));
797 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
798 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered, true));
799 i->set_active (normal == 0 && tape == 0 && non_layered != 0);
800 i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0));
802 items.push_back (MenuElem (_("Record Mode"), *mode_menu));
804 items.push_back (SeparatorElem());
806 build_playlist_menu ();
807 items.push_back (MenuElem (_("Playlist"), *playlist_action_menu));
808 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
811 route_group_menu->detach ();
814 for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
815 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
817 r.push_back (rtv->route ());
822 r.push_back (route ());
825 route_group_menu->build (r);
826 items.push_back (MenuElem (_("Group"), *route_group_menu->menu ()));
828 build_automation_action_menu (true);
829 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
831 items.push_back (SeparatorElem());
835 TrackSelection const & s = _editor.get_selection().tracks;
836 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
837 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
842 if (r->route()->active()) {
849 items.push_back (CheckMenuElem (_("Active")));
850 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
851 bool click_sets_active = true;
852 if (active > 0 && inactive == 0) {
853 i->set_active (true);
854 click_sets_active = false;
855 } else if (active > 0 && inactive > 0) {
856 i->set_inconsistent (true);
858 i->set_sensitive(! _session->transport_rolling());
859 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true));
861 items.push_back (SeparatorElem());
862 items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
863 if (_route && !_route->is_master()) {
864 items.push_back (SeparatorElem());
865 items.push_back (MenuElem (_("Duplicate..."), boost::bind (&ARDOUR_UI::start_duplicate_routes, ARDOUR_UI::instance())));
867 items.push_back (SeparatorElem());
868 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(_editor, &PublicEditor::remove_tracks)));
872 RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection)
874 if (apply_to_selection) {
875 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false));
878 bool needs_bounce = false;
880 if (!track()->can_use_mode (mode, needs_bounce)) {
886 cerr << "would bounce this one\n";
891 track()->set_mode (mode);
896 RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer)
898 TimeAxisView::show_timestretch (start, end, layers, layer);
908 /* check that the time selection was made in our route, or our route group.
909 remember that route_group() == 0 implies the route is *not* in a edit group.
912 if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
913 /* this doesn't apply to us */
917 /* ignore it if our edit group is not active */
919 if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
924 if (timestretch_rect == 0) {
925 timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ());
926 timestretch_rect->set_fill_color (ArdourCanvas::HSV (UIConfiguration::instance().color ("time stretch fill")).mod (UIConfiguration::instance().modifier ("time stretch fill")).color());
927 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
930 timestretch_rect->show ();
931 timestretch_rect->raise_to_top ();
933 double const x1 = start / _editor.get_current_zoom();
934 double const x2 = (end - 1) / _editor.get_current_zoom();
936 timestretch_rect->set (ArdourCanvas::Rect (x1, current_height() * (layers - layer - 1) / layers,
937 x2, current_height() * (layers - layer) / layers));
941 RouteTimeAxisView::hide_timestretch ()
943 TimeAxisView::hide_timestretch ();
945 if (timestretch_rect) {
946 timestretch_rect->hide ();
951 RouteTimeAxisView::show_selection (TimeSelection& ts)
955 /* ignore it if our edit group is not active or if the selection was started
956 in some other track or route group (remember that route_group() == 0 means
957 that the track is not in an route group).
960 if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
961 (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
967 TimeAxisView::show_selection (ts);
971 RouteTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
974 bool height_changed = (height == 0) || (h != height);
977 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
980 gm.get_level_meter().setup_meters (gmlen, meter_width);
982 TimeAxisView::set_height (h, m);
985 _view->set_height ((double) current_height());
988 if (height >= preset_height (HeightNormal)) {
992 gm.get_gain_slider().show();
994 if (!_route || _route->is_monitor()) {
999 if (rec_enable_button)
1000 rec_enable_button->show();
1002 route_group_button.show();
1003 automation_button.show();
1005 if (is_track() && track()->mode() == ARDOUR::Normal) {
1006 playlist_button.show();
1013 gm.get_gain_slider().hide();
1014 mute_button->show();
1015 if (!_route || _route->is_monitor()) {
1016 solo_button->hide();
1018 solo_button->show();
1020 if (rec_enable_button)
1021 rec_enable_button->show();
1023 route_group_button.hide ();
1024 automation_button.hide ();
1026 if (is_track() && track()->mode() == ARDOUR::Normal) {
1027 playlist_button.hide ();
1032 if (height_changed && !no_redraw) {
1033 /* only emit the signal if the height really changed */
1039 RouteTimeAxisView::route_color_changed ()
1042 _view->apply_color (color(), StreamView::RegionColor);
1045 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1049 RouteTimeAxisView::reset_samples_per_pixel ()
1051 set_samples_per_pixel (_editor.get_current_zoom());
1055 RouteTimeAxisView::set_samples_per_pixel (double fpp)
1060 speed = track()->speed();
1064 _view->set_samples_per_pixel (fpp * speed);
1067 TimeAxisView::set_samples_per_pixel (fpp * speed);
1071 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
1073 if (!mitem->get_active()) {
1074 /* this is one of the two calls made when these radio menu items change status. this one
1075 is for the item that became inactive, and we want to ignore it.
1080 if (apply_to_selection) {
1081 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
1084 track()->set_align_choice (choice);
1090 RouteTimeAxisView::rename_current_playlist ()
1092 ArdourPrompter prompter (true);
1095 boost::shared_ptr<Track> tr = track();
1096 if (!tr || tr->destructive()) {
1100 boost::shared_ptr<Playlist> pl = tr->playlist();
1105 prompter.set_title (_("Rename Playlist"));
1106 prompter.set_prompt (_("New name for playlist:"));
1107 prompter.set_initial_text (pl->name());
1108 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1109 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1111 switch (prompter.run ()) {
1112 case Gtk::RESPONSE_ACCEPT:
1113 prompter.get_result (name);
1114 if (name.length()) {
1115 pl->set_name (name);
1125 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1127 std::string ret (basename);
1129 std::string const group_string = "." + route_group()->name() + ".";
1131 // iterate through all playlists
1133 for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1134 std::string tmp = (*i)->name();
1136 std::string::size_type idx = tmp.find(group_string);
1137 // find those which belong to this group
1138 if (idx != string::npos) {
1139 tmp = tmp.substr(idx + group_string.length());
1141 // and find the largest current number
1143 if (x > maxnumber) {
1152 snprintf (buf, sizeof(buf), "%d", maxnumber);
1154 ret = this->name() + "." + route_group()->name () + "." + buf;
1160 RouteTimeAxisView::use_copy_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1164 boost::shared_ptr<Track> tr = track ();
1165 if (!tr || tr->destructive()) {
1169 boost::shared_ptr<const Playlist> pl = tr->playlist();
1176 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1177 name = resolve_new_group_playlist_name(name, playlists_before_op);
1180 while (_session->playlists->by_name(name)) {
1181 name = Playlist::bump_name (name, *_session);
1184 // TODO: The prompter "new" button should be de-activated if the user
1185 // specifies a playlist name which already exists in the session.
1189 ArdourPrompter prompter (true);
1191 prompter.set_title (_("New Copy Playlist"));
1192 prompter.set_prompt (_("Name for new playlist:"));
1193 prompter.set_initial_text (name);
1194 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1195 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1196 prompter.show_all ();
1198 switch (prompter.run ()) {
1199 case Gtk::RESPONSE_ACCEPT:
1200 prompter.get_result (name);
1208 if (name.length()) {
1209 tr->use_copy_playlist ();
1210 tr->playlist()->set_name (name);
1215 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1219 boost::shared_ptr<Track> tr = track ();
1220 if (!tr || tr->destructive()) {
1224 boost::shared_ptr<const Playlist> pl = tr->playlist();
1231 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1232 name = resolve_new_group_playlist_name(name,playlists_before_op);
1235 while (_session->playlists->by_name(name)) {
1236 name = Playlist::bump_name (name, *_session);
1242 ArdourPrompter prompter (true);
1244 prompter.set_title (_("New Playlist"));
1245 prompter.set_prompt (_("Name for new playlist:"));
1246 prompter.set_initial_text (name);
1247 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1248 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1250 switch (prompter.run ()) {
1251 case Gtk::RESPONSE_ACCEPT:
1252 prompter.get_result (name);
1260 if (name.length()) {
1261 tr->use_new_playlist ();
1262 tr->playlist()->set_name (name);
1267 RouteTimeAxisView::clear_playlist ()
1269 boost::shared_ptr<Track> tr = track ();
1270 if (!tr || tr->destructive()) {
1274 boost::shared_ptr<Playlist> pl = tr->playlist();
1279 _editor.clear_playlist (pl);
1283 RouteTimeAxisView::speed_changed ()
1285 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_pixel, this));
1289 RouteTimeAxisView::update_diskstream_display ()
1299 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1301 if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1303 /* special case: select/deselect all tracks */
1305 _editor.begin_reversible_selection_op (X_("Selection Click"));
1307 if (_editor.get_selection().selected (this)) {
1308 _editor.get_selection().clear_tracks ();
1310 _editor.select_all_tracks ();
1313 _editor.commit_reversible_selection_op ();
1318 _editor.begin_reversible_selection_op (X_("Selection Click"));
1320 switch (ArdourKeyboard::selection_type (ev->state)) {
1321 case Selection::Toggle:
1322 _editor.get_selection().toggle (this);
1325 case Selection::Set:
1326 _editor.get_selection().set (this);
1329 case Selection::Extend:
1330 _editor.extend_selection_to_track (*this);
1333 case Selection::Add:
1334 _editor.get_selection().add (this);
1338 _editor.commit_reversible_selection_op ();
1342 RouteTimeAxisView::set_selected_points (PointSelection& points)
1344 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1345 (*i)->set_selected_points (points);
1347 AudioStreamView* asv = dynamic_cast<AudioStreamView*>(_view);
1349 asv->set_selected_points (points);
1354 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1357 _view->set_selected_regionviews (regions);
1361 /** Add the selectable things that we have to a list.
1362 * @param results List to add things to.
1365 RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results, bool within)
1370 speed = track()->speed();
1373 framepos_t const start_adjusted = session_frame_to_track_frame(start, speed);
1374 framepos_t const end_adjusted = session_frame_to_track_frame(end, speed);
1376 if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1377 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1380 /* pick up visible automation tracks */
1382 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1383 if (!(*i)->hidden()) {
1384 (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1390 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1393 _view->get_inverted_selectables (sel, results);
1396 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1397 if (!(*i)->hidden()) {
1398 (*i)->get_inverted_selectables (sel, results);
1406 RouteTimeAxisView::route_group () const
1408 return _route->route_group();
1412 RouteTimeAxisView::name() const
1414 return _route->name();
1417 boost::shared_ptr<Playlist>
1418 RouteTimeAxisView::playlist () const
1420 boost::shared_ptr<Track> tr;
1422 if ((tr = track()) != 0) {
1423 return tr->playlist();
1425 return boost::shared_ptr<Playlist> ();
1430 RouteTimeAxisView::name_entry_changed (string const& str)
1432 if (str == _route->name()) {
1438 strip_whitespace_edges (x);
1444 if (_session->route_name_internal (x)) {
1445 ARDOUR_UI::instance()->popup_error (string_compose (_("The name \"%1\" is reserved for %2"), x, PROGRAM_NAME));
1447 } else if (RouteUI::verify_new_route_name (x)) {
1448 _route->set_name (x);
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);
1823 playlist_button.set_sensitive (true);
1826 RouteUI::map_frozen ();
1830 RouteTimeAxisView::color_handler ()
1832 //case cTimeStretchOutline:
1833 if (timestretch_rect) {
1834 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
1836 //case cTimeStretchFill:
1837 if (timestretch_rect) {
1838 timestretch_rect->set_fill_color (UIConfiguration::instance().color ("time stretch fill"));
1844 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1845 * Will add track if necessary.
1848 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1850 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1851 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1854 /* it doesn't exist yet, so we don't care about the button state: just add it */
1855 create_automation_child (param, true);
1858 bool yn = menu->get_active();
1859 bool changed = false;
1861 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1863 /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1864 will have done that for us.
1867 if (changed && !no_redraw) {
1875 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1877 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1883 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1885 if (menu && !_hidden) {
1886 ignore_toggle = true;
1887 menu->set_active (false);
1888 ignore_toggle = false;
1891 if (_route && !no_redraw) {
1897 RouteTimeAxisView::update_gain_track_visibility ()
1899 bool const showit = gain_automation_item->get_active();
1901 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1902 gain_track->set_marked_for_display (showit);
1904 /* now trigger a redisplay */
1907 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1913 RouteTimeAxisView::update_trim_track_visibility ()
1915 bool const showit = trim_automation_item->get_active();
1917 if (showit != string_is_affirmative (trim_track->gui_property ("visible"))) {
1918 trim_track->set_marked_for_display (showit);
1920 /* now trigger a redisplay */
1923 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1929 RouteTimeAxisView::update_mute_track_visibility ()
1931 bool const showit = mute_automation_item->get_active();
1933 if (showit != string_is_affirmative (mute_track->gui_property ("visible"))) {
1934 mute_track->set_marked_for_display (showit);
1936 /* now trigger a redisplay */
1939 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1945 RouteTimeAxisView::update_pan_track_visibility ()
1947 bool const showit = pan_automation_item->get_active();
1948 bool changed = false;
1950 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1951 if ((*i)->set_marked_for_display (showit)) {
1957 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1962 RouteTimeAxisView::ensure_pan_views (bool show)
1964 bool changed = false;
1965 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1967 (*i)->set_marked_for_display (false);
1970 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1974 if (!_route->panner()) {
1978 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1979 set<Evoral::Parameter>::iterator p;
1981 for (p = params.begin(); p != params.end(); ++p) {
1982 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1984 if (pan_control->parameter().type() == NullAutomation) {
1985 error << "Pan control has NULL automation type!" << endmsg;
1989 if (automation_child (pan_control->parameter ()).get () == 0) {
1991 /* we don't already have an AutomationTimeAxisView for this parameter */
1993 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1995 boost::shared_ptr<AutomationTimeAxisView> t (
1996 new AutomationTimeAxisView (_session,
2000 pan_control->parameter (),
2008 pan_tracks.push_back (t);
2009 add_automation_child (*p, t, show);
2011 pan_tracks.push_back (automation_child (pan_control->parameter ()));
2018 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
2020 if (apply_to_selection) {
2021 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
2025 /* Show our automation */
2027 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2028 i->second->set_marked_for_display (true);
2030 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2033 menu->set_active(true);
2038 /* Show processor automation */
2040 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2041 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2042 if ((*ii)->view == 0) {
2043 add_processor_automation_curve ((*i)->processor, (*ii)->what);
2046 (*ii)->menu_item->set_active (true);
2059 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
2061 if (apply_to_selection) {
2062 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
2066 /* Show our automation */
2068 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2069 if (i->second->has_automation()) {
2070 i->second->set_marked_for_display (true);
2072 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2074 menu->set_active(true);
2079 /* Show processor automation */
2081 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2082 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2083 if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
2084 (*ii)->menu_item->set_active (true);
2096 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
2098 if (apply_to_selection) {
2099 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
2103 /* Hide our automation */
2105 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2106 i->second->set_marked_for_display (false);
2108 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2111 menu->set_active (false);
2115 /* Hide processor automation */
2117 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2118 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2119 (*ii)->menu_item->set_active (false);
2130 RouteTimeAxisView::region_view_added (RegionView* rv)
2132 /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
2133 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
2134 boost::shared_ptr<AutomationTimeAxisView> atv;
2136 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
2141 for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
2142 (*i)->add_ghost(rv);
2146 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
2148 for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
2154 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
2156 parent.remove_processor_automation_node (this);
2160 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
2163 remove_child (pan->view);
2167 RouteTimeAxisView::ProcessorAutomationNode*
2168 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2170 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2172 if ((*i)->processor == processor) {
2174 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2175 if ((*ii)->what == what) {
2185 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
2187 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2190 ProcessorAutomationNode* pan;
2192 if ((pan = find_processor_automation_node (processor, what)) == 0) {
2193 /* session state may never have been saved with new plugin */
2194 error << _("programming error: ")
2195 << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
2196 processor->name(), what.type(), (int) what.channel(), what.id() )
2198 abort(); /*NOTREACHED*/
2206 boost::shared_ptr<AutomationControl> control
2207 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2209 pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2210 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2211 _editor, *this, false, parent_canvas,
2212 processor->describe_parameter (what), processor->name()));
2214 pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2216 add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2219 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2224 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2227 pan->menu_item->set_active (false);
2236 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2238 boost::shared_ptr<Processor> processor (p.lock ());
2240 if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2241 /* The Amp processor is a special case and is dealt with separately */
2245 set<Evoral::Parameter> existing;
2247 processor->what_has_data (existing);
2249 for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2251 Evoral::Parameter param (*i);
2252 boost::shared_ptr<AutomationLine> al;
2254 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2257 add_processor_automation_curve (processor, param);
2263 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
2265 using namespace Menu_Helpers;
2269 track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
2271 _automation_tracks[param] = track;
2273 /* existing state overrides "show" argument */
2274 string s = track->gui_property ("visible");
2276 show = string_is_affirmative (s);
2279 /* this might or might not change the visibility status, so don't rely on it */
2280 track->set_marked_for_display (show);
2282 if (show && !no_redraw) {
2286 if (!ARDOUR::parameter_is_midi((AutomationType)param.type())) {
2287 /* MIDI-related parameters are always in the menu, there's no
2288 reason to rebuild the menu just because we added a automation
2289 lane for one of them. But if we add a non-MIDI automation
2290 lane, then we need to invalidate the display menu.
2292 delete display_menu;
2298 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2300 boost::shared_ptr<Processor> processor (p.lock ());
2302 if (!processor || !processor->display_to_user ()) {
2306 /* we use this override to veto the Amp processor from the plugin menu,
2307 as its automation lane can be accessed using the special "Fader" menu
2311 if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2315 using namespace Menu_Helpers;
2316 ProcessorAutomationInfo *rai;
2317 list<ProcessorAutomationInfo*>::iterator x;
2319 const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2321 if (automatable.empty()) {
2325 for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2326 if ((*x)->processor == processor) {
2331 if (x == processor_automation.end()) {
2332 rai = new ProcessorAutomationInfo (processor);
2333 processor_automation.push_back (rai);
2338 /* any older menu was deleted at the top of processors_changed()
2339 when we cleared the subplugin menu.
2342 rai->menu = manage (new Menu);
2343 MenuList& items = rai->menu->items();
2344 rai->menu->set_name ("ArdourContextMenu");
2348 std::set<Evoral::Parameter> has_visible_automation;
2349 AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2351 for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2353 ProcessorAutomationNode* pan;
2354 Gtk::CheckMenuItem* mitem;
2356 string name = processor->describe_parameter (*i);
2358 if (name == X_("hidden")) {
2362 items.push_back (CheckMenuElem (name));
2363 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2365 _subplugin_menu_map[*i] = mitem;
2367 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2368 mitem->set_active(true);
2371 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2375 pan = new ProcessorAutomationNode (*i, mitem, *this);
2377 rai->lines.push_back (pan);
2381 pan->menu_item = mitem;
2385 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2388 if (items.size() == 0) {
2392 /* add the menu for this processor, because the subplugin
2393 menu is always cleared at the top of processors_changed().
2394 this is the result of some poor design in gtkmm and/or
2398 subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2403 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2404 RouteTimeAxisView::ProcessorAutomationNode* pan)
2406 bool showit = pan->menu_item->get_active();
2407 bool redraw = false;
2409 if (pan->view == 0 && showit) {
2410 add_processor_automation_curve (rai->processor, pan->what);
2414 if (pan->view && pan->view->set_marked_for_display (showit)) {
2418 if (redraw && !no_redraw) {
2424 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2426 if (c.type == RouteProcessorChange::MeterPointChange) {
2427 /* nothing to do if only the meter point has changed */
2431 using namespace Menu_Helpers;
2433 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2434 (*i)->valid = false;
2437 setup_processor_menu_and_curves ();
2439 bool deleted_processor_automation = false;
2441 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2443 list<ProcessorAutomationInfo*>::iterator tmp;
2451 processor_automation.erase (i);
2452 deleted_processor_automation = true;
2459 if (deleted_processor_automation && !no_redraw) {
2464 boost::shared_ptr<AutomationLine>
2465 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2467 ProcessorAutomationNode* pan;
2469 if ((pan = find_processor_automation_node (processor, what)) != 0) {
2475 return boost::shared_ptr<AutomationLine>();
2479 RouteTimeAxisView::reset_processor_automation_curves ()
2481 for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2487 RouteTimeAxisView::can_edit_name () const
2489 /* we do not allow track name changes if it is record enabled
2491 boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track> (_route));
2495 return !trk->rec_enable_control()->get_value();
2499 RouteTimeAxisView::blink_rec_display (bool onoff)
2501 RouteUI::blink_rec_display (onoff);
2505 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2507 if (_ignore_set_layer_display) {
2511 if (apply_to_selection) {
2512 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2516 _view->set_layer_display (d);
2519 set_gui_property (X_("layer-display"), enum_2_string (d));
2524 RouteTimeAxisView::layer_display () const
2527 return _view->layer_display ();
2530 /* we don't know, since we don't have a _view, so just return something */
2536 boost::shared_ptr<AutomationTimeAxisView>
2537 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2539 AutomationTracks::iterator i = _automation_tracks.find(param);
2540 if (i != _automation_tracks.end()) {
2543 return boost::shared_ptr<AutomationTimeAxisView>();
2548 RouteTimeAxisView::fast_update ()
2550 gm.get_level_meter().update_meters ();
2554 RouteTimeAxisView::hide_meter ()
2557 gm.get_level_meter().hide_meters ();
2561 RouteTimeAxisView::show_meter ()
2567 RouteTimeAxisView::reset_meter ()
2569 if (UIConfiguration::instance().get_show_track_meters()) {
2570 int meter_width = 3;
2571 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2574 gm.get_level_meter().setup_meters (height - 9, meter_width);
2581 RouteTimeAxisView::clear_meter ()
2583 gm.get_level_meter().clear_meters ();
2587 RouteTimeAxisView::meter_changed ()
2589 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2591 if (_route && !no_redraw && UIConfiguration::instance().get_show_track_meters()) {
2594 // reset peak when meter point changes
2595 gm.reset_peak_display();
2599 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2602 if (_route && !no_redraw) {
2608 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2610 using namespace Menu_Helpers;
2612 if (!_underlay_streams.empty()) {
2613 MenuList& parent_items = parent_menu->items();
2614 Menu* gs_menu = manage (new Menu);
2615 gs_menu->set_name ("ArdourContextMenu");
2616 MenuList& gs_items = gs_menu->items();
2618 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2620 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2621 gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2622 sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2628 RouteTimeAxisView::set_underlay_state()
2630 if (!underlay_xml_node) {
2634 XMLNodeList nlist = underlay_xml_node->children();
2635 XMLNodeConstIterator niter;
2636 XMLNode *child_node;
2638 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2639 child_node = *niter;
2641 if (child_node->name() != "Underlay") {
2645 XMLProperty const * prop = child_node->property ("id");
2647 PBD::ID id (prop->value());
2649 RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2652 add_underlay(v->view(), false);
2661 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2667 RouteTimeAxisView& other = v->trackview();
2669 if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2670 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2671 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2672 abort(); /*NOTREACHED*/
2675 _underlay_streams.push_back(v);
2676 other._underlay_mirrors.push_back(this);
2678 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2680 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2682 if (!underlay_xml_node) {
2683 underlay_xml_node = xml_node->add_child("Underlays");
2686 XMLNode* node = underlay_xml_node->add_child("Underlay");
2687 XMLProperty const * prop = node->add_property("id");
2688 prop->set_value(v->trackview().route()->id().to_s());
2695 RouteTimeAxisView::remove_underlay (StreamView* v)
2701 UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2702 RouteTimeAxisView& other = v->trackview();
2704 if (it != _underlay_streams.end()) {
2705 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2707 if (gm == other._underlay_mirrors.end()) {
2708 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2709 abort(); /*NOTREACHED*/
2712 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2714 _underlay_streams.erase(it);
2715 other._underlay_mirrors.erase(gm);
2717 if (underlay_xml_node) {
2718 underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2724 RouteTimeAxisView::set_button_names ()
2726 if (_route && _route->solo_safe_control()->solo_safe()) {
2727 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2729 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2731 if (Config->get_solo_control_is_listen_control()) {
2732 switch (Config->get_listen_position()) {
2733 case AfterFaderListen:
2734 solo_button->set_text (S_("AfterFader|A"));
2735 set_tooltip (*solo_button, _("After-fade listen (AFL)"));
2737 case PreFaderListen:
2738 solo_button->set_text (S_("PreFader|P"));
2739 set_tooltip (*solo_button, _("Pre-fade listen (PFL)"));
2743 solo_button->set_text (S_("Solo|S"));
2744 set_tooltip (*solo_button, _("Solo"));
2746 mute_button->set_text (S_("Mute|M"));
2750 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2752 ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2753 if (i != _main_automation_menu_map.end()) {
2757 i = _subplugin_menu_map.find (param);
2758 if (i != _subplugin_menu_map.end()) {
2766 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2768 boost::shared_ptr<AutomationControl> c = _route->gain_control();
2770 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2774 gain_track.reset (new AutomationTimeAxisView (_session,
2775 _route, _route->amp(), c, param,
2780 _route->amp()->describe_parameter(param)));
2783 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2786 add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2790 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2792 boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2793 if (!c || ! _route->trim()->active()) {
2797 trim_track.reset (new AutomationTimeAxisView (_session,
2798 _route, _route->trim(), c, param,
2803 _route->trim()->describe_parameter(param)));
2806 _view->foreach_regionview (sigc::mem_fun (*trim_track.get(), &TimeAxisView::add_ghost));
2809 add_automation_child (Evoral::Parameter(TrimAutomation), trim_track, show);
2813 RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
2815 boost::shared_ptr<AutomationControl> c = _route->mute_control();
2817 error << "Route has no mute automation, unable to add automation track view." << endmsg;
2821 mute_track.reset (new AutomationTimeAxisView (_session,
2822 _route, _route, c, param,
2827 _route->describe_parameter(param)));
2830 _view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
2833 add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
2837 void add_region_to_list (RegionView* rv, RegionList* l)
2839 l->push_back (rv->region());
2843 RouteTimeAxisView::combine_regions ()
2845 /* as of may 2011, we do not offer uncombine for MIDI tracks
2848 if (!is_audio_track()) {
2856 RegionList selected_regions;
2857 boost::shared_ptr<Playlist> playlist = track()->playlist();
2859 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2861 if (selected_regions.size() < 2) {
2865 playlist->clear_changes ();
2866 boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2868 _session->add_command (new StatefulDiffCommand (playlist));
2869 /* make the new region be selected */
2871 return _view->find_view (compound_region);
2875 RouteTimeAxisView::uncombine_regions ()
2877 /* as of may 2011, we do not offer uncombine for MIDI tracks
2879 if (!is_audio_track()) {
2887 RegionList selected_regions;
2888 boost::shared_ptr<Playlist> playlist = track()->playlist();
2890 /* have to grab selected regions first because the uncombine is going
2891 * to change that in the middle of the list traverse
2894 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2896 playlist->clear_changes ();
2898 for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2899 playlist->uncombine (*i);
2902 _session->add_command (new StatefulDiffCommand (playlist));
2906 RouteTimeAxisView::state_id() const
2908 return string_compose ("rtav %1", _route->id().to_s());
2913 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2915 TimeAxisView::remove_child (c);
2917 boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2919 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2920 if (i->second == a) {
2921 _automation_tracks.erase (i);