X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=1c9c613e4b72ffdafef6660ff62bd3cbf2a6cfb5;hb=82be348d429b97f3e223b3a5b1c6807d23fcdaa0;hp=c118a2ee76f7d70cc259e862655c3c9f718c519a;hpb=a0723271459cd3124a3ded4a961fd0d90ddc3aa3;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index c118a2ee76..1c9c613e4b 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -43,6 +43,8 @@ #include "pbd/enumwriter.h" #include "pbd/memento_command.h" #include "pbd/unknown_type.h" +#include "pbd/unwind.h" +#include "pbd/stacktrace.h" #include #include @@ -59,20 +61,14 @@ #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h" #include "ardour/audio_track.h" -#include "ardour/audioplaylist.h" +#include "ardour/audioengine.h" #include "ardour/audioregion.h" #include "ardour/location.h" -#include "ardour/midi_region.h" -#include "ardour/plugin_manager.h" #include "ardour/profile.h" #include "ardour/route_group.h" -#include "ardour/session_directory.h" -#include "ardour/session_route.h" -#include "ardour/session_state_utils.h" +#include "ardour/session_playlists.h" #include "ardour/tempo.h" #include "ardour/utils.h" -#include "ardour/session_playlists.h" -#include "ardour/audioengine.h" #include "control_protocol/control_protocol.h" @@ -88,7 +84,6 @@ #include "canvas-noevent-text.h" #include "canvas_impl.h" #include "crossfade_edit.h" -#include "crossfade_view.h" #include "debug.h" #include "editing.h" #include "editor.h" @@ -149,6 +144,8 @@ static const gchar *_snap_type_strings[] = { N_("Timecode Minutes"), N_("Seconds"), N_("Minutes"), + N_("Beats/128"), + N_("Beats/64"), N_("Beats/32"), N_("Beats/28"), N_("Beats/24"), @@ -211,24 +208,22 @@ static const gchar *_rb_opt_strings[] = { }; #endif -void -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. + it is: + + X: hard to access + Quartz: impossible to access + + so stop that by preventing it from ever getting too narrow. 35 + pixels is basically a rough guess at the tab width. ugh. */ - int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25; + int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35; gint pos = pane->get_position (); @@ -236,7 +231,6 @@ pane_size_watcher (Paned* pane) pane->set_position (max_width_of_lhs); } } -#endif Editor::Editor () : _join_object_range_state (JOIN_OBJECT_RANGE_NONE) @@ -284,6 +278,8 @@ Editor::Editor () , _region_selection_change_updates_region_list (true) , _following_mixer_selection (false) + , _control_point_toggled_on_press (false) + , _stepping_axis_view (0) { constructed = false; @@ -299,7 +295,6 @@ Editor::Editor () clicked_regionview = 0; clicked_axisview = 0; clicked_routeview = 0; - clicked_crossfadeview = 0; clicked_control_point = 0; last_update_frame = 0; pre_press_cursor = 0; @@ -330,12 +325,12 @@ Editor::Editor () current_interthread_info = 0; _show_measures = true; + _maximised = false; show_gain_after_trim = false; 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; @@ -365,6 +360,7 @@ Editor::Editor () layering_order_editor = 0; no_save_visual = false; resize_idle_id = -1; + within_track_canvas = false; scrubbing_direction = 0; @@ -388,67 +384,67 @@ Editor::Editor () set_zoom_focus (ZoomFocusLeft); zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed)); - bbt_label.set_name ("EditorTimeButton"); + bbt_label.set_name ("EditorRulerLabel"); bbt_label.set_size_request (-1, (int)timebar_height); bbt_label.set_alignment (1.0, 0.5); bbt_label.set_padding (5,0); bbt_label.hide (); bbt_label.set_no_show_all(); - minsec_label.set_name ("EditorTimeButton"); + minsec_label.set_name ("EditorRulerLabel"); minsec_label.set_size_request (-1, (int)timebar_height); minsec_label.set_alignment (1.0, 0.5); minsec_label.set_padding (5,0); minsec_label.hide (); minsec_label.set_no_show_all(); - timecode_label.set_name ("EditorTimeButton"); + timecode_label.set_name ("EditorRulerLabel"); timecode_label.set_size_request (-1, (int)timebar_height); timecode_label.set_alignment (1.0, 0.5); timecode_label.set_padding (5,0); timecode_label.hide (); timecode_label.set_no_show_all(); - samples_label.set_name ("EditorTimeButton"); + samples_label.set_name ("EditorRulerLabel"); samples_label.set_size_request (-1, (int)timebar_height); samples_label.set_alignment (1.0, 0.5); samples_label.set_padding (5,0); samples_label.hide (); samples_label.set_no_show_all(); - tempo_label.set_name ("EditorTimeButton"); + tempo_label.set_name ("EditorRulerLabel"); tempo_label.set_size_request (-1, (int)timebar_height); tempo_label.set_alignment (1.0, 0.5); tempo_label.set_padding (5,0); tempo_label.hide(); tempo_label.set_no_show_all(); - meter_label.set_name ("EditorTimeButton"); + meter_label.set_name ("EditorRulerLabel"); meter_label.set_size_request (-1, (int)timebar_height); meter_label.set_alignment (1.0, 0.5); meter_label.set_padding (5,0); meter_label.hide(); meter_label.set_no_show_all(); - mark_label.set_name ("EditorTimeButton"); + mark_label.set_name ("EditorRulerLabel"); mark_label.set_size_request (-1, (int)timebar_height); mark_label.set_alignment (1.0, 0.5); mark_label.set_padding (5,0); mark_label.hide(); mark_label.set_no_show_all(); - cd_mark_label.set_name ("EditorTimeButton"); + cd_mark_label.set_name ("EditorRulerLabel"); cd_mark_label.set_size_request (-1, (int)timebar_height); cd_mark_label.set_alignment (1.0, 0.5); cd_mark_label.set_padding (5,0); cd_mark_label.hide(); cd_mark_label.set_no_show_all(); - range_mark_label.set_name ("EditorTimeButton"); + range_mark_label.set_name ("EditorRulerLabel"); range_mark_label.set_size_request (-1, (int)timebar_height); range_mark_label.set_alignment (1.0, 0.5); range_mark_label.set_padding (5,0); range_mark_label.hide(); range_mark_label.set_no_show_all(); - transport_mark_label.set_name ("EditorTimeButton"); + transport_mark_label.set_name ("EditorRulerLabel"); transport_mark_label.set_size_request (-1, (int)timebar_height); transport_mark_label.set_alignment (1.0, 0.5); transport_mark_label.set_padding (5,0); @@ -545,7 +541,7 @@ Editor::Editor () add_notebook_page (_("Regions"), _regions->widget ()); add_notebook_page (_("Tracks & Busses"), _routes->widget ()); add_notebook_page (_("Snapshots"), _snapshots->widget ()); - add_notebook_page (_("Route Groups"), _route_groups->widget ()); + add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ()); add_notebook_page (_("Ranges & Marks"), _locations->widget ()); _the_notebook.set_show_tabs (true); @@ -554,10 +550,6 @@ Editor::Editor () _the_notebook.set_tab_pos (Gtk::POS_RIGHT); _the_notebook.show_all (); - post_maximal_editor_width = 0; - post_maximal_horizontal_pane_position = 0; - post_maximal_editor_height = 0; - post_maximal_vertical_pane_position = 0; _notebook_shrunk = false; editor_summary_pane.pack1(edit_packer); @@ -607,13 +599,13 @@ Editor::Editor () 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 */ + /* XXX: editor_summary_pane might need similar 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); HBox *hbox = manage (new HBox); @@ -648,20 +640,26 @@ Editor::Editor () set_snap_mode (_snap_mode); set_mouse_mode (MouseObject, true); pre_internal_mouse_mode = MouseObject; + pre_internal_snap_type = _snap_type; + pre_internal_snap_mode = _snap_mode; + internal_snap_type = _snap_type; + internal_snap_mode = _snap_mode; set_edit_point_preference (EditAtMouse, true); _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, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context()); + RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::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"))))); + nudge_forward_button.set_name ("zoom button"); + nudge_forward_button.add_elements (ArdourButton::FlatFace); + nudge_forward_button.set_image(::get_icon("nudge_right")); - nudge_forward_button.set_name ("TransportButton"); - nudge_backward_button.set_name ("TransportButton"); + nudge_backward_button.set_name ("zoom button"); + nudge_backward_button.add_elements (ArdourButton::FlatFace); + nudge_backward_button.set_image(::get_icon("nudge_left")); fade_context_menu.set_name ("ArdourContextMenu"); @@ -698,22 +696,40 @@ Editor::Editor () signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler)); signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close)); + Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released)); + /* allow external control surfaces/protocols to do various things */ 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()); - ControlProtocol::SelectByRID.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1), gui_context()); - BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context()); + ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context()); + ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context()); + ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context()); + ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context()); + ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context()); + ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context()); + ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context()); + ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context()); + ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context()); + ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context()); + ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context()); + + ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context()); + ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context()); + ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context()); + ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context()); + ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context()); + + BasicUI::AccessAction.connect (*this, invalidator (*this), boost::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, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context()); + Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context()); - TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context()); + TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context()); _ignore_region_action = false; _last_region_menu_was_main = false; @@ -767,7 +783,6 @@ Editor::button_settings () const XMLNode* node = find_named_node (*settings, X_("Buttons")); if (!node) { - cerr << "new empty Button node\n"; node = new XMLNode (X_("Buttons")); } @@ -781,6 +796,12 @@ Editor::add_toplevel_controls (Container& cont) cont.show_all (); } +bool +Editor::get_smart_mode () const +{ + return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() ); +} + void Editor::catch_vanishing_regionview (RegionView *rv) { @@ -901,12 +922,9 @@ Editor::zoom_adjustment_changed () } double fpu = zoom_range_clock->current_duration() / _canvas_width; - - if (fpu < 1.0) { - fpu = 1.0; - zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width)); - } else if (fpu > _session->current_end_frame() / _canvas_width) { - fpu = _session->current_end_frame() / _canvas_width; + bool clamped = clamp_frames_per_unit (fpu); + + if (clamped) { zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width)); } @@ -914,7 +932,43 @@ Editor::zoom_adjustment_changed () } void -Editor::control_select (uint32_t rid) +Editor::control_vertical_zoom_in_all () +{ + tav_zoom_smooth (false, true); +} + +void +Editor::control_vertical_zoom_out_all () +{ + tav_zoom_smooth (true, true); +} + +void +Editor::control_vertical_zoom_in_selected () +{ + tav_zoom_smooth (false, false); +} + +void +Editor::control_vertical_zoom_out_selected () +{ + tav_zoom_smooth (true, false); +} + +void +Editor::control_view (uint32_t view) +{ + goto_visual_state (view); +} + +void +Editor::control_unselect () +{ + selection->clear_tracks (); +} + +void +Editor::control_select (uint32_t rid, Selection::Operation op) { /* handles the (static) signal from the ControlProtocol class that * requests setting the selected track to a given RID @@ -933,12 +987,36 @@ Editor::control_select (uint32_t rid) TimeAxisView* tav = axis_view_from_route (r); if (tav) { - selection->set (tav); + switch (op) { + case Selection::Add: + selection->add (tav); + break; + case Selection::Toggle: + selection->toggle (tav); + break; + case Selection::Extend: + break; + case Selection::Set: + selection->set (tav); + break; + } } else { selection->clear_tracks (); } } +void +Editor::control_step_tracks_up () +{ + scroll_tracks_up_line (); +} + +void +Editor::control_step_tracks_down () +{ + scroll_tracks_down_line (); +} + void Editor::control_scroll (float fraction) { @@ -1102,6 +1180,8 @@ Editor::update_title () WindowTitle title(session_name); title += Glib::get_application_name(); set_title (title.get_string()); + } else { + /* ::session_going_away() will have taken care of it */ } } @@ -1192,35 +1272,21 @@ Editor::set_session (Session *t) but use Gtkmm2ext::UI::instance()->call_slot(); */ - _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context()); + _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::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->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context()); + _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context()); _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context()); - _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context()); + _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::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->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context()); + _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context()); + _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context()); + _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::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, this), gui_context()); + _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context()); _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context()); - if (Profile->get_sae()) { - Timecode::BBT_Time bbt; - bbt.bars = 0; - bbt.beats = 0; - bbt.ticks = 120; - framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1); - nudge_clock->set_mode(AudioClock::BBT); - nudge_clock->set (pos, true); - - } else { - nudge_clock->set_mode (AudioClock::Timecode); - nudge_clock->set (_session->frame_rate() * 5, true); - } - playhead_cursor->canvas_item.show (); boost::function pc (boost::bind (&Editor::parameter_changed, this, _1)); @@ -1276,6 +1342,101 @@ Editor::action_pre_activated (Glib::RefPtr const & a) } } +void +Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start) +{ + using namespace Menu_Helpers; + + void (Editor::*emf)(FadeShape); + std::map* images; + + if (start) { + images = &_xfade_in_images; + emf = &Editor::set_fade_in_shape; + } else { + images = &_xfade_out_images; + emf = &Editor::set_fade_out_shape; + } + + items.push_back ( + ImageMenuElem ( + _("Linear (for highly correlated material)"), + *(*images)[FadeLinear], + sigc::bind (sigc::mem_fun (*this, emf), FadeLinear) + ) + ); + + dynamic_cast(&items.back())->set_always_show_image (); + + items.push_back ( + ImageMenuElem ( + _("Constant power"), + *(*images)[FadeConstantPower], + sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower) + )); + + dynamic_cast(&items.back())->set_always_show_image (); + + items.push_back ( + ImageMenuElem ( + _("Symmetric"), + *(*images)[FadeSymmetric], + sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric) + ) + ); + + dynamic_cast(&items.back())->set_always_show_image (); + + items.push_back ( + ImageMenuElem ( + _("Slow"), + *(*images)[FadeSlow], + sigc::bind (sigc::mem_fun (*this, emf), FadeSlow) + )); + + dynamic_cast(&items.back())->set_always_show_image (); + + items.push_back ( + ImageMenuElem ( + _("Fast"), + *(*images)[FadeFast], + sigc::bind (sigc::mem_fun (*this, emf), FadeFast) + )); + + dynamic_cast(&items.back())->set_always_show_image (); +} + +/** Pop up a context menu for when the user clicks on a start crossfade */ +void +Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/) +{ + using namespace Menu_Helpers; + + MenuList& items (xfade_in_context_menu.items()); + + if (items.empty()) { + fill_xfade_menu (items, true); + } + + xfade_in_context_menu.popup (button, time); +} + +/** Pop up a context menu for when the user clicks on an end crossfade */ +void +Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/) +{ + using namespace Menu_Helpers; + + MenuList& items (xfade_out_context_menu.items()); + + if (items.empty()) { + fill_xfade_menu (items, false); + } + + xfade_out_context_menu.popup (button, time); +} + + /** Pop up a context menu for when the user clicks on a fade in or fade out */ void Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type) @@ -1289,7 +1450,6 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i } MenuList& items (fade_context_menu.items()); - items.clear (); switch (item_type) { @@ -1300,16 +1460,16 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i } else { items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true))); } - + items.push_back (SeparatorElem()); - + if (Profile->get_sae()) { - + items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear))); items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast))); - + } else { - + items.push_back ( ImageMenuElem ( _("Linear"), @@ -1317,41 +1477,39 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear) ) ); - + dynamic_cast(&items.back())->set_always_show_image (); - + items.push_back ( ImageMenuElem ( - _("Slowest"), - *_fade_in_images[FadeFast], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast) + _("Slow"), + *_fade_in_images[FadeSlow], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow) )); - + dynamic_cast(&items.back())->set_always_show_image (); - + items.push_back ( ImageMenuElem ( - _("Slow"), - *_fade_in_images[FadeLogB], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB) + _("Fast"), + *_fade_in_images[FadeFast], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast) )); - + dynamic_cast(&items.back())->set_always_show_image (); - + items.push_back ( ImageMenuElem ( - _("Fast"), - *_fade_in_images[FadeLogA], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA) + _("Symmetric"), + *_fade_in_images[FadeSymmetric], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric) )); - - dynamic_cast(&items.back())->set_always_show_image (); - + items.push_back ( ImageMenuElem ( - _("Fastest"), - *_fade_in_images[FadeSlow], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow) + _("Constant power"), + *_fade_in_images[FadeConstantPower], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower) )); dynamic_cast(&items.back())->set_always_show_image (); @@ -1386,8 +1544,8 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i items.push_back ( ImageMenuElem ( - _("Slowest"), - *_fade_out_images[FadeFast], + _("Slow"), + *_fade_out_images[FadeSlow], sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow) )); @@ -1395,27 +1553,25 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i items.push_back ( ImageMenuElem ( - _("Slow"), - *_fade_out_images[FadeLogB], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA) + _("Fast"), + *_fade_out_images[FadeFast], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast) )); dynamic_cast(&items.back())->set_always_show_image (); items.push_back ( ImageMenuElem ( - _("Fast"), - *_fade_out_images[FadeLogA], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB) + _("Symmetric"), + *_fade_out_images[FadeSymmetric], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric) )); - dynamic_cast(&items.back())->set_always_show_image (); - items.push_back ( ImageMenuElem ( - _("Fastest"), - *_fade_out_images[FadeSlow], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast) + _("Constant power"), + *_fade_out_images[FadeConstantPower], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower) )); dynamic_cast(&items.back())->set_always_show_image (); @@ -1461,10 +1617,6 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, } break; - case CrossfadeViewItem: - build_menu_function = &Editor::build_track_crossfade_context_menu; - break; - case StreamItem: if (clicked_routeview->track()) { build_menu_function = &Editor::build_track_context_menu; @@ -1510,9 +1662,6 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, case SelectionItem: break; - case CrossfadeViewItem: - break; - case StreamItem: break; @@ -1597,11 +1746,6 @@ Editor::build_track_region_context_menu () region_edit_menu_split_item = 0; region_edit_menu_split_multichannel_item = 0; - /* we might try to use items that are currently attached to a crossfade menu, - so clear that, too. - */ - track_crossfade_context_menu.items().clear (); - RouteTimeAxisView* rtv = dynamic_cast (clicked_axisview); if (rtv) { @@ -1618,54 +1762,6 @@ Editor::build_track_region_context_menu () return &track_region_context_menu; } -Menu* -Editor::build_track_crossfade_context_menu () -{ - using namespace Menu_Helpers; - MenuList& edit_items = track_crossfade_context_menu.items(); - edit_items.clear (); - - /* we might try to use items that are currently attached to a crossfade menu, - so clear that, too. - */ - track_region_context_menu.items().clear (); - - AudioTimeAxisView* atv = dynamic_cast (clicked_axisview); - - if (atv) { - boost::shared_ptr tr; - boost::shared_ptr pl; - boost::shared_ptr apl; - - if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast (pl)) != 0)) { - - AudioPlaylist::Crossfades xfades; - framepos_t where; - bool ignored; - - /* The xfade menu is a bit of a special case, as we always use the mouse position - to decide whether or not to display it (rather than the edit point). No particularly - strong reasons for this, other than it is a bit surprising to right-click on a xfade - and not get a menu. - */ - mouse_frame (where, ignored); - apl->crossfades_at (where, xfades); - - bool const many = xfades.size() > 1; - - for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) { - add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many); - } - - add_region_context_items (edit_items, tr); - } - } - - add_dstream_context_items (edit_items); - - return &track_crossfade_context_menu; -} - void Editor::analyze_region_selection () { @@ -1716,66 +1812,6 @@ Editor::build_track_selection_context_menu () return &track_selection_context_menu; } -/** Add context menu items relevant to crossfades. - * @param edit_items List to add the items to. - */ -void -Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr xfade, Menu_Helpers::MenuList& edit_items, bool many) -{ - using namespace Menu_Helpers; - Menu *xfade_menu = manage (new Menu); - MenuList& items = xfade_menu->items(); - xfade_menu->set_name ("ArdourContextMenu"); - string str; - - if (xfade->active()) { - str = _("Mute"); - } else { - str = _("Unmute"); - } - - 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)))); - - if (xfade->can_follow_overlap()) { - - if (xfade->following_overlap()) { - str = _("Convert to Short"); - } else { - str = _("Convert to Full"); - } - - items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade))); - } - - if (many) { - str = xfade->out()->name(); - str += "->"; - str += xfade->in()->name(); - } else { - str = _("Crossfade"); - } - - edit_items.push_back (MenuElem (str, *xfade_menu)); - edit_items.push_back (SeparatorElem()); -} - -void -Editor::xfade_edit_left_region () -{ - if (clicked_crossfadeview) { - clicked_crossfadeview->left_view.show_region_editor (); - } -} - -void -Editor::xfade_edit_right_region () -{ - if (clicked_crossfadeview) { - clicked_crossfadeview->right_view.show_region_editor (); - } -} - void Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr track) { @@ -1877,7 +1913,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) edit_items.push_back (SeparatorElem()); edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection))); edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection))); - edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false))); + edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false))); edit_items.push_back (SeparatorElem()); edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false))); @@ -1961,10 +1997,10 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) nudge_menu->set_name ("ArdourContextMenu"); edit_items.push_back (SeparatorElem()); - nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true)))); - nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true)))); - nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false)))); - nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false)))); + nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true)))); + nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true)))); + nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false)))); + nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false)))); edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu)); } @@ -2017,10 +2053,10 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items) nudge_menu->set_name ("ArdourContextMenu"); edit_items.push_back (SeparatorElem()); - nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true)))); - nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true)))); - nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false)))); - nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false)))); + nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true)))); + nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true)))); + nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false)))); + nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false)))); edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu)); } @@ -2058,6 +2094,8 @@ Editor::set_snap_to (SnapType st) instant_save (); switch (_snap_type) { + case SnapToBeatDiv128: + case SnapToBeatDiv64: case SnapToBeatDiv32: case SnapToBeatDiv28: case SnapToBeatDiv24: @@ -2072,10 +2110,17 @@ Editor::set_snap_to (SnapType st) case SnapToBeatDiv5: case SnapToBeatDiv4: case SnapToBeatDiv3: - case SnapToBeatDiv2: - compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames()); - update_tempo_based_rulers (); + case SnapToBeatDiv2: { + ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin; + ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end; + + compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(), + current_bbt_points_begin, current_bbt_points_end); + compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(), + current_bbt_points_begin, current_bbt_points_end); + update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end); break; + } case SnapToRegionStart: case SnapToRegionEnd: @@ -2095,9 +2140,16 @@ Editor::set_snap_to (SnapType st) void Editor::set_snap_mode (SnapMode mode) { - _snap_mode = mode; string str = snap_mode_strings[(int)mode]; + if (_internal_editing) { + internal_snap_mode = mode; + } else { + pre_internal_snap_mode = mode; + } + + _snap_mode = mode; + if (str != snap_mode_selector.get_active_text ()) { snap_mode_selector.set_active_text (str); } @@ -2216,7 +2268,7 @@ Editor::set_state (const XMLNode& node, int /*version*/) } if ((prop = node.property ("zoom-focus"))) { - set_zoom_focus ((ZoomFocus) atoi (prop->value())); + set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus)); } if ((prop = node.property ("zoom"))) { @@ -2226,11 +2278,28 @@ Editor::set_state (const XMLNode& node, int /*version*/) } if ((prop = node.property ("snap-to"))) { - set_snap_to ((SnapType) atoi (prop->value())); + set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type)); } if ((prop = node.property ("snap-mode"))) { - set_snap_mode ((SnapMode) atoi (prop->value())); + set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode)); + } + + if ((prop = node.property ("internal-snap-to"))) { + internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type); + } + + if ((prop = node.property ("internal-snap-mode"))) { + internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode); + } + + if ((prop = node.property ("pre-internal-snap-to"))) { + pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type); + } + + + if ((prop = node.property ("pre-internal-snap-mode"))) { + pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode); } if ((prop = node.property ("mouse-mode"))) { @@ -2243,6 +2312,9 @@ Editor::set_state (const XMLNode& node, int /*version*/) if ((prop = node.property ("left-frame")) != 0) { framepos_t pos; if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) { + if (pos < 0) { + pos = 0; + } reset_x_origin (pos); } } @@ -2262,7 +2334,14 @@ Editor::set_state (const XMLNode& node, int /*version*/) } if ((prop = node.property ("join-object-range"))) { - join_object_range_button.set_active (string_is_affirmative (prop->value ())); + RefPtr act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range")); + bool yn = string_is_affirmative (prop->value()); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + tact->set_active (!yn); + tact->set_active (yn); + } + set_mouse_mode(mouse_mode, true); } if ((prop = node.property ("edit-point"))) { @@ -2310,12 +2389,6 @@ Editor::set_state (const XMLNode& node, int /*version*/) _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true); } - if ((prop = node.property ("xfades-visible"))) { - bool yn = string_is_affirmative (prop->value()); - _xfade_visibility = !yn; - // set_xfade_visibility (yn); - } - if ((prop = node.property ("show-editor-mixer"))) { Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer")); @@ -2364,6 +2437,22 @@ Editor::set_state (const XMLNode& node, int /*version*/) _regions->set_state (**i); } + if ((prop = node.property ("maximised"))) { + bool yn = string_is_affirmative (prop->value()); + if (yn) { + ActionManager::do_action ("Common", "ToggleMaximalEditor"); + } + } + + if ((prop = node.property ("nudge-clock-value"))) { + framepos_t f; + sscanf (prop->value().c_str(), "%" PRId64, &f); + nudge_clock->set (f); + } else { + nudge_clock->set_mode (AudioClock::Timecode); + nudge_clock->set (_session->frame_rate() * 5, true); + } + return 0; } @@ -2396,8 +2485,6 @@ Editor::get_state () snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast(&edit_pane)->gobj())); geometry->add_property("edit-horizontal-pane-pos", string(buf)); geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0"); - snprintf(buf,sizeof(buf), "%d",pre_maximal_horizontal_pane_position); - geometry->add_property("pre-maximal-horizontal-pane-position", 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)); @@ -2406,15 +2493,15 @@ Editor::get_state () maybe_add_mixer_strip_width (*node); - snprintf (buf, sizeof(buf), "%d", (int) zoom_focus); - node->add_property ("zoom-focus", buf); + node->add_property ("zoom-focus", enum_2_string (zoom_focus)); snprintf (buf, sizeof(buf), "%f", frames_per_unit); node->add_property ("zoom", buf); - snprintf (buf, sizeof(buf), "%d", (int) _snap_type); - node->add_property ("snap-to", buf); - snprintf (buf, sizeof(buf), "%d", (int) _snap_mode); - node->add_property ("snap-mode", buf); - + node->add_property ("snap-to", enum_2_string (_snap_type)); + node->add_property ("snap-mode", enum_2_string (_snap_mode)); + node->add_property ("internal-snap-to", enum_2_string (internal_snap_type)); + node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode)); + node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type)); + node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode)); node->add_property ("edit-point", enum_2_string (_edit_point)); snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame); @@ -2425,13 +2512,13 @@ Editor::get_state () node->add_property ("y-origin", buf); node->add_property ("show-measures", _show_measures ? "yes" : "no"); + node->add_property ("maximised", _maximised ? "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)); node->add_property ("internal-edit", _internal_editing ? "yes" : "no"); - node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no"); + node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no"); Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer")); if (act) { @@ -2459,6 +2546,9 @@ Editor::get_state () node->add_child_nocopy (selection->get_state ()); node->add_child_nocopy (_regions->get_state ()); + snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration()); + node->add_property ("nudge-clock-value", buf); + return *node; } @@ -2620,6 +2710,12 @@ Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark) start = _session->tempo_map().round_to_beat (start, direction); break; + case SnapToBeatDiv128: + start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction); + break; + case SnapToBeatDiv64: + start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction); + break; case SnapToBeatDiv32: start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction); break; @@ -2673,7 +2769,10 @@ Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark) _session->locations()->marks_either_side (start, before, after); - if (before == max_framepos) { + if (before == max_framepos && after == max_framepos) { + /* No marks to snap to, so just don't snap */ + return; + } else if (before == max_framepos) { start = after; } else if (after == max_framepos) { start = before; @@ -2752,29 +2851,43 @@ Editor::setup_toolbar () mode_box->set_border_width (2); mode_box->set_spacing(4); - /* table containing mode buttons */ + HBox* mouse_mode_box = manage (new HBox); + HBox* mouse_mode_hbox = manage (new HBox); + VBox* mouse_mode_vbox = manage (new VBox); + Alignment* mouse_mode_align = manage (new Alignment); - HBox* mouse_mode_button_box = manage (new HBox ()); - mouse_mode_button_box->set_spacing (2); + Glib::RefPtr mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH); +// mouse_mode_size_group->add_widget (smart_mode_button); + mouse_mode_size_group->add_widget (mouse_move_button); + mouse_mode_size_group->add_widget (mouse_select_button); + mouse_mode_size_group->add_widget (mouse_zoom_button); + mouse_mode_size_group->add_widget (mouse_gain_button); + mouse_mode_size_group->add_widget (mouse_timefx_button); + mouse_mode_size_group->add_widget (mouse_audition_button); + mouse_mode_size_group->add_widget (mouse_draw_button); + mouse_mode_size_group->add_widget (internal_edit_button); - if (Profile->get_sae()) { - mouse_mode_button_box->pack_start (mouse_move_button); - } else { - 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); - } + /* make them just a bit bigger */ + mouse_move_button.set_size_request (-1, 30); - mouse_mode_button_box->pack_start (mouse_zoom_button); + mouse_mode_hbox->set_spacing (2); - if (!Profile->get_sae()) { - mouse_mode_button_box->pack_start (mouse_gain_button); - } + mouse_mode_hbox->pack_start (smart_mode_button, false, false); + mouse_mode_hbox->pack_start (mouse_move_button, false, false); + mouse_mode_hbox->pack_start (mouse_select_button, false, false); + mouse_mode_hbox->pack_start (mouse_zoom_button, false, false); + mouse_mode_hbox->pack_start (mouse_gain_button, false, false); + mouse_mode_hbox->pack_start (mouse_timefx_button, false, false); + mouse_mode_hbox->pack_start (mouse_audition_button, false, false); + mouse_mode_hbox->pack_start (mouse_draw_button, false, false); + mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8); - mouse_mode_button_box->pack_start (mouse_timefx_button); - mouse_mode_button_box->pack_start (mouse_audition_button); - mouse_mode_button_box->pack_start (mouse_draw_button); - mouse_mode_button_box->pack_start (internal_edit_button); + mouse_mode_vbox->pack_start (*mouse_mode_hbox); + + mouse_mode_align->add (*mouse_mode_vbox); + mouse_mode_align->set (0.5, 1.0, 0.0, 0.0); + + mouse_mode_box->pack_start (*mouse_mode_align, false, false); edit_mode_strings.push_back (edit_mode_to_string (Slide)); if (!Profile->get_sae()) { @@ -2787,7 +2900,7 @@ 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, false, false); - mode_box->pack_start (*mouse_mode_button_box, false, false); + mode_box->pack_start (*mouse_mode_box, false, false); _mouse_mode_tearoff = manage (new TearOff (*mode_box)); _mouse_mode_tearoff->set_name ("MouseModeBase"); @@ -2814,20 +2927,23 @@ Editor::setup_toolbar () RefPtr act; zoom_in_button.set_name ("zoom button"); - zoom_in_button.set_image (::get_icon ("zoom_in")); - zoom_in_button.set_tweaks (ArdourButton::ShowClick); + zoom_in_button.add_elements ( ArdourButton::FlatFace ); + zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); + zoom_in_button.set_image(::get_icon ("zoom_in")); act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in")); zoom_in_button.set_related_action (act); zoom_out_button.set_name ("zoom button"); - zoom_out_button.set_image (::get_icon ("zoom_out")); - zoom_out_button.set_tweaks (ArdourButton::ShowClick); + zoom_out_button.add_elements ( ArdourButton::FlatFace ); + zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); + zoom_out_button.set_image(::get_icon ("zoom_out")); act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out")); zoom_out_button.set_related_action (act); zoom_out_full_button.set_name ("zoom button"); - zoom_out_full_button.set_image (::get_icon ("zoom_full")); - zoom_out_full_button.set_tweaks (ArdourButton::ShowClick); + zoom_out_full_button.add_elements ( ArdourButton::FlatFace ); + zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); + zoom_out_full_button.set_image(::get_icon ("zoom_full")); act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session")); zoom_out_full_button.set_related_action (act); @@ -2842,17 +2958,21 @@ Editor::setup_toolbar () _zoom_box.pack_start (zoom_focus_selector, false, false); /* Track zoom buttons */ - tav_expand_button.set_name ("TrackHeightButton"); + tav_expand_button.set_name ("zoom button"); + tav_expand_button.add_elements ( ArdourButton::FlatFace ); + tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); tav_expand_button.set_size_request (-1, 20); - tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp"))))); + tav_expand_button.set_image(::get_icon ("tav_exp")); act = ActionManager::get_action (X_("Editor"), X_("expand-tracks")); - act->connect_proxy (tav_expand_button); + tav_expand_button.set_related_action (act); - tav_shrink_button.set_name ("TrackHeightButton"); + tav_shrink_button.set_name ("zoom button"); + tav_shrink_button.add_elements ( ArdourButton::FlatFace ); + tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); tav_shrink_button.set_size_request (-1, 20); - tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink"))))); + tav_shrink_button.set_image(::get_icon ("tav_shrink")); act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks")); - act->connect_proxy (tav_shrink_button); + tav_shrink_button.set_related_action (act); _zoom_box.pack_start (tav_shrink_button); _zoom_box.pack_start (tav_expand_button); @@ -2868,7 +2988,7 @@ Editor::setup_toolbar () _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_spacing (2); snap_box.set_border_width (2); snap_type_selector.set_name ("SnapTypeSelector"); @@ -2896,6 +3016,9 @@ Editor::setup_toolbar () nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false); nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false); + nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); + nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); + nudge_box->pack_start (nudge_backward_button, false, false); nudge_box->pack_start (nudge_forward_button, false, false); nudge_box->pack_start (*nudge_clock, false, false); @@ -2955,18 +3078,18 @@ Editor::setup_toolbar () void Editor::setup_tooltips () { - ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects")); - ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges")); + ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)")); + ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)")); + ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)")); ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes")); ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain")); 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 (internal_edit_button, _("Note Level Editing")); ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other 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 (nudge_forward_button, _("Nudge Region/Selection Later")); + ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier")); 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")); @@ -2977,6 +3100,7 @@ Editor::setup_tooltips () 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 (edit_mode_selector, _("Edit Mode")); + ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)")); } int @@ -3016,8 +3140,8 @@ Editor::convert_drop_to_paths ( const char* q; p = (const char *) malloc (txt.length() + 1); - txt.copy ((char *) p, txt.length(), 0); - ((char*)p)[txt.length()] = '\0'; + txt.copy (const_cast (p), txt.length(), 0); + const_cast(p)[txt.length()] = '\0'; while (p) { @@ -3059,14 +3183,13 @@ Editor::convert_drop_to_paths ( if ((*i).substr (0,7) == "file://") { - string p = *i; - PBD::url_decode (p); + string const p = PBD::url_decode (*i); // scan forward past three slashes string::size_type slashcnt = 0; string::size_type n = 0; - string::iterator x = p.begin(); + string::const_iterator x = p.begin(); while (slashcnt < 3 && x != p.end()) { if ((*x) == '/') { @@ -3099,7 +3222,7 @@ Editor::new_tempo_section () void Editor::map_transport_state () { - ENSURE_GUI_THREAD (*this, &Editor::map_transport_state) + ENSURE_GUI_THREAD (*this, &Editor::map_transport_state); if (_session && _session->transport_stopped()) { have_pending_keyboard_selection = false; @@ -3110,16 +3233,6 @@ Editor::map_transport_state () /* UNDO/REDO */ -Editor::State::State (PublicEditor const * e) -{ - selection = new Selection (e); -} - -Editor::State::~State () -{ - delete selection; -} - void Editor::begin_reversible_command (string name) { @@ -3169,19 +3282,13 @@ Editor::history_changed () } void -Editor::duplicate_dialog (bool with_dialog) +Editor::duplicate_range (bool with_dialog) { float times = 1.0f; - if (mouse_mode == MouseRange) { - if (selection->time.length() == 0) { - return; - } - } - RegionSelection rs = get_regions_from_selection_and_entered (); - if (mouse_mode != MouseRange && rs.empty()) { + if ( selection->time.length() == 0 && rs.empty()) { return; } @@ -3228,8 +3335,15 @@ Editor::duplicate_dialog (bool with_dialog) times = adjustment.get_value(); } - if (mouse_mode == MouseRange) { - duplicate_selection (times); + if ((current_mouse_mode() == Editing::MouseRange)) { + if (selection->time.length()) { + duplicate_selection (times); + } + } else if (get_smart_mode()) { + if (selection->time.length()) { + duplicate_selection (times); + } else + duplicate_some_regions (rs, times); } else { duplicate_some_regions (rs, times); } @@ -3307,6 +3421,10 @@ Editor::snap_type_selection_done () snaptype = SnapToBeatDiv28; } else if (choice == _("Beats/32")) { snaptype = SnapToBeatDiv32; + } else if (choice == _("Beats/64")) { + snaptype = SnapToBeatDiv64; + } else if (choice == _("Beats/128")) { + snaptype = SnapToBeatDiv128; } else if (choice == _("Beats")) { snaptype = SnapToBeat; } else if (choice == _("Bars")) { @@ -3469,6 +3587,31 @@ Editor::set_zoom_focus (ZoomFocus f) } } +void +Editor::cycle_zoom_focus () +{ + switch (zoom_focus) { + case ZoomFocusLeft: + set_zoom_focus (ZoomFocusRight); + break; + case ZoomFocusRight: + set_zoom_focus (ZoomFocusCenter); + break; + case ZoomFocusCenter: + set_zoom_focus (ZoomFocusPlayhead); + break; + case ZoomFocusPlayhead: + set_zoom_focus (ZoomFocusMouse); + break; + case ZoomFocusMouse: + set_zoom_focus (ZoomFocusEdit); + break; + case ZoomFocusEdit: + set_zoom_focus (ZoomFocusLeft); + break; + } +} + void Editor::ensure_float (Window& win) { @@ -3506,10 +3649,6 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) _notebook_shrunk = string_is_affirmative (prop->value ()); } - if (geometry && (prop = geometry->property ("pre-maximal-horizontal-pane-position"))) { - pre_maximal_horizontal_pane_position = atoi (prop->value ()); - } - 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); @@ -3520,9 +3659,6 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) { edit_pane.set_position (pos); - if (pre_maximal_horizontal_pane_position == 0) { - pre_maximal_horizontal_pane_position = pos; - } } done = (Pane) (done | Horizontal); @@ -3538,12 +3674,12 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) 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); @@ -3575,9 +3711,10 @@ Editor::set_show_measures (bool yn) hide_measures (); if ((_show_measures = yn) == true) { - if (tempo_lines) + if (tempo_lines) { tempo_lines->show(); - draw_measures (); + } + (void) redraw_measures (); } instant_save (); } @@ -3631,51 +3768,6 @@ Editor::set_stationary_playhead (bool yn) } } -void -Editor::toggle_xfade_active (boost::weak_ptr wxfade) -{ - boost::shared_ptr xfade (wxfade.lock()); - if (xfade) { - xfade->set_active (!xfade->active()); - } -} - -void -Editor::toggle_xfade_length (boost::weak_ptr wxfade) -{ - boost::shared_ptr xfade (wxfade.lock()); - if (xfade) { - xfade->set_follow_overlap (!xfade->following_overlap()); - } -} - -void -Editor::edit_xfade (boost::weak_ptr wxfade) -{ - boost::shared_ptr xfade (wxfade.lock()); - - if (!xfade) { - return; - } - - CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0); - - ensure_float (cew); - - switch (cew.run ()) { - case RESPONSE_ACCEPT: - break; - default: - return; - } - - cew.apply (); - 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& Editor::playlist_selector () const { @@ -3692,6 +3784,12 @@ Editor::get_grid_type_as_beats (bool& success, framepos_t position) return 1.0; break; + case SnapToBeatDiv128: + return 1.0/128.0; + break; + case SnapToBeatDiv64: + return 1.0/64.0; + break; case SnapToBeatDiv32: return 1.0/32.0; break; @@ -3892,100 +3990,36 @@ Editor::session_state_saved (string) } void -Editor::maximise_editing_space () +Editor::update_tearoff_visibility() { - /* these calls will leave each tearoff visible *if* it is torn off - */ - - _mouse_mode_tearoff->set_visible (false); - _tools_tearoff->set_visible (false); - _zoom_tearoff->set_visible (false); - - 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_horizontal_pane_position == 0) { - post_maximal_horizontal_pane_position = edit_pane.get_width(); - } + bool visible = Config->get_keep_tearoffs(); + _mouse_mode_tearoff->set_visible (visible); + _tools_tearoff->set_visible (visible); + _zoom_tearoff->set_visible (visible); +} - if (post_maximal_vertical_pane_position == 0) { - post_maximal_vertical_pane_position = editor_summary_pane.get_height(); +void +Editor::maximise_editing_space () +{ + if (_maximised) { + return; } fullscreen (); - 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_horizontal_pane_position); - } - - /* Hack: we must do this in an idle handler for it to work; see comment in - restore_editing_space() - */ - - Glib::signal_idle().connect ( - sigc::bind ( - sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position), - post_maximal_vertical_pane_position - ) - ); - - if (Config->get_keep_tearoffs()) { - _mouse_mode_tearoff->set_visible (true); - _tools_tearoff->set_visible (true); - if (Config->get_show_zoom_tools ()) { - _zoom_tearoff->set_visible (true); - } - } - -} - -bool -Editor::idle_reset_vertical_pane_position (int p) -{ - editor_summary_pane.set_position (p); - return false; + _maximised = true; } void Editor::restore_editing_space () { - // user changed width/height of panes during fullscreen - - 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(); + if (!_maximised) { + return; } unfullscreen(); - _mouse_mode_tearoff->set_visible (true); - _tools_tearoff->set_visible (true); - if (Config->get_show_zoom_tools ()) { - _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_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width)); - - /* This is a bit of a hack, but it seems that if you set the vertical pane position - here it gets reset to some wrong value after this method has finished. Doing - the setup in an idle callback seems to work. - */ - Glib::signal_idle().connect ( - sigc::bind ( - sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position), - pre_maximal_vertical_pane_position - ) - ); + _maximised = false; } /** @@ -4000,7 +4034,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, ARDOUR::Properties::edit.property_id); + mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id); commit_reversible_command (); } @@ -4016,7 +4050,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, ARDOUR::Properties::edit.property_id); + mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id); commit_reversible_command (); } @@ -4031,7 +4065,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, ARDOUR::Properties::edit.property_id); + mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id); commit_reversible_command (); } @@ -4072,19 +4106,31 @@ Editor::on_key_release_event (GdkEventKey* ev) void Editor::reset_x_origin (framepos_t frame) { - queue_visual_change (frame); + pending_visual_change.add (VisualChange::TimeOrigin); + pending_visual_change.time_origin = frame; + ensure_visual_change_idle_handler (); } void Editor::reset_y_origin (double y) { - queue_visual_change_y (y); + pending_visual_change.add (VisualChange::YOrigin); + pending_visual_change.y_origin = y; + ensure_visual_change_idle_handler (); } void Editor::reset_zoom (double fpu) { - queue_visual_change (fpu); + clamp_frames_per_unit (fpu); + + if (fpu == frames_per_unit) { + return; + } + + pending_visual_change.add (VisualChange::ZoomLevel); + pending_visual_change.frames_per_unit = fpu; + ensure_visual_change_idle_handler (); } void @@ -4098,8 +4144,8 @@ Editor::reposition_and_zoom (framepos_t frame, double fpu) } } -Editor::VisualState::VisualState () - : gui_state (new GUIObjectState) +Editor::VisualState::VisualState (bool with_tracks) + : gui_state (with_tracks ? new GUIObjectState : 0) { } @@ -4111,14 +4157,14 @@ Editor::VisualState::~VisualState () Editor::VisualState* Editor::current_visual_state (bool with_tracks) { - VisualState* vs = new VisualState; + VisualState* vs = new VisualState (with_tracks); vs->y_position = vertical_adjustment.get_value(); vs->frames_per_unit = frames_per_unit; vs->leftmost_frame = leftmost_frame; vs->zoom_focus = zoom_focus; if (with_tracks) { - *(vs->gui_state) = *ARDOUR_UI::instance()->gui_object_state; + *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state; } return vs; @@ -4131,10 +4177,12 @@ Editor::undo_visual_state () return; } - redo_visual_stack.push_back (current_visual_state()); - VisualState* vs = undo_visual_stack.back(); undo_visual_stack.pop_back(); + + + redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false)); + use_visual_state (*vs); } @@ -4145,10 +4193,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(); + + undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false)); + use_visual_state (*vs); } @@ -4165,7 +4214,7 @@ Editor::swap_visual_state () void Editor::use_visual_state (VisualState& vs) { - no_save_visual = true; + PBD::Unwinder nsv (no_save_visual, true); _routes->suspend_redisplay (); @@ -4174,53 +4223,32 @@ Editor::use_visual_state (VisualState& vs) set_zoom_focus (vs.zoom_focus); reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit); - *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state; - - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->reset_visual_state (); + if (vs.gui_state) { + *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state; + + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + (*i)->reset_visual_state (); + } } _routes->update_visibility (); _routes->resume_redisplay (); - - no_save_visual = false; } +/** This is the core function that controls the zoom level of the canvas. It is called + * whenever one or more calls are made to reset_zoom(). It executes in an idle handler. + * @param fpu New frames per unit; should already have been clamped so that it is sensible. + */ void Editor::set_frames_per_unit (double fpu) { - /* this is the core function that controls the zoom level of the canvas. it is called - whenever one or more calls are made to reset_zoom(). it executes in an idle handler. - */ - - if (fpu == frames_per_unit) { - return; - } - - if (fpu < 2.0) { - fpu = 2.0; - } - - - /* don't allow zooms that fit more than the maximum number - of frames into an 800 pixel wide space. - */ - - if (max_framepos / fpu < 800.0) { - return; - } - - if (tempo_lines) + if (tempo_lines) { tempo_lines->tempo_map_changed(); + } frames_per_unit = fpu; - post_zoom (); -} -void -Editor::post_zoom () -{ - // convert fpu to frame count + /* convert fpu to frame count */ framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width); @@ -4228,7 +4256,9 @@ Editor::post_zoom () zoom_range_clock->set (frames); } - if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) { + bool const showing_time_selection = selection->time.length() > 0; + + if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) { for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { (*i)->reshow_selection (selection->time); } @@ -4250,32 +4280,6 @@ Editor::post_zoom () instant_save (); } -void -Editor::queue_visual_change (framepos_t where) -{ - pending_visual_change.add (VisualChange::TimeOrigin); - pending_visual_change.time_origin = where; - ensure_visual_change_idle_handler (); -} - -void -Editor::queue_visual_change (double fpu) -{ - pending_visual_change.add (VisualChange::ZoomLevel); - pending_visual_change.frames_per_unit = fpu; - - ensure_visual_change_idle_handler (); -} - -void -Editor::queue_visual_change_y (double y) -{ - pending_visual_change.add (VisualChange::YOrigin); - pending_visual_change.y_origin = y; - - ensure_visual_change_idle_handler (); -} - void Editor::ensure_visual_change_idle_handler () { @@ -4293,30 +4297,37 @@ Editor::_idle_visual_changer (void* arg) int Editor::idle_visual_changer () { + /* set_horizontal_position() below (and maybe other calls) call + gtk_main_iteration(), so it's possible that a signal will be handled + half-way through this method. If this signal wants an + idle_visual_changer we must schedule another one after this one, so + mark the idle_handler_id as -1 here to allow that. Also make a note + that we are doing the visual change, so that changes in response to + super-rapid-screen-update can be dropped if we are still processing + the last one. + */ + + pending_visual_change.idle_handler_id = -1; + pending_visual_change.being_handled = true; + VisualChange::Type p = pending_visual_change.pending; pending_visual_change.pending = (VisualChange::Type) 0; double const last_time_origin = horizontal_position (); - if (p & VisualChange::TimeOrigin) { - /* This is a bit of a hack, but set_frames_per_unit - below will (if called) end up with the - CrossfadeViews looking at Editor::leftmost_frame, - and if we're changing origin and zoom in the same - operation it will be the wrong value unless we - update it here. - */ - - leftmost_frame = pending_visual_change.time_origin; - } - if (p & VisualChange::ZoomLevel) { set_frames_per_unit (pending_visual_change.frames_per_unit); compute_fixed_ruler_scale (); - compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames()); - compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames()); - update_tempo_based_rulers (); + + ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin; + ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end; + + compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(), + current_bbt_points_begin, current_bbt_points_end); + compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(), + current_bbt_points_begin, current_bbt_points_end); + update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end); } if (p & VisualChange::TimeOrigin) { set_horizontal_position (pending_visual_change.time_origin / frames_per_unit); @@ -4333,7 +4344,7 @@ Editor::idle_visual_changer () _summary->set_overlays_dirty (); - pending_visual_change.idle_handler_id = -1; + pending_visual_change.being_handled = false; return 0; /* this is always a one-shot call */ } @@ -4443,7 +4454,7 @@ Editor::set_punch_range (framepos_t start, framepos_t end, string cmd) Location* tpl; if ((tpl = transport_punch_location()) == 0) { - Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch); + Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch); XMLNode &before = _session->locations()->get_state(); _session->locations()->add (loc, true); _session->set_auto_loop_location (loc); @@ -4487,10 +4498,10 @@ Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewLi if ((tr = rtv->track()) && ((pl = tr->playlist()))) { - boost::shared_ptr regions = pl->regions_at ( + boost::shared_ptr regions = pl->regions_at ( (framepos_t) floor ( (double) where * tr->speed())); - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { + for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { RegionView* rv = rtv->view()->find_view (*i); if (rv) { rs.add (rv); @@ -4520,10 +4531,10 @@ Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackVie if ((tr = rtv->track()) && ((pl = tr->playlist()))) { - boost::shared_ptr regions = pl->regions_touched ( + boost::shared_ptr regions = pl->regions_touched ( (framepos_t) floor ( (double)where * tr->speed()), max_framepos); - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { + for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { RegionView* rv = rtv->view()->find_view (*i); @@ -4544,7 +4555,7 @@ Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackVie RegionSelection Editor::get_regions_from_selection () { - return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id); + return get_equivalent_regions (selection->regions, ARDOUR::Properties::select.property_id); } /** Get regions using the following method: @@ -4553,16 +4564,15 @@ Editor::get_regions_from_selection () * the edit point is `mouse' and the mouse is over an unselected * region. In this case, start with just that region. * - * Then, make an initial track list of the tracks that these - * regions are on, and if the edit point is not `mouse', add the - * selected tracks. + * Then, add equivalent regions in active edit groups to the region list. * - * Look at this track list and add any other tracks that are on the - * same active edit-enabled route group as one of the initial tracks. + * Then, search the list of selected tracks to find any selected tracks which + * do not contain regions already in the region list. If there are no selected + * tracks and 'No Selection = All Tracks' is active, search all tracks rather + * than just the selected. * - * Finally take the initial region list and add any regions that are - * under the edit point on one of the tracks on the track list to get - * the returned region list. + * Add any regions that are under the edit point on these tracks to get the + * returned region list. * * The rationale here is that the mouse edit point is special in that * its position describes both a time and a track; the other edit @@ -4590,22 +4600,40 @@ Editor::get_regions_from_selection_and_edit_point () tracks = selection->tracks; } - /* Add any other tracks that have regions that are in the same + /* Add any other regions that are in the same edit-activated route group as one of our regions. */ - for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) { + regions = get_equivalent_regions (regions, ARDOUR::Properties::select.property_id); + framepos_t const where = get_preferred_edit_position (); - RouteGroup* g = (*i)->get_time_axis_view().route_group (); - - if (g && g->is_active() && g->is_edit()) { - tracks.add (axis_views_from_routes (g->route_list())); - } + if (_route_groups->all_group_active_button().get_active() && tracks.empty()) { + /* tracks is empty (no track selected), and 'No Selection = All Tracks' + * is enabled, so consider all tracks + */ + tracks = track_views; } if (!tracks.empty()) { - /* now find regions that are at the edit position on those tracks */ - framepos_t const where = get_preferred_edit_position (); - get_regions_at (regions, where, tracks); + /* now search the selected tracks for tracks which don't + already contain regions to be acted upon, and get regions at + the edit point on those tracks too. + */ + TrackViewList tracks_without_relevant_regions; + + for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) { + if (!regions.involves (**t)) { + /* there are no equivalent regions on this track */ + tracks_without_relevant_regions.push_back (*t); + } + } + + if (!tracks_without_relevant_regions.empty()) { + /* there are some selected tracks with neither selected + * regions or their equivalents: act upon all regions in + * those tracks + */ + get_regions_at (regions, where, tracks_without_relevant_regions); + } } return regions; @@ -4625,11 +4653,11 @@ Editor::get_regions_from_selection_and_entered () regions.add (entered_regionview); } - return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id); + return get_equivalent_regions (regions, ARDOUR::Properties::select.property_id); } void -Editor::get_regions_corresponding_to (boost::shared_ptr region, vector& regions) +Editor::get_regions_corresponding_to (boost::shared_ptr region, vector& regions, bool src_comparison) { for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { @@ -4648,7 +4676,11 @@ Editor::get_regions_corresponding_to (boost::shared_ptr region, vectorplaylist())) != 0) { - pl->get_region_list_equivalent_regions (region, results); + if (src_comparison) { + pl->get_source_equivalent_regions (region, results); + } else { + pl->get_region_list_equivalent_regions (region, results); + } } for (vector >::iterator ir = results.begin(); ir != results.end(); ++ir) { @@ -4768,9 +4800,11 @@ 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 (); + if (_session) { + playhead_cursor->set_position (_session->audible_frame ()); + if (_follow_playhead && !_pending_initial_locate) { + reset_x_origin_to_follow_playhead (); + } } _pending_locate_request = false; @@ -4820,9 +4854,8 @@ Editor::axis_views_from_routes (boost::shared_ptr r) const return t; } - void -Editor::handle_new_route (RouteList& routes) +Editor::add_routes (RouteList& routes) { ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes) @@ -5159,32 +5192,33 @@ Editor::reset_x_origin_to_follow_playhead () } else { + framepos_t l = 0; + if (frame < leftmost_frame) { /* moving left */ - framepos_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; + /* not rolling: end up with the playhead 1/4 of the way along the page */ + l = frame - current_page_frames() / 4; } - - 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 ()); + l = frame; } 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 ()); + /* 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 ()); } } } @@ -5237,7 +5271,14 @@ Editor::super_rapid_screen_update () if (!_stationary_playhead) { - if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) { + if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) { + /* We only do this if we aren't already + handling a visual change (ie if + pending_visual_change.being_handled is + false) so that these requests don't stack + up there are too many of them to handle in + time. + */ reset_x_origin_to_follow_playhead (); } @@ -5282,7 +5323,6 @@ Editor::session_going_away () clicked_regionview = 0; clicked_axisview = 0; clicked_routeview = 0; - clicked_crossfadeview = 0; entered_regionview = 0; entered_track = 0; last_update_frame = 0; @@ -5326,8 +5366,8 @@ Editor::session_going_away () hide_measures (); clear_marker_display (); - current_bbt_points_begin = current_bbt_points_end; - + stop_step_editing (); + /* get rid of any existing editor mixer strip */ WindowTitle title(Glib::get_application_name()); @@ -5393,19 +5433,31 @@ Editor::update_region_layering_order_editor () void Editor::setup_fade_images () { - _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear"))); - _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut"))); - _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut"))); - _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut"))); - _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut"))); + _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear"))); + _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut"))); + _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut"))); + _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut"))); + _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut"))); + + _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear"))); + _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut"))); + _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut"))); + _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut"))); + _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut"))); + + _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear"))); + _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut"))); + _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut"))); + _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut"))); + _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut"))); - _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear"))); - _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut"))); - _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut"))); - _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut"))); - _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut"))); -} + _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear"))); + _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut"))); + _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut"))); + _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut"))); + _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut"))); +} /** @return Gtk::manage()d menu item for a given action from `editor_actions' */ Gtk::MenuItem& @@ -5441,10 +5493,16 @@ Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page) /* double-click on a notebook tab shrinks or expands the notebook */ if (_notebook_shrunk) { - edit_pane.set_position (pre_maximal_horizontal_pane_position); + if (pre_notebook_shrink_pane_width) { + edit_pane.set_position (*pre_notebook_shrink_pane_width); + } _notebook_shrunk = false; } else { - pre_maximal_horizontal_pane_position = edit_pane.get_position (); + pre_notebook_shrink_pane_width = edit_pane.get_position(); + + /* this expands the LHS of the edit pane to cover the notebook + PAGE but leaves the tabs visible. + */ edit_pane.set_position (edit_pane.get_position() + page->get_width()); _notebook_shrunk = true; } @@ -5470,3 +5528,8 @@ Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* ev _control_point_context_menu.popup (event->button.button, event->button.time); } +void +Editor::shift_key_released () +{ + _stepping_axis_view = 0; +}