X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=6514f4665aee8d7e005cc3bd69227142cad5797f;hb=ff2d51ddd8288ec967efab2cb8192f43c893909e;hp=c5e34c38de020cf29afd94d182d15cb97eec0418;hpb=8aa9508c82f32efcf9c7c00e2c9e76268d4dddce;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index c5e34c38de..6514f4665a 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -84,6 +84,7 @@ #include "gui_thread.h" #include "simpleline.h" #include "rhythm_ferret.h" +#include "actions.h" #ifdef FFT_ANALYSIS #include "analysis_window.h" @@ -153,7 +154,7 @@ static const gchar *_zoom_focus_strings[] = { N_("Center"), N_("Playhead"), N_("Mouse"), - N_("Edit Point"), + N_("Active Mark"), 0 }; @@ -182,6 +183,7 @@ Gdk::Cursor* Editor::fader_cursor = 0; Gdk::Cursor* Editor::speaker_cursor = 0; Gdk::Cursor* Editor::midi_pencil_cursor = 0; Gdk::Cursor* Editor::midi_select_cursor = 0; +Gdk::Cursor* Editor::midi_resize_cursor = 0; Gdk::Cursor* Editor::midi_erase_cursor = 0; Gdk::Cursor* Editor::wait_cursor = 0; Gdk::Cursor* Editor::timebar_cursor = 0; @@ -193,6 +195,15 @@ show_me_the_size (Requisition* r, const char* what) cerr << "size of " << what << " = " << r->width << " x " << r->height << endl; } +void +DragInfo::clear_copied_locations () +{ + for (list::iterator i = copied_locations.begin(); i != copied_locations.end(); ++i) { + delete *i; + } + copied_locations.clear (); +} + Editor::Editor () : /* time display buttons */ @@ -207,8 +218,7 @@ Editor::Editor () range_mark_label (_("Range Markers")), transport_mark_label (_("Loop/Punch Ranges")), cd_mark_label (_("CD Markers")), - - edit_packer (3, 3, true), + edit_packer (3, 4, true), /* the values here don't matter: layout widgets reset them as needed. @@ -217,9 +227,6 @@ Editor::Editor () vertical_adjustment (0.0, 0.0, 10.0, 400.0), horizontal_adjustment (0.0, 0.0, 20.0, 1200.0), - tempo_lines(0), - marker_tempo_lines(0), - /* tool bar related */ edit_point_clock (X_("editpoint"), false, X_("EditPointClock"), true), @@ -247,6 +254,7 @@ Editor::Editor () PublicEditor::_instance = this; session = 0; + _have_idled = false; selection = new Selection (this); cut_buffer = new Selection (this); @@ -279,6 +287,8 @@ Editor::Editor () bbt_beat_subdivision = 4; canvas_width = 0; canvas_height = 0; + last_autoscroll_x = 0; + last_autoscroll_y = 0; autoscroll_active = false; autoscroll_timeout_tag = -1; interthread_progress_window = 0; @@ -293,8 +303,6 @@ Editor::Editor () _show_waveforms = true; _show_waveforms_recording = true; first_action_message = 0; - export_dialog = 0; - export_range_markers_dialog = 0; show_gain_after_trim = false; ignore_route_list_reorder = false; no_route_list_redisplay = false; @@ -339,13 +347,19 @@ Editor::Editor () last_canvas_frame = 0; playhead_cursor = 0; button_release_can_deselect = true; - canvas_idle_queued = false; _dragging_playhead = false; _dragging_edit_point = false; _dragging_hscrollbar = false; select_new_marker = false; zoomed_to_region = false; rhythm_ferret = 0; + allow_vertical_scroll = false; + no_save_visual = false; + need_resize_line = false; + resize_line_y = 0; + old_resize_line_y = -1; + no_region_list_redisplay = false; + resize_idle_id = -1; _scrubbing = false; scrubbing_direction = 0; @@ -362,12 +376,9 @@ Editor::Editor () range_marker_drag_rect = 0; marker_drag_line = 0; tempo_map_change_idle_handler_id = -1; - canvas_hroizontally_scrolled_handler_id = -1; set_midi_edit_mode (MidiEditPencil, true); set_mouse_mode (MouseObject, true); - last_visual_state.frames_per_unit = 0; - frames_per_unit = 2048; /* too early to use reset_zoom () */ reset_hscrollbar_stepping (); @@ -379,16 +390,10 @@ Editor::Editor () initialize_canvas (); edit_controls_vbox.set_spacing (0); - horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled), false); + horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::scroll_canvas_horizontally), false); vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true); - - track_canvas.set_hadjustment (horizontal_adjustment); - track_canvas.set_vadjustment (vertical_adjustment); - time_canvas.set_hadjustment (horizontal_adjustment); + track_canvas->signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler)); - track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler)); - time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler)); - controls_layout.add (edit_controls_vbox); controls_layout.set_name ("EditControlsBase"); controls_layout.add_events (Gdk::SCROLL_MASK); @@ -425,9 +430,8 @@ Editor::Editor () time_canvas_vbox.pack_start (*smpte_ruler, false, false); time_canvas_vbox.pack_start (*frames_ruler, false, false); time_canvas_vbox.pack_start (*bbt_ruler, false, false); - time_canvas_vbox.pack_start (time_canvas, true, true); - time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 5); - + //time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2); + time_canvas_vbox.set_size_request (-1, -1); bbt_label.set_name ("EditorTimeButton"); bbt_label.set_size_request (-1, (int)timebar_height); bbt_label.set_alignment (1.0, 0.5); @@ -444,6 +448,7 @@ Editor::Editor () frame_label.set_size_request (-1, (int)timebar_height); frame_label.set_alignment (1.0, 0.5); frame_label.set_padding (5,0); + tempo_label.set_name ("EditorTimeButton"); tempo_label.set_size_request (-1, (int)timebar_height); tempo_label.set_alignment (1.0, 0.5); @@ -468,31 +473,31 @@ Editor::Editor () 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); + + ruler_label_vbox.pack_start (minsec_label, false, false); + ruler_label_vbox.pack_start (smpte_label, false, false); + ruler_label_vbox.pack_start (frame_label, false, false); + ruler_label_vbox.pack_start (bbt_label, false, false); - time_button_vbox.pack_start (minsec_label, false, false); - time_button_vbox.pack_start (smpte_label, false, false); - time_button_vbox.pack_start (frame_label, false, false); - time_button_vbox.pack_start (bbt_label, false, false); + ruler_label_event_box.add (ruler_label_vbox); + ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); + ruler_label_event_box.set_name ("TimebarLabelBase"); + ruler_label_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release)); + time_button_vbox.pack_start (meter_label, false, false); time_button_vbox.pack_start (tempo_label, false, false); time_button_vbox.pack_start (mark_label, false, false); time_button_event_box.add (time_button_vbox); time_button_event_box.set_name ("TimebarLabelBase"); - time_button_frame.set_shadow_type (Gtk::SHADOW_NONE); - time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release)); - time_button_frame.add (time_button_event_box); - time_button_frame.set_name ("TimebarLabelBase"); - time_button_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT); - /* these enable us to have a dedicated window (for cursor setting, etc.) for the canvas areas. */ - track_canvas_event_box.add (track_canvas); + track_canvas_event_box.add (*track_canvas); time_canvas_event_box.add (time_canvas_vbox); time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK); @@ -502,17 +507,36 @@ Editor::Editor () edit_packer.set_homogeneous (false); edit_packer.set_border_width (0); edit_packer.set_name ("EditorWindow"); + +#ifndef THE_OLD_WAY + + edit_packer.attach (ruler_label_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0); + + edit_packer.attach (time_button_event_box, 0, 1, 1, 2, FILL, SHRINK, 0, 0); + edit_packer.attach (time_canvas_event_box, 1, 2, 0, 1, FILL|EXPAND, FILL, 0, 0); + + edit_packer.attach (controls_layout, 0, 1, 2, 3, FILL, FILL|EXPAND, 0, 0); + edit_packer.attach (track_canvas_event_box, 1, 2, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0); + + edit_packer.attach (zoom_box, 0, 1, 3, 4, FILL, FILL, 0, 0); + edit_packer.attach (edit_hscrollbar, 1, 2, 3, 4, FILL|EXPAND, FILL, 0, 0); + + edit_packer.attach (edit_vscrollbar, 3, 4, 2, 3, FILL, FILL|EXPAND, 0, 0); + +#else - edit_packer.attach (edit_vscrollbar, 3, 4, 1, 2, FILL, FILL|EXPAND, 0, 0); + edit_packer.attach (edit_vscrollbar, 0, 1, 0, 4, FILL, FILL|EXPAND, 0, 0); - edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, SHRINK, 0, 0); - edit_packer.attach (time_canvas_event_box, 2, 4, 0, 1, FILL|EXPAND, FILL, 0, 0); + edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0); + edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0); + edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0); - edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0); - edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0); + edit_packer.attach (controls_layout, 1, 2, 2, 3, FILL, FILL|EXPAND, 0, 0); + edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0); - edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0); - edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0); + edit_packer.attach (zoom_box, 1, 2, 3, 4, FILL, FILL, 0, 0); + edit_packer.attach (edit_hscrollbar, 2, 3, 3, 4, FILL|EXPAND, FILL, 0, 0); +#endif bottom_hbox.set_border_width (2); bottom_hbox.set_spacing (3); @@ -613,6 +637,10 @@ Editor::Editor () region_list_display.set_size_request (100, -1); region_list_display.set_name ("RegionListDisplay"); + /* Try to prevent single mouse presses from initiating edits. + This relies on a hack in gtktreeview.c:gtk_treeview_button_press() + */ + region_list_display.set_data ("mouse-edits-require-mod1", (gpointer) 0x1); region_list_model = TreeStore::create (region_list_columns); region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter)); @@ -620,7 +648,12 @@ Editor::Editor () region_list_display.set_model (region_list_model); region_list_display.append_column (_("Regions"), region_list_columns.name); - region_list_display.set_headers_visible (false); + region_list_display.append_column (_("Start"), region_list_columns.start); + region_list_display.append_column (_("End"), region_list_columns.end); + region_list_display.append_column (_("Length"), region_list_columns.length); + region_list_display.append_column (_("Used"), region_list_columns.used); + region_list_display.append_column (_("Path to parent file"), region_list_columns.path); + region_list_display.set_headers_visible (true); CellRendererText* region_name_cell = dynamic_cast(region_list_display.get_column_cell_renderer (0)); region_name_cell->property_editable() = true; @@ -635,7 +668,7 @@ Editor::Editor () region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE); region_list_display.add_object_drag (region_list_columns.region.index(), "regions"); - + /* setup DnD handling */ list region_list_target_table; @@ -648,8 +681,8 @@ Editor::Editor () region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received)); region_list_scroller.add (region_list_display); - region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC); - + region_list_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC); + region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press)); region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release)); region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false); @@ -657,6 +690,9 @@ Editor::Editor () region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed)); // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0)); + ARDOUR_UI::instance()->secondary_clock.mode_changed.connect (mem_fun(*this, &Editor::redisplay_regions)); + ARDOUR::Region::RegionPropertyChanged.connect (mem_fun(*this, &Editor::update_region_row)); + named_selection_scroller.add (named_selection_display); named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC); @@ -713,6 +749,7 @@ Editor::Editor () the_notebook.set_scrollable (true); the_notebook.popup_enable (); the_notebook.set_tab_pos (Gtk::POS_RIGHT); + the_notebook.show_all (); post_maximal_editor_width = 0; post_maximal_pane_position = 0; @@ -748,8 +785,7 @@ Editor::Editor () set_snap_to (snap_type); snap_mode = SnapOff; set_snap_mode (snap_mode); - _edit_point = EditAtMouse; - set_edit_point_preference (_edit_point); + set_edit_point_preference (EditAtMouse, true); XMLNode* node = ARDOUR_UI::instance()->editor_settings(); set_state (*node); @@ -811,6 +847,7 @@ Editor::Editor () ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false)); ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true)); ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll)); + BasicUI::AccessAction.connect (mem_fun (*this, &Editor::access_action)); Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed)); Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys)); @@ -822,8 +859,7 @@ Editor::Editor () Editor::~Editor() { #ifdef WITH_CMT - if(image_socket_listener) - { + if(image_socket_listener) { if(image_socket_listener->is_connected()) { image_socket_listener->close_connection() ; @@ -833,6 +869,11 @@ Editor::~Editor() image_socket_listener = 0 ; } #endif + + if (track_canvas) { + delete track_canvas; + track_canvas = 0; + } } void @@ -954,10 +995,10 @@ Editor::zoom_adjustment_changed () if (fpu < 1.0) { fpu = 1.0; - zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width)); + zoom_range_clock.set ((nframes64_t) floor (fpu * canvas_width)); } else if (fpu > session->current_end_frame() / canvas_width) { fpu = session->current_end_frame() / canvas_width; - zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width)); + zoom_range_clock.set ((nframes64_t) floor (fpu * canvas_width)); } temporal_zoom (fpu); @@ -977,7 +1018,7 @@ Editor::control_scroll (float fraction) /* _control_scroll_target is an optional - it acts like a pointer to an nframes_t, with + it acts like a pointer to an nframes64_t, with a operator conversion to boolean to check that it has a value could possibly use playhead_cursor->current_frame to store the @@ -990,12 +1031,12 @@ Editor::control_scroll (float fraction) _dragging_playhead = true; } - if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) { + if ((fraction < 0.0f) && (*_control_scroll_target < (nframes64_t) fabs(step))) { *_control_scroll_target = 0; } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) { *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen } else { - *_control_scroll_target += (nframes_t) floor (step); + *_control_scroll_target += (nframes64_t) floor (step); } /* move visuals, we'll catch up with it later */ @@ -1026,7 +1067,7 @@ Editor::control_scroll (float fraction) } bool -Editor::deferred_control_scroll (nframes_t target) +Editor::deferred_control_scroll (nframes64_t target) { session->request_locate (*_control_scroll_target, session->transport_rolling()); // reset for next stream @@ -1035,6 +1076,27 @@ Editor::deferred_control_scroll (nframes_t target) return false; } +void +Editor::access_action (std::string action_group, std::string action_item) +{ + if (!session) { + return; + } + + ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::access_action), action_group, action_item)); + + cout<< "OSC: Recieved: "<< action_item << endl; + + RefPtr act; + act = ActionManager::get_action( action_group.c_str(), action_item.c_str() ); + + if (act) { + act->activate(); + } + + +} + void Editor::on_realize () { @@ -1047,6 +1109,7 @@ Editor::start_scrolling () { scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun(*this, &Editor::update_current_screen)); + } void @@ -1056,7 +1119,7 @@ Editor::stop_scrolling () } void -Editor::map_position_change (nframes_t frame) +Editor::map_position_change (nframes64_t frame) { ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame)); @@ -1069,7 +1132,7 @@ Editor::map_position_change (nframes_t frame) } void -Editor::center_screen (nframes_t frame) +Editor::center_screen (nframes64_t frame) { double page = canvas_width * frames_per_unit; @@ -1082,12 +1145,12 @@ Editor::center_screen (nframes_t frame) } void -Editor::center_screen_internal (nframes_t frame, float page) +Editor::center_screen_internal (nframes64_t frame, float page) { page /= 2; if (frame > page) { - frame -= (nframes_t) page; + frame -= (nframes64_t) page; } else { frame = 0; } @@ -1100,15 +1163,16 @@ Editor::handle_new_duration () { ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration)); - nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f); + nframes64_t new_end = session->get_maximum_extent() + (nframes64_t) floorf (current_page_frames() * 0.10f); if (new_end > last_canvas_frame) { last_canvas_frame = new_end; horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit); - reset_scrolling_region (); + //reset_scrolling_region (); } horizontal_adjustment.set_value (leftmost_frame/frames_per_unit); + //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() << ":" << last_canvas_frame << endl;//DEBUG } void @@ -1150,6 +1214,10 @@ Editor::connect_to_session (Session *t) { session = t; + /* there are never any selected regions at startup */ + + sensitize_the_right_region_actions (false); + XMLNode* node = ARDOUR_UI::instance()->editor_settings(); set_state (*node); @@ -1196,6 +1264,9 @@ Editor::connect_to_session (Session *t) zoom_range_clock.set_session (session); _playlist_selector->set_session (session); nudge_clock.set_session (session); + nudge_clock.set (session->frame_rate() * 5); // default of 5 seconds + + playhead_cursor->canvas_item.show (); if (rhythm_ferret) { rhythm_ferret->set_session (session); @@ -1288,12 +1359,23 @@ Editor::connect_to_session (Session *t) no_route_list_redisplay = false; redisplay_route_list (); } + + switch (snap_type) { + case SnapToRegionStart: + case SnapToRegionEnd: + case SnapToRegionSync: + case SnapToRegionBoundary: + build_region_boundary_cache (); + break; + + default: + break; + } /* register for undo history */ - session->register_with_memento_command_factory(_id, this); - start_updating (); + start_updating (); } void @@ -1361,6 +1443,7 @@ Editor::build_cursors () timebar_cursor = new Gdk::Cursor(LEFT_PTR); midi_pencil_cursor = new Gdk::Cursor (PENCIL); midi_select_cursor = new Gdk::Cursor (CENTER_PTR); + midi_resize_cursor = new Gdk::Cursor (SIZING); midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX); } @@ -1438,10 +1521,10 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i } void -Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame) +Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes64_t frame) { using namespace Menu_Helpers; - Menu* (Editor::*build_menu_function)(nframes_t); + Menu* (Editor::*build_menu_function)(nframes64_t); Menu *menu; switch (item_type) { @@ -1557,7 +1640,7 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, } Menu* -Editor::build_track_context_menu (nframes_t ignored) +Editor::build_track_context_menu (nframes64_t ignored) { using namespace Menu_Helpers; @@ -1569,7 +1652,7 @@ Editor::build_track_context_menu (nframes_t ignored) } Menu* -Editor::build_track_bus_context_menu (nframes_t ignored) +Editor::build_track_bus_context_menu (nframes64_t ignored) { using namespace Menu_Helpers; @@ -1581,7 +1664,7 @@ Editor::build_track_bus_context_menu (nframes_t ignored) } Menu* -Editor::build_track_region_context_menu (nframes_t frame) +Editor::build_track_region_context_menu (nframes64_t frame) { using namespace Menu_Helpers; MenuList& edit_items = track_region_context_menu.items(); @@ -1594,10 +1677,20 @@ Editor::build_track_region_context_menu (nframes_t frame) boost::shared_ptr pl; if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) { - Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed())); - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (rtv->view(), (*i), edit_items); + Playlist::RegionList* regions = pl->regions_at ((nframes64_t) floor ( (double)frame * ds->speed())); + + 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; } } @@ -1608,7 +1701,7 @@ Editor::build_track_region_context_menu (nframes_t frame) } Menu* -Editor::build_track_crossfade_context_menu (nframes_t frame) +Editor::build_track_crossfade_context_menu (nframes64_t frame) { using namespace Menu_Helpers; MenuList& edit_items = track_crossfade_context_menu.items(); @@ -1634,10 +1727,17 @@ Editor::build_track_crossfade_context_menu (nframes_t frame) add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many); } - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (atv->audio_view(), (*i), edit_items); + 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); + } } - delete regions; } } @@ -1686,7 +1786,7 @@ Editor::analyze_range_selection() #endif /* FFT_ANALYSIS */ Menu* -Editor::build_track_selection_context_menu (nframes_t ignored) +Editor::build_track_selection_context_menu (nframes64_t ignored) { using namespace Menu_Helpers; MenuList& edit_items = track_selection_context_menu.items(); @@ -1787,16 +1887,18 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi if (region) { ar = boost::dynamic_pointer_cast (region); mr = boost::dynamic_pointer_cast (region); - } - /* when this particular menu pops up, make the relevant region - become selected. - */ + /* when this particular menu pops up, make the relevant region + become selected. + */ - region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr(region))); + region_menu->signal_map_event().connect ( + bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr(region))); + + items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::rename_region))); + items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region))); + } - items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::rename_region))); - items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region))); items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top))); items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom))); items.push_back (SeparatorElem()); @@ -1809,25 +1911,33 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection))); #ifdef FFT_ANALYSIS - if (ar) - items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection))); + if (ar) { + items.push_back (MenuElem (_("Spectral Analysis"), mem_fun(*this, &Editor::analyze_region_selection))); + } #endif 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->locked()) { + if (region_to_check->locked()) { region_lock_item->set_active(); } region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock)); - + items.push_back (CheckMenuElem (_("Glue to Bars&Beats"))); CheckMenuItem* bbt_glue_item = static_cast(&items.back()); - - switch (region->positional_lock_style()) { + + switch (region_to_check->positional_lock_style()) { case Region::MusicTime: bbt_glue_item->set_active (true); break; @@ -1835,13 +1945,13 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi bbt_glue_item->set_active (false); break; } - + bbt_glue_item->signal_activate().connect (bind (mem_fun (*this, &Editor::set_region_lock_style), Region::MusicTime)); - + items.push_back (CheckMenuElem (_("Mute"))); CheckMenuItem* region_mute_item = static_cast(&items.back()); fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute)); - if (region->muted()) { + if (region_to_check->muted()) { fooc.block (true); region_mute_item->set_active(); fooc.block (false); @@ -1851,15 +1961,15 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi items.push_back (CheckMenuElem (_("Opaque"))); CheckMenuItem* region_opaque_item = static_cast(&items.back()); fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque)); - if (region->opaque()) { + if (region_to_check->opaque()) { fooc.block (true); region_opaque_item->set_active(); fooc.block (false); } } - + items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize))); - if (region->at_natural_position()) { + if (region_to_check->at_natural_position()) { items.back().set_sensitive (false); } @@ -1951,7 +2061,7 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi items.push_back (MenuElem (_("Multi-Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true)))); items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track)))); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region))); + items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions))); /* OK, stick the region submenu at the top of the list, and then add the standard items. @@ -1962,7 +2072,7 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi */ string::size_type pos = 0; - string menu_item_name = region->name(); + string menu_item_name = (region) ? region->name() : _("Selected regions"); while ((pos = menu_item_name.find ("_", pos)) != string::npos) { menu_item_name.replace (pos, 1, "__"); @@ -1989,7 +2099,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) #ifdef FFT_ANALYSIS items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection))); + items.push_back (MenuElem (_("Spectral Analysis"), mem_fun(*this, &Editor::analyze_range_selection))); #endif items.push_back (SeparatorElem()); @@ -2015,8 +2125,9 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false))); items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection))); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection))); - items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection))); + items.push_back (MenuElem (_("Consolidate range"), bind (mem_fun(*this, &Editor::bounce_range_selection), true))); + items.push_back (MenuElem (_("Bounce range to region list"), bind (mem_fun(*this, &Editor::bounce_range_selection), false))); + items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_range))); } @@ -2090,7 +2201,7 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) edit_items.push_back (SeparatorElem()); edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f))); - edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack))); + edit_items.push_back (MenuElem (_("Insert Existing Media"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack))); /* Nudge track */ @@ -2163,19 +2274,18 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items) edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu)); } -/* CURSOR SETTING AND MARKS AND STUFF */ - void Editor::set_snap_to (SnapType st) -{ - unsigned int snap_ind = (unsigned int)st; - snap_type = st; - - if ( snap_ind > snap_type_strings.size() - 1 ) { - snap_ind = 0; - snap_type = (SnapType)snap_ind; - } +{ + unsigned int snap_ind = (unsigned int)st; + snap_type = st; + + if (snap_ind > snap_type_strings.size() - 1) { + snap_ind = 0; + snap_type = (SnapType)snap_ind; + } + string str = snap_type_strings[snap_ind]; if (str != snap_type_selector.get_active_text()) { @@ -2190,9 +2300,17 @@ Editor::set_snap_to (SnapType st) case SnapToAEighthBeat: case SnapToAQuarterBeat: case SnapToAThirdBeat: - compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + (nframes_t)(canvas_width * frames_per_unit)); - update_tempo_based_rulers (); + compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + (nframes_t)(edit_packer.get_width() * frames_per_unit)); + update_tempo_based_rulers (); + break; + + case SnapToRegionStart: + case SnapToRegionEnd: + case SnapToRegionSync: + case SnapToRegionBoundary: + build_region_boundary_cache (); break; + default: /* relax */ break; @@ -2212,9 +2330,9 @@ Editor::set_snap_mode (SnapMode mode) instant_save (); } void -Editor::set_edit_point_preference (EditPoint ep) +Editor::set_edit_point_preference (EditPoint ep, bool force) { - bool changed = _edit_point != ep; + bool changed = (_edit_point != ep); _edit_point = ep; string str = edit_point_strings[(int)ep]; @@ -2225,32 +2343,57 @@ Editor::set_edit_point_preference (EditPoint ep) set_canvas_cursor (); - if (!changed) { + if (!force && !changed) { return; } - if (Profile->get_sae()) { - - switch (zoom_focus) { - case ZoomFocusMouse: - case ZoomFocusPlayhead: - case ZoomFocusEdit: - switch (_edit_point) { - case EditAtMouse: - set_zoom_focus (ZoomFocusMouse); - break; - case EditAtPlayhead: - set_zoom_focus (ZoomFocusPlayhead); - break; - case EditAtSelectedMarker: - set_zoom_focus (ZoomFocusEdit); - break; - } + switch (zoom_focus) { + case ZoomFocusMouse: + case ZoomFocusPlayhead: + case ZoomFocusEdit: + switch (_edit_point) { + case EditAtMouse: + set_zoom_focus (ZoomFocusMouse); break; - default: + case EditAtPlayhead: + set_zoom_focus (ZoomFocusPlayhead); + break; + case EditAtSelectedMarker: + set_zoom_focus (ZoomFocusEdit); break; } - } + break; + default: + break; + } + + const char* action; + + switch (_edit_point) { + case EditAtPlayhead: + action = "edit-at-playhead"; + break; + case EditAtSelectedMarker: + action = "edit-at-marker"; + break; + case EditAtMouse: + action = "edit-at-mouse"; + break; + } + + Glib::RefPtr act = ActionManager::get_action ("Editor", action); + if (act) { + Glib::RefPtr::cast_dynamic(act)->set_active (true); + } + + nframes64_t foo; + bool in_track_canvas; + + if (!mouse_frame (foo, in_track_canvas)) { + in_track_canvas = false; + } + + reset_canvas_action_sensitivity (in_track_canvas); instant_save (); } @@ -2290,7 +2433,7 @@ Editor::set_state (const XMLNode& node) move (x, y); if (session && (prop = node.property ("playhead"))) { - nframes_t pos = atol (prop->value().c_str()); + nframes64_t pos = atol (prop->value().c_str()); playhead_cursor->set_position (pos); } else { playhead_cursor->set_position (0); @@ -2325,7 +2468,7 @@ Editor::set_state (const XMLNode& node) } if ((prop = node.property ("edit-point"))) { - set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point)); + set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true); } if ((prop = node.property ("mouse-mode"))) { @@ -2340,7 +2483,7 @@ Editor::set_state (const XMLNode& node) if ((prop = node.property ("show-waveforms"))) { bool yn = (prop->value() == "yes"); _show_waveforms = !yn; - RefPtr act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility")); + RefPtr act = ActionManager::get_action (X_("Editor"), X_("toggle-waveform-visible")); if (act) { RefPtr tact = RefPtr::cast_dynamic(act); /* do it twice to force the change */ @@ -2481,7 +2624,7 @@ Editor::get_state () node->add_property ("edit-point", enum_2_string (_edit_point)); - snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame); + snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame); node->add_property ("playhead", buf); node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no"); @@ -2527,13 +2670,19 @@ Editor::trackview_by_y_position (double y) void Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) { - Location* before = 0; - Location* after = 0; - if (!session || snap_mode == SnapOff) { return; } + snap_to_internal (start, direction, for_mark); +} + +void +Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark) +{ + Location* before = 0; + Location* after = 0; + const nframes64_t one_second = session->frame_rate(); const nframes64_t one_minute = session->frame_rate() * 60; const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame()); @@ -2542,18 +2691,18 @@ Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) switch (snap_type) { case SnapToCDFrame: - if (direction) { - start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75); + if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) { + start = (nframes64_t) ceil ((double) start / (one_second / 75)) * (one_second / 75); } else { - start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75); + start = (nframes64_t) floor ((double) start / (one_second / 75)) * (one_second / 75); } break; case SnapToSMPTEFrame: - if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) { - start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame()); + if (((direction == 0) && (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2))) || (direction > 0)) { + start = (nframes64_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame()); } else { - start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame()); + start = (nframes64_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame()); } break; @@ -2564,10 +2713,10 @@ Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) } else { start -= session->smpte_offset (); } - if (start % one_smpte_second > one_smpte_second / 2) { - start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second; + if (((direction == 0) && (start % one_smpte_second > one_smpte_second / 2)) || direction > 0) { + start = (nframes64_t) ceil ((double) start / one_smpte_second) * one_smpte_second; } else { - start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second; + start = (nframes64_t) floor ((double) start / one_smpte_second) * one_smpte_second; } if (session->smpte_offset_negative()) @@ -2585,10 +2734,10 @@ Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) } else { start -= session->smpte_offset (); } - if (start % one_smpte_minute > one_smpte_minute / 2) { - start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute; + if (((direction == 0) && (start % one_smpte_minute > one_smpte_minute / 2)) || direction > 0) { + start = (nframes64_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute; } else { - start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute; + start = (nframes64_t) floor ((double) start / one_smpte_minute) * one_smpte_minute; } if (session->smpte_offset_negative()) { @@ -2599,18 +2748,18 @@ Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) break; case SnapToSeconds: - if (start % one_second > one_second / 2) { - start = (nframes_t) ceil ((double) start / one_second) * one_second; + if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) { + start = (nframes64_t) ceil ((double) start / one_second) * one_second; } else { - start = (nframes_t) floor ((double) start / one_second) * one_second; + start = (nframes64_t) floor ((double) start / one_second) * one_second; } break; case SnapToMinutes: - if (start % one_minute > one_minute / 2) { - start = (nframes_t) ceil ((double) start / one_minute) * one_minute; + if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) { + start = (nframes64_t) ceil ((double) start / one_minute) * one_minute; } else { - start = (nframes_t) floor ((double) start / one_minute) * one_minute; + start = (nframes64_t) floor ((double) start / one_minute) * one_minute; } break; @@ -2687,7 +2836,7 @@ Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) case SnapToRegionSync: case SnapToRegionBoundary: if (!region_boundary_cache.empty()) { - vector::iterator i; + vector::iterator i; if (direction > 0) { i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start); @@ -2696,11 +2845,19 @@ Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) } if (i != region_boundary_cache.end()) { + + /* lower bound doesn't quite to the right thing for our purposes */ + + if (direction < 0 && i != region_boundary_cache.begin()) { + --i; + } + start = *i; + } else { start = region_boundary_cache.back(); } - } + } break; } @@ -2729,7 +2886,7 @@ Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) } double -Editor::snap_length_beats (nframes_t start) +Editor::snap_length_beats (nframes64_t start) { if (!session) { return 1.0; @@ -3019,6 +3176,9 @@ Editor::setup_midi_toolbar () midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select"))))); midi_tool_select_button.set_relief(Gtk::RELIEF_NONE); midi_tool_buttons.push_back (&midi_tool_select_button); + midi_tool_resize_button.add (*(manage (new Image (::get_icon("strip_width"))))); + midi_tool_resize_button.set_relief(Gtk::RELIEF_NONE); + midi_tool_buttons.push_back (&midi_tool_resize_button); midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase"))))); midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE); midi_tool_buttons.push_back (&midi_tool_erase_button); @@ -3028,29 +3188,34 @@ Editor::setup_midi_toolbar () midi_tool_button_set = new GroupedButtons (midi_tool_buttons); midi_tool_button_box.set_border_width (2); - midi_tool_button_box.set_spacing(4); midi_tool_button_box.set_spacing(1); midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true); midi_tool_button_box.pack_start(midi_tool_select_button, true, true); + midi_tool_button_box.pack_start(midi_tool_resize_button, true, true); midi_tool_button_box.pack_start(midi_tool_erase_button, true, true); midi_tool_button_box.set_homogeneous(true); midi_tool_pencil_button.set_name ("MouseModeButton"); midi_tool_select_button.set_name ("MouseModeButton"); + midi_tool_resize_button.set_name ("MouseModeButton"); midi_tool_erase_button.set_name ("MouseModeButton"); ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes")); ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes")); + ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_resize_button, _("Resize Notes")); ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes")); midi_tool_pencil_button.unset_flags (CAN_FOCUS); midi_tool_select_button.unset_flags (CAN_FOCUS); + midi_tool_resize_button.unset_flags (CAN_FOCUS); midi_tool_erase_button.unset_flags (CAN_FOCUS); midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil)); midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect)); + midi_tool_resize_button.signal_toggled().connect (bind (mem_fun(*this, + &Editor::midi_edit_mode_toggled), Editing::MidiEditResize)); midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::midi_edit_mode_toggled), Editing::MidiEditErase)); @@ -3401,13 +3566,23 @@ Editor::hide_verbose_canvas_cursor () double Editor::clamp_verbose_cursor_x (double x) { - return min (horizontal_adjustment.get_value() + canvas_width - 75.0, x); + if (x < 0) { + x = 0; + } else { + x = min (canvas_width - 200.0, x); + } + return x; } double Editor::clamp_verbose_cursor_y (double y) { - return min (vertical_adjustment.get_value() + canvas_height - 50.0, y); + if (y < canvas_timebars_vsize) { + y = canvas_timebars_vsize; + } else { + y = min (canvas_height - 50, y); + } + return y; } void @@ -3416,7 +3591,7 @@ Editor::set_verbose_canvas_cursor (const string & txt, double x, double y) verbose_canvas_cursor->property_text() = txt.c_str(); /* don't get too close to the edge */ verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x); - verbose_canvas_cursor->property_y() = clamp_verbose_cursor_x (y); + verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (y); } void @@ -3596,7 +3771,9 @@ Editor::zoom_focus_selection_done () focus_type = ZoomFocusPlayhead; } else if (choice == _("Edit")) { focus_type = ZoomFocusEdit; - } else if (choice == _("Edit Point")) { + } else if (choice == _("Active Mark")) { + focus_type = ZoomFocusEdit; + } else if (choice == _("Active Mark")) { focus_type = ZoomFocusEdit; } else { focus_type = ZoomFocusMouse; @@ -3646,7 +3823,7 @@ Editor::get_valid_views (TimeAxisView* track, RouteGroup* group) v->push_back (*i); } - } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) { + } else if ((track != 0 && group == 0) || (track != 0 && group != 0 && !group->is_active())) { /* just the view for this track */ @@ -3728,7 +3905,7 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) } else { pos = atoi (prop->value()); } - + if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) { edit_pane.set_position (pos); pre_maximal_pane_position = pos; @@ -3836,10 +4013,10 @@ Editor::playlist_selector () const return *_playlist_selector; } -nframes_t -Editor::get_nudge_distance (nframes_t pos, nframes_t& next) +nframes64_t +Editor::get_nudge_distance (nframes64_t pos, nframes64_t& next) { - nframes_t ret; + nframes64_t ret; ret = nudge_clock.current_duration (pos); next = ret + 1; /* XXXX fix me */ @@ -3851,7 +4028,8 @@ void Editor::end_location_changed (Location* location) { ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location)); - reset_scrolling_region (); + //reset_scrolling_region (); + horizontal_adjustment.set_upper ( location->start()); } int @@ -3891,7 +4069,7 @@ Editor::playlist_deletion_dialog (boost::shared_ptr pl) } bool -Editor::audio_region_selection_covers (nframes_t where) +Editor::audio_region_selection_covers (nframes64_t where) { for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) { if ((*a)->region()->covers (where)) { @@ -3910,6 +4088,15 @@ Editor::prepare_for_cleanup () selection->clear_regions (); selection->clear_playlists (); + + no_region_list_redisplay = true; +} + +void +Editor::finish_cleanup () +{ + no_region_list_redisplay = false; + redisplay_regions (); } Location* @@ -4113,8 +4300,6 @@ Editor::session_state_saved (string snap_name) void Editor::maximise_editing_space () { - initial_ruler_update_required = true; - mouse_mode_tearoff->set_visible (false); tools_tearoff->set_visible (false); @@ -4125,8 +4310,8 @@ Editor::maximise_editing_space () post_maximal_pane_position = edit_pane.get_width(); } - fullscreen(); + if(post_maximal_editor_width) { edit_pane.set_position (post_maximal_pane_position - abs(post_maximal_editor_width - pre_maximal_editor_width)); @@ -4138,9 +4323,8 @@ Editor::maximise_editing_space () void Editor::restore_editing_space () { - initial_ruler_update_required = true; - // user changed width of pane during fullscreen + if(post_maximal_pane_position != edit_pane.get_position()) { post_maximal_pane_position = edit_pane.get_position(); } @@ -4151,10 +4335,7 @@ Editor::restore_editing_space () tools_tearoff->set_visible (true); post_maximal_editor_width = this->get_width(); - - edit_pane.set_position ( - pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width) - ); + edit_pane.set_position (pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)); } /** @@ -4231,8 +4412,9 @@ Editor::on_key_release_event (GdkEventKey* ev) } void -Editor::reset_x_origin (nframes_t frame) +Editor::reset_x_origin (nframes64_t frame) { + //cerr << "resetting x origin" << endl; queue_visual_change (frame); } @@ -4243,28 +4425,97 @@ Editor::reset_zoom (double fpu) } void -Editor::reposition_and_zoom (nframes_t frame, double fpu) +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); + + if (!no_save_visual) { + undo_visual_stack.push_back (current_visual_state(false)); + } +} + +Editor::VisualState* +Editor::current_visual_state (bool with_tracks) +{ + VisualState* vs = new VisualState; + vs->y_position = vertical_adjustment.get_value(); + vs->frames_per_unit = frames_per_unit; + vs->leftmost_frame = leftmost_frame; + vs->zoom_focus = zoom_focus; + vs->zoomed_to_region = zoomed_to_region; + + if (with_tracks) { + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + vs->track_states.push_back (TAVState ((*i), &(*i)->get_state())); + } + } + + return vs; } void -Editor::swap_visual_state () +Editor::undo_visual_state () { - if (last_visual_state.frames_per_unit == 0) { - // never set + if (undo_visual_stack.empty()) { return; } - /* note: the correct functionality here is very dependent on the ordering of - setting zoom focus, horizontal position and finally zoom. this is because - it is set_frames_per_unit() that overwrites last_visual_state. - */ + VisualState* vs = undo_visual_stack.back(); + undo_visual_stack.pop_back(); + use_visual_state (*vs); + redo_visual_stack.push_back (vs); +} - set_zoom_focus (last_visual_state.zoom_focus); - reposition_and_zoom (last_visual_state.leftmost_frame, last_visual_state.frames_per_unit); - zoomed_to_region = false; +void +Editor::redo_visual_state () +{ + if (redo_visual_stack.empty()) { + return; + } + + VisualState* vs = redo_visual_stack.back(); + redo_visual_stack.pop_back(); + use_visual_state (*vs); + undo_visual_stack.push_back (vs); +} + +void +Editor::swap_visual_state () +{ + if (undo_visual_stack.empty()) { + redo_visual_state (); + } else { + undo_visual_state (); + } +} + +void +Editor::use_visual_state (VisualState& vs) +{ + no_save_visual = true; + + vertical_adjustment.set_value (vs.y_position); + + set_zoom_focus (vs.zoom_focus); + reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit); + + for (list::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) { + TrackViewList::iterator t; + + /* check if the track still exists - it could have been deleted */ + + if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) { + (*t)->set_state (*(i->second)); + } + } + + if (!vs.track_states.empty()) { + update_route_visibility (); + } + + no_save_visual = false; } void @@ -4291,14 +4542,6 @@ Editor::set_frames_per_unit (double fpu) return; } - if (fpu == frames_per_unit) { - return; - } - - last_visual_state.frames_per_unit = frames_per_unit; - last_visual_state.leftmost_frame = leftmost_frame; - last_visual_state.zoom_focus = zoom_focus; - frames_per_unit = fpu; post_zoom (); } @@ -4308,7 +4551,7 @@ Editor::post_zoom () { // convert fpu to frame count - nframes_t frames = (nframes_t) floor (frames_per_unit * canvas_width); + nframes64_t frames = (nframes64_t) floor (frames_per_unit * canvas_width); if (frames_per_unit != zoom_range_clock.current_duration()) { zoom_range_clock.set (frames); @@ -4329,20 +4572,24 @@ Editor::post_zoom () ZoomChanged (); /* EMIT_SIGNAL */ reset_hscrollbar_stepping (); - reset_scrolling_region (); + //reset_scrolling_region (); - if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame); + if (playhead_cursor) { + playhead_cursor->set_position (playhead_cursor->current_frame); + } instant_save (); } void -Editor::queue_visual_change (nframes_t where) +Editor::queue_visual_change (nframes64_t where) { - pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin); - pending_visual_change.time_origin = where; - +// pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin); +// pending_visual_change.time_origin = where; + if (pending_visual_change.idle_handler_id < 0) { + pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin); + pending_visual_change.time_origin = where; pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this); } } @@ -4369,30 +4616,41 @@ int Editor::idle_visual_changer () { VisualChange::Type p = pending_visual_change.pending; - pending_visual_change.pending = (VisualChange::Type) 0; 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 + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit)); - compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit)); + compute_fixed_ruler_scale (); + compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(edit_packer.get_width() * pending_visual_change.frames_per_unit)); + compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(edit_packer.get_width() * pending_visual_change.frames_per_unit)); update_tempo_based_rulers (); } if (p & VisualChange::TimeOrigin) { - - nframes_t time_origin = (nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit); - if (time_origin != pending_visual_change.time_origin) { - horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit); + nframes64_t csf, cef; + nframes64_t current_time_origin = (nframes64_t) floor (horizontal_adjustment.get_value() * frames_per_unit); + + if (session) { + csf = session->current_start_frame(); + cef = session->current_end_frame() + (current_page_frames() / 24);// Add a little extra so we can see the end marker + } + + /* if we seek beyond the current end of the canvas, move the end */ + + if (current_time_origin != pending_visual_change.time_origin) { + //if (horizontal_adjustment.get_upper() < pending_visual_change.time_origin) { + last_canvas_frame = (cef > (pending_visual_change.time_origin + current_page_frames())) ? cef : pending_visual_change.time_origin + current_page_frames(); + horizontal_adjustment.set_upper ((cef - csf) / frames_per_unit); + //} + horizontal_adjustment.set_value (pending_visual_change.time_origin / frames_per_unit); } else { update_fixed_rulers(); redisplay_tempo (true); } } + //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 */ } @@ -4463,7 +4721,7 @@ Editor::get_preferred_edit_position (bool ignore_playhead) } void -Editor::set_loop_range (nframes_t start, nframes_t end, string cmd) +Editor::set_loop_range (nframes64_t start, nframes64_t end, string cmd) { if (!session) return; @@ -4478,8 +4736,7 @@ Editor::set_loop_range (nframes_t start, nframes_t end, string cmd) session->set_auto_loop_location (loc); XMLNode &after = session->locations()->get_state(); session->add_command (new MementoCommand(*(session->locations()), &before, &after)); - } - else { + } else { XMLNode &before = tll->get_state(); tll->set_hidden (false, this); tll->set (start, end); @@ -4491,7 +4748,7 @@ Editor::set_loop_range (nframes_t start, nframes_t end, string cmd) } void -Editor::set_punch_range (nframes_t start, nframes_t end, string cmd) +Editor::set_punch_range (nframes64_t start, nframes64_t end, string cmd) { if (!session) return; @@ -4539,14 +4796,14 @@ Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackSelec if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) { - Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)where * ds->speed())); + Playlist::RegionList* regions = pl->regions_at ((nframes64_t) floor ( (double)where * ds->speed())); for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { RegionView* rv = atv->audio_view()->find_view (*i); if (rv) { - rs.push_back (rv); + rs.add (rv); } } @@ -4577,7 +4834,7 @@ Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSe if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) { - Playlist::RegionList* regions = pl->regions_touched ((nframes_t) floor ( (double)where * ds->speed()), max_frames); + Playlist::RegionList* regions = pl->regions_touched ((nframes64_t) floor ( (double)where * ds->speed()), max_frames); for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { @@ -4597,21 +4854,24 @@ Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSe void Editor::get_regions_for_action (RegionSelection& rs, bool allow_entered) { - bool use_regions_at = true; - if (selection->regions.empty()) { if (selection->tracks.empty()) { - /* no regions or tracks selected, but entered regionview is valid - and we're in object mode - just use entered regionview + /* no regions or tracks selected */ - if (entered_regionview && (mouse_mode == Editing::MouseObject)) { + if (entered_regionview && mouse_mode == Editing::MouseObject) { + + /* entered regionview is valid and we're in object mode - + just use entered regionview + */ + rs.add (entered_regionview); - return; } + return; + } else { /* no regions selected, so get all regions at the edit point across @@ -4694,3 +4954,198 @@ Editor::show_rhythm_ferret () rhythm_ferret->show (); rhythm_ferret->present (); } + +void +Editor::first_idle () +{ + MessageDialog* dialog = 0; + + if (track_views.size() > 1) { + dialog = new MessageDialog (*this, + _("Please wait while Ardour loads visual data"), + true, + Gtk::MESSAGE_INFO, + Gtk::BUTTONS_NONE); + dialog->present (); + ARDOUR_UI::instance()->flush_pending (); + } + + for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) { + (*t)->first_idle(); + } + + if (dialog) { + delete dialog; + } + + _have_idled = true; +} + +void +Editor::start_resize_line_ops () +{ +#if 0 + old_resize_line_y = -1; + resize_line_y = -1; + need_resize_line = true; +#endif +} + +void +Editor::end_resize_line_ops () +{ +#if 0 + need_resize_line = false; + + if (old_resize_line_y >= 0) { + Gdk::Rectangle r (0, old_resize_line_y, (int) canvas_width, 3); + Glib::RefPtr win = get_window(); + cerr << "Final invalidation at " << old_resize_line_y << endl; + win->invalidate_rect (r, false); + } +#endif +} + +void +Editor::queue_draw_resize_line (int at) +{ +#if 0 + Glib::RefPtr win = get_window(); + + resize_line_y = at; + + if (win && canvas_width) { + + int controls_width = controls_layout.get_width(); + int xroot, discard; + + controls_layout.get_window()->get_origin (xroot, discard); + + if (old_resize_line_y >= 0) { + + /* redraw where it used to be */ + + + Gdk::Rectangle r (0, old_resize_line_y - 1, controls_width + (int) canvas_width, 3); + win->invalidate_rect (r, true); + cerr << "invalidate " << xroot << "," << old_resize_line_y - 1 << ' ' + << controls_width + canvas_width << " x 3\n"; + } + + /* draw where it is */ + + Gdk::Rectangle r (0, at - 1, controls_width + (int) canvas_width, 3); + win->invalidate_rect (r, true); + } +#endif +} + +bool +Editor::on_expose_event (GdkEventExpose* ev) +{ + /* cerr << "+++ editor expose " + << ev->area.x << ',' << ev->area.y + << ' ' + << ev->area.width << " x " << ev->area.height + << " need reize ? " << need_resize_line + << endl; + */ + bool ret = Window::on_expose_event (ev); + +#if 0 + if (need_resize_line) { + + int xroot, yroot, discard; + int controls_width; + + /* Our root coordinates for drawing the line will be the left edge + of the track controls, and the upper left edge of our own window. + */ + + get_window()->get_origin (discard, yroot); + controls_layout.get_window()->get_origin (xroot, discard); + controls_width = controls_layout.get_width(); + + GdkRectangle lr; + GdkRectangle intersection; + + lr.x = 0; + lr.y = resize_line_y; + lr.width = controls_width + (int) canvas_width; + lr.height = 3; + + if (gdk_rectangle_intersect (&lr, &ev->area, &intersection)) { + + Glib::RefPtr style (get_style()); + Glib::RefPtr black_gc (style->get_black_gc ()); + Glib::RefPtr gc = wrap (black_gc->gobj_copy(), false); + + /* draw on root window */ + + GdkWindow* win = gdk_get_default_root_window(); + + gc->set_subwindow (Gdk::INCLUDE_INFERIORS); + gc->set_line_attributes (3, Gdk::LINE_SOLID, + Gdk::CAP_NOT_LAST, + Gdk::JOIN_MITER); + + gdk_draw_line (win, gc->gobj(), + 0, + resize_line_y, + (int) canvas_width + controls_width, + resize_line_y); +#if 0 + cerr << "drew line @ " << xroot << ", " << yroot + resize_line_y + << " to " << xroot + (int) canvas_width + controls_width + << ", " << yroot + resize_line_y + << endl; +#endif + old_resize_line_y = resize_line_y; + cerr << "NEXT EXPOSE SHOULD BE AT " << old_resize_line_y << endl; + } else { + cerr << "no intersect with " + << lr.x << ',' << lr.y + << ' ' + << lr.width << " x " << lr.height + << endl; + } + } + + //cerr << "--- editor expose\n"; +#endif + + return ret; +} + +static gboolean +_idle_resizer (gpointer arg) +{ + return ((Editor*)arg)->idle_resize (); +} + +void +Editor::add_to_idle_resize (TimeAxisView* view, uint32_t h) +{ + if (resize_idle_id < 0) { + resize_idle_id = g_idle_add (_idle_resizer, this); + } + + resize_idle_target = h; + + pending_resizes.push_back (view); + + if (selection->selected (view) && !selection->tracks.empty()) { + pending_resizes.insert (pending_resizes.end(), selection->tracks.begin(), selection->tracks.end()); + } +} + +bool +Editor::idle_resize () +{ + for (vector::iterator i = pending_resizes.begin(); i != pending_resizes.end(); ++i) { + (*i)->idle_resize (resize_idle_target); + } + pending_resizes.clear(); + resize_idle_id = -1; + return false; +}