X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=58f66fcd8a69870fe6107edd4984ce8655537dfd;hb=86244875a40206694c142af8fe1128f28293c467;hp=ca1a35cb4b046c5275d563bd0738475f354eaad5;hpb=2c16f7aa7f7b78e84399d9ed0d8cf99a84d09eb6;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index ca1a35cb4b..58f66fcd8a 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -114,6 +114,8 @@ #include "editor_regions.h" #include "editor_locations.h" #include "editor_snapshots.h" +#include "editor_summary.h" +#include "region_layering_order_editor.h" #include "i18n.h" @@ -145,10 +147,20 @@ static const gchar *_snap_type_strings[] = { N_("Seconds"), N_("Minutes"), N_("Beats/32"), + N_("Beats/28"), + N_("Beats/24"), + N_("Beats/20"), N_("Beats/16"), + N_("Beats/14"), + N_("Beats/12"), + N_("Beats/10"), N_("Beats/8"), + N_("Beats/7"), + N_("Beats/6"), + N_("Beats/5"), N_("Beats/4"), N_("Beats/3"), + N_("Beats/2"), N_("Beats"), N_("Bars"), N_("Marks"), @@ -191,6 +203,7 @@ static const gchar *_rb_opt_strings[] = { N_("Unpitched percussion with stable notes"), N_("Crisp monophonic instrumental"), N_("Unpitched solo percussion"), + N_("Resample without preserving pitch"), 0 }; #endif @@ -200,7 +213,12 @@ static const gchar *_rb_opt_strings[] = { Gdk::Cursor* Editor::cross_hair_cursor = 0; Gdk::Cursor* Editor::selector_cursor = 0; Gdk::Cursor* Editor::trimmer_cursor = 0; +Gdk::Cursor* Editor::left_side_trim_cursor = 0; +Gdk::Cursor* Editor::right_side_trim_cursor = 0; +Gdk::Cursor* Editor::fade_in_cursor = 0; +Gdk::Cursor* Editor::fade_out_cursor = 0; Gdk::Cursor* Editor::grabber_cursor = 0; +Gdk::Cursor* Editor::grabber_note_cursor = 0; Gdk::Cursor* Editor::grabber_edit_point_cursor = 0; Gdk::Cursor* Editor::zoom_cursor = 0; Gdk::Cursor* Editor::time_fx_cursor = 0; @@ -213,6 +231,7 @@ Gdk::Cursor* Editor::midi_erase_cursor = 0; Gdk::Cursor* Editor::wait_cursor = 0; Gdk::Cursor* Editor::timebar_cursor = 0; Gdk::Cursor* Editor::transparent_cursor = 0; +Gdk::Cursor* Editor::up_down_cursor = 0; void show_me_the_size (Requisition* r, const char* what) @@ -220,6 +239,27 @@ show_me_the_size (Requisition* r, const char* what) cerr << "size of " << what << " = " << r->width << " x " << r->height << endl; } +#ifdef GTKOSX +static void +pane_size_watcher (Paned* pane) +{ + /* if the handle of a pane vanishes into (at least) the tabs of a notebook, + it is no longer accessible. so stop that. this doesn't happen on X11, + just the quartz backend. + + ugh. + */ + + int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25; + + gint pos = pane->get_position (); + + if (pos > max_width_of_lhs) { + pane->set_position (max_width_of_lhs); + } +} +#endif + Editor::Editor () : _join_object_range_state (JOIN_OBJECT_RANGE_NONE) @@ -241,7 +281,6 @@ Editor::Editor () */ , vertical_adjustment (0.0, 0.0, 10.0, 400.0) - , horizontal_adjustment (0.0, 0.0, 20.0, 1200.0) /* tool bar related */ @@ -263,7 +302,8 @@ Editor::Editor () , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true) , meters_running(false) , _pending_locate_request (false) - + , _pending_initial_locate (false) + , _last_cut_copy_source_track (0) { constructed = false; @@ -293,6 +333,7 @@ Editor::Editor () edit_point_strings = I18N (_edit_point_strings); #ifdef USE_RUBBERBAND rb_opt_strings = I18N (_rb_opt_strings); + rb_current_opt = 4; #endif snap_threshold = 5.0; @@ -303,29 +344,27 @@ Editor::Editor () last_autoscroll_y = 0; autoscroll_active = false; autoscroll_timeout_tag = -1; - interthread_progress_window = 0; logo_item = 0; analysis_window = 0; current_interthread_info = 0; _show_measures = true; - _show_waveforms_recording = true; show_gain_after_trim = false; verbose_cursor_on = true; last_item_entered = 0; - last_item_entered_n = 0; have_pending_keyboard_selection = false; _follow_playhead = true; + _stationary_playhead = false; _xfade_visibility = true; editor_ruler_menu = 0; no_ruler_shown_update = false; marker_menu = 0; - start_end_marker_menu = 0; + session_range_marker_menu = 0; range_marker_menu = 0; marker_menu_item = 0; - tm_marker_menu = 0; + tempo_or_meter_marker_menu = 0; transport_marker_menu = 0; new_transport_marker_menu = 0; editor_mixer_strip_width = Wide; @@ -339,7 +378,6 @@ Editor::Editor () entered_regionview = 0; entered_marker = 0; clear_entered_track = false; - _new_regionviews_show_envelope = false; current_timefx = 0; playhead_cursor = 0; button_release_can_deselect = true; @@ -347,11 +385,8 @@ Editor::Editor () _dragging_edit_point = false; select_new_marker = false; rhythm_ferret = 0; + layering_order_editor = 0; _bundle_manager = 0; - for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) { - _global_port_matrix[*i] = 0; - } - allow_vertical_scroll = false; no_save_visual = false; resize_idle_id = -1; @@ -371,9 +406,11 @@ Editor::Editor () frames_per_unit = 2048; /* too early to use reset_zoom () */ + _scroll_callbacks = 0; + zoom_focus = ZoomFocusLeft; set_zoom_focus (ZoomFocusLeft); - zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed)); + zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed)); bbt_label.set_name ("EditorTimeButton"); bbt_label.set_size_request (-1, (int)timebar_height); @@ -448,7 +485,6 @@ Editor::Editor () selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed)); edit_controls_vbox.set_spacing (0); - horizontal_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::scroll_canvas_horizontally), false); vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true); track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler)); @@ -458,8 +494,6 @@ Editor::Editor () h->pack_start (edit_controls_vbox); controls_layout.add (*h); - ARDOUR_UI::instance()->tooltips().set_tip (*_group_tabs, _("Groups: context-click for possible operations")); - controls_layout.set_name ("EditControlsBase"); controls_layout.add_events (Gdk::SCROLL_MASK); controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false); @@ -503,7 +537,6 @@ Editor::Editor () edit_packer.set_border_width (0); edit_packer.set_name ("EditorWindow"); - edit_packer.attach (zoom_vbox, 0, 1, 0, 2, SHRINK, FILL, 0, 0); /* labels for the rulers */ edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0); /* labels for the marker "tracks" */ @@ -529,7 +562,7 @@ Editor::Editor () nlabel = manage (new Label (_("Regions"))); nlabel->set_angle (-90); the_notebook.append_page (_regions->widget (), *nlabel); - nlabel = manage (new Label (_("Tracks/Busses"))); + nlabel = manage (new Label (_("Tracks & Busses"))); nlabel->set_angle (-90); the_notebook.append_page (_routes->widget (), *nlabel); nlabel = manage (new Label (_("Snapshots"))); @@ -549,27 +582,32 @@ Editor::Editor () the_notebook.show_all (); post_maximal_editor_width = 0; - post_maximal_pane_position = 0; + post_maximal_horizontal_pane_position = 0; + post_maximal_editor_height = 0; + post_maximal_vertical_pane_position = 0; - VPaned *editor_summary_pane = manage(new VPaned()); - editor_summary_pane->pack1(edit_packer); + editor_summary_pane.pack1(edit_packer); Button* summary_arrows_left_left = manage (new Button); summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE))); - summary_arrows_left_left->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left)); + summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press))); + summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release)); Button* summary_arrows_left_right = manage (new Button); summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE))); - summary_arrows_left_right->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right)); + summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press))); + summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release)); VBox* summary_arrows_left = manage (new VBox); summary_arrows_left->pack_start (*summary_arrows_left_left); summary_arrows_left->pack_start (*summary_arrows_left_right); Button* summary_arrows_right_left = manage (new Button); summary_arrows_right_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE))); - summary_arrows_right_left->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left)); + summary_arrows_right_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press))); + summary_arrows_right_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release)); Button* summary_arrows_right_right = manage (new Button); summary_arrows_right_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE))); - summary_arrows_right_right->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right)); + summary_arrows_right_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press))); + summary_arrows_right_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release)); VBox* summary_arrows_right = manage (new VBox); summary_arrows_right->pack_start (*summary_arrows_right_left); summary_arrows_right->pack_start (*summary_arrows_right_right); @@ -583,13 +621,20 @@ Editor::Editor () _summary_hbox.pack_start (*summary_frame, true, true); _summary_hbox.pack_start (*summary_arrows_right, false, false); - editor_summary_pane->pack2 (_summary_hbox); + editor_summary_pane.pack2 (_summary_hbox); - edit_pane.pack1 (*editor_summary_pane, true, true); + edit_pane.pack1 (editor_summary_pane, true, true); edit_pane.pack2 (the_notebook, false, true); - edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast (&edit_pane))); + editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast (&editor_summary_pane))); + + /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */ + edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast (&edit_pane))); +#ifdef GTKOSX + Glib::PropertyProxy proxy = edit_pane.property_position(); + proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast (&edit_pane))); +#endif top_hbox.pack_start (toolbar_frame, false, true); HBox *hbox = manage (new HBox); @@ -622,22 +667,16 @@ Editor::Editor () set_mouse_mode (MouseObject, true); set_edit_point_preference (EditAtMouse, true); - XMLNode* node = ARDOUR_UI::instance()->editor_settings(); - set_state (*node, Stateful::loading_state_version); - _playlist_selector = new PlaylistSelector(); _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast (_playlist_selector))); - RegionView::RegionViewGoingAway.connect (*this, ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context()); + RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context()); /* nudge stuff */ nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right"))))); nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left"))))); - ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards")); - ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards")); - nudge_forward_button.set_name ("TransportButton"); nudge_backward_button.set_name ("TransportButton"); @@ -668,7 +707,7 @@ Editor::Editor () WindowTitle title(Glib::get_application_name()); title += _("Editor"); set_title (title.get_string()); - set_wmclass (X_("ardour_editor"), "Ardour"); + set_wmclass (X_("ardour_editor"), PROGRAM_NAME); add (vpacker); add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); @@ -678,19 +717,19 @@ Editor::Editor () /* allow external control surfaces/protocols to do various things */ - ControlProtocol::ZoomToSession.connect (*this, boost::bind (&Editor::temporal_zoom_session, this), gui_context()); - ControlProtocol::ZoomIn.connect (*this, boost::bind (&Editor::temporal_zoom_step, this, false), gui_context()); - ControlProtocol::ZoomOut.connect (*this, boost::bind (&Editor::temporal_zoom_step, this, true), gui_context()); - ControlProtocol::ScrollTimeline.connect (*this, ui_bind (&Editor::control_scroll, this, _1), gui_context()); - BasicUI::AccessAction.connect (*this, ui_bind (&Editor::access_action, this, _1, _2), gui_context()); + ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context()); + ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context()); + ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context()); + ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context()); + BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context()); /* problematic: has to return a value and thus cannot be x-thread */ Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1)); - Config->ParameterChanged.connect (*this, ui_bind (&Editor::parameter_changed, this, _1), gui_context()); + Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context()); - TimeAxisView::CatchDeletion.connect (*this, ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context()); + TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context()); _last_normalization_value = 0; @@ -711,7 +750,7 @@ Editor::~Editor() image_socket_listener = 0 ; } #endif - + delete _routes; delete _route_groups; delete track_canvas; @@ -757,7 +796,7 @@ Editor::set_entered_regionview (RegionView* rv) } if ((entered_regionview = rv) != 0) { - entered_regionview->entered (); + entered_regionview->entered (internal_editing ()); } } @@ -923,8 +962,6 @@ Editor::access_action (std::string action_group, std::string action_item) if (act) { act->activate(); } - - } void @@ -934,30 +971,19 @@ Editor::on_realize () Realized (); } -void -Editor::start_scrolling () -{ - scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect - (sigc::mem_fun(*this, &Editor::update_current_screen)); - -} - -void -Editor::stop_scrolling () -{ - scroll_connection.disconnect (); -} - void Editor::map_position_change (nframes64_t frame) { ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame) - if (_session == 0 || !_follow_playhead) { + if (_session == 0) { return; } - center_screen (frame); + if (_follow_playhead) { + center_screen (frame); + } + playhead_cursor->set_position (frame); } @@ -988,24 +1014,6 @@ Editor::center_screen_internal (nframes64_t frame, float page) reset_x_origin (frame); } -void -Editor::handle_new_duration () -{ - if (!_session) { - return; - } - - ENSURE_GUI_THREAD (*this, &Editor::handle_new_duration) - nframes64_t new_end = _session->current_end_frame() + (nframes64_t) floorf (current_page_frames() * 0.10f); - - horizontal_adjustment.set_upper (new_end / frames_per_unit); - horizontal_adjustment.set_page_size (current_page_frames()/frames_per_unit); - - if (horizontal_adjustment.get_value() + _canvas_width > horizontal_adjustment.get_upper()) { - horizontal_adjustment.set_value (horizontal_adjustment.get_upper() - _canvas_width); - } - //cerr << "Editor::handle_new_duration () called ha v:l:u:ps:lcf = " << horizontal_adjustment.get_value() << ":" << horizontal_adjustment.get_lower() << ":" << horizontal_adjustment.get_upper() << ":" << horizontal_adjustment.get_page_size() << ":" << endl;//DEBUG -} void Editor::update_title () @@ -1068,7 +1076,6 @@ Editor::set_session (Session *t) compute_fixed_ruler_scale (); /* there are never any selected regions at startup */ - sensitize_the_right_region_actions (false); XMLNode* node = ARDOUR_UI::instance()->editor_settings(); @@ -1077,6 +1084,7 @@ Editor::set_session (Session *t) /* catch up with the playhead */ _session->request_locate (playhead_cursor->current_frame); + _pending_initial_locate = true; update_title (); @@ -1085,22 +1093,21 @@ Editor::set_session (Session *t) but use Gtkmm2ext::UI::instance()->call_slot(); */ - _session->TransportStateChange.connect (_session_connections, boost::bind (&Editor::map_transport_state, this), gui_context()); - _session->PositionChanged.connect (_session_connections, ui_bind (&Editor::map_position_change, this, _1), gui_context()); - _session->RouteAdded.connect (_session_connections, ui_bind (&Editor::handle_new_route, this, _1), gui_context()); - _session->DurationChanged.connect (_session_connections, boost::bind (&Editor::handle_new_duration, this), gui_context()); - _session->DirtyChanged.connect (_session_connections, boost::bind (&Editor::update_title, this), gui_context()); - _session->TimecodeOffsetChanged.connect (_session_connections, boost::bind (&Editor::update_just_timecode, this), gui_context()); - _session->tempo_map().StateChanged.connect (_session_connections, ui_bind (&Editor::tempo_map_changed, this, _1), gui_context()); - _session->Located.connect (_session_connections, boost::bind (&Editor::located, this), gui_context()); - _session->config.ParameterChanged.connect (_session_connections, ui_bind (&Editor::parameter_changed, this, _1), gui_context()); - _session->StateSaved.connect (_session_connections, ui_bind (&Editor::session_state_saved, this, _1), gui_context()); - _session->locations()->added.connect (_session_connections, ui_bind (&Editor::add_new_location, this, _1), gui_context()); - _session->locations()->removed.connect (_session_connections, ui_bind (&Editor::location_gone, this, _1), gui_context()); - _session->locations()->changed.connect (_session_connections, boost::bind (&Editor::refresh_location_display, this), gui_context()); - _session->locations()->StateChanged.connect (_session_connections, ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context()); - _session->locations()->end_location()->changed.connect (_session_connections, ui_bind (&Editor::end_location_changed, this, _1), gui_context()); - _session->history().Changed.connect (_session_connections, boost::bind (&Editor::history_changed, this), gui_context()); + _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context()); + _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context()); + _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context()); + _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context()); + _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context()); + _session->TimecodeOffsetChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_just_timecode, this), gui_context()); + _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context()); + _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context()); + _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context()); + _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context()); + _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context()); + _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context()); + _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context()); + _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context()); + _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context()); if (Profile->get_sae()) { BBT_Time bbt; @@ -1119,7 +1126,7 @@ Editor::set_session (Session *t) Location* loc = _session->locations()->auto_loop_location(); if (loc == 0) { - loc = new Location (0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden)); + loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden)); if (loc->start() == loc->end()) { loc->set_end (loc->start() + 1); } @@ -1132,7 +1139,7 @@ Editor::set_session (Session *t) loc = _session->locations()->auto_punch_location(); if (loc == 0) { - loc = new Location (0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden)); + loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden)); if (loc->start() == loc->end()) { loc->set_end (loc->start() + 1); } @@ -1148,18 +1155,19 @@ Editor::set_session (Session *t) _session->config.map_parameters (pc); refresh_location_display (); - handle_new_duration (); restore_ruler_visibility (); - //tempo_map_changed (Change (0)); + //tempo_map_changed (PropertyChange (0)); _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { (static_cast(*i))->set_samples_per_unit (frames_per_unit); } - start_scrolling (); - + super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect ( + sigc::mem_fun (*this, &Editor::super_rapid_screen_update) + ); + switch (_snap_type) { case SnapToRegionStart: case SnapToRegionEnd: @@ -1175,7 +1183,7 @@ Editor::set_session (Session *t) /* register for undo history */ _session->register_with_memento_command_factory(_id, this); - start_updating (); + start_updating_meters (); } void @@ -1230,6 +1238,11 @@ Editor::build_cursors () grabber_cursor = new Gdk::Cursor (HAND2); + { + Glib::RefPtr grabber_note_pixbuf (::get_icon ("grabber_note")); + grabber_note_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_note_pixbuf, 5, 10); + } + { Glib::RefPtr grabber_edit_point_pixbuf (::get_icon ("grabber_edit_point")); grabber_edit_point_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_edit_point_pixbuf, 5, 17); @@ -1237,6 +1250,27 @@ Editor::build_cursors () cross_hair_cursor = new Gdk::Cursor (CROSSHAIR); trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW); + + { + Glib::RefPtr apixbuf (::get_icon ("trim_left_cursor")); + left_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 5, 11); + } + + { + Glib::RefPtr apixbuf (::get_icon ("trim_right_cursor")); + right_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 23, 11); + } + + { + Glib::RefPtr apixbuf (::get_icon ("fade_in_cursor")); + fade_in_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 0, 40); + } + + { + Glib::RefPtr apixbuf (::get_icon ("fade_out_cursor")); + fade_out_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 27, 40); + } + selector_cursor = new Gdk::Cursor (XTERM); time_fx_cursor = new Gdk::Cursor (SIZING); wait_cursor = new Gdk::Cursor (WATCH); @@ -1245,6 +1279,7 @@ Editor::build_cursors () midi_select_cursor = new Gdk::Cursor (CENTER_PTR); midi_resize_cursor = new Gdk::Cursor (SIZING); midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX); + up_down_cursor = new Gdk::Cursor (Gdk::SB_V_DOUBLE_ARROW); } /** Pop up a context menu for when the user clicks on a fade in or fade out */ @@ -1331,6 +1366,8 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, case RegionItem: case RegionViewName: case RegionViewNameHighlight: + case LeftFrameHandle: + case RightFrameHandle: if (with_selection) { build_menu_function = &Editor::build_track_selection_context_menu; } else { @@ -1351,7 +1388,7 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, break; case StreamItem: - if (clicked_routeview->get_diskstream()) { + if (clicked_routeview->track()) { build_menu_function = &Editor::build_track_context_menu; } else { build_menu_function = &Editor::build_track_bus_context_menu; @@ -1372,6 +1409,8 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, case RegionItem: case RegionViewName: case RegionViewNameHighlight: + case LeftFrameHandle: + case RightFrameHandle: if (!with_selection) { if (region_edit_menu_split_item) { if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) { @@ -1380,16 +1419,13 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false); } } - /* if (region_edit_menu_split_multichannel_item) { - if (clicked_regionview && clicked_regionview->region().n_channels() > 1) { - // GTK2FIX find the action, change its sensitivity - // region_edit_menu_split_multichannel_item->set_sensitive (true); + if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) { + region_edit_menu_split_multichannel_item->set_sensitive (true); } else { - // GTK2FIX see above - // region_edit_menu_split_multichannel_item->set_sensitive (false); + region_edit_menu_split_multichannel_item->set_sensitive (false); } - }*/ + } } break; @@ -1470,28 +1506,42 @@ Editor::build_track_region_context_menu (nframes64_t frame) MenuList& edit_items = track_region_context_menu.items(); edit_items.clear(); + /* we've just cleared the track region context menu, so the menu that these + two items were on will have disappeared; stop them dangling. + */ + region_edit_menu_split_item = 0; + region_edit_menu_split_multichannel_item = 0; + RouteTimeAxisView* rtv = dynamic_cast (clicked_axisview); if (rtv) { - boost::shared_ptr ds; + boost::shared_ptr tr; boost::shared_ptr pl; - if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) { - Playlist::RegionList* regions = pl->regions_at ((nframes64_t) floor ( (double)frame * ds->speed())); + /* Don't offer a region submenu if we are in internal edit mode, as we don't select regions in this + mode and so offering region context is somewhat confusing. + */ + if ((tr = rtv->track()) && ((pl = tr->playlist())) && !internal_editing()) { + framepos_t framepos = (framepos_t) floor ((double)frame * tr->speed()); + uint32_t regions_at = pl->count_regions_at (framepos); + list > regions_for_menu; if (selection->regions.size() > 1) { // there's already a multiple selection: just add a // single region context menu that will act on all // selected regions - boost::shared_ptr dummy_region; // = NULL - add_region_context_items (rtv->view(), dummy_region, edit_items); - } else { - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (rtv->view(), (*i), edit_items); - } - } - delete regions; + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + regions_for_menu.push_back ((*i)->region ()); + } + } else { + boost::shared_ptr top_region = pl->top_region_at (framepos); + if (top_region) { + regions_for_menu.push_back (top_region); + } + } + + add_region_context_items (rtv->view(), regions_for_menu, edit_items, framepos, regions_at > 1); } } @@ -1510,13 +1560,12 @@ Editor::build_track_crossfade_context_menu (nframes64_t frame) AudioTimeAxisView* atv = dynamic_cast (clicked_axisview); if (atv) { - boost::shared_ptr ds; + boost::shared_ptr tr; boost::shared_ptr pl; boost::shared_ptr apl; - if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast (pl)) != 0)) { + if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast (pl)) != 0)) { - Playlist::RegionList* regions = pl->regions_at (frame); AudioPlaylist::Crossfades xfades; apl->crossfades_at (frame, xfades); @@ -1527,18 +1576,26 @@ Editor::build_track_crossfade_context_menu (nframes64_t frame) add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many); } + framepos_t framepos = (framepos_t) floor ((double)frame * tr->speed()); + uint32_t regions_at = pl->count_regions_at (framepos); + list > regions_for_menu; + if (selection->regions.size() > 1) { - // there's already a multiple selection: just add a - // single region context menu that will act on all - // selected regions - boost::shared_ptr dummy_region; // = NULL - add_region_context_items (atv->audio_view(), dummy_region, edit_items); - } else { - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (atv->audio_view(), (*i), edit_items); + // there's already a multiple selection: just add a + // single region context menu that will act on all + // selected regions + + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + regions_for_menu.push_back ((*i)->region ()); } - } - delete regions; + } else { + boost::shared_ptr top_region = pl->top_region_at (framepos); + if (top_region) { + regions_for_menu.push_back (top_region); + } + } + + add_region_context_items (atv->audio_view(), regions_for_menu, edit_items, framepos, regions_at > 1); } } @@ -1616,7 +1673,7 @@ Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_pt } items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr (xfade)))); - items.push_back (MenuElem (_("Edit"), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr (xfade)))); + items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr (xfade)))); if (xfade->can_follow_overlap()) { @@ -1658,7 +1715,8 @@ Editor::xfade_edit_right_region () } void -Editor::add_region_context_items (StreamView* sv, boost::shared_ptr region, Menu_Helpers::MenuList& edit_items) +Editor::add_region_context_items (StreamView* sv, list > regions, Menu_Helpers::MenuList& edit_items, + framepos_t position, bool multiple_regions_at_position) { using namespace Menu_Helpers; Gtk::MenuItem* foo_item; @@ -1666,26 +1724,101 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi MenuList& items = region_menu->items(); region_menu->set_name ("ArdourContextMenu"); - boost::shared_ptr ar; - boost::shared_ptr mr; + /* Look through the regions that we are handling and make notes about what we have got */ + + bool have_audio = false; + bool have_midi = false; + bool have_locked = false; + bool have_unlocked = false; + bool have_position_lock_style_audio = false; + bool have_position_lock_style_music = false; + bool have_muted = false; + bool have_unmuted = false; + bool have_opaque = false; + bool have_non_opaque = false; + bool have_not_at_natural_position = false; + bool have_envelope_visible = false; + bool have_envelope_invisible = false; + bool have_envelope_active = false; + bool have_envelope_inactive = false; + bool have_non_unity_scale_amplitude = false; + + for (list >::const_iterator i = regions.begin(); i != regions.end(); ++i) { + boost::shared_ptr ar = boost::dynamic_pointer_cast (*i); + if (ar) { + have_audio = true; + } + if (boost::dynamic_pointer_cast (*i)) { + have_midi = true; + } - if (region) { - ar = boost::dynamic_pointer_cast (region); - mr = boost::dynamic_pointer_cast (region); + if ((*i)->locked()) { + have_locked = true; + } else { + have_unlocked = true; + } + + if ((*i)->position_lock_style() == MusicTime) { + have_position_lock_style_music = true; + } else { + have_position_lock_style_audio = true; + } + + if ((*i)->muted()) { + have_muted = true; + } else { + have_unmuted = true; + } + + if ((*i)->opaque()) { + have_opaque = true; + } else { + have_non_opaque = true; + } + + if (!(*i)->at_natural_position()) { + have_not_at_natural_position = true; + } + + if (ar) { + RegionView* rv = sv->find_view (ar); + AudioRegionView* arv = dynamic_cast (rv); + + if (rv && arv && arv->envelope_visible()) { + have_envelope_visible = true; + } else { + have_envelope_invisible = true; + } + + if (ar->envelope_active()) { + have_envelope_active = true; + } else { + have_envelope_inactive = true; + } + + if (ar->scale_amplitude() != 1) { + have_non_unity_scale_amplitude = true; + } + } + } + + if (regions.size() == 1) { /* when this particular menu pops up, make the relevant region become selected. */ region_menu->signal_map_event().connect ( - sigc::bind (sigc::mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr(region))); + sigc::bind (sigc::mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr (regions.front())) + ); items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &Editor::rename_region))); - if (mr && internal_editing()) { - items.push_back (MenuElem (_("List editor..."), sigc::mem_fun(*this, &Editor::show_midi_list_editor))); - } else { - items.push_back (MenuElem (_("Region Properties..."), sigc::mem_fun(*this, &Editor::edit_region))); + + if (have_midi) { + items.push_back (MenuElem (_("List Editor..."), sigc::mem_fun(*this, &Editor::show_midi_list_editor))); } + + items.push_back (MenuElem (_("Region Properties..."), sigc::mem_fun(*this, &Editor::edit_region))); } items.push_back (MenuElem (_("Raise to Top Layer"), sigc::mem_fun(*this, &Editor::raise_region_to_top))); @@ -1699,109 +1832,101 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi items.push_back (SeparatorElem()); items.push_back (MenuElem (_("Audition"), sigc::mem_fun(*this, &Editor::play_selected_region))); - items.push_back (MenuElem (_("Export"), sigc::mem_fun(*this, &Editor::export_region))); + items.push_back (MenuElem (_("Export..."), sigc::mem_fun(*this, &Editor::export_region))); items.push_back (MenuElem (_("Bounce"), sigc::mem_fun(*this, &Editor::bounce_region_selection))); - if (ar) { - items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_region_selection))); + if (have_audio) { + items.push_back (MenuElem (_("Spectral Analysis..."), sigc::mem_fun(*this, &Editor::analyze_region_selection))); } items.push_back (SeparatorElem()); - sigc::connection fooc; - boost::shared_ptr region_to_check; - - if (region) { - region_to_check = region; - } else { - region_to_check = selection->regions.front()->region(); - } - items.push_back (CheckMenuElem (_("Lock"))); CheckMenuItem* region_lock_item = static_cast(&items.back()); - if (region_to_check->locked()) { + if (have_locked && !have_unlocked) { region_lock_item->set_active(); + } else if (have_locked && have_unlocked) { + region_lock_item->set_inconsistent (); } region_lock_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_lock)); items.push_back (CheckMenuElem (_("Glue to Bars and Beats"))); CheckMenuItem* bbt_glue_item = static_cast(&items.back()); - switch (region_to_check->positional_lock_style()) { - case Region::MusicTime: - bbt_glue_item->set_active (true); - break; - default: - bbt_glue_item->set_active (false); - break; + if (have_position_lock_style_music && !have_position_lock_style_audio) { + bbt_glue_item->set_active (); + } else if (have_position_lock_style_music && have_position_lock_style_audio) { + bbt_glue_item->set_inconsistent (); } - bbt_glue_item->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::set_region_lock_style), Region::MusicTime)); + bbt_glue_item->signal_activate().connect (sigc::mem_fun (*this, &Editor::toggle_region_lock_style)); items.push_back (CheckMenuElem (_("Mute"))); CheckMenuItem* region_mute_item = static_cast(&items.back()); - fooc = region_mute_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_mute)); - if (region_to_check->muted()) { - fooc.block (true); + + if (have_muted && !have_unmuted) { region_mute_item->set_active(); - fooc.block (false); + } else if (have_muted && have_unmuted) { + region_mute_item->set_inconsistent (); } + + region_mute_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_mute)); + + items.push_back (MenuElem (_("Transpose..."), mem_fun(*this, &Editor::pitch_shift_regions))); if (!Profile->get_sae()) { items.push_back (CheckMenuElem (_("Opaque"))); CheckMenuItem* region_opaque_item = static_cast(&items.back()); - fooc = region_opaque_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_opaque)); - if (region_to_check->opaque()) { - fooc.block (true); + if (have_opaque && !have_non_opaque) { region_opaque_item->set_active(); - fooc.block (false); + } else if (have_opaque && have_non_opaque) { + region_opaque_item->set_inconsistent (); } + region_opaque_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_opaque)); } items.push_back (CheckMenuElem (_("Original Position"), sigc::mem_fun(*this, &Editor::naturalize))); - if (region_to_check->at_natural_position()) { + if (!have_not_at_natural_position) { items.back().set_sensitive (false); } items.push_back (SeparatorElem()); - if (ar) { - - RegionView* rv = sv->find_view (ar); - AudioRegionView* arv = dynamic_cast(rv); + if (have_audio) { if (!Profile->get_sae()) { items.push_back (MenuElem (_("Reset Envelope"), sigc::mem_fun(*this, &Editor::reset_region_gain_envelopes))); items.push_back (CheckMenuElem (_("Envelope Visible"))); CheckMenuItem* region_envelope_visible_item = static_cast (&items.back()); - fooc = region_envelope_visible_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_visibility)); - if (arv->envelope_visible()) { - fooc.block (true); - region_envelope_visible_item->set_active (true); - fooc.block (false); + if (have_envelope_visible && !have_envelope_invisible) { + region_envelope_visible_item->set_active (); + } else if (have_envelope_visible && have_envelope_invisible) { + region_envelope_visible_item->set_inconsistent (); } + region_envelope_visible_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_visibility)); items.push_back (CheckMenuElem (_("Envelope Active"))); CheckMenuItem* region_envelope_active_item = static_cast (&items.back()); - fooc = region_envelope_active_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_active)); - if (ar->envelope_active()) { - fooc.block (true); - region_envelope_active_item->set_active (true); - fooc.block (false); + if (have_envelope_active && !have_envelope_inactive) { + region_envelope_active_item->set_active (); + } else if (have_envelope_active && have_envelope_inactive) { + region_envelope_active_item->set_inconsistent (); } + region_envelope_active_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_active)); items.push_back (SeparatorElem()); } - items.push_back (MenuElem (_("Normalize"), sigc::mem_fun(*this, &Editor::normalize_region))); - if (ar->scale_amplitude() != 1) { + items.push_back (MenuElem (_("Normalize..."), sigc::mem_fun(*this, &Editor::normalize_region))); + if (have_non_unity_scale_amplitude) { items.push_back (MenuElem (_("Reset Gain"), sigc::mem_fun(*this, &Editor::reset_region_scale_amplitude))); } - } else if (mr) { + } else if (have_midi) { items.push_back (MenuElem (_("Quantize"), sigc::mem_fun(*this, &Editor::quantize_region))); + items.push_back (MenuElem (_("Fork"), sigc::mem_fun(*this, &Editor::fork_region))); items.push_back (SeparatorElem()); } @@ -1861,11 +1986,13 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi region_edit_menu_split_item->set_sensitive (false); } - items.push_back (MenuElem (_("Make Mono Regions"), (sigc::mem_fun(*this, &Editor::split_multichannel_region)))); - region_edit_menu_split_multichannel_item = &items.back(); + if (have_audio) { + items.push_back (MenuElem (_("Make Mono Regions"), (sigc::mem_fun(*this, &Editor::split_multichannel_region)))); + region_edit_menu_split_multichannel_item = &items.back(); + } items.push_back (MenuElem (_("Duplicate"), (sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)))); - items.push_back (MenuElem (_("Multi-Duplicate"), (sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), true)))); + items.push_back (MenuElem (_("Multi-Duplicate..."), (sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), true)))); items.push_back (MenuElem (_("Fill Track"), (sigc::mem_fun(*this, &Editor::region_fill_track)))); items.push_back (SeparatorElem()); items.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::remove_selected_regions))); @@ -1879,7 +2006,7 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi */ string::size_type pos = 0; - string menu_item_name = (region) ? region->name() : _("Selected Regions"); + string menu_item_name = (regions.size() == 1) ? regions.front()->name() : _("Selected Regions"); while ((pos = menu_item_name.find ("_", pos)) != string::npos) { menu_item_name.replace (pos, 1, "__"); @@ -1887,6 +2014,9 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi } edit_items.push_back (MenuElem (menu_item_name, *region_menu)); + if (multiple_regions_at_position && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) { + edit_items.push_back (MenuElem (_("Choose Top Region..."), (bind (mem_fun(*this, &Editor::change_region_layering_order), position)))); + } edit_items.push_back (SeparatorElem()); } @@ -1911,7 +2041,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) } edit_items.push_back (SeparatorElem()); - edit_items.push_back (MenuElem (_("Silence Range"), sigc::mem_fun(*this, &Editor::separate_region_from_selection))); + edit_items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection))); edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection))); edit_items.push_back (SeparatorElem()); @@ -1934,7 +2064,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true))); edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false))); edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true))); - edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_range))); + edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection))); } @@ -2108,11 +2238,21 @@ Editor::set_snap_to (SnapType st) instant_save (); switch (_snap_type) { - case SnapToAThirtysecondBeat: - case SnapToASixteenthBeat: - case SnapToAEighthBeat: - case SnapToAQuarterBeat: - case SnapToAThirdBeat: + case SnapToBeatDiv32: + case SnapToBeatDiv28: + case SnapToBeatDiv24: + case SnapToBeatDiv20: + case SnapToBeatDiv16: + case SnapToBeatDiv14: + case SnapToBeatDiv12: + case SnapToBeatDiv10: + case SnapToBeatDiv8: + case SnapToBeatDiv7: + case SnapToBeatDiv6: + case SnapToBeatDiv5: + case SnapToBeatDiv4: + case SnapToBeatDiv3: + case SnapToBeatDiv2: compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames()); update_tempo_based_rulers (); break; @@ -2127,7 +2267,9 @@ Editor::set_snap_to (SnapType st) default: /* relax */ break; - } + } + + SnapChanged (); /* EMIT SIGNAL */ } void @@ -2259,7 +2401,8 @@ Editor::set_state (const XMLNode& node, int /*version*/) move (x, y); if (_session && (prop = node.property ("playhead"))) { - nframes64_t pos = atol (prop->value().c_str()); + nframes64_t pos; + sscanf (prop->value().c_str(), "%" PRIi64, &pos); playhead_cursor->set_position (pos); } else { playhead_cursor->set_position (0); @@ -2275,6 +2418,8 @@ Editor::set_state (const XMLNode& node, int /*version*/) if ((prop = node.property ("zoom"))) { reset_zoom (PBD::atof (prop->value())); + } else { + reset_zoom (frames_per_unit); } if ((prop = node.property ("snap-to"))) { @@ -2296,11 +2441,13 @@ Editor::set_state (const XMLNode& node, int /*version*/) nframes64_t pos; if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) { reset_x_origin (pos); - /* this hack prevents the initial call to update_current_screen() from doing re-centering on the playhead */ - last_update_frame = pos; } } + if ((prop = node.property ("y-origin")) != 0) { + reset_y_origin (atof (prop->value ())); + } + if ((prop = node.property ("internal-edit"))) { bool yn = string_is_affirmative (prop->value()); RefPtr act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit")); @@ -2319,21 +2466,9 @@ Editor::set_state (const XMLNode& node, int /*version*/) set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true); } - if ((prop = node.property ("show-waveforms-recording"))) { - bool yn = string_is_affirmative (prop->value()); - _show_waveforms_recording = !yn; - RefPtr act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording")); - if (act) { - RefPtr tact = RefPtr::cast_dynamic(act); - /* do it twice to force the change */ - tact->set_active (!yn); - tact->set_active (yn); - } - } - if ((prop = node.property ("show-measures"))) { bool yn = string_is_affirmative (prop->value()); - _show_measures = !yn; + _show_measures = yn; RefPtr act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility")); if (act) { RefPtr tact = RefPtr::cast_dynamic(act); @@ -2355,6 +2490,18 @@ Editor::set_state (const XMLNode& node, int /*version*/) } } + if ((prop = node.property ("stationary-playhead"))) { + bool yn = (prop->value() == "yes"); + set_stationary_playhead (yn); + RefPtr act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead")); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + if (tact->get_active() != yn) { + tact->set_active (yn); + } + } + } + if ((prop = node.property ("region-list-sort-type"))) { RegionListSortType st; _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true); @@ -2397,6 +2544,14 @@ Editor::set_state (const XMLNode& node, int /*version*/) } } + if ((prop = node.property (X_("editor-list-page")))) { + the_notebook.set_current_page (atoi (prop->value ())); + } + + XMLNodeList children = node.children (); + for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { + selection->set_state (**i, Stateful::current_state_version); + } return 0; } @@ -2433,7 +2588,9 @@ Editor::get_state () snprintf(buf, sizeof(buf), "%d", yoff); geometry->add_property("y-off", string(buf)); snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast(&edit_pane)->gobj())); - geometry->add_property("edit_pane_pos", string(buf)); + geometry->add_property("edit-horizontal-pane-pos", string(buf)); + snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast(&editor_summary_pane)->gobj())); + geometry->add_property("edit-vertical-pane-pos", string(buf)); node->add_child_nocopy (*geometry); } @@ -2455,10 +2612,12 @@ Editor::get_state () node->add_property ("playhead", buf); snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame); node->add_property ("left-frame", buf); + snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ()); + node->add_property ("y-origin", buf); - node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no"); node->add_property ("show-measures", _show_measures ? "yes" : "no"); node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no"); + node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no"); node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no"); node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ())); node->add_property ("mouse-mode", enum2str(mouse_mode)); @@ -2477,6 +2636,11 @@ Editor::get_state () node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no"); } + snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ()); + node->add_property (X_("editor-list-page"), buf); + + node->add_child_nocopy (selection->get_state ()); + return *node; } @@ -2642,25 +2806,51 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark) start = _session->tempo_map().round_to_beat (start, direction); break; - case SnapToAThirtysecondBeat: + case SnapToBeatDiv32: start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction); break; - - case SnapToASixteenthBeat: + case SnapToBeatDiv28: + start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction); + break; + case SnapToBeatDiv24: + start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction); + break; + case SnapToBeatDiv20: + start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction); + break; + case SnapToBeatDiv16: start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction); break; - - case SnapToAEighthBeat: + case SnapToBeatDiv14: + start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction); + break; + case SnapToBeatDiv12: + start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction); + break; + case SnapToBeatDiv10: + start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction); + break; + case SnapToBeatDiv8: start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction); break; - - case SnapToAQuarterBeat: + case SnapToBeatDiv7: + start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction); + break; + case SnapToBeatDiv6: + start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction); + break; + case SnapToBeatDiv5: + start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction); + break; + case SnapToBeatDiv4: start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction); break; - - case SnapToAThirdBeat: + case SnapToBeatDiv3: start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction); break; + case SnapToBeatDiv2: + start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction); + break; case SnapToMark: if (for_mark) { @@ -2763,37 +2953,26 @@ Editor::setup_toolbar () /* table containing mode buttons */ - Table* mouse_mode_button_table = manage (new Table (Profile->get_sae() ? 4 : 6, 2)); - - int c = 0; + HBox* mouse_mode_button_box = manage (new HBox ()); if (Profile->get_sae()) { - mouse_mode_button_table->attach (mouse_move_button, c, c + 1, 0, 1); - ++c; + mouse_mode_button_box->pack_start (mouse_move_button); } else { - mouse_mode_button_table->attach (mouse_move_button, c, c + 1, 0, 1); - mouse_mode_button_table->attach (mouse_select_button, c + 1, c + 2, 0, 1); - mouse_mode_button_table->attach (join_object_range_button, c, c + 2, 1, 2); - c += 2; + mouse_mode_button_box->pack_start (mouse_move_button); + mouse_mode_button_box->pack_start (join_object_range_button); + mouse_mode_button_box->pack_start (mouse_select_button); } - mouse_mode_button_table->attach (mouse_zoom_button, c, c + 1, 0, 1); - ++c; - + mouse_mode_button_box->pack_start (mouse_zoom_button); + if (!Profile->get_sae()) { - mouse_mode_button_table->attach (mouse_gain_button, c, c + 1, 0, 1); - ++c; + mouse_mode_button_box->pack_start (mouse_gain_button); } - - mouse_mode_button_table->attach (mouse_timefx_button, c, c + 1, 0, 1); - ++c; - - mouse_mode_button_table->attach (mouse_audition_button, c, c + 1, 0, 1); - ++c; - - mouse_mode_button_table->attach (internal_edit_button, c, c + 1, 0, 1); - ++c; - + + mouse_mode_button_box->pack_start (mouse_timefx_button); + mouse_mode_button_box->pack_start (mouse_audition_button); + mouse_mode_button_box->pack_start (internal_edit_button); + vector edit_mode_strings; edit_mode_strings.push_back (edit_mode_to_string (Slide)); if (!Profile->get_sae()) { @@ -2806,24 +2985,24 @@ Editor::setup_toolbar () edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done)); mode_box->pack_start (edit_mode_selector); - mode_box->pack_start (*mouse_mode_button_table); + mode_box->pack_start (*mouse_mode_button_box); - mouse_mode_tearoff = manage (new TearOff (*mode_box)); - mouse_mode_tearoff->set_name ("MouseModeBase"); - mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &mouse_mode_tearoff->tearoff_window()), false); + _mouse_mode_tearoff = manage (new TearOff (*mode_box)); + _mouse_mode_tearoff->set_name ("MouseModeBase"); + _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false); if (Profile->get_sae()) { - mouse_mode_tearoff->set_can_be_torn_off (false); + _mouse_mode_tearoff->set_can_be_torn_off (false); } - mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), - &mouse_mode_tearoff->tearoff_window())); - mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), - &mouse_mode_tearoff->tearoff_window(), 1)); - mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), - &mouse_mode_tearoff->tearoff_window())); - mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), - &mouse_mode_tearoff->tearoff_window(), 1)); + _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_mouse_mode_tearoff->tearoff_window())); + _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_mouse_mode_tearoff->tearoff_window(), 1)); + _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_mouse_mode_tearoff->tearoff_window())); + _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_mouse_mode_tearoff->tearoff_window(), 1)); mouse_move_button.set_mode (false); mouse_select_button.set_mode (false); @@ -2853,75 +3032,70 @@ Editor::setup_toolbar () /* Zoom */ - zoom_box.set_spacing (1); - zoom_box.set_border_width (0); + _zoom_box.set_spacing (1); + _zoom_box.set_border_width (0); zoom_in_button.set_name ("EditorTimeButton"); - zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_BUTTON)))); + zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_MENU)))); zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false)); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In")); zoom_out_button.set_name ("EditorTimeButton"); - zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_BUTTON)))); + zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_MENU)))); zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true)); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out")); zoom_out_full_button.set_name ("EditorTimeButton"); - zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_BUTTON)))); + zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_MENU)))); zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session)); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session")); zoom_focus_selector.set_name ("ZoomFocusSelector"); set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true); zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done)); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus")); - zoom_box.pack_start (zoom_out_button, false, false); - zoom_box.pack_start (zoom_in_button, false, false); - zoom_box.pack_start (zoom_out_full_button, false, false); + _zoom_box.pack_start (zoom_out_button, false, false); + _zoom_box.pack_start (zoom_in_button, false, false); + _zoom_box.pack_start (zoom_out_full_button, false, false); + _zoom_box.pack_start (zoom_focus_selector); + /* Track zoom buttons */ tav_expand_button.set_name ("TrackHeightButton"); tav_expand_button.set_size_request(-1,20); tav_expand_button.add (*(manage (new Image (::get_icon("tav_exp"))))); tav_expand_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), true)); - ARDOUR_UI::instance()->tooltips().set_tip (tav_expand_button, _("Expand Tracks")); tav_shrink_button.set_name ("TrackHeightButton"); tav_shrink_button.set_size_request(-1,20); tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink"))))); tav_shrink_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), false)); - ARDOUR_UI::instance()->tooltips().set_tip (tav_shrink_button, _("Shrink Tracks")); - - track_zoom_box.set_spacing (1); - track_zoom_box.set_border_width (0); - - track_zoom_box.pack_start (tav_shrink_button, false, false); - track_zoom_box.pack_start (tav_expand_button, false, false); - - HBox* zbc = manage (new HBox); - zbc->pack_start (zoom_focus_selector, PACK_SHRINK); - zoom_vbox.pack_start (*zbc, PACK_SHRINK); - zoom_vbox.pack_start (zoom_box, PACK_SHRINK); - zoom_vbox.pack_start (track_zoom_box, PACK_SHRINK); + _zoom_box.pack_start (tav_shrink_button); + _zoom_box.pack_start (tav_expand_button); + + _zoom_tearoff = manage (new TearOff (_zoom_box)); + + _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_zoom_tearoff->tearoff_window())); + _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_zoom_tearoff->tearoff_window(), 0)); + _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_zoom_tearoff->tearoff_window())); + _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_zoom_tearoff->tearoff_window(), 0)); + snap_box.set_spacing (1); snap_box.set_border_width (2); snap_type_selector.set_name ("SnapTypeSelector"); set_popdown_strings (snap_type_selector, snap_type_strings, true); snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done)); - ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units")); snap_mode_selector.set_name ("SnapModeSelector"); set_popdown_strings (snap_mode_selector, snap_mode_strings, true); snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done)); - ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode")); edit_point_selector.set_name ("EditPointSelector"); set_popdown_strings (edit_point_selector, edit_point_strings, true); edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done)); - ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point")); snap_box.pack_start (snap_mode_selector, false, false); snap_box.pack_start (snap_type_selector, false, false); @@ -2946,28 +3120,29 @@ Editor::setup_toolbar () HBox* hbox = manage (new HBox); hbox->set_spacing(10); - tools_tearoff = manage (new TearOff (*hbox)); - tools_tearoff->set_name ("MouseModeBase"); - tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &tools_tearoff->tearoff_window()), false); - + _tools_tearoff = manage (new TearOff (*hbox)); + _tools_tearoff->set_name ("MouseModeBase"); + _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false); + if (Profile->get_sae()) { - tools_tearoff->set_can_be_torn_off (false); + _tools_tearoff->set_can_be_torn_off (false); } - tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), - &tools_tearoff->tearoff_window())); - tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), - &tools_tearoff->tearoff_window(), 0)); - tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), - &tools_tearoff->tearoff_window())); - tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), - &tools_tearoff->tearoff_window(), 0)); + _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_tools_tearoff->tearoff_window())); + _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_tools_tearoff->tearoff_window(), 0)); + _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_tools_tearoff->tearoff_window())); + _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_tools_tearoff->tearoff_window(), 0)); toolbar_hbox.set_spacing (10); toolbar_hbox.set_border_width (1); - toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false); - toolbar_hbox.pack_start (*tools_tearoff, false, false); + toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false); + toolbar_hbox.pack_start (*_zoom_tearoff, false, false); + toolbar_hbox.pack_start (*_tools_tearoff, false, false); hbox->pack_start (snap_box, false, false); hbox->pack_start (*nudge_box, false, false); @@ -2983,6 +3158,33 @@ Editor::setup_toolbar () toolbar_frame.add (toolbar_base); } +void +Editor::setup_tooltips () +{ + ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects")); + ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Gain Automation")); + ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range")); + ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes")); + ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions")); + ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges")); + ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)")); + ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: context-click for possible operations")); + ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards")); + ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards")); + ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In")); + ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out")); + ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session")); + ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus")); + ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks")); + ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks")); + ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units")); + ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode")); + ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point")); + ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes")); + ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels")); + ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode")); +} + void Editor::midi_panic () { @@ -3001,14 +3203,12 @@ Editor::setup_midi_toolbar () /* Midi sound notes */ midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes"))))); midi_sound_notes.set_relief(Gtk::RELIEF_NONE); - ARDOUR_UI::instance()->tooltips().set_tip (midi_sound_notes, _("Sound Notes")); midi_sound_notes.unset_flags (CAN_FOCUS); /* Panic */ act = ActionManager::get_action (X_("MIDI"), X_("panic")); midi_panic_button.set_name("MidiPanicButton"); - ARDOUR_UI::instance()->tooltips().set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels")); act->connect_proxy (midi_panic_button); panic_box.pack_start (midi_sound_notes , true, true); @@ -3137,7 +3337,7 @@ Editor::map_transport_state () { ENSURE_GUI_THREAD (*this, &Editor::map_transport_state) - if (_session->transport_stopped()) { + if (_session && _session->transport_stopped()) { have_pending_keyboard_selection = false; } @@ -3160,7 +3360,6 @@ void Editor::begin_reversible_command (string name) { if (_session) { - before = &get_state(); _session->begin_reversible_command (name); } } @@ -3169,7 +3368,7 @@ void Editor::commit_reversible_command () { if (_session) { - _session->commit_reversible_command (new MementoCommand(*this, before, &get_state())); + _session->commit_reversible_command (); } } @@ -3244,8 +3443,8 @@ Editor::duplicate_dialog (bool with_dialog) if (with_dialog) { - ArdourDialog win ("Duplicate"); - Label label (_("Number of Duplications:")); + ArdourDialog win (_("Duplicate")); + Label label (_("Number of duplications:")); Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0); SpinButton spinner (adjustment, 0.0, 1); HBox hbox; @@ -3391,22 +3590,7 @@ Editor::cycle_edit_mode () void Editor::edit_mode_selection_done () { - if (_session == 0) { - return; - } - - string choice = edit_mode_selector.get_active_text(); - EditMode mode = Slide; - - if (choice == _("Splice Edit")) { - mode = Splice; - } else if (choice == _("Slide Edit")) { - mode = Slide; - } else if (choice == _("Lock Edit")) { - mode = Lock; - } - - Config->set_edit_mode (mode); + Config->set_edit_mode (string_to_edit_mode (edit_mode_selector.get_active_text ())); } void @@ -3415,16 +3599,36 @@ Editor::snap_type_selection_done () string choice = snap_type_selector.get_active_text(); SnapType snaptype = SnapToBeat; - if (choice == _("Beats/3")) { - snaptype = SnapToAThirdBeat; + if (choice == _("Beats/2")) { + snaptype = SnapToBeatDiv2; + } else if (choice == _("Beats/3")) { + snaptype = SnapToBeatDiv3; } else if (choice == _("Beats/4")) { - snaptype = SnapToAQuarterBeat; + snaptype = SnapToBeatDiv4; + } else if (choice == _("Beats/5")) { + snaptype = SnapToBeatDiv5; + } else if (choice == _("Beats/6")) { + snaptype = SnapToBeatDiv6; + } else if (choice == _("Beats/7")) { + snaptype = SnapToBeatDiv7; } else if (choice == _("Beats/8")) { - snaptype = SnapToAEighthBeat; + snaptype = SnapToBeatDiv8; + } else if (choice == _("Beats/10")) { + snaptype = SnapToBeatDiv10; + } else if (choice == _("Beats/12")) { + snaptype = SnapToBeatDiv12; + } else if (choice == _("Beats/14")) { + snaptype = SnapToBeatDiv14; } else if (choice == _("Beats/16")) { - snaptype = SnapToASixteenthBeat; + snaptype = SnapToBeatDiv16; + } else if (choice == _("Beats/20")) { + snaptype = SnapToBeatDiv20; + } else if (choice == _("Beats/24")) { + snaptype = SnapToBeatDiv24; + } else if (choice == _("Beats/28")) { + snaptype = SnapToBeatDiv28; } else if (choice == _("Beats/32")) { - snaptype = SnapToAThirtysecondBeat; + snaptype = SnapToBeatDiv32; } else if (choice == _("Beats")) { snaptype = SnapToBeat; } else if (choice == _("Bars")) { @@ -3605,7 +3809,14 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) char buf[32]; XMLNode* node = ARDOUR_UI::instance()->editor_settings(); int width, height; - static int32_t done; + + enum Pane { + Horizontal = 0x1, + Vertical = 0x2 + }; + + static Pane done; + XMLNode* geometry; width = default_width; @@ -3613,15 +3824,11 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) if ((geometry = find_named_node (*node, "geometry")) != 0) { - if ((prop = geometry->property ("x_size")) == 0) { - prop = geometry->property ("x-size"); - } + prop = geometry->property ("x-size"); if (prop) { width = atoi (prop->value()); } - if ((prop = geometry->property ("y_size")) == 0) { - prop = geometry->property ("y-size"); - } + prop = geometry->property ("y-size"); if (prop) { height = atoi (prop->value()); } @@ -3629,11 +3836,11 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) if (which == static_cast (&edit_pane)) { - if (done) { + if (done & Horizontal) { return; } - if (!geometry || (prop = geometry->property ("edit-pane-pos")) == 0) { + if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) { /* initial allocation is 90% to canvas, 10% to notebook */ pos = (int) floor (alloc.get_width() * 0.90f); snprintf (buf, sizeof(buf), "%d", pos); @@ -3641,20 +3848,40 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) pos = atoi (prop->value()); } - if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) { + if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) { edit_pane.set_position (pos); - pre_maximal_pane_position = pos; + pre_maximal_horizontal_pane_position = pos; + } + + done = (Pane) (done | Horizontal); + + } else if (which == static_cast (&editor_summary_pane)) { + + if (done & Vertical) { + return; } + + if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) { + /* initial allocation is 90% to canvas, 10% to summary */ + pos = (int) floor (alloc.get_height() * 0.90f); + snprintf (buf, sizeof(buf), "%d", pos); + } else { + pos = atoi (prop->value()); + } + + if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) { + editor_summary_pane.set_position (pos); + pre_maximal_vertical_pane_position = pos; + } + + done = (Pane) (done | Vertical); } } void Editor::detach_tearoff (Box* /*b*/, Window* /*w*/) { - cerr << "remove tearoff\n"; - - if (tools_tearoff->torn_off() && - mouse_mode_tearoff->torn_off()) { + if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) { top_hbox.remove (toolbar_frame); } } @@ -3662,7 +3889,6 @@ Editor::detach_tearoff (Box* /*b*/, Window* /*w*/) void Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/) { - cerr << "reattach tearoff\n"; if (toolbar_frame.get_parent() == 0) { top_hbox.pack_end (toolbar_frame); } @@ -3699,12 +3925,35 @@ Editor::set_follow_playhead (bool yn) if (_follow_playhead != yn) { if ((_follow_playhead = yn) == true) { /* catch up */ - update_current_screen (); + reset_x_origin_to_follow_playhead (); } instant_save (); } } +void +Editor::toggle_stationary_playhead () +{ + RefPtr act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead")); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + set_stationary_playhead (tact->get_active()); + } +} + +void +Editor::set_stationary_playhead (bool yn) +{ + if (_stationary_playhead != yn) { + if ((_stationary_playhead = yn) == true) { + /* catch up */ + // FIXME need a 3.0 equivalent of this 2.X call + // update_current_screen (); + } + instant_save (); + } +} + void Editor::toggle_xfade_active (boost::weak_ptr wxfade) { @@ -3744,7 +3993,10 @@ Editor::edit_xfade (boost::weak_ptr wxfade) } cew.apply (); - xfade->StateChanged (Change (~0)); + PropertyChange all_crossfade_properties; + all_crossfade_properties.add (ARDOUR::Properties::active); + all_crossfade_properties.add (ARDOUR::Properties::follow_overlap); + xfade->PropertyChanged (all_crossfade_properties); } PlaylistSelector& @@ -3763,25 +4015,51 @@ Editor::get_grid_type_as_beats (bool& success, nframes64_t position) return 1.0; break; - case SnapToAThirtysecondBeat: + case SnapToBeatDiv32: return 1.0/32.0; break; - - case SnapToASixteenthBeat: + case SnapToBeatDiv28: + return 1.0/28.0; + break; + case SnapToBeatDiv24: + return 1.0/24.0; + break; + case SnapToBeatDiv20: + return 1.0/20.0; + break; + case SnapToBeatDiv16: return 1.0/16.0; break; - - case SnapToAEighthBeat: + case SnapToBeatDiv14: + return 1.0/14.0; + break; + case SnapToBeatDiv12: + return 1.0/12.0; + break; + case SnapToBeatDiv10: + return 1.0/10.0; + break; + case SnapToBeatDiv8: return 1.0/8.0; break; - - case SnapToAQuarterBeat: + case SnapToBeatDiv7: + return 1.0/7.0; + break; + case SnapToBeatDiv6: + return 1.0/6.0; + break; + case SnapToBeatDiv5: + return 1.0/5.0; + break; + case SnapToBeatDiv4: return 1.0/4.0; break; - - case SnapToAThirdBeat: + case SnapToBeatDiv3: return 1.0/3.0; break; + case SnapToBeatDiv2: + return 1.0/2.0; + break; case SnapToBar: if (_session) { @@ -3818,19 +4096,10 @@ Editor::get_nudge_distance (nframes64_t pos, nframes64_t& next) return ret; } -void -Editor::end_location_changed (Location* location) -{ - ENSURE_GUI_THREAD (*this, &Editor::end_location_changed, location) - //reset_scrolling_region (); - nframes64_t session_span = location->start() + (nframes64_t) floorf (current_page_frames() * 0.10f); - horizontal_adjustment.set_upper (session_span / frames_per_unit); -} - int Editor::playlist_deletion_dialog (boost::shared_ptr pl) { - ArdourDialog dialog ("playlist deletion dialog"); + ArdourDialog dialog (_("Playlist Deletion")); Label label (string_compose (_("Playlist %1 is currently unused.\n" "If left alone, no audio files used by it will be cleaned.\n" "If deleted, audio files used by it alone by will cleaned."), @@ -3939,10 +4208,8 @@ Editor::control_layout_scroll (GdkEventScroll* ev) } void -Editor::session_state_saved (string snap_name) +Editor::session_state_saved (string) { - ENSURE_GUI_THREAD (*this, &Editor::session_state_saved, snap_name); - update_title (); _snapshots->redisplay (); } @@ -3950,42 +4217,69 @@ Editor::session_state_saved (string snap_name) void Editor::maximise_editing_space () { - mouse_mode_tearoff->set_visible (false); - tools_tearoff->set_visible (false); + _mouse_mode_tearoff->set_visible (false); + _tools_tearoff->set_visible (false); + _zoom_tearoff->set_visible (false); - pre_maximal_pane_position = edit_pane.get_position(); - pre_maximal_editor_width = this->get_width(); + pre_maximal_horizontal_pane_position = edit_pane.get_position (); + pre_maximal_vertical_pane_position = editor_summary_pane.get_position (); + pre_maximal_editor_width = this->get_width (); + pre_maximal_editor_height = this->get_height (); - if(post_maximal_pane_position == 0) { - post_maximal_pane_position = edit_pane.get_width(); + if (post_maximal_horizontal_pane_position == 0) { + post_maximal_horizontal_pane_position = edit_pane.get_width(); } - fullscreen(); + if (post_maximal_vertical_pane_position == 0) { + post_maximal_vertical_pane_position = editor_summary_pane.get_height(); + } + + fullscreen (); - if(post_maximal_editor_width) { - edit_pane.set_position (post_maximal_pane_position - + if (post_maximal_editor_width) { + edit_pane.set_position (post_maximal_horizontal_pane_position - abs(post_maximal_editor_width - pre_maximal_editor_width)); } else { - edit_pane.set_position (post_maximal_pane_position); + edit_pane.set_position (post_maximal_horizontal_pane_position); + } + + if (post_maximal_editor_height) { + editor_summary_pane.set_position (post_maximal_vertical_pane_position - + abs(post_maximal_editor_height - pre_maximal_editor_height)); + } else { + editor_summary_pane.set_position (post_maximal_vertical_pane_position); + } + + if (Config->get_keep_tearoffs()) { + _mouse_mode_tearoff->set_visible (true); + _tools_tearoff->set_visible (true); + _zoom_tearoff->set_visible (true); } } void Editor::restore_editing_space () { - // user changed width of pane during fullscreen + // user changed width/height of panes during fullscreen - if(post_maximal_pane_position != edit_pane.get_position()) { - post_maximal_pane_position = edit_pane.get_position(); + if (post_maximal_horizontal_pane_position != edit_pane.get_position()) { + post_maximal_horizontal_pane_position = edit_pane.get_position(); } + if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) { + post_maximal_vertical_pane_position = editor_summary_pane.get_position(); + } + unfullscreen(); - mouse_mode_tearoff->set_visible (true); - tools_tearoff->set_visible (true); + _mouse_mode_tearoff->set_visible (true); + _tools_tearoff->set_visible (true); + _zoom_tearoff->set_visible (true); post_maximal_editor_width = this->get_width(); + post_maximal_editor_height = this->get_height(); - edit_pane.set_position (pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)); + edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width)); + editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height)); } /** @@ -4000,7 +4294,7 @@ Editor::new_playlists (TimeAxisView* v) begin_reversible_command (_("new playlists")); vector > playlists; _session->playlists->get (playlists); - mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, RouteGroup::Edit); + mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id); commit_reversible_command (); } @@ -4016,7 +4310,7 @@ Editor::copy_playlists (TimeAxisView* v) begin_reversible_command (_("copy playlists")); vector > playlists; _session->playlists->get (playlists); - mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, RouteGroup::Edit); + mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id); commit_reversible_command (); } @@ -4031,7 +4325,7 @@ Editor::clear_playlists (TimeAxisView* v) begin_reversible_command (_("clear playlists")); vector > playlists; _session->playlists->get (playlists); - mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, RouteGroup::Edit); + mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id); commit_reversible_command (); } @@ -4066,10 +4360,12 @@ Editor::on_key_release_event (GdkEventKey* ev) // return key_press_focus_accelerator_handler (*this, ev); } +/** Queue up a change to the viewport x origin. + * @param frame New x origin. + */ void Editor::reset_x_origin (nframes64_t frame) { - //cerr << "resetting x origin" << endl; queue_visual_change (frame); } @@ -4088,7 +4384,6 @@ Editor::reset_zoom (double fpu) void Editor::reposition_and_zoom (nframes64_t frame, double fpu) { - //cerr << "Editor::reposition_and_zoom () called ha v:l:u:ps:fpu = " << horizontal_adjustment.get_value() << ":" << horizontal_adjustment.get_lower() << ":" << horizontal_adjustment.get_upper() << ":" << horizontal_adjustment.get_page_size() << ":" << frames_per_unit << endl;//DEBUG reset_x_origin (frame); reset_zoom (fpu); @@ -4122,10 +4417,11 @@ Editor::undo_visual_state () return; } + redo_visual_stack.push_back (current_visual_state()); + VisualState* vs = undo_visual_stack.back(); undo_visual_stack.pop_back(); use_visual_state (*vs); - redo_visual_stack.push_back (vs); } void @@ -4135,10 +4431,11 @@ Editor::redo_visual_state () return; } + undo_visual_stack.push_back (current_visual_state()); + VisualState* vs = redo_visual_stack.back(); redo_visual_stack.pop_back(); use_visual_state (*vs); - undo_visual_stack.push_back (vs); } void @@ -4217,8 +4514,6 @@ Editor::set_frames_per_unit (double fpu) void Editor::post_zoom () { - nframes64_t cef = 0; - // convert fpu to frame count nframes64_t frames = (nframes64_t) floor (frames_per_unit * _canvas_width); @@ -4233,15 +4528,8 @@ Editor::post_zoom () } } - leftmost_frame = (nframes64_t) floor (horizontal_adjustment.get_value() * frames_per_unit); - ZoomChanged (); /* EMIT_SIGNAL */ - if (_session) { - cef = _session->current_end_frame() + (current_page_frames() / 10);// Add a little extra so we can see the end marker - } - horizontal_adjustment.set_upper (cef / frames_per_unit); - //reset_scrolling_region (); if (playhead_cursor) { @@ -4258,17 +4546,7 @@ void Editor::queue_visual_change (nframes64_t where) { pending_visual_change.add (VisualChange::TimeOrigin); - - /* if we're moving beyond the end, make sure the upper limit of the horizontal adjustment - can reach. - */ - - if (_session && (where > _session->current_end_frame())) { - horizontal_adjustment.set_upper ((where + current_page_frames()) / frames_per_unit); - } - pending_visual_change.time_origin = where; - ensure_visual_change_idle_handler (); } @@ -4310,7 +4588,7 @@ Editor::idle_visual_changer () VisualChange::Type p = pending_visual_change.pending; pending_visual_change.pending = (VisualChange::Type) 0; - double last_time_origin = horizontal_adjustment.get_value(); + double last_time_origin = horizontal_position (); if (p & VisualChange::ZoomLevel) { set_frames_per_unit (pending_visual_change.frames_per_unit); @@ -4321,13 +4599,13 @@ Editor::idle_visual_changer () update_tempo_based_rulers (); } if (p & VisualChange::TimeOrigin) { - horizontal_adjustment.set_value (pending_visual_change.time_origin / frames_per_unit); + set_horizontal_position (pending_visual_change.time_origin / frames_per_unit); } if (p & VisualChange::YOrigin) { vertical_adjustment.set_value (pending_visual_change.y_origin); } - if (last_time_origin == horizontal_adjustment.get_value()) { + if (last_time_origin == horizontal_position ()) { /* changed signal not emitted */ update_fixed_rulers (); redisplay_tempo (true); @@ -4335,7 +4613,6 @@ Editor::idle_visual_changer () _summary->set_overlays_dirty (); - // cerr << "Editor::idle_visual_changer () called ha v:l:u:ps:fpu = " << horizontal_adjustment.get_value() << ":" << horizontal_adjustment.get_lower() << ":" << horizontal_adjustment.get_upper() << ":" << horizontal_adjustment.get_page_size() << ":" << frames_per_unit << endl;//DEBUG pending_visual_change.idle_handler_id = -1; return 0; /* this is always a one-shot call */ } @@ -4416,7 +4693,7 @@ Editor::set_loop_range (nframes64_t start, nframes64_t end, string cmd) Location* tll; if ((tll = transport_loop_location()) == 0) { - Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop); + Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop); XMLNode &before = _session->locations()->get_state(); _session->locations()->add (loc, true); _session->set_auto_loop_location (loc); @@ -4443,7 +4720,7 @@ Editor::set_punch_range (nframes64_t start, nframes64_t end, string cmd) Location* tpl; if ((tpl = transport_punch_location()) == 0) { - Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch); + Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch); XMLNode &before = _session->locations()->get_state(); _session->locations()->add (loc, true); _session->set_auto_loop_location (loc); @@ -4480,13 +4757,13 @@ Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackViewL for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) { RouteTimeAxisView* rtv = dynamic_cast(*t); if (rtv) { - boost::shared_ptr ds; + boost::shared_ptr tr; boost::shared_ptr pl; - if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) { + if ((tr = rtv->track()) && ((pl = tr->playlist()))) { Playlist::RegionList* regions = pl->regions_at ( - (nframes64_t) floor ( (double)where * ds->speed())); + (nframes64_t) floor ( (double)where * tr->speed())); for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { RegionView* rv = rtv->view()->find_view (*i); @@ -4515,13 +4792,13 @@ Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackVi for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) { RouteTimeAxisView* rtv = dynamic_cast(*t); if (rtv) { - boost::shared_ptr ds; + boost::shared_ptr tr; boost::shared_ptr pl; - if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) { + if ((tr = rtv->track()) && ((pl = tr->playlist()))) { Playlist::RegionList* regions = pl->regions_touched ( - (nframes64_t) floor ( (double)where * ds->speed()), max_frames); + (nframes64_t) floor ( (double)where * tr->speed()), max_frames); for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { @@ -4567,7 +4844,7 @@ Editor::get_regions_for_action (RegionSelection& rs, bool allow_entered, bool al for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) { RouteGroup* g = (*i)->get_time_axis_view().route_group (); - if (g && g->active_property (RouteGroup::Edit)) { + if (g && g->is_active() && g->is_edit()) { tracks.add (axis_views_from_routes (g->route_list())); } @@ -4593,14 +4870,14 @@ Editor::get_regions_corresponding_to (boost::shared_ptr region, vector pl; vector > results; RegionView* marv; - boost::shared_ptr ds; + boost::shared_ptr tr; - if ((ds = tatv->get_diskstream()) == 0) { + if ((tr = tatv->track()) == 0) { /* bus */ continue; } - if ((pl = (ds->playlist())) != 0) { + if ((pl = (tr->playlist())) != 0) { pl->get_region_list_equivalent_regions (region, results); } @@ -4626,16 +4903,6 @@ Editor::show_rhythm_ferret () rhythm_ferret->present (); } -void -Editor::show_global_port_matrix (ARDOUR::DataType t) -{ - if (_global_port_matrix[t] == 0) { - _global_port_matrix[t] = new GlobalPortMatrixWindow (_session, t); - } - - _global_port_matrix[t]->show (); -} - void Editor::first_idle () { @@ -4643,7 +4910,7 @@ Editor::first_idle () if (track_views.size() > 1) { dialog = new MessageDialog (*this, - _("Please wait while Ardour loads visual data"), + string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME), true, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE); @@ -4663,8 +4930,8 @@ Editor::first_idle () _have_idled = true; } -static gboolean -_idle_resizer (gpointer arg) +gboolean +Editor::_idle_resize (gpointer arg) { return ((Editor*)arg)->idle_resize (); } @@ -4673,7 +4940,7 @@ void Editor::add_to_idle_resize (TimeAxisView* view, int32_t h) { if (resize_idle_id < 0) { - resize_idle_id = g_idle_add (_idle_resizer, this); + resize_idle_id = g_idle_add (_idle_resize, this); _pending_resize_amount = 0; } @@ -4698,8 +4965,8 @@ Editor::add_to_idle_resize (TimeAxisView* view, int32_t h) } /* clamp */ - if (uint32_t (min_resulting) < TimeAxisView::hSmall) { - _pending_resize_amount += TimeAxisView::hSmall - min_resulting; + if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) { + _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting; } } @@ -4719,6 +4986,7 @@ Editor::idle_resize () } } + _pending_resize_amount = 0; flush_canvas (); _group_tabs->set_dirty (); resize_idle_id = -1; @@ -4731,7 +4999,13 @@ Editor::located () { ENSURE_GUI_THREAD (*this, &Editor::located); + playhead_cursor->set_position (_session->audible_frame ()); + if (_follow_playhead && !_pending_initial_locate) { + reset_x_origin_to_follow_playhead (); + } + _pending_locate_request = false; + _pending_initial_locate = false; } void @@ -4740,12 +5014,6 @@ Editor::region_view_added (RegionView *) _summary->set_dirty (); } -void -Editor::streamview_height_changed () -{ - _summary->set_dirty (); -} - TimeAxisView* Editor::axis_view_from_route (boost::shared_ptr r) const { @@ -4789,7 +5057,7 @@ Editor::handle_new_route (RouteList& routes) for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { boost::shared_ptr route = (*x); - if (route->is_hidden()) { + if (route->is_hidden() || route->is_monitor()) { continue; } @@ -4809,7 +5077,6 @@ Editor::handle_new_route (RouteList& routes) rtv->effective_gain_display (); rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added)); - rtv->view()->HeightChanged.connect (sigc::mem_fun (*this, &Editor::streamview_height_changed)); } _routes->routes_added (new_views); @@ -4832,14 +5099,22 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) } ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv); - + RouteTimeAxisView* rtav = dynamic_cast (tv); + _routes->route_removed (tv); if (tv == entered_track) { entered_track = 0; } - + + TimeAxisView::Children c = tv->get_child_list (); + for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) { + if (entered_track == i->get()) { + entered_track = 0; + } + } + /* remove it from the list of track views */ TrackViewList::iterator i; @@ -4851,7 +5126,6 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) /* update whatever the current mixer strip is displaying, if revelant */ boost::shared_ptr route; - RouteTimeAxisView* rtav = dynamic_cast (tv); if (rtav) { route = rtav->route (); @@ -4883,16 +5157,16 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) } void -Editor::hide_track_in_display (TimeAxisView& tv, bool /*temponly*/) +Editor::hide_track_in_display (TimeAxisView* tv, bool /*temponly*/) { - RouteTimeAxisView* rtv = dynamic_cast (&tv); + RouteTimeAxisView* rtv = dynamic_cast (tv); if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) { // this will hide the mixer strip - set_selected_mixer_strip (tv); + set_selected_mixer_strip (*tv); } - _routes->hide_track_in_display (tv); + _routes->hide_track_in_display (*tv); } bool @@ -4914,12 +5188,13 @@ Editor::foreach_time_axis_view (sigc::slot theslot) } } +/** Find a RouteTimeAxisView by the ID of its route */ RouteTimeAxisView* -Editor::get_route_view_by_id (PBD::ID& id) +Editor::get_route_view_by_route_id (PBD::ID& id) const { RouteTimeAxisView* v; - for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) { if((v = dynamic_cast(*i)) != 0) { if(v->route()->id() == id) { return v; @@ -4966,9 +5241,9 @@ Editor::hide_a_region (boost::shared_ptr r) } void -Editor::remove_a_region (boost::shared_ptr r) +Editor::show_a_region (boost::shared_ptr r) { - _session->remove_region_from_region_list (r); + r->set_hidden (false); } void @@ -4983,6 +5258,22 @@ Editor::hide_region_from_region_list () _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region)); } +void +Editor::show_region_in_region_list () +{ + _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region)); +} + +void +Editor::step_edit_status_change (bool yn) +{ + if (yn) { + start_step_editing (); + } else { + stop_step_editing (); + } +} + void Editor::start_step_editing () { @@ -5008,132 +5299,187 @@ Editor::check_step_edit () return true; // do it again, till we stop } -void -Editor::horizontal_scroll_left () +bool +Editor::horizontal_scroll_left_press () { + ++_scroll_callbacks; + + if (_scroll_connection.connected() && _scroll_callbacks < 5) { + /* delay the first auto-repeat */ + return true; + } + double x = leftmost_position() - current_page_frames() / 5; if (x < 0) { x = 0; } reset_x_origin (x); + + /* do hacky auto-repeat */ + if (!_scroll_connection.connected ()) { + _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press), 100); + _scroll_callbacks = 0; + } + + return true; } void -Editor::horizontal_scroll_right () +Editor::horizontal_scroll_left_release () { - reset_x_origin (leftmost_position() + current_page_frames() / 5); + _scroll_connection.disconnect (); } -void -Editor::update_current_screen () +bool +Editor::horizontal_scroll_right_press () { - if (_pending_locate_request) { - /* we don't update things when there's a pending locate request, otherwise - when the editor requests a locate there is a chance that this method - will move the playhead before the locate request is processed, causing - a visual glitch. */ - return; + ++_scroll_callbacks; + + if (_scroll_connection.connected() && _scroll_callbacks < 5) { + /* delay the first auto-repeat */ + return true; } - if (_session && _session->engine().running()) { - - nframes64_t const frame = _session->audible_frame(); - - if (_dragging_playhead) { - goto almost_done; - } - - /* only update if the playhead is on screen or we are following it */ + reset_x_origin (leftmost_position() + current_page_frames() / 5); - if (_follow_playhead && _session->requested_return_frame() < 0) { + /* do hacky auto-repeat */ + if (!_scroll_connection.connected ()) { + _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press), 100); + _scroll_callbacks = 0; + } - //playhead_cursor->canvas_item.show(); + return true; +} - if (frame != last_update_frame) { +void +Editor::horizontal_scroll_right_release () +{ + _scroll_connection.disconnect (); +} +/** Queue a change for the Editor viewport x origin to follow the playhead */ +void +Editor::reset_x_origin_to_follow_playhead () +{ + nframes64_t const frame = playhead_cursor->current_frame; -#undef CONTINUOUS_SCROLL -#ifndef CONTINUOUS_SCROLL - if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) { + if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) { - if (_session->transport_speed() < 0) { - if (frame > (current_page_frames()/2)) { - center_screen (frame-(current_page_frames()/2)); - } else { - center_screen (current_page_frames()/2); - } + if (_session->transport_speed() < 0) { + + if (frame > (current_page_frames() / 2)) { + center_screen (frame-(current_page_frames()/2)); + } else { + center_screen (current_page_frames()/2); + } + + } else { - } else { - - if (frame < leftmost_frame) { - /* moving left */ - nframes64_t l = 0; - if (_session->transport_rolling()) { - /* rolling; end up with the playhead at the right of the page */ - l = frame - current_page_frames (); - } else { - /* not rolling: end up with the playhead 3/4 of the way along the page */ - l = frame - (3 * current_page_frames() / 4); - } - - if (l < 0) { - l = 0; - } - - center_screen_internal (l + (current_page_frames() / 2), current_page_frames ()); - } else { - /* moving right */ - if (_session->transport_rolling()) { - /* rolling: end up with the playhead on the left of the page */ - center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ()); - } else { - /* not rolling: end up with the playhead 1/4 of the way along the page */ - center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ()); - } - } - } + if (frame < leftmost_frame) { + /* moving left */ + nframes64_t l = 0; + if (_session->transport_rolling()) { + /* rolling; end up with the playhead at the right of the page */ + l = frame - current_page_frames (); + } else { + /* not rolling: end up with the playhead 3/4 of the way along the page */ + l = frame - (3 * current_page_frames() / 4); } + + if (l < 0) { + l = 0; + } + + center_screen_internal (l + (current_page_frames() / 2), current_page_frames ()); + } else { + /* moving right */ + if (_session->transport_rolling()) { + /* rolling: end up with the playhead on the left of the page */ + center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ()); + } else { + /* not rolling: end up with the playhead 1/4 of the way along the page */ + center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ()); + } + } + } + } +} - playhead_cursor->set_position (frame); +void +Editor::super_rapid_screen_update () +{ + if (!_session || !_session->engine().running()) { + return; + } -#else // CONTINUOUS_SCROLL + /* METERING / MIXER STRIPS */ - /* don't do continuous scroll till the new position is in the rightmost quarter of the - editor canvas - */ + /* update track meters, if required */ + if (is_mapped() && meters_running) { + RouteTimeAxisView* rtv; + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + if ((rtv = dynamic_cast(*i)) != 0) { + rtv->fast_update (); + } + } + } - if (_session->transport_speed()) { - double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit; - if (target <= 0.0) target = 0.0; - if ( fabs(target - current) < current_page_frames()/frames_per_unit ) { - target = (target * 0.15) + (current * 0.85); - } else { - /* relax */ - } - //printf("frame: %d, cpf: %d, fpu: %6.6f, current: %6.6f, target : %6.6f\n", frame, current_page_frames(), frames_per_unit, current, target ); - current = target; - horizontal_adjustment.set_value ( current ); - } + /* and any current mixer strip */ + if (current_mixer_strip) { + current_mixer_strip->fast_update (); + } - playhead_cursor->set_position (frame); + /* PLAYHEAD AND VIEWPORT */ -#endif // CONTINUOUS_SCROLL + nframes64_t const frame = _session->audible_frame(); - } + /* There are a few reasons why we might not update the playhead / viewport stuff: + * + * 1. we don't update things when there's a pending locate request, otherwise + * when the editor requests a locate there is a chance that this method + * will move the playhead before the locate request is processed, causing + * a visual glitch. + * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere). + * 3. if we're still at the same frame that we were last time, there's nothing to do. + */ - } else { - if (frame != last_update_frame) { - playhead_cursor->set_position (frame); - } - } + if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) { - almost_done: last_update_frame = frame; - if (current_mixer_strip) { - current_mixer_strip->fast_update (); + + if (!_dragging_playhead) { + playhead_cursor->set_position (frame); } + if (!_stationary_playhead) { + + if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) { + reset_x_origin_to_follow_playhead (); + } + + } else { + + /* don't do continuous scroll till the new position is in the rightmost quarter of the + editor canvas + */ +#if 0 + // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code + double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit; + if (target <= 0.0) { + target = 0.0; + } + if (fabs(target - current) < current_page_frames() / frames_per_unit) { + target = (target * 0.15) + (current * 0.85); + } else { + /* relax */ + } + + current = target; + set_horizontal_position (current); +#endif + } + } } @@ -5145,7 +5491,8 @@ Editor::session_going_away () _session_connections.drop_connections (); - stop_scrolling (); + super_rapid_screen_update_connection.disconnect (); + selection->clear (); cut_buffer->clear (); @@ -5219,3 +5566,41 @@ Editor::show_editor_list (bool yn) the_notebook.hide(); } } + +void +Editor::change_region_layering_order (framepos_t position) +{ + if (!clicked_routeview) { + if (layering_order_editor) { + layering_order_editor->hide (); + } + return; + } + + boost::shared_ptr track = boost::dynamic_pointer_cast (clicked_routeview->route()); + + if (!track) { + return; + } + + boost::shared_ptr pl = track->playlist(); + + if (!pl) { + return; + } + + if (layering_order_editor == 0) { + layering_order_editor = new RegionLayeringOrderEditor(*this); + } + + layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position); + layering_order_editor->maybe_present (); +} + +void +Editor::update_region_layering_order_editor (framepos_t frame) +{ + if (layering_order_editor && layering_order_editor->is_visible ()) { + change_region_layering_order (frame); + } +}