X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Froute_time_axis.cc;h=b0fec293cf7376f772b7a9b4bb94dbf0290665d5;hb=90ea64d1fc9e64347aca9df8c64ff0aeb674410d;hp=16e1d72d53ead52c6debfe3217d32c6357124e41;hpb=9c733915a0bc4b5274fac749b1adc874da79a6ee;p=ardour.git diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 16e1d72d53..b0fec293cf 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -43,30 +43,22 @@ #include #include "ardour/amp.h" -#include "ardour/audioplaylist.h" -#include "ardour/diskstream.h" +#include "ardour/meter.h" #include "ardour/event_type_map.h" -#include "ardour/ladspa_plugin.h" -#include "ardour/location.h" -#include "ardour/panner.h" -#include "ardour/playlist.h" -#include "ardour/playlist.h" #include "ardour/processor.h" #include "ardour/profile.h" #include "ardour/route_group.h" #include "ardour/session.h" -#include "ardour/session_playlist.h" -#include "ardour/debug.h" -#include "ardour/utils.h" +#include "ardour/session_playlists.h" #include "evoral/Parameter.hpp" #include "ardour_ui.h" +#include "ardour_button.h" #include "debug.h" #include "global_signals.h" #include "route_time_axis.h" #include "automation_time_axis.h" #include "canvas_impl.h" -#include "crossfade_view.h" #include "enums.h" #include "gui_thread.h" #include "keyboard.h" @@ -92,41 +84,57 @@ using namespace Gtkmm2ext; using namespace Gtk; using namespace Editing; using namespace std; +using std::list; -Glib::RefPtr RouteTimeAxisView::slider; - -void -RouteTimeAxisView::setup_slider_pix () -{ - if ((slider = ::get_icon ("fader_belt_h")) == 0) { - throw failed_constructor (); - } -} - -RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::shared_ptr rt, Canvas& canvas) +RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas) : AxisView(sess) - , RouteUI(rt, sess) + , RouteUI(sess) , TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas) + , _view (0) , parent_canvas (canvas) + , no_redraw (false) , button_table (3, 3) , route_group_button (_("g")) , playlist_button (_("p")) , automation_button (_("a")) - , gm (sess, slider, true, 115) + , automation_action_menu (0) + , plugins_submenu_item (0) + , route_group_menu (0) + , playlist_action_menu (0) + , mode_menu (0) + , color_mode_menu (0) + , gm (sess, true, 125, 18) + , _ignore_set_layer_display (false) { +} + +void +RouteTimeAxisView::set_route (boost::shared_ptr rt) +{ + RouteUI::set_route (rt); + + int meter_width = 3; + if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) { + meter_width = 6; + } gm.set_controls (_route, _route->shared_peak_meter(), _route->amp()); gm.get_level_meter().set_no_show_all(); - gm.get_level_meter().setup_meters(50); + gm.get_level_meter().setup_meters(50, meter_width); + gm.update_gain_sensitive (); - _has_state = true; - playlist_action_menu = 0; - automation_action_menu = 0; - plugins_submenu_item = 0; - mode_menu = 0; - _view = 0; + string str = gui_property ("height"); + if (!str.empty()) { + set_height (atoi (str)); + } else { + set_height (preset_height (HeightNormal)); + } - if (!_route->is_hidden()) { - _marked_for_display = true; + if (!_route->is_auditioner()) { + if (gui_property ("visible").empty()) { + set_gui_property ("visible", true); + } + } else { + set_gui_property ("visible", false); } mute_changed (0); @@ -137,50 +145,56 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh ignore_toggle = false; - route_group_button.set_name ("TrackGroupButton"); - playlist_button.set_name ("TrackPlaylistButton"); - automation_button.set_name ("TrackAutomationButton"); - - route_group_button.unset_flags (Gtk::CAN_FOCUS); - playlist_button.unset_flags (Gtk::CAN_FOCUS); - automation_button.unset_flags (Gtk::CAN_FOCUS); + route_group_button.set_name ("route button"); + playlist_button.set_name ("route button"); + automation_button.set_name ("route button"); route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false); - playlist_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click)); - automation_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click)); + playlist_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click)); + automation_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click)); if (is_track()) { /* use icon */ - - rec_enable_button->remove (); - + switch (track()->mode()) { case ARDOUR::Normal: case ARDOUR::NonLayered: - rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red")))))); + rec_enable_button->set_image (::get_icon (X_("record_normal_red"))); break; case ARDOUR::Destructive: - rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red")))))); + rec_enable_button->set_image (::get_icon (X_("record_tape_red"))); break; } - rec_enable_button->show_all (); controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); if (is_midi_track()) { ARDOUR_UI::instance()->set_tip(*rec_enable_button, _("Record (Right-click for Step Edit)")); + gm.set_fader_name ("MidiTrackFader"); } else { ARDOUR_UI::instance()->set_tip(*rec_enable_button, _("Record")); + gm.set_fader_name ("AudioTrackFader"); } rec_enable_button->set_sensitive (_session->writable()); + + /* set playlist button tip to the current playlist, and make it update when it changes */ + update_playlist_tip (); + track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context()); + + } else { + gm.set_fader_name ("AudioBusFader"); } - controls_hbox.pack_start(gm.get_level_meter(), false, false); + Gtk::VBox *mtrbox = manage(new Gtk::VBox()); + mtrbox->pack_start(gm.get_level_meter(), false, false, 2); + controls_hbox.pack_start(*mtrbox, false, false, 4); + mtrbox->show(); + _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context()); - _route->input()->changed.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context()); - _route->output()->changed.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context()); + _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context()); + _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context()); controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); @@ -189,13 +203,17 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh } controls_table.attach (route_group_button, 7, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); - controls_table.attach (gm.get_gain_slider(), 0, 5, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 0, 0); + controls_table.attach (gm.get_gain_slider(), 0, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::AttachOptions (0), 3, 0); ARDOUR_UI::instance()->set_tip(*solo_button,_("Solo")); ARDOUR_UI::instance()->set_tip(*mute_button,_("Mute")); ARDOUR_UI::instance()->set_tip(route_group_button, _("Route Group")); - ARDOUR_UI::instance()->set_tip(playlist_button,_("Playlist")); - ARDOUR_UI::instance()->set_tip(automation_button, _("Automation")); + + if (is_midi_track()) { + ARDOUR_UI::instance()->set_tip(automation_button, _("MIDI Controllers and Automation")); + } else { + ARDOUR_UI::instance()->set_tip(automation_button, _("Automation")); + } label_view (); @@ -207,36 +225,38 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh _y_position = -1; - _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context()); - _route->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::route_property_changed, this, _1), gui_context()); + _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context()); + _route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::route_property_changed, this, _1), gui_context()); if (is_track()) { + str = gui_property ("layer-display"); + if (!str.empty()) { + set_layer_display (LayerDisplay (string_2_enum (str, _view->layer_display ()))); + } + track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context()); track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context()); /* pick up the correct freeze state */ map_frozen (); - } + } _editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit)); _editor.HorizontalPositionChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::horizontal_position_changed)); ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler)); PropertyList* plist = new PropertyList(); - - plist->add (ARDOUR::Properties::edit, true); + plist->add (ARDOUR::Properties::mute, true); plist->add (ARDOUR::Properties::solo, true); - + route_group_menu = new RouteGroupMenu (_session, plist); gm.get_gain_slider().signal_scroll_event().connect(sigc::mem_fun(*this, &RouteTimeAxisView::controls_ebox_scroll), false); - gm.get_gain_slider().set_name ("TrackGainFader"); - show_name_entry (); - hide_name_label (); + gm.get_level_meter().signal_scroll_event().connect (sigc::mem_fun (*this, &RouteTimeAxisView::controls_ebox_scroll), false); } RouteTimeAxisView::~RouteTimeAxisView () @@ -264,12 +284,20 @@ RouteTimeAxisView::post_construct () /* map current state of the route */ update_diskstream_display (); + setup_processor_menu_and_curves (); + reset_processor_automation_curves (); +} +/** Set up the processor menu for the current set of processors, and + * display automation curves for any parameters which have data. + */ +void +RouteTimeAxisView::setup_processor_menu_and_curves () +{ _subplugin_menu_map.clear (); subplugin_menu.items().clear (); _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu)); _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves)); - reset_processor_automation_curves (); } gint @@ -284,7 +312,7 @@ RouteTimeAxisView::route_group_click (GdkEventButton *ev) WeakRouteList r; r.push_back (route ()); - + route_group_menu->build (r); route_group_menu->menu()->popup (ev->button, ev->time); @@ -302,15 +330,10 @@ RouteTimeAxisView::label_view () { string x = _route->name(); - if (x != name_entry.get_text()) { - name_entry.set_text (x); - } - if (x != name_label.get_text()) { name_label.set_text (x); } - ARDOUR_UI::instance()->set_tip (name_entry, x); } void @@ -345,35 +368,6 @@ RouteTimeAxisView::automation_click () automation_action_menu->popup (1, gtk_get_current_event_time()); } -int -RouteTimeAxisView::set_state (const XMLNode& node, int version) -{ - TimeAxisView::set_state (node, version); - - XMLNodeList kids = node.children(); - XMLNodeConstIterator iter; - const XMLProperty* prop; - - if (_view && (prop = node.property ("layer-display"))) { - set_layer_display (LayerDisplay (string_2_enum (prop->value(), _view->layer_display ()))); - } - - for (iter = kids.begin(); iter != kids.end(); ++iter) { - if ((*iter)->name() == AutomationTimeAxisView::state_node_name) { - if ((prop = (*iter)->property ("automation-id")) != 0) { - - Evoral::Parameter param = ARDOUR::EventTypeMap::instance().new_parameter(prop->value()); - bool show = ((prop = (*iter)->property ("shown")) != 0) && string_is_affirmative (prop->value()); - create_automation_child(param, show); - } else { - warning << "Automation child has no ID" << endmsg; - } - } - } - - return 0; -} - void RouteTimeAxisView::build_automation_action_menu (bool for_selection) { @@ -392,23 +386,25 @@ RouteTimeAxisView::build_automation_action_menu (bool for_selection) MenuList& items = automation_action_menu->items(); automation_action_menu->set_name ("ArdourContextMenu"); - + items.push_back (MenuElem (_("Show All Automation"), sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_all_automation), for_selection))); - + items.push_back (MenuElem (_("Show Existing Automation"), sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_existing_automation), for_selection))); - + items.push_back (MenuElem (_("Hide All Automation"), sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::hide_all_automation), for_selection))); - items.push_back (SeparatorElem ()); - /* Attach the plugin submenu. It may have previously been used elsewhere, - so it was detached above */ - - items.push_back (MenuElem (_("Plugins"), subplugin_menu)); - items.back().set_sensitive (!subplugin_menu.items().empty() && (!for_selection || _editor.get_selection().tracks.size() == 1));; + so it was detached above + */ + + if (!subplugin_menu.items().empty()) { + items.push_back (SeparatorElem ()); + items.push_back (MenuElem (_("Processor automation"), subplugin_menu)); + items.back().set_sensitive (!for_selection || _editor.get_selection().tracks.size() == 1);; + } } void @@ -468,6 +464,7 @@ RouteTimeAxisView::build_display_menu () ++overlaid; break; case Stacked: + case Expanded: ++stacked; break; } @@ -478,6 +475,8 @@ RouteTimeAxisView::build_display_menu () as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you select the active one, no toggled signal is emitted so nothing happens. */ + + _ignore_set_layer_display = true; layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid"))); RadioMenuItem* i = dynamic_cast (&layers_items.back ()); @@ -485,16 +484,14 @@ RouteTimeAxisView::build_display_menu () i->set_inconsistent (overlaid != 0 && stacked != 0); i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true)); - layers_items.push_back ( - RadioMenuElem (layers_group, _("Stacked"), - sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true)) - ); - + layers_items.push_back (RadioMenuElem (layers_group, _("Stacked"))); i = dynamic_cast (&layers_items.back ()); - i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true)); i->set_active (overlaid == 0 && stacked != 0); i->set_inconsistent (overlaid != 0 && stacked != 0); + i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true)); + _ignore_set_layer_display = false; + items.push_back (MenuElem (_("Layers"), *layers_menu)); if (!Profile->get_sae()) { @@ -502,7 +499,7 @@ RouteTimeAxisView::build_display_menu () Menu* alignment_menu = manage (new Menu); MenuList& alignment_items = alignment_menu->items(); alignment_menu->set_name ("ArdourContextMenu"); - + RadioMenuItem::Group align_group; /* Same verbose hacks as for the layering options above */ @@ -566,12 +563,12 @@ RouteTimeAxisView::build_display_menu () alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)"))); i = dynamic_cast (&alignment_items.back()); - i->set_active (automatic != 0 && existing == 0 && capture == 0); + i->set_active (automatic != 0 && existing == 0 && capture == 0); i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true)); switch (first_track->alignment_choice()) { case Automatic: - switch (first_track->alignment_style()) { + switch (first_track->alignment_style()) { case ExistingMaterial: alignment_items.push_back (MenuElem (_("(Currently: Existing Material)"))); break; @@ -583,12 +580,12 @@ RouteTimeAxisView::build_display_menu () default: break; } - + alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material"))); i = dynamic_cast (&alignment_items.back()); i->set_active (existing != 0 && capture == 0 && automatic == 0); i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true)); - + alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time"))); i = dynamic_cast (&alignment_items.back()); i->set_active (existing == 0 && capture != 0 && automatic == 0); @@ -615,7 +612,7 @@ RouteTimeAxisView::build_display_menu () if (!r || !r->is_track ()) { continue; } - + switch (r->track()->mode()) { case Normal: ++normal; @@ -650,40 +647,36 @@ RouteTimeAxisView::build_display_menu () items.push_back (MenuElem (_("Mode"), *mode_menu)); } - color_mode_menu = build_color_mode_menu(); - if (color_mode_menu) { - items.push_back (MenuElem (_("Color Mode"), *color_mode_menu)); - } items.push_back (SeparatorElem()); build_playlist_menu (); items.push_back (MenuElem (_("Playlist"), *playlist_action_menu)); items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1); + } - route_group_menu->detach (); - - WeakRouteList r; - for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) { - RouteTimeAxisView* rtv = dynamic_cast (*i); - if (rtv) { - r.push_back (rtv->route ()); - } - } - - if (r.empty ()) { - r.push_back (route ()); + route_group_menu->detach (); + + WeakRouteList r; + for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) { + RouteTimeAxisView* rtv = dynamic_cast (*i); + if (rtv) { + r.push_back (rtv->route ()); } - - route_group_menu->build (r); - items.push_back (MenuElem (_("Route Group"), *route_group_menu->menu ())); - - build_automation_action_menu (true); - items.push_back (MenuElem (_("Automation"), *automation_action_menu)); - - items.push_back (SeparatorElem()); + } + + if (r.empty ()) { + r.push_back (route ()); } + route_group_menu->build (r); + items.push_back (MenuElem (_("Group"), *route_group_menu->menu ())); + + build_automation_action_menu (true); + items.push_back (MenuElem (_("Automation"), *automation_action_menu)); + + items.push_back (SeparatorElem()); + int active = 0; int inactive = 0; TrackSelection const & s = _editor.get_selection().tracks; @@ -731,7 +724,7 @@ RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection) bool needs_bounce; if (!track()->can_use_mode (mode, needs_bounce)) { - + if (!needs_bounce) { /* cannot be done */ return; @@ -740,33 +733,31 @@ RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection) return; } } - + track()->set_mode (mode); - + rec_enable_button->remove (); - + switch (mode) { case ARDOUR::NonLayered: case ARDOUR::Normal: - rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red")))))); + rec_enable_button->set_image (::get_icon (X_("record_normal_red"))); + rec_enable_button->set_text (string()); break; case ARDOUR::Destructive: - rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red")))))); + rec_enable_button->set_image (::get_icon (X_("record_tape_red"))); + rec_enable_button->set_text (string()); break; } - + rec_enable_button->show_all (); } } void -RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end) +RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer) { - double x1; - double x2; - double y2; - - TimeAxisView::show_timestretch (start, end); + TimeAxisView::show_timestretch (start, end, layers, layer); hide_timestretch (); @@ -805,14 +796,13 @@ RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end) timestretch_rect->show (); timestretch_rect->raise_to_top (); - x1 = start / _editor.get_current_zoom(); - x2 = (end - 1) / _editor.get_current_zoom(); - y2 = current_height() - 2; + double const x1 = start / _editor.get_current_zoom(); + double const x2 = (end - 1) / _editor.get_current_zoom(); timestretch_rect->property_x1() = x1; - timestretch_rect->property_y1() = 1.0; + timestretch_rect->property_y1() = current_height() * (layers - layer - 1) / layers; timestretch_rect->property_x2() = x2; - timestretch_rect->property_y2() = y2; + timestretch_rect->property_y2() = current_height() * (layers - layer) / layers; } void @@ -848,26 +838,23 @@ RouteTimeAxisView::show_selection (TimeSelection& ts) void RouteTimeAxisView::set_height (uint32_t h) { - int gmlen = h - 5; + int gmlen = h - 9; bool height_changed = (height == 0) || (h != height); - gm.get_level_meter().setup_meters (gmlen); - TimeAxisView::set_height (h); + int meter_width = 3; + if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) { + meter_width = 6; + } + gm.get_level_meter().setup_meters (gmlen, meter_width); - ensure_xml_node (); + TimeAxisView::set_height (h); if (_view) { _view->set_height ((double) current_height()); } - char buf[32]; - snprintf (buf, sizeof (buf), "%u", height); - xml_node->add_property ("height", buf); - if (height >= preset_height (HeightNormal)) { - - _controls_padding_table.set_row_spacings (2); - + reset_meter(); gm.get_gain_slider().show(); @@ -887,9 +874,7 @@ RouteTimeAxisView::set_height (uint32_t h) playlist_button.show(); } - } else if (height >= preset_height (HeightSmaller)) { - - _controls_padding_table.set_row_spacings (2); + } else { reset_meter(); @@ -910,25 +895,19 @@ RouteTimeAxisView::set_height (uint32_t h) playlist_button.hide (); } - } else { - - _controls_padding_table.set_row_spacings (0); - } if (height_changed && !no_redraw) { /* only emit the signal if the height really changed */ - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + request_redraw (); } } void -RouteTimeAxisView::set_color (Gdk::Color const & c) +RouteTimeAxisView::route_color_changed () { - RouteUI::set_color (c); - if (_view) { - _view->apply_color (_color, StreamView::RegionColor); + _view->apply_color (color(), StreamView::RegionColor); } } @@ -1034,7 +1013,7 @@ RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector tmp = tmp.substr(idx + group_string.length()); // and find the largest current number - int x = atoi(tmp.c_str()); + int x = atoi(tmp); if (x > maxnumber) { maxnumber = x; } @@ -1068,7 +1047,7 @@ RouteTimeAxisView::use_copy_playlist (bool prompt, vectorname(); - if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::edit.property_id)) { + if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::select.property_id)) { name = resolve_new_group_playlist_name(name, playlists_before_op); } @@ -1123,7 +1102,7 @@ RouteTimeAxisView::use_new_playlist (bool prompt, vectorname(); - if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::edit.property_id)) { + if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::select.property_id)) { name = resolve_new_group_playlist_name(name,playlists_before_op); } @@ -1311,30 +1290,29 @@ RouteTimeAxisView::playlist () const void RouteTimeAxisView::name_entry_changed () { - string x; + TimeAxisView::name_entry_changed (); - x = name_entry.get_text (); + string x = name_entry->get_text (); if (x == _route->name()) { return; } - strip_whitespace_edges(x); + strip_whitespace_edges (x); if (x.length() == 0) { - name_entry.set_text (_route->name()); + name_entry->set_text (_route->name()); return; } - if (!_session->route_name_unique (x)) { - ARDOUR_UI::instance()->popup_error (_("A track already exists with that name")); - name_entry.set_text (_route->name()); - } else if (_session->route_name_internal (x)) { + if (_session->route_name_internal (x)) { ARDOUR_UI::instance()->popup_error (string_compose (_("You cannot create a track with that name as it is reserved for %1"), - PROGRAM_NAME)); - name_entry.set_text (_route->name()); - } else { + PROGRAM_NAME)); + name_entry->grab_focus (); + } else if (RouteUI::verify_new_route_name (x)) { _route->set_name (x); + } else { + name_entry->grab_focus (); } } @@ -1389,14 +1367,23 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) playlist->clear_owned_changes (); switch (op) { + case Delete: + if (playlist->cut (time) != 0) { + vector cmds; + playlist->rdiff (cmds); + _session->add_commands (cmds); + + _session->add_command (new StatefulDiffCommand (playlist)); + } + break; + case Cut: if ((what_we_got = playlist->cut (time)) != 0) { _editor.get_cut_buffer().add (what_we_got); - vector cmds; playlist->rdiff (cmds); _session->add_commands (cmds); - + _session->add_command (new StatefulDiffCommand (playlist)); } break; @@ -1473,40 +1460,32 @@ RouteTimeAxisView::build_playlist_menu () playlist_action_menu->set_name ("ArdourContextMenu"); playlist_items.clear(); - vector > playlists, playlists_tr; - boost::shared_ptr tr = track(); RadioMenuItem::Group playlist_group; + boost::shared_ptr tr = track (); - _session->playlists->get (playlists); - - /* find the playlists for this diskstream */ - for (vector >::iterator i = playlists.begin(); i != playlists.end(); ++i) { - if (((*i)->get_orig_diskstream_id() == tr->diskstream_id()) || (tr->playlist()->id() == (*i)->id())) { - playlists_tr.push_back(*i); - } - } + vector > playlists_tr = _session->playlists->playlists_for_track (tr); /* sort the playlists */ PlaylistSorter cmp; sort (playlists_tr.begin(), playlists_tr.end(), cmp); - + /* add the playlists to the menu */ for (vector >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) { playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name())); RadioMenuItem *item = static_cast(&playlist_items.back()); item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr (*i))); - + if (tr->playlist()->id() == (*i)->id()) { item->set_active(); - + } } - + playlist_items.push_back (SeparatorElem()); playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist))); playlist_items.push_back (SeparatorElem()); - if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::edit.property_id)) { + if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::select.property_id)) { playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this))); playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this))); @@ -1540,56 +1519,89 @@ RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr return; } - boost::shared_ptr apl = boost::dynamic_pointer_cast (pl); + if (track()->playlist() == pl) { + // exit when use_playlist is called by the creation of the playlist menu + // or the playlist choice is unchanged + return; + } - if (apl) { - if (track()->playlist() == apl) { - // exit when use_playlist is called by the creation of the playlist menu - // or the playlist choice is unchanged + track()->use_playlist (pl); + + RouteGroup* rg = route_group(); + + if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) { + std::string group_string = "." + rg->name() + "."; + + std::string take_name = pl->name(); + std::string::size_type idx = take_name.find(group_string); + + if (idx == std::string::npos) return; - } - track()->use_playlist (apl); - - RouteGroup* rg = route_group(); - - if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::edit.property_id)) { - std::string group_string = "." + rg->name() + "."; - - std::string take_name = apl->name(); - std::string::size_type idx = take_name.find(group_string); - - if (idx == std::string::npos) - return; - - take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name - - boost::shared_ptr rl (rg->route_list()); - - for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) { - if ( (*i) == this->route()) { - continue; - } - - std::string playlist_name = (*i)->name()+group_string+take_name; + + take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name + + boost::shared_ptr rl (rg->route_list()); + + for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) { + if ((*i) == this->route()) { + continue; + } - boost::shared_ptr track = boost::dynamic_pointer_cast(*i); - if (!track) { - continue; - } + std::string playlist_name = (*i)->name()+group_string+take_name; + + boost::shared_ptr track = boost::dynamic_pointer_cast(*i); + if (!track) { + continue; + } - boost::shared_ptr ipl = session()->playlists->by_name(playlist_name); - if (!ipl) { - // No playlist for this track for this take yet, make it - track->use_new_playlist(); - track->playlist()->set_name(playlist_name); - } else { - track->use_playlist(ipl); - } + if (track->freeze_state() == Track::Frozen) { + /* Don't change playlists of frozen tracks */ + continue; } + + boost::shared_ptr ipl = session()->playlists->by_name(playlist_name); + if (!ipl) { + // No playlist for this track for this take yet, make it + track->use_new_playlist(); + track->playlist()->set_name(playlist_name); + } else { + track->use_playlist(ipl); + } + } + } +} + +void +RouteTimeAxisView::update_playlist_tip () +{ + RouteGroup* rg = route_group (); + if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) { + string group_string = "." + rg->name() + "."; + + string take_name = track()->playlist()->name(); + string::size_type idx = take_name.find(group_string); + + if (idx != string::npos) { + /* find the bit containing the take number / name */ + take_name = take_name.substr (idx + group_string.length()); + + /* set the playlist button tooltip to the take name */ + ARDOUR_UI::instance()->set_tip ( + playlist_button, + string_compose(_("Take: %1.%2"), + Glib::Markup::escape_text(rg->name()), + Glib::Markup::escape_text(take_name)) + ); + + return; } } + + /* set the playlist button tooltip to the playlist name */ + ARDOUR_UI::instance()->set_tip (playlist_button, _("Playlist") + std::string(": ") + Glib::Markup::escape_text(track()->playlist()->name())); } + void RouteTimeAxisView::show_playlist_selector () { @@ -1640,22 +1652,24 @@ RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param) { boost::shared_ptr track = automation_child (param); Gtk::CheckMenuItem* menu = automation_child_menu_item (param); - + if (!track) { /* it doesn't exist yet, so we don't care about the button state: just add it */ create_automation_child (param, true); } else { assert (menu); bool yn = menu->get_active(); - if (track->set_visibility (menu->get_active()) && yn) { - + bool changed = false; + + if ((changed = track->set_marked_for_display (menu->get_active())) && yn) { + /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden() will have done that for us. */ - - if (!no_redraw) { - _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */ - } + + if (changed && !no_redraw) { + request_redraw (); + } } } } @@ -1671,9 +1685,6 @@ RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param) Gtk::CheckMenuItem* menu = automation_child_menu_item (param); - // if Evoral::Parameter::operator< doesn't obey strict weak ordering, we may crash here.... - track->get_state_node()->add_property (X_("shown"), X_("no")); - if (menu && !_hidden) { ignore_toggle = true; menu->set_active (false); @@ -1681,7 +1692,7 @@ RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param) } if (_route && !no_redraw) { - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + request_redraw (); } } @@ -1693,42 +1704,40 @@ RouteTimeAxisView::show_all_automation (bool apply_to_selection) _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false)); } else { no_redraw = true; - + /* Show our automation */ - + for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { i->second->set_marked_for_display (true); - i->second->canvas_display()->show(); - i->second->get_state_node()->add_property ("shown", X_("yes")); - + Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first); - + if (menu) { menu->set_active(true); } } - - + + /* Show processor automation */ - + for (list::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) { for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { if ((*ii)->view == 0) { add_processor_automation_curve ((*i)->processor, (*ii)->what); } - + (*ii)->menu_item->set_active (true); } } - + no_redraw = false; - + /* Redraw */ - - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + + request_redraw (); } } - + void RouteTimeAxisView::show_existing_automation (bool apply_to_selection) { @@ -1736,25 +1745,22 @@ RouteTimeAxisView::show_existing_automation (bool apply_to_selection) _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false)); } else { no_redraw = true; - + /* Show our automation */ - + for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { if (i->second->has_automation()) { i->second->set_marked_for_display (true); - i->second->canvas_display()->show(); - i->second->get_state_node()->add_property ("shown", X_("yes")); - + Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first); if (menu) { menu->set_active(true); } } } - - + /* Show processor automation */ - + for (list::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) { for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) { @@ -1762,10 +1768,10 @@ RouteTimeAxisView::show_existing_automation (bool apply_to_selection) } } } - + no_redraw = false; - - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + + request_redraw (); } } @@ -1778,29 +1784,27 @@ RouteTimeAxisView::hide_all_automation (bool apply_to_selection) no_redraw = true; /* Hide our automation */ - + for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { i->second->set_marked_for_display (false); - i->second->hide (); - i->second->get_state_node()->add_property ("shown", X_("no")); - + Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first); - + if (menu) { menu->set_active (false); } } - + /* Hide processor automation */ - + for (list::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) { for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { (*ii)->menu_item->set_active (false); } } - + no_redraw = false; - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + request_redraw (); } } @@ -1811,7 +1815,7 @@ RouteTimeAxisView::region_view_added (RegionView* rv) /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */ for (Children::iterator i = children.begin(); i != children.end(); ++i) { boost::shared_ptr atv; - + if ((atv = boost::dynamic_pointer_cast (*i)) != 0) { atv->add_ghost(rv); } @@ -1861,25 +1865,7 @@ RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr return 0; } -static string -legalize_for_xml_node (string str) -{ - string::size_type pos; - string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_=:"; - string legal; - - legal = str; - pos = 0; - - while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) { - legal.replace (pos, 1, "_"); - pos += 1; - } - - return legal; -} - - +/** Add an AutomationTimeAxisView to display automation for a processor's parameter */ void RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr processor, Evoral::Parameter what) { @@ -1900,50 +1886,32 @@ RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr return; } - name = processor->describe_parameter (what); - - /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */ - - /* FIXME: ew */ - - char state_name[256]; - snprintf (state_name, sizeof (state_name), "%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id()); - boost::shared_ptr control - = boost::dynamic_pointer_cast(processor->control(what, true)); - + = boost::dynamic_pointer_cast(processor->control(what, true)); + pan->view = boost::shared_ptr( new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (), - _editor, *this, false, parent_canvas, name, state_name)); + _editor, *this, false, parent_canvas, + processor->describe_parameter (what), processor->name())); pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor)); - if (!pan->view->marked_for_display()) { - pan->view->hide (); - } else { - pan->menu_item->set_active (true); - } - - add_child (pan->view); + add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ()); if (_view) { _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost)); } - - processor->mark_automation_visible (what, true); } void -RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr i) +RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr) { if (!_hidden) { pan->menu_item->set_active (false); } - i->mark_automation_visible (pan->what, false); - if (!no_redraw) { - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + request_redraw (); } } @@ -1951,21 +1919,25 @@ void RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr p) { boost::shared_ptr processor (p.lock ()); - if (!processor) { + + if (!processor || boost::dynamic_pointer_cast (processor)) { + /* The Amp processor is a special case and is dealt with separately */ return; } - set s; - boost::shared_ptr al; + set existing; - processor->what_has_visible_data (s); + processor->what_has_data (existing); - for (set::iterator i = s.begin(); i != s.end(); ++i) { + for (set::iterator i = existing.begin(); i != existing.end(); ++i) { + + Evoral::Parameter param (*i); + boost::shared_ptr al; - if ((al = find_processor_automation_curve (processor, *i)) != 0) { + if ((al = find_processor_automation_curve (processor, param)) != 0) { al->queue_reset (); } else { - add_processor_automation_curve (processor, (*i)); + add_processor_automation_curve (processor, param); } } } @@ -1975,29 +1947,23 @@ RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ { using namespace Menu_Helpers; - XMLProperty* prop; - XMLNode* node; - add_child (track); track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param)); - bool hideit = (!show); + _automation_tracks[param] = track; - if ((node = track->get_state_node()) != 0) { - if ((prop = node->property ("shown")) != 0) { - if (string_is_affirmative (prop->value())) { - hideit = false; - } - } + /* existing state overrides "show" argument */ + string s = track->gui_property ("visible"); + if (!s.empty()) { + show = string_is_affirmative (s); } - _automation_tracks[param] = track; - - track->set_visibility (!hideit); + /* this might or might not change the visibility status, so don't rely on it */ + track->set_marked_for_display (show); - if (!no_redraw) { - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + if (show && !no_redraw) { + request_redraw (); } if (!EventTypeMap::instance().is_midi_parameter(param)) { @@ -2020,14 +1986,20 @@ RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr p return; } + /* we use this override to veto the Amp processor from the plugin menu, + as its automation lane can be accessed using the special "Fader" menu + option + */ + + if (boost::dynamic_pointer_cast (processor) != 0) { + return; + } + using namespace Menu_Helpers; ProcessorAutomationInfo *rai; list::iterator x; const std::set& automatable = processor->what_can_be_automated (); - std::set has_visible_automation; - - processor->what_has_visible_data(has_visible_automation); if (automatable.empty()) { return; @@ -2060,6 +2032,9 @@ RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr p items.clear (); + std::set has_visible_automation; + AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation); + for (std::set::const_iterator i = automatable.begin(); i != automatable.end(); ++i) { ProcessorAutomationNode* pan; @@ -2069,7 +2044,7 @@ RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr p items.push_back (CheckMenuElem (name)); mitem = dynamic_cast (&items.back()); - + _subplugin_menu_map[*i] = mitem; if (has_visible_automation.find((*i)) != has_visible_automation.end()) { @@ -2115,25 +2090,12 @@ RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAuto redraw = true; } - if (pan->view && showit != pan->view->marked_for_display()) { - - if (showit) { - pan->view->set_marked_for_display (true); - pan->view->canvas_display()->show(); - pan->view->canvas_background()->show(); - } else { - rai->processor->mark_automation_visible (pan->what, true); - pan->view->set_marked_for_display (false); - pan->view->hide (); - } - + if (pan->view && pan->view->set_marked_for_display (showit)) { redraw = true; - } - + if (redraw && !no_redraw) { - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ - + request_redraw (); } } @@ -2151,11 +2113,7 @@ RouteTimeAxisView::processors_changed (RouteProcessorChange c) (*i)->valid = false; } - _subplugin_menu_map.clear (); - subplugin_menu.items().clear (); - - _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu)); - _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves)); + setup_processor_menu_and_curves (); bool deleted_processor_automation = false; @@ -2178,7 +2136,7 @@ RouteTimeAxisView::processors_changed (RouteProcessorChange c) } if (deleted_processor_automation && !no_redraw) { - _route->gui_changed ("track_height", this); + request_redraw (); } } @@ -2204,26 +2162,36 @@ RouteTimeAxisView::reset_processor_automation_curves () } } +bool +RouteTimeAxisView::can_edit_name () const +{ + /* we do not allow track name changes if it is record enabled + */ + return !_route->record_enabled(); +} + void RouteTimeAxisView::update_rec_display () { RouteUI::update_rec_display (); - name_entry.set_sensitive (!_route->record_enabled()); } void RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection) { + if (_ignore_set_layer_display) { + return; + } + if (apply_to_selection) { _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false)); } else { - + if (_view) { _view->set_layer_display (d); } - - ensure_xml_node (); - xml_node->add_property (N_("layer-display"), enum_2_string (d)); + + set_gui_property (X_("layer-display"), enum_2_string (d)); } } @@ -2274,7 +2242,11 @@ void RouteTimeAxisView::reset_meter () { if (Config->get_show_track_meters()) { - gm.get_level_meter().setup_meters (height-5); + int meter_width = 3; + if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) { + meter_width = 6; + } + gm.get_level_meter().setup_meters (height - 9, meter_width); } else { hide_meter (); } @@ -2291,12 +2263,18 @@ RouteTimeAxisView::meter_changed () { ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed) reset_meter(); + if (_route && !no_redraw) { + request_redraw (); + } } void RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/) { reset_meter (); + if (_route && !no_redraw) { + request_redraw (); + } } void @@ -2353,7 +2331,7 @@ RouteTimeAxisView::set_underlay_state() } void -RouteTimeAxisView::add_underlay (StreamView* v, bool update_xml) +RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/) { if (!v) { return; @@ -2372,9 +2350,9 @@ RouteTimeAxisView::add_underlay (StreamView* v, bool update_xml) v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost)); +#ifdef GUI_OBJECT_STATE_FIX_REQUIRED if (update_xml) { if (!underlay_xml_node) { - ensure_xml_node(); underlay_xml_node = xml_node->add_child("Underlays"); } @@ -2382,6 +2360,7 @@ RouteTimeAxisView::add_underlay (StreamView* v, bool update_xml) XMLProperty* prop = node->add_property("id"); prop->set_value(v->trackview().route()->id().to_s()); } +#endif } } @@ -2417,25 +2396,27 @@ RouteTimeAxisView::remove_underlay (StreamView* v) void RouteTimeAxisView::set_button_names () { - rec_enable_button_label.set_text (_("r")); - - if (_route && _route->solo_safe()) { - solo_button_label.set_text (X_("!")); - } else { - if (Config->get_solo_control_is_listen_control()) { - switch (Config->get_listen_position()) { - case AfterFaderListen: - solo_button_label.set_text (_("A")); - break; - case PreFaderListen: - solo_button_label.set_text (_("P")); - break; - } - } else { - solo_button_label.set_text (_("s")); - } - } - mute_button_label.set_text (_("m")); + if (_route && _route->solo_safe()) { + solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive)); + } else { + solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive)); + } + if (Config->get_solo_control_is_listen_control()) { + switch (Config->get_listen_position()) { + case AfterFaderListen: + solo_button->set_text (_("A")); + ARDOUR_UI::instance()->set_tip (*solo_button, _("After-fade listen (AFL)")); + break; + case PreFaderListen: + solo_button->set_text (_("P")); + ARDOUR_UI::instance()->set_tip (*solo_button, _("Pre-fade listen (PFL)")); + break; + } + } else { + solo_button->set_text (_("s")); + ARDOUR_UI::instance()->set_tip (*solo_button, _("Solo")); + } + mute_button->set_text (_("m")); } Gtk::CheckMenuItem* @@ -2445,7 +2426,7 @@ RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param) if (i != _main_automation_menu_map.end()) { return i->second; } - + i = _subplugin_menu_map.find (param); if (i != _subplugin_menu_map.end()) { return i->second; @@ -2474,64 +2455,98 @@ RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, if (_view) { _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost)); } - + add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show); } static -void add_region_to_list (RegionView* rv, Playlist::RegionList* l, uint32_t* max_level) +void add_region_to_list (RegionView* rv, RegionList* l) { l->push_back (rv->region()); - *max_level = max (*max_level, rv->region()->max_source_level()); } -void +RegionView* RouteTimeAxisView::combine_regions () { - assert (is_track()); + /* as of may 2011, we do not offer uncombine for MIDI tracks + */ + + if (!is_audio_track()) { + return 0; + } if (!_view) { - return; + return 0; } - Playlist::RegionList selected_regions; + RegionList selected_regions; boost::shared_ptr playlist = track()->playlist(); - uint32_t max_level = 0; - _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions, &max_level)); - - string name = string_compose (_("%1 compound-%2 (%3)"), playlist->name(), playlist->combine_ops()+1, max_level+1); + _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions)); + + if (selected_regions.size() < 2) { + return 0; + } playlist->clear_changes (); - playlist->combine (selected_regions, name); + boost::shared_ptr compound_region = playlist->combine (selected_regions); + _session->add_command (new StatefulDiffCommand (playlist)); + /* make the new region be selected */ + + return _view->find_view (compound_region); } void RouteTimeAxisView::uncombine_regions () { - assert (is_track()); + /* as of may 2011, we do not offer uncombine for MIDI tracks + */ + if (!is_audio_track()) { + return; + } if (!_view) { return; } - Playlist::RegionList selected_regions; + RegionList selected_regions; boost::shared_ptr playlist = track()->playlist(); - uint32_t max_level = 0; /* have to grab selected regions first because the uncombine is going * to change that in the middle of the list traverse */ - _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions, &max_level)); + _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions)); playlist->clear_changes (); - for (Playlist::RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) { + for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) { playlist->uncombine (*i); } _session->add_command (new StatefulDiffCommand (playlist)); } +string +RouteTimeAxisView::state_id() const +{ + return string_compose ("rtav %1", _route->id().to_s()); +} + + +void +RouteTimeAxisView::remove_child (boost::shared_ptr c) +{ + TimeAxisView::remove_child (c); + + boost::shared_ptr a = boost::dynamic_pointer_cast (c); + if (a) { + for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { + if (i->second == a) { + _automation_tracks.erase (i); + return; + } + } + } +}