X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=fec951f9d20987bc403d7a67d46ca856286b2468;hb=e35621772ee93f7fbadeac5ff636d2c83eb6780f;hp=c0fd7b0a20b8dfb85ee709059382240edff4ecc9;hpb=a0e85682664b612e555c5757cac3945acc2e8034;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index c0fd7b0a20..fec951f9d2 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -62,6 +63,7 @@ #include "selection.h" #include "audio_streamview.h" #include "time_axis_view.h" +#include "audio_time_axis.h" #include "utils.h" #include "crossfade_view.h" #include "editing.h" @@ -176,7 +178,7 @@ Editor::Editor (AudioEngine& eng) minsec_label (_("Mins:Secs")), bbt_label (_("Bars:Beats")), - smpte_label (_("SMPTE")), + smpte_label (_("Timecode")), frame_label (_("Frames")), tempo_label (_("Tempo")), meter_label (_("Meter")), @@ -195,8 +197,8 @@ Editor::Editor (AudioEngine& eng) /* tool bar related */ - edit_cursor_clock (X_("EditCursorClock"), true), - zoom_range_clock (X_("ZoomRangeClock"), true, true), + edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true), + zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true), toolbar_selection_clock_table (2,3), @@ -209,7 +211,7 @@ Editor::Editor (AudioEngine& eng) /* nudge */ - nudge_clock (X_("NudgeClock"), true, true) + nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true) { constructed = false; @@ -282,13 +284,14 @@ Editor::Editor (AudioEngine& eng) route_list_menu = 0; region_list_menu = 0; marker_menu = 0; + start_end_marker_menu = 0; range_marker_menu = 0; marker_menu_item = 0; tm_marker_menu = 0; transport_marker_menu = 0; new_transport_marker_menu = 0; editor_mixer_strip_width = Wide; - repos_zoom_queued = false; + show_editor_mixer_when_tracks_arrive = false; region_edit_menu_split_item = 0; temp_location = 0; region_edit_menu_split_multichannel_item = 0; @@ -305,6 +308,8 @@ Editor::Editor (AudioEngine& eng) edit_cursor = 0; playhead_cursor = 0; button_release_can_deselect = true; + canvas_idle_queued = false; + _dragging_playhead = false; location_marker_color = color_map[cLocationMarker]; location_range_color = color_map[cLocationRange]; @@ -317,7 +322,7 @@ Editor::Editor (AudioEngine& eng) set_mouse_mode (MouseObject, true); - frames_per_unit = 2048; /* too early to use set_frames_per_unit */ + frames_per_unit = 2048; /* too early to use reset_zoom () */ reset_hscrollbar_stepping (); zoom_focus = ZoomFocusLeft; @@ -354,6 +359,8 @@ Editor::Editor (AudioEngine& eng) edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release)); edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate)); + edit_hscrollbar.set_name ("EditorHScrollbar"); + build_cursors (); setup_toolbar (); @@ -440,6 +447,7 @@ Editor::Editor (AudioEngine& eng) 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 (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0); edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0); bottom_hbox.set_border_width (2); @@ -447,7 +455,7 @@ Editor::Editor (AudioEngine& eng) route_display_model = ListStore::create(route_display_columns); route_list_display.set_model (route_display_model); - route_list_display.append_column (_("Visible"), route_display_columns.visible); + route_list_display.append_column (_("Show"), route_display_columns.visible); route_list_display.append_column (_("Name"), route_display_columns.text); route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); @@ -473,7 +481,7 @@ Editor::Editor (AudioEngine& eng) edit_group_display.set_model (group_model); edit_group_display.append_column (_("Name"), group_columns.text); edit_group_display.append_column (_("Active"), group_columns.is_active); - edit_group_display.append_column (_("Visible"), group_columns.is_visible); + edit_group_display.append_column (_("Show"), group_columns.is_visible); edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2)); @@ -498,12 +506,11 @@ Editor::Editor (AudioEngine& eng) active_cell->property_activatable() = true; active_cell->property_radio() = false; - edit_group_display.set_name ("EditGroupList"); - group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change)); edit_group_display.set_name ("EditGroupList"); edit_group_display.get_selection()->set_mode (SELECTION_SINGLE); + edit_group_display.set_headers_visible (false); edit_group_display.set_reorderable (false); edit_group_display.set_rules_hint (true); edit_group_display.set_size_request (75, -1); @@ -514,7 +521,7 @@ Editor::Editor (AudioEngine& eng) edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false); VBox* edit_group_display_packer = manage (new VBox()); - HButtonBox* edit_group_display_button_box = manage (new HButtonBox()); + HBox* edit_group_display_button_box = manage (new HBox()); edit_group_display_button_box->set_homogeneous (true); Button* edit_group_add_button = manage (new Button ()); @@ -549,7 +556,6 @@ Editor::Editor (AudioEngine& eng) 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.set_hover_expand (true); region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter)); @@ -590,11 +596,12 @@ Editor::Editor (AudioEngine& eng) named_selection_display.append_column (_("Chunks"), named_selection_columns.text); named_selection_display.set_headers_visible (false); named_selection_display.set_size_request (100, -1); - named_selection_display.set_name ("RegionListDisplay"); + named_selection_display.set_name ("NamedSelectionDisplay"); named_selection_display.get_selection()->set_mode (SELECTION_SINGLE); named_selection_display.set_size_request (100, -1); - named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press), false); + named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false); + named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false); named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed)); /* SNAPSHOTS */ @@ -602,7 +609,7 @@ Editor::Editor (AudioEngine& eng) snapshot_display_model = ListStore::create (snapshot_display_columns); snapshot_display.set_model (snapshot_display_model); snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name); - snapshot_display.set_name ("SnapshotDisplayList"); + snapshot_display.set_name ("SnapshotDisplay"); snapshot_display.set_size_request (75, -1); snapshot_display.set_headers_visible (false); snapshot_display.set_reorderable (false); @@ -635,6 +642,8 @@ Editor::Editor (AudioEngine& eng) the_notebook.popup_enable (); the_notebook.set_tab_pos (Gtk::POS_RIGHT); + post_maximal_editor_width = 0; + post_maximal_pane_position = 0; edit_pane.pack1 (edit_packer, true, true); edit_pane.pack2 (the_notebook, false, true); @@ -680,8 +689,29 @@ Editor::Editor (AudioEngine& eng) fade_context_menu.set_name ("ArdourContextMenu"); + /* icons, titles, WM stuff */ + + list > window_icons; + Glib::RefPtr icon; + + if ((icon = ::get_icon ("ardour_icon_16px")) != 0) { + window_icons.push_back (icon); + } + if ((icon = ::get_icon ("ardour_icon_22px")) != 0) { + window_icons.push_back (icon); + } + if ((icon = ::get_icon ("ardour_icon_32px")) != 0) { + window_icons.push_back (icon); + } + if ((icon = ::get_icon ("ardour_icon_48px")) != 0) { + window_icons.push_back (icon); + } + if (!window_icons.empty()) { + set_icon_list (window_icons); + set_default_icon_list (window_icons); + } set_title (_("ardour: editor")); - set_wmclass (_("ardour_editor"), "Ardour"); + set_wmclass (X_("ardour_editor"), "Ardour"); add (vpacker); add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); @@ -796,65 +826,6 @@ Editor::tie_vertical_scrolling () edit_cursor->set_y_axis(y1); } -void -Editor::set_frames_per_unit (double fpu) -{ - nframes_t frames; - - if (fpu == frames_per_unit) { - return; - } - - if (fpu < 2.0) { - fpu = 2.0; - } - - // convert fpu to frame count - - frames = (nframes_t) floor (fpu * canvas_width); - - /* don't allow zooms that fit more than the maximum number - of frames into an 800 pixel wide space. - */ - - if (max_frames / fpu < 800.0) { - return; - } - - if (fpu == frames_per_unit) { - return; - } - - frames_per_unit = fpu; - - if (frames != zoom_range_clock.current_duration()) { - zoom_range_clock.set (frames); - } - - if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) { - if (!selection->tracks.empty()) { - for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - (*i)->reshow_selection (selection->time); - } - } else { - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->reshow_selection (selection->time); - } - } - } - - ZoomChanged (); /* EMIT_SIGNAL */ - - reset_hscrollbar_stepping (); - reset_scrolling_region (); - - if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame); - if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame); - - instant_save (); - -} - void Editor::instant_save () { @@ -869,26 +840,6 @@ Editor::instant_save () } } -void -Editor::reposition_x_origin (nframes_t frame) -{ - if (frame != leftmost_frame) { - leftmost_frame = frame; - - nframes_t rightmost_frame = leftmost_frame + current_page_frames (); - - if (rightmost_frame > last_canvas_frame) { - last_canvas_frame = rightmost_frame; - reset_scrolling_region (); - } - - horizontal_adjustment.set_value (frame/frames_per_unit); - } else { - update_fixed_rulers(); - tempo_map_changed (Change (0)); - } -} - void Editor::edit_cursor_clock_changed() { @@ -944,9 +895,9 @@ Editor::control_scroll (float fraction) if (target > (current_page_frames() / 2)) { /* try to center PH in window */ - reposition_x_origin (target - (current_page_frames()/2)); + reset_x_origin (target - (current_page_frames()/2)); } else { - reposition_x_origin (0); + reset_x_origin (0); } /* cancel the existing */ @@ -965,36 +916,6 @@ Editor::deferred_control_scroll (nframes_t target) return false; } -void -Editor::canvas_horizontally_scrolled () -{ - - leftmost_frame = (nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit); - update_fixed_rulers (); - tempo_map_changed (Change (0)); - -} - -void -Editor::reposition_and_zoom (nframes_t frame, double nfpu) -{ - if (!repos_zoom_queued) { - repos_zoom_queued = true; - Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu)); - } -} - -gint -Editor::deferred_reposition_and_zoom (nframes_t frame, double nfpu) -{ - - set_frames_per_unit (nfpu); - reposition_x_origin (frame); - repos_zoom_queued = false; - - return FALSE; -} - void Editor::on_realize () { @@ -1052,7 +973,7 @@ Editor::center_screen_internal (nframes_t frame, float page) frame = 0; } - reposition_x_origin (frame); + reset_x_origin (frame); } void @@ -1112,6 +1033,13 @@ Editor::connect_to_session (Session *t) { session = t; + XMLNode* node = ARDOUR_UI::instance()->editor_settings(); + set_state (*node); + + /* catch up with the playhead */ + + session->request_locate (playhead_cursor->current_frame); + if (first_action_message) { first_action_message->hide(); } @@ -1119,6 +1047,7 @@ Editor::connect_to_session (Session *t) update_title (); session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away)); + session->history().Changed.connect (mem_fun (*this, &Editor::history_changed)); /* These signals can all be emitted by a non-GUI thread. Therefore the handlers for them must not attempt to directly interact with the GUI, @@ -1207,27 +1136,12 @@ Editor::connect_to_session (Session *t) (static_cast(*i))->set_samples_per_unit (frames_per_unit); } - /* ::reposition_x_origin() doesn't work right here, since the old - position may be zero already, and it does nothing in such - circumstances. - */ - - leftmost_frame = 0; - - horizontal_adjustment.set_value (0); - restore_ruler_visibility (); //tempo_map_changed (Change (0)); session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); - edit_cursor->set_position (0); - playhead_cursor->set_position (0); - start_scrolling (); - XMLNode* node = ARDOUR_UI::instance()->editor_settings(); - set_state (*node); - /* don't show master bus in a new session */ if (ARDOUR_UI::instance()->session_is_new ()) { @@ -1311,7 +1225,6 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i } MenuList& items (fade_context_menu.items()); - AudioRegion& ar (*arv->audio_region().get()); // FIXME items.clear (); @@ -1319,37 +1232,38 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i case FadeInItem: case FadeInHandleItem: if (arv->audio_region()->fade_in_active()) { - items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false))); + items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false))); } else { - items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true))); + items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true))); } items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Linear"), bind (mem_fun (ar, &AudioRegion::set_fade_in_shape), AudioRegion::Linear))); - items.push_back (MenuElem (_("Slowest"), bind (mem_fun (ar, &AudioRegion::set_fade_in_shape), AudioRegion::LogB))); - items.push_back (MenuElem (_("Slow"), bind (mem_fun (ar, &AudioRegion::set_fade_in_shape), AudioRegion::Fast))); - items.push_back (MenuElem (_("Fast"), bind (mem_fun (ar, &AudioRegion::set_fade_in_shape), AudioRegion::LogA))); - items.push_back (MenuElem (_("Fastest"), bind (mem_fun (ar, &AudioRegion::set_fade_in_shape), AudioRegion::Slow))); + items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB))); + items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast))); + items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA))); + items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow))); break; case FadeOutItem: case FadeOutHandleItem: if (arv->audio_region()->fade_out_active()) { - items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false))); + items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false))); } else { - items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true))); + items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true))); } items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Linear"), bind (mem_fun (ar, &AudioRegion::set_fade_out_shape), AudioRegion::Linear))); - items.push_back (MenuElem (_("Slowest"), bind (mem_fun (ar, &AudioRegion::set_fade_out_shape), AudioRegion::Fast))); - items.push_back (MenuElem (_("Slow"), bind (mem_fun (ar, &AudioRegion::set_fade_out_shape), AudioRegion::LogB))); - items.push_back (MenuElem (_("Fast"), bind (mem_fun (ar, &AudioRegion::set_fade_out_shape), AudioRegion::LogA))); - items.push_back (MenuElem (_("Fastest"), bind (mem_fun (ar, &AudioRegion::set_fade_out_shape), AudioRegion::Slow))); + items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast))); + items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB))); + items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA))); + items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow))); break; + default: fatal << _("programming error: ") << X_("non-fade canvas item passed to popup_fade_context_menu()") @@ -1510,7 +1424,7 @@ Editor::build_track_region_context_menu (nframes_t frame) if (atv) { boost::shared_ptr ds; - Playlist* pl; + boost::shared_ptr pl; if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) { Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed())); @@ -1537,10 +1451,10 @@ Editor::build_track_crossfade_context_menu (nframes_t frame) if (atv) { boost::shared_ptr ds; - Playlist* pl; - AudioPlaylist* apl; + boost::shared_ptr pl; + boost::shared_ptr apl; - if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast (pl)) != 0)) { + if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast (pl)) != 0)) { Playlist::RegionList* regions = pl->regions_at (frame); AudioPlaylist::Crossfades xfades; @@ -1620,7 +1534,7 @@ Editor::build_track_selection_context_menu (nframes_t ignored) } void -Editor::add_crossfade_context_items (AudioStreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many) +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); @@ -1634,8 +1548,8 @@ Editor::add_crossfade_context_items (AudioStreamView* view, Crossfade* xfade, Me str = _("Unmute"); } - items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade))); - items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade))); + items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr (xfade)))); + items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr (xfade)))); if (xfade->can_follow_overlap()) { @@ -1714,32 +1628,50 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr items.push_back (SeparatorElem()); - /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler - might be able to figure out which overloaded member function to use in - a bind() call ... - */ + items.push_back (CheckMenuElem (_("Lock"), mem_fun(*this, &Editor::toggle_region_lock))); + region_lock_item = static_cast(&items.back()); + if (region->locked()) { + region_lock_item->set_active(); + } + items.push_back (CheckMenuElem (_("Mute"), mem_fun(*this, &Editor::toggle_region_mute))); + region_mute_item = static_cast(&items.back()); + if (region->muted()) { + region_mute_item->set_active(); + } + items.push_back (CheckMenuElem (_("Opaque"), mem_fun(*this, &Editor::toggle_region_opaque))); + region_opaque_item = static_cast(&items.back()); + if (region->opaque()) { + region_opaque_item->set_active(); + } - void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op; + items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize))); + if (region->at_natural_position()) { + items.back().set_sensitive (false); + } - items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true))); - items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false))); items.push_back (SeparatorElem()); - if (region->muted()) { - items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false))); - } else { - items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true))); - } - items.push_back (SeparatorElem()); + if (ar) { + + RegionView* rv = sv->find_view (ar); + AudioRegionView* arv = dynamic_cast(rv); - items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize))); - items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes))); + + items.push_back (CheckMenuElem (_("Envelope Visible"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility))); + region_envelope_visible_item = static_cast (&items.back()); + if (arv->envelope_visible()) { + region_envelope_visible_item->set_active (true); + } - if (ar) { + items.push_back (CheckMenuElem (_("Envelope Active"), mem_fun(*this, &Editor::toggle_gain_envelope_active))); + region_envelope_active_item = static_cast (&items.back()); + + if (ar->envelope_active()) { + region_envelope_active_item->set_active (true); + } - items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility))); - items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active))); items.push_back (SeparatorElem()); if (ar->scale_amplitude() != 1.0f) { @@ -1755,7 +1687,7 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr /* range related stuff */ items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region))); - items.push_back (MenuElem (_("Set Range"), mem_fun (*this, &Editor::set_selection_from_audio_region))); + items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region))); items.push_back (SeparatorElem()); /* Nudge region */ @@ -1792,8 +1724,6 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr 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 (SeparatorElem()); - items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region))); /* OK, stick the region submenu at the top of the list, and then add the standard items. @@ -1838,13 +1768,14 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) items.push_back (SeparatorElem()); items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection))); items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection))); items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop))); items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch))); items.push_back (SeparatorElem()); items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection))); items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection))); 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::name_selection))); + 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))); @@ -1864,7 +1795,7 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) MenuList& play_items = play_menu->items(); play_menu->set_name ("ArdourContextMenu"); - play_items.push_back (MenuElem (_("Play from edit cursor"))); + play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor))); play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start))); play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region))); play_items.push_back (SeparatorElem()); @@ -1949,7 +1880,7 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items) MenuList& play_items = play_menu->items(); play_menu->set_name ("ArdourContextMenu"); - play_items.push_back (MenuElem (_("Play from edit cursor"))); + play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor))); play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start))); edit_items.push_back (MenuElem (_("Play"), *play_menu)); @@ -2068,12 +1999,34 @@ Editor::set_state (const XMLNode& node) set_default_size (g.base_width, g.base_height); move (x, y); + if (session && (prop = node.property ("playhead"))) { + nframes_t pos = atol (prop->value().c_str()); + playhead_cursor->set_position (pos); + } else { + playhead_cursor->set_position (0); + + /* reset_x_origin() doesn't work right here, since the old + position may be zero already, and it does nothing in such + circumstances. + */ + + leftmost_frame = 0; + horizontal_adjustment.set_value (0); + } + + if (session && (prop = node.property ("edit-cursor"))) { + nframes_t pos = atol (prop->value().c_str()); + edit_cursor->set_position (pos); + } else { + edit_cursor->set_position (0); + } + if ((prop = node.property ("zoom-focus"))) { set_zoom_focus ((ZoomFocus) atoi (prop->value())); } if ((prop = node.property ("zoom"))) { - set_frames_per_unit (PBD::atof (prop->value())); + reset_zoom (PBD::atof (prop->value())); } if ((prop = node.property ("snap-to"))) { @@ -2156,6 +2109,7 @@ Editor::set_state (const XMLNode& node) Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer")); if (act) { + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); bool yn = (prop->value() == X_("yes")); @@ -2216,6 +2170,11 @@ Editor::get_state () snprintf (buf, sizeof(buf), "%d", (int) snap_mode); node->add_property ("snap-mode", buf); + snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame); + node->add_property ("playhead", buf); + snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame); + node->add_property ("edit-cursor", buf); + node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no"); node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no"); node->add_property ("show-measures", _show_measures ? "yes" : "no"); @@ -2238,18 +2197,11 @@ Editor::get_state () TimeAxisView * Editor::trackview_by_y_position (double y) { - TrackViewList::iterator iter; - TimeAxisView *tv; - - for (iter = track_views.begin(); iter != track_views.end(); ++iter) { + for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) { - tv = *iter; + TimeAxisView *tv; - if (tv->hidden()) { - continue; - } - - if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) { + if ((tv = (*iter)->covers_y_position (y)) != 0) { return tv; } } @@ -2269,7 +2221,8 @@ Editor::snap_to (nframes_t& start, int32_t direction, bool for_mark) const nframes_t one_second = session->frame_rate(); const nframes_t one_minute = session->frame_rate() * 60; - + const nframes_t one_smpte_second = (nframes_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame()); + nframes_t one_smpte_minute = (nframes_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60); nframes_t presnap = start; switch (snap_type) { @@ -2283,8 +2236,9 @@ Editor::snap_to (nframes_t& start, int32_t direction, bool for_mark) start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75); } break; + case SnapToSMPTEFrame: - if (direction) { + 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()); } else { start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame()); @@ -2298,10 +2252,10 @@ Editor::snap_to (nframes_t& start, int32_t direction, bool for_mark) } else { start -= session->smpte_offset (); } - if (direction > 0) { - start = (nframes_t) ceil ((double) start / one_second) * one_second; + if (start % one_smpte_second > one_smpte_second / 2) { + start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second; } else { - start = (nframes_t) floor ((double) start / one_second) * one_second; + start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second; } if (session->smpte_offset_negative()) @@ -2319,10 +2273,10 @@ Editor::snap_to (nframes_t& start, int32_t direction, bool for_mark) } else { start -= session->smpte_offset (); } - if (direction) { - start = (nframes_t) ceil ((double) start / one_minute) * one_minute; + if (start % one_smpte_minute > one_smpte_minute / 2) { + start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute; } else { - start = (nframes_t) floor ((double) start / one_minute) * one_minute; + start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute; } if (session->smpte_offset_negative()) { @@ -2333,7 +2287,7 @@ Editor::snap_to (nframes_t& start, int32_t direction, bool for_mark) break; case SnapToSeconds: - if (direction) { + if (start % one_second > one_second / 2) { start = (nframes_t) ceil ((double) start / one_second) * one_second; } else { start = (nframes_t) floor ((double) start / one_second) * one_second; @@ -2341,7 +2295,7 @@ Editor::snap_to (nframes_t& start, int32_t direction, bool for_mark) break; case SnapToMinutes: - if (direction) { + if (start % one_minute > one_minute / 2) { start = (nframes_t) ceil ((double) start / one_minute) * one_minute; } else { start = (nframes_t) floor ((double) start / one_minute) * one_minute; @@ -2573,35 +2527,33 @@ Editor::setup_toolbar () zoom_box.set_border_width (2); zoom_in_button.set_name ("EditorTimeButton"); + zoom_in_button.set_size_request(-1,16); zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in"))))); zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false)); ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In")); zoom_out_button.set_name ("EditorTimeButton"); + zoom_out_button.set_size_request(-1,16); zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out"))))); zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true)); ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out")); zoom_out_full_button.set_name ("EditorTimeButton"); + zoom_out_full_button.set_size_request(-1,16); zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full"))))); zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session)); ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session")); - - zoom_box.pack_start (zoom_out_button, false, false); - zoom_box.pack_start (zoom_in_button, false, false); - zoom_box.pack_start (zoom_range_clock, false, false); - zoom_box.pack_start (zoom_out_full_button, false, false); - - ARDOUR_UI::instance()->tooltips().set_tip (zoom_range_clock, _("Current Zoom Range\n(Width of visible area)")); zoom_focus_selector.set_name ("ZoomFocusSelector"); - Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Focus Center", 2+FUDGE, 0); + Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edit Cursor", FUDGE, 0); set_popdown_strings (zoom_focus_selector, zoom_focus_strings); zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done)); ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus")); - zoom_box.pack_start (zoom_focus_selector, false, false); - + zoom_box.pack_start (zoom_focus_selector, true, true); + zoom_box.pack_start (zoom_out_button, false, false); + zoom_box.pack_start (zoom_in_button, false, false); + zoom_box.pack_start (zoom_out_full_button, false, false); /* Edit Cursor / Snap */ @@ -2663,7 +2615,7 @@ Editor::setup_toolbar () hbox->pack_start (snap_box, false, false); - hbox->pack_start (zoom_box, false, false); + // hbox->pack_start (zoom_box, false, false); hbox->pack_start (*nudge_box, false, false); hbox->show_all (); @@ -2827,560 +2779,82 @@ Editor::commit_reversible_command () } } -bool -Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool with_undo, bool no_remove) +void +Editor::set_edit_group_solo (Route& route, bool yn) { - bool commit = false; - - if (!clicked_trackview) { - return false; - } - - switch (op) { - case Selection::Toggle: - if (selection->selected (clicked_trackview)) { - if (!no_remove) { - selection->remove (clicked_trackview); - commit = true; - } - } else { - selection->add (clicked_trackview); - commit = false; - } - break; - - case Selection::Set: - if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) { - /* no commit necessary */ - } + RouteGroup *edit_group; - selection->set (clicked_trackview); - break; - - case Selection::Extend: - /* not defined yet */ - break; + if ((edit_group = route.edit_group()) != 0) { + edit_group->apply (&Route::set_solo, yn, this); + } else { + route.set_solo (yn, this); } - - return commit; } -bool -Editor::set_selected_control_point_from_click (bool press, Selection::Operation op, bool with_undo, bool no_remove) +void +Editor::set_edit_group_mute (Route& route, bool yn) { - if (!clicked_control_point) { - return false; - } - - /* select this point and any others that it represents */ - - double y1, y2; - nframes_t x1, x2; - - x1 = pixel_to_frame (clicked_control_point->get_x() - 10); - x2 = pixel_to_frame (clicked_control_point->get_x() + 10); - y1 = clicked_control_point->get_x() - 10; - y2 = clicked_control_point->get_y() + 10; + RouteGroup *edit_group = 0; - return select_all_within (x1, x2, y1, y2, op); + if ((edit_group == route.edit_group()) != 0) { + edit_group->apply (&Route::set_mute, yn, this); + } else { + route.set_mute (yn, this); + } } - + void -Editor::get_relevant_audio_tracks (AudioTimeAxisView& base, set& relevant_tracks) +Editor::history_changed () { - /* step one: get all selected tracks and all tracks in the relevant edit groups */ - - for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) { - - AudioTimeAxisView* atv = dynamic_cast(*ti); + string label; - if (!atv) { - continue; + if (undo_action && session) { + if (session->undo_depth() == 0) { + label = _("Undo"); + } else { + label = string_compose(_("Undo (%1)"), session->next_undo()); } + undo_action->property_label() = label; + } - RouteGroup* group = atv->route()->edit_group(); - - if (group && group->is_active()) { - - /* active group for this track, loop over all tracks and get every member of the group */ - - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - - AudioTimeAxisView* tatv; - - if ((tatv = dynamic_cast (*i)) != 0) { - - if (tatv->route()->edit_group() == group) { - relevant_tracks.insert (tatv); - } - } - } - + if (redo_action && session) { + if (session->redo_depth() == 0) { + label = _("Redo"); } else { - - /* no active group, or no group */ - - relevant_tracks.insert (&base); + label = string_compose(_("Redo (%1)"), session->next_redo()); } - + redo_action->property_label() = label; } } void -Editor::mapover_audio_tracks (slot sl) +Editor::duplicate_dialog (bool dup_region) { - set relevant_tracks; - - if (!clicked_audio_trackview) { - return; + if (dup_region) { + if (clicked_regionview == 0) { + return; + } + } else { + if (selection->time.length() == 0) { + return; + } } - get_relevant_audio_tracks (*clicked_audio_trackview, relevant_tracks); + ArdourDialog win ("duplicate dialog"); + Entry entry; + Label label (_("Duplicate how many times?")); - uint32_t sz = relevant_tracks.size(); - - for (set::iterator ati = relevant_tracks.begin(); ati != relevant_tracks.end(); ++ati) { - sl (**ati, sz); - } -} + win.get_vbox()->pack_start (label); + win.add_action_widget (entry, RESPONSE_ACCEPT); + win.add_button (Stock::OK, RESPONSE_ACCEPT); + win.add_button (Stock::CANCEL, RESPONSE_CANCEL); -void -Editor::mapped_set_selected_regionview_from_click (RouteTimeAxisView& tv, uint32_t ignored, - RegionView* basis, vector* all_equivs) -{ - Playlist* pl; - vector > results; - RegionView* marv; - boost::shared_ptr ds; + win.set_position (WIN_POS_MOUSE); - if ((ds = tv.get_diskstream()) == 0) { - /* bus */ - return; - } - - if (&tv == &basis->get_time_axis_view()) { - /* looking in same track as the original */ - return; - } - - - if ((pl = dynamic_cast(ds->playlist())) != 0) { - pl->get_equivalent_regions (basis->region(), results); - } - - for (vector >::iterator ir = results.begin(); ir != results.end(); ++ir) { - if ((marv = tv.view()->find_view (*ir)) != 0) { - all_equivs->push_back (marv); - } - } -} - -bool -Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove) -{ - vector all_equivalent_regions; - bool commit = false; - - if (!clicked_regionview || !clicked_audio_trackview) { - return false; - } - - if (op == Selection::Toggle || op == Selection::Set) { - - mapover_audio_tracks (bind (mem_fun (*this, &Editor::mapped_set_selected_regionview_from_click), - clicked_regionview, &all_equivalent_regions)); - - - /* add clicked regionview since we skipped all other regions in the same track as the one it was in */ - - all_equivalent_regions.push_back (clicked_regionview); - - switch (op) { - case Selection::Toggle: - - if (clicked_regionview->get_selected()) { - if (press) { - - /* whatever was clicked was selected already; do nothing here but allow - the button release to deselect it - */ - - button_release_can_deselect = true; - - } else { - - if (button_release_can_deselect) { - - /* just remove this one region, but only on a permitted button release */ - - selection->remove (clicked_regionview); - commit = true; - - /* no more deselect action on button release till a new press - finds an already selected object. - */ - - button_release_can_deselect = false; - } - } - - } else { - - if (press) { - /* add all the equivalent regions, but only on button press */ - - if (!all_equivalent_regions.empty()) { - commit = true; - } - - for (vector::iterator i = all_equivalent_regions.begin(); i != all_equivalent_regions.end(); ++i) { - selection->add (*i); - } - } - } - break; - - case Selection::Set: - if (!clicked_regionview->get_selected()) { - selection->set (all_equivalent_regions); - commit = true; - } else { - /* no commit necessary: clicked on an already selected region */ - goto out; - } - break; - - default: - /* silly compiler */ - break; - } - - } else if (op == Selection::Extend) { - - list results; - nframes_t last_frame; - nframes_t first_frame; - - /* 1. find the last selected regionview in the track that was clicked in */ - - last_frame = 0; - first_frame = max_frames; - - for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) { - if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) { - - if ((*x)->region()->last_frame() > last_frame) { - last_frame = (*x)->region()->last_frame(); - } - - if ((*x)->region()->first_frame() < first_frame) { - first_frame = (*x)->region()->first_frame(); - } - } - } - - /* 2. figure out the boundaries for our search for new objects */ - - switch (clicked_regionview->region()->coverage (first_frame, last_frame)) { - case OverlapNone: - if (last_frame < clicked_regionview->region()->first_frame()) { - first_frame = last_frame; - last_frame = clicked_regionview->region()->last_frame(); - } else { - last_frame = first_frame; - first_frame = clicked_regionview->region()->first_frame(); - } - break; - - case OverlapExternal: - if (last_frame < clicked_regionview->region()->first_frame()) { - first_frame = last_frame; - last_frame = clicked_regionview->region()->last_frame(); - } else { - last_frame = first_frame; - first_frame = clicked_regionview->region()->first_frame(); - } - break; - - case OverlapInternal: - if (last_frame < clicked_regionview->region()->first_frame()) { - first_frame = last_frame; - last_frame = clicked_regionview->region()->last_frame(); - } else { - last_frame = first_frame; - first_frame = clicked_regionview->region()->first_frame(); - } - break; - - case OverlapStart: - case OverlapEnd: - /* nothing to do except add clicked region to selection, since it - overlaps with the existing selection in this track. - */ - break; - } - - /* 2. find all selectable objects (regionviews in this case) between that one and the end of the - one that was clicked. - */ - - set relevant_tracks; - - get_relevant_audio_tracks (*clicked_audio_trackview, relevant_tracks); - - for (set::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) { - (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results); - } - - /* 3. convert to a vector of audio regions */ - - vector regions; - - for (list::iterator x = results.begin(); x != results.end(); ++x) { - RegionView* arv; - - if ((arv = dynamic_cast(*x)) != 0) { - regions.push_back (arv); - } - } - - if (!regions.empty()) { - selection->add (regions); - commit = true; - } - } - - out: - return commit; -} - -void -Editor::set_selected_regionview_from_region_list (boost::shared_ptr region, Selection::Operation op) -{ - vector all_equivalent_regions; - - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - - RouteTimeAxisView* tatv; - - if ((tatv = dynamic_cast (*i)) != 0) { - - Playlist* pl; - vector > results; - RegionView* marv; - boost::shared_ptr ds; - - if ((ds = tatv->get_diskstream()) == 0) { - /* bus */ - continue; - } - - if ((pl = dynamic_cast(ds->playlist())) != 0) { - pl->get_region_list_equivalent_regions (region, results); - } - - for (vector >::iterator ir = results.begin(); ir != results.end(); ++ir) { - if ((marv = tatv->view()->find_view (*ir)) != 0) { - all_equivalent_regions.push_back (marv); - } - } - - } - } - - begin_reversible_command (_("set selected regions")); - - switch (op) { - case Selection::Toggle: - /* XXX this is not correct */ - selection->toggle (all_equivalent_regions); - break; - case Selection::Set: - selection->set (all_equivalent_regions); - break; - case Selection::Extend: - selection->add (all_equivalent_regions); - break; - } - - commit_reversible_command () ; -} - -bool -Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr weak_r) -{ - RegionView* rv; - boost::shared_ptr r (weak_r.lock()); - - if (!r) { - return true; - } - - boost::shared_ptr ar; - - if ((ar = boost::dynamic_pointer_cast (r)) == 0) { - return true; - } - - if ((rv = sv->find_view (ar)) == 0) { - return true; - } - - /* don't reset the selection if its something other than - a single other region. - */ - - if (selection->regions.size() > 1) { - return true; - } - - begin_reversible_command (_("set selected regions")); - - selection->set (rv); - - commit_reversible_command () ; - - return true; -} - -void -Editor::set_edit_group_solo (Route& route, bool yn) -{ - RouteGroup *edit_group; - - if ((edit_group = route.edit_group()) != 0) { - edit_group->apply (&Route::set_solo, yn, this); - } else { - route.set_solo (yn, this); - } -} - -void -Editor::set_edit_group_mute (Route& route, bool yn) -{ - RouteGroup *edit_group = 0; - - if ((edit_group == route.edit_group()) != 0) { - edit_group->apply (&Route::set_mute, yn, this); - } else { - route.set_mute (yn, this); - } -} - -void -Editor::set_edit_menu (Menu& menu) -{ - edit_menu = &menu; - edit_menu->signal_map_event().connect (mem_fun(*this, &Editor::edit_menu_map_handler)); -} - -bool -Editor::edit_menu_map_handler (GdkEventAny* ev) -{ - using namespace Menu_Helpers; - MenuList& edit_items = edit_menu->items(); - string label; - - /* Nuke all the old items */ - - edit_items.clear (); - - if (session == 0) { - return false; - } - - if (session->undo_depth() == 0) { - label = _("Undo"); - } else { - label = string_compose(_("Undo (%1)"), session->next_undo()); - } - - edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U))); - - if (session->undo_depth() == 0) { - edit_items.back().set_sensitive (false); - } - - if (session->redo_depth() == 0) { - label = _("Redo"); - } else { - label = string_compose(_("Redo (%1)"), session->next_redo()); - } - - edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U))); - if (session->redo_depth() == 0) { - edit_items.back().set_sensitive (false); - } - - vector mitems; - - edit_items.push_back (SeparatorElem()); - edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut))); - mitems.push_back (&edit_items.back()); - edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy))); - mitems.push_back (&edit_items.back()); - edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f))); - mitems.push_back (&edit_items.back()); - edit_items.push_back (SeparatorElem()); - edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint))); - mitems.push_back (&edit_items.back()); - edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint))); - mitems.push_back (&edit_items.back()); - edit_items.push_back (SeparatorElem()); - - if (selection->empty()) { - for (vector::iterator i = mitems.begin(); i != mitems.end(); ++i) { - (*i)->set_sensitive (false); - } - } - - Menu* import_menu = manage (new Menu()); - import_menu->set_name ("ArdourContextMenu"); - MenuList& import_items = import_menu->items(); - - import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsTrack))); - import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsRegion))); - - edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu)); - edit_items.push_back (SeparatorElem()); - - edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture))); - - if (!session->have_captured()) { - edit_items.back().set_sensitive (false); - } - - return false; -} - -void -Editor::duplicate_dialog (bool dup_region) -{ - if (dup_region) { - if (clicked_regionview == 0) { - return; - } - } else { - if (selection->time.length() == 0) { - return; - } - } - - ArdourDialog win ("duplicate dialog"); - Entry entry; - Label label (_("Duplicate how many times?")); - - win.get_vbox()->pack_start (label); - win.add_action_widget (entry, RESPONSE_ACCEPT); - win.add_button (Stock::OK, RESPONSE_ACCEPT); - win.add_button (Stock::CANCEL, RESPONSE_CANCEL); - - win.set_position (WIN_POS_MOUSE); - - entry.set_text ("1"); - set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15); - entry.select_region (0, entry.get_text_length()); - entry.grab_focus (); + entry.set_text ("1"); + set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15); + entry.select_region (0, -1); + entry.grab_focus (); switch (win.run ()) { @@ -3562,82 +3036,16 @@ Editor::edit_controls_button_release (GdkEventButton* ev) return TRUE; } -void -Editor::track_selection_changed () -{ - switch (selection->tracks.size()){ - case 0: - break; - default: - set_selected_mixer_strip (*(selection->tracks.front())); - break; - } - - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->set_selected (false); - if (mouse_mode == MouseRange) { - (*i)->hide_selection (); - } - } - - for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - (*i)->set_selected (true); - if (mouse_mode == MouseRange) { - (*i)->show_selection (selection->time); - } - } -} - -void -Editor::time_selection_changed () -{ - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->hide_selection (); - } - - if (selection->tracks.empty()) { - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->show_selection (selection->time); - } - } else { - for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - (*i)->show_selection (selection->time); - } - } - - if (selection->time.empty()) { - ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false); - } else { - ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true); - } -} - -void -Editor::region_selection_changed () -{ - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->set_selected_regionviews (selection->regions); - } -} - -void -Editor::point_selection_changed () -{ - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->set_selected_points (selection->points); - } -} - gint Editor::mouse_select_button_release (GdkEventButton* ev) { /* this handles just right-clicks */ if (ev->button != 3) { - return FALSE; + return false; } - return TRUE; + return true; } Editor::TrackViewList * @@ -3801,21 +3209,33 @@ Editor::set_follow_playhead (bool yn) } void -Editor::toggle_xfade_active (Crossfade* xfade) +Editor::toggle_xfade_active (boost::weak_ptr wxfade) { - xfade->set_active (!xfade->active()); + boost::shared_ptr xfade (wxfade.lock()); + if (xfade) { + xfade->set_active (!xfade->active()); + } } void -Editor::toggle_xfade_length (Crossfade* xfade) +Editor::toggle_xfade_length (boost::weak_ptr wxfade) { - xfade->set_follow_overlap (!xfade->following_overlap()); + boost::shared_ptr xfade (wxfade.lock()); + if (xfade) { + xfade->set_follow_overlap (!xfade->following_overlap()); + } } void -Editor::edit_xfade (Crossfade* xfade) +Editor::edit_xfade (boost::weak_ptr wxfade) { - CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0); + boost::shared_ptr xfade (wxfade.lock()); + + if (!xfade) { + return; + } + + CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0); ensure_float (cew); @@ -3855,17 +3275,19 @@ Editor::end_location_changed (Location* location) } int -Editor::playlist_deletion_dialog (Playlist* pl) +Editor::playlist_deletion_dialog (boost::shared_ptr pl) { ArdourDialog dialog ("playlist deletion dialog"); Label label (string_compose (_("Playlist %1 is currently unused.\n" - "If left alone, no audio files used by it will be cleaned.\n" - "If deleted, audio files used by it alone by will cleaned."), - pl->name())); - + "If left alone, no audio files used by it will be cleaned.\n" + "If deleted, audio files used by it alone by will cleaned."), + pl->name())); + dialog.set_position (WIN_POS_CENTER); dialog.get_vbox()->pack_start (label); + label.show (); + dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT); dialog.add_button (_("Keep playlist"), RESPONSE_CANCEL); dialog.add_button (_("Cancel"), RESPONSE_CANCEL); @@ -3996,7 +3418,19 @@ Editor::redisplay_snapshots () for (vector::iterator i = states->begin(); i != states->end(); ++i) { string statename = *(*i); TreeModel::Row row = *(snapshot_display_model->append()); - row[snapshot_display_columns.visible_name] = statename; + + /* this lingers on in case we ever want to change the visible + name of the snapshot. + */ + + string display_name; + display_name = statename; + + if (statename == session->snap_name()) { + snapshot_display.get_selection()->select(row); + } + + row[snapshot_display_columns.visible_name] = display_name; row[snapshot_display_columns.real_name] = statename; } @@ -4013,24 +3447,48 @@ 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); pre_maximal_pane_position = edit_pane.get_position(); - edit_pane.set_position (edit_pane.get_width()); + pre_maximal_editor_width = this->get_width(); + + if(post_maximal_pane_position == 0) { + 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)); + } else { + edit_pane.set_position (post_maximal_pane_position); + } } 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(); + } + + unfullscreen(); + mouse_mode_tearoff->set_visible (true); tools_tearoff->set_visible (true); + post_maximal_editor_width = this->get_width(); - edit_pane.set_position (pre_maximal_pane_position); - unfullscreen(); + edit_pane.set_position ( + pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width) + ); } void @@ -4081,3 +3539,170 @@ Editor::on_key_press_event (GdkEventKey* ev) return key_press_focus_accelerator_handler (*this, ev); } +void +Editor::reset_x_origin (nframes_t frame) +{ + queue_visual_change (frame); +} + +void +Editor::reset_zoom (double fpu) +{ + queue_visual_change (fpu); +} + +void +Editor::reposition_and_zoom (nframes_t frame, double fpu) +{ + reset_x_origin (frame); + reset_zoom (fpu); +} + +void +Editor::set_frames_per_unit (double fpu) +{ + nframes_t frames; + + /* 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; + } + + // convert fpu to frame count + + frames = (nframes_t) floor (fpu * canvas_width); + + /* don't allow zooms that fit more than the maximum number + of frames into an 800 pixel wide space. + */ + + if (max_frames / fpu < 800.0) { + return; + } + + if (fpu == frames_per_unit) { + return; + } + + frames_per_unit = fpu; + + if (frames != zoom_range_clock.current_duration()) { + zoom_range_clock.set (frames); + } + + if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) { + if (!selection->tracks.empty()) { + for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { + (*i)->reshow_selection (selection->time); + } + } else { + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + (*i)->reshow_selection (selection->time); + } + } + } + + ZoomChanged (); /* EMIT_SIGNAL */ + + reset_hscrollbar_stepping (); + reset_scrolling_region (); + + if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame); + if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame); + + instant_save (); +} + +void +Editor::canvas_horizontally_scrolled () +{ + /* this is the core function that controls horizontal scrolling of the canvas. it is called + whenever the horizontal_adjustment emits its "value_changed" signal. it executes in an + idle handler. + */ + + leftmost_frame = (nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit); + nframes_t rightmost_frame = leftmost_frame + current_page_frames (); + + if (rightmost_frame > last_canvas_frame) { + last_canvas_frame = rightmost_frame; + reset_scrolling_region (); + } + + update_fixed_rulers (); + tempo_map_changed (Change (0)); +} + +void +Editor::queue_visual_change (nframes_t 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.idle_handler_id = g_idle_add (_idle_visual_changer, this); + } +} + +void +Editor::queue_visual_change (double fpu) +{ + pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel); + pending_visual_change.frames_per_unit = fpu; + + if (pending_visual_change.idle_handler_id < 0) { + pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0); + } +} + +int +Editor::_idle_visual_changer (void* arg) +{ + return static_cast(arg)->idle_visual_changer (); +} + +int +Editor::idle_visual_changer () +{ + VisualChange::Type p = pending_visual_change.pending; + + pending_visual_change.pending = (VisualChange::Type) 0; + pending_visual_change.idle_handler_id = -1; + + if (p & VisualChange::ZoomLevel) { + set_frames_per_unit (pending_visual_change.frames_per_unit); + } + + if (p & VisualChange::TimeOrigin) { + if (pending_visual_change.time_origin != leftmost_frame) { + horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit); + /* the signal handler will do the rest */ + } else { + update_fixed_rulers(); + tempo_map_changed (Change (0)); + } + } + + return 0; +} + +struct EditorOrderTimeAxisSorter { + bool operator() (const TimeAxisView* a, const TimeAxisView* b) const { + return a->order < b->order; + } +}; + +void +Editor::sort_track_selection () +{ + EditorOrderTimeAxisSorter cmp; + selection->tracks.sort (cmp); +} +