X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor.cc;h=3c7bd3f37c7e2373d4c3d914c5c7d5421c41a7f8;hb=bbb65d07d33160366533d9f2390f3f8d56fcb8e1;hp=f8209b8a5644a8d5fc1dc3d5d61b5e4283a89ec3;hpb=b0424889b32e136ca25186037b032b229824ac79;p=ardour.git diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index f8209b8a56..3c7bd3f37c 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2007 Paul Davis + Copyright (C) 2000-2009 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,20 +19,31 @@ /* Note: public Editor methods are documented in public_editor.h */ +#define __STDC_LIMIT_MACROS 1 +#include #include #include #include #include #include +#include + +#include "ardour_ui.h" +/* + * ardour_ui.h include was moved to the top of the list + * due to a conflicting definition of 'Style' between + * Apple's MacTypes.h and BarController. + */ #include #include -#include -#include -#include -#include +#include "pbd/convert.h" +#include "pbd/error.h" +#include "pbd/enumwriter.h" +#include "pbd/memento_command.h" +#include "pbd/unknown_type.h" #include #include @@ -45,24 +56,26 @@ #include #include #include +#include + +#include "ardour/audio_diskstream.h" +#include "ardour/audio_track.h" +#include "ardour/audioplaylist.h" +#include "ardour/audioregion.h" +#include "ardour/location.h" +#include "ardour/midi_region.h" +#include "ardour/plugin_manager.h" +#include "ardour/profile.h" +#include "ardour/route_group.h" +#include "ardour/session_directory.h" +#include "ardour/session_route.h" +#include "ardour/session_state_utils.h" +#include "ardour/tempo.h" +#include "ardour/utils.h" +#include "ardour/session_playlists.h" + +#include "control_protocol/control_protocol.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "ardour_ui.h" #include "editor.h" #include "keyboard.h" #include "marker.h" @@ -75,6 +88,7 @@ #include "audio_time_axis.h" #include "utils.h" #include "crossfade_view.h" +#include "canvas-noevent-text.h" #include "editing.h" #include "public_editor.h" #include "crossfade_edit.h" @@ -85,10 +99,20 @@ #include "simpleline.h" #include "rhythm_ferret.h" #include "actions.h" - -#ifdef FFT_ANALYSIS +#include "tempo_lines.h" #include "analysis_window.h" -#endif +#include "bundle_manager.h" +#include "global_port_matrix.h" +#include "editor_drag.h" +#include "editor_group_tabs.h" +#include "automation_time_axis.h" +#include "editor_routes.h" +#include "midi_time_axis.h" +#include "mixer_strip.h" +#include "editor_route_groups.h" +#include "editor_regions.h" +#include "editor_locations.h" +#include "editor_snapshots.h" #include "i18n.h" @@ -97,7 +121,6 @@ #endif using namespace std; -using namespace sigc; using namespace ARDOUR; using namespace PBD; using namespace Gtk; @@ -107,6 +130,7 @@ using namespace Editing; using PBD::internationalize; using PBD::atoi; +using Gtkmm2ext::Keyboard; const double Editor::timebar_height = 15.0; @@ -114,9 +138,9 @@ const double Editor::timebar_height = 15.0; static const gchar *_snap_type_strings[] = { N_("CD Frames"), - N_("SMPTE Frames"), - N_("SMPTE Seconds"), - N_("SMPTE Minutes"), + N_("Timecode Frames"), + N_("Timecode Seconds"), + N_("Timecode Minutes"), N_("Seconds"), N_("Minutes"), N_("Beats/32"), @@ -154,7 +178,7 @@ static const gchar *_zoom_focus_strings[] = { N_("Center"), N_("Playhead"), N_("Mouse"), - N_("Active Mark"), + N_("Edit point"), 0 }; @@ -196,46 +220,48 @@ show_me_the_size (Requisition* r, const char* what) } Editor::Editor () - : - /* time display buttons */ + : _join_object_range_state (JOIN_OBJECT_RANGE_NONE) - minsec_label (_("Mins:Secs")), - bbt_label (_("Bars:Beats")), - smpte_label (_("Timecode")), - frame_label (_("Samples")), - tempo_label (_("Tempo")), - meter_label (_("Meter")), - mark_label (_("Location Markers")), - range_mark_label (_("Range Markers")), - transport_mark_label (_("Loop/Punch Ranges")), - cd_mark_label (_("CD Markers")), - edit_packer (3, 4, true), + /* time display buttons */ + , minsec_label (_("Mins:Secs")) + , bbt_label (_("Bars:Beats")) + , timecode_label (_("Timecode")) + , frame_label (_("Samples")) + , tempo_label (_("Tempo")) + , meter_label (_("Meter")) + , mark_label (_("Location Markers")) + , range_mark_label (_("Range Markers")) + , transport_mark_label (_("Loop/Punch Ranges")) + , cd_mark_label (_("CD Markers")) + , edit_packer (4, 4, true) /* the values here don't matter: layout widgets reset them as needed. */ - vertical_adjustment (0.0, 0.0, 10.0, 400.0), - horizontal_adjustment (0.0, 0.0, 20.0, 1200.0), + , vertical_adjustment (0.0, 0.0, 10.0, 400.0) + , horizontal_adjustment (0.0, 0.0, 20.0, 1200.0) /* tool bar related */ - edit_point_clock (X_("editpoint"), false, X_("EditPointClock"), true), - zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true), - - toolbar_selection_clock_table (2,3), - - automation_mode_button (_("mode")), - global_automation_button (_("automation")), + , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true) + + , toolbar_selection_clock_table (2,3) + + , automation_mode_button (_("mode")) + , global_automation_button (_("automation")) + + , midi_panic_button (_("Panic")) #ifdef WITH_CMT - image_socket_listener(0), + , image_socket_listener(0) #endif /* nudge */ - nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true), - meters_running(false) + , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true) + , meters_running(false) + , _pending_locate_request (false) { constructed = false; @@ -244,29 +270,22 @@ Editor::Editor () PublicEditor::_instance = this; - session = 0; _have_idled = false; selection = new Selection (this); cut_buffer = new Selection (this); - selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed)); - selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed)); - selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed)); - selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed)); - selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed)); - clicked_regionview = 0; clicked_axisview = 0; clicked_routeview = 0; clicked_crossfadeview = 0; clicked_control_point = 0; last_update_frame = 0; - drag_info.item = 0; - drag_info.copied_location = 0; + _drags = new DragManager (this); current_mixer_strip = 0; current_bbt_points = 0; - + tempo_lines = 0; + snap_type_strings = I18N (_snap_type_strings); snap_mode_strings = I18N (_snap_mode_strings); zoom_focus_strings = I18N (_zoom_focus_strings); @@ -274,11 +293,11 @@ Editor::Editor () #ifdef USE_RUBBERBAND rb_opt_strings = I18N (_rb_opt_strings); #endif - + snap_threshold = 5.0; bbt_beat_subdivision = 4; - canvas_width = 0; - canvas_height = 0; + _canvas_width = 0; + _canvas_height = 0; last_autoscroll_x = 0; last_autoscroll_y = 0; autoscroll_active = false; @@ -286,35 +305,21 @@ Editor::Editor () interthread_progress_window = 0; logo_item = 0; -#ifdef FFT_ANALYSIS analysis_window = 0; -#endif current_interthread_info = 0; _show_measures = true; - _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; verbose_cursor_on = true; - route_removal = false; - show_automatic_regions_in_region_list = true; last_item_entered = 0; last_item_entered_n = 0; - region_list_sort_type = (Editing::RegionListSortType) 0; have_pending_keyboard_selection = false; _follow_playhead = true; _xfade_visibility = true; editor_ruler_menu = 0; no_ruler_shown_update = false; - edit_group_list_menu = 0; - route_list_menu = 0; - region_list_menu = 0; marker_menu = 0; start_end_marker_menu = 0; range_marker_menu = 0; @@ -328,8 +333,6 @@ Editor::Editor () region_edit_menu_split_item = 0; temp_location = 0; leftmost_frame = 0; - ignore_mouse_mode_toggle = false; - ignore_midi_edit_mode_toggle = false; current_stepping_trackview = 0; entered_track = 0; entered_regionview = 0; @@ -337,30 +340,23 @@ Editor::Editor () clear_entered_track = false; _new_regionviews_show_envelope = false; current_timefx = 0; - in_edit_group_row_change = false; - 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; + _bundle_manager = 0; + for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) { + _global_port_matrix[*i] = 0; + } allow_vertical_scroll = false; no_save_visual = false; - 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; sfbrowser = 0; - ignore_route_order_sync = false; location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get(); location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get(); @@ -368,127 +364,130 @@ Editor::Editor () location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get(); location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get(); - range_marker_drag_rect = 0; - marker_drag_line = 0; - tempo_map_change_idle_handler_id = -1; - set_midi_edit_mode (MidiEditPencil, true); - set_mouse_mode (MouseObject, true); + _edit_point = EditAtMouse; + _internal_editing = false; + current_canvas_cursor = 0; frames_per_unit = 2048; /* too early to use reset_zoom () */ - reset_hscrollbar_stepping (); - + zoom_focus = ZoomFocusLeft; set_zoom_focus (ZoomFocusLeft); - zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed)); - - initialize_rulers (); - initialize_canvas (); - - edit_controls_vbox.set_spacing (0); - 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->signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler)); - - controls_layout.add (edit_controls_vbox); - controls_layout.set_name ("EditControlsBase"); - controls_layout.add_events (Gdk::SCROLL_MASK); - controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false); - - controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK); - controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release)); - controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request)); - - edit_vscrollbar.set_adjustment (vertical_adjustment); - edit_hscrollbar.set_adjustment (horizontal_adjustment); - - edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false); - edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false); - edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate)); - - edit_hscrollbar.set_name ("EditorHScrollbar"); - - build_cursors (); - setup_toolbar (); - setup_midi_toolbar (); - - edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed)); - - ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas()); - ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(), - 0.0, 1.0, 100.0, 1.0)); - pad_line_1->property_color_rgba() = 0xFF0000FF; - pad_line_1->show(); - time_pad->show(); + zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed)); - time_canvas_vbox.pack_start (*_ruler_separator, false, false); - time_canvas_vbox.pack_start (*minsec_ruler, false, false); - 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.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); bbt_label.set_padding (5,0); + bbt_label.hide (); + bbt_label.set_no_show_all(); minsec_label.set_name ("EditorTimeButton"); minsec_label.set_size_request (-1, (int)timebar_height); minsec_label.set_alignment (1.0, 0.5); minsec_label.set_padding (5,0); - smpte_label.set_name ("EditorTimeButton"); - smpte_label.set_size_request (-1, (int)timebar_height); - smpte_label.set_alignment (1.0, 0.5); - smpte_label.set_padding (5,0); + minsec_label.hide (); + minsec_label.set_no_show_all(); + timecode_label.set_name ("EditorTimeButton"); + timecode_label.set_size_request (-1, (int)timebar_height); + timecode_label.set_alignment (1.0, 0.5); + timecode_label.set_padding (5,0); + timecode_label.hide (); + timecode_label.set_no_show_all(); frame_label.set_name ("EditorTimeButton"); frame_label.set_size_request (-1, (int)timebar_height); frame_label.set_alignment (1.0, 0.5); frame_label.set_padding (5,0); + frame_label.hide (); + frame_label.set_no_show_all(); tempo_label.set_name ("EditorTimeButton"); tempo_label.set_size_request (-1, (int)timebar_height); tempo_label.set_alignment (1.0, 0.5); tempo_label.set_padding (5,0); + tempo_label.hide(); + tempo_label.set_no_show_all(); meter_label.set_name ("EditorTimeButton"); meter_label.set_size_request (-1, (int)timebar_height); meter_label.set_alignment (1.0, 0.5); meter_label.set_padding (5,0); + meter_label.hide(); + meter_label.set_no_show_all(); mark_label.set_name ("EditorTimeButton"); mark_label.set_size_request (-1, (int)timebar_height); mark_label.set_alignment (1.0, 0.5); mark_label.set_padding (5,0); + mark_label.hide(); + mark_label.set_no_show_all(); cd_mark_label.set_name ("EditorTimeButton"); cd_mark_label.set_size_request (-1, (int)timebar_height); cd_mark_label.set_alignment (1.0, 0.5); cd_mark_label.set_padding (5,0); + cd_mark_label.hide(); + cd_mark_label.set_no_show_all(); range_mark_label.set_name ("EditorTimeButton"); range_mark_label.set_size_request (-1, (int)timebar_height); range_mark_label.set_alignment (1.0, 0.5); range_mark_label.set_padding (5,0); + range_mark_label.hide(); + range_mark_label.set_no_show_all(); transport_mark_label.set_name ("EditorTimeButton"); transport_mark_label.set_size_request (-1, (int)timebar_height); transport_mark_label.set_alignment (1.0, 0.5); transport_mark_label.set_padding (5,0); + transport_mark_label.hide(); + transport_mark_label.set_no_show_all(); - 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); - - 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)); + initialize_rulers (); + initialize_canvas (); + _summary = new EditorSummary (this); + + selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed)); + selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed)); + editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed)); + selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed)); + selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed)); + + edit_controls_vbox.set_spacing (0); + horizontal_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::scroll_canvas_horizontally), false); + vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true); + track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler)); + + HBox* h = manage (new HBox); + _group_tabs = new EditorGroupTabs (this); + h->pack_start (*_group_tabs, PACK_SHRINK); + h->pack_start (edit_controls_vbox); + controls_layout.add (*h); + + ARDOUR_UI::instance()->tooltips().set_tip (*_group_tabs, _("Groups: context-click for possible operations")); + + controls_layout.set_name ("EditControlsBase"); + controls_layout.add_events (Gdk::SCROLL_MASK); + controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false); + + controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK); + controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release)); + controls_layout_size_request_connection = controls_layout.signal_size_request().connect (sigc::mem_fun (*this, &Editor::controls_layout_size_request)); + + build_cursors (); + + ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas()); + ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(), + 0.0, 1.0, 100.0, 1.0)); + pad_line_1->property_color_rgba() = 0xFF0000FF; + pad_line_1->show(); + time_pad->show(); - 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_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2); + time_canvas_vbox.set_size_request (-1, -1); + + 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.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release)); time_button_event_box.add (time_button_vbox); - time_button_event_box.set_name ("TimebarLabelBase"); 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_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release)); - /* these enable us to have a dedicated window (for cursor setting, etc.) + /* these enable us to have a dedicated window (for cursor setting, etc.) for the canvas areas. */ @@ -496,237 +495,101 @@ Editor::Editor () 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); - + edit_packer.set_col_spacings (0); edit_packer.set_row_spacings (0); edit_packer.set_homogeneous (false); edit_packer.set_border_width (0); edit_packer.set_name ("EditorWindow"); - - edit_packer.attach (edit_vscrollbar, 0, 1, 0, 4, FILL, FILL|EXPAND, 0, 0); + + edit_packer.attach (zoom_vbox, 0, 1, 0, 2, SHRINK, FILL, 0, 0); + /* labels for the rulers */ edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0); + /* labels for the marker "tracks" */ edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0); + /* the rulers */ edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0); - - edit_packer.attach (controls_layout, 1, 2, 2, 3, FILL, FILL|EXPAND, 0, 0); + /* track controls */ + edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0); + /* main canvas */ edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 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); - bottom_hbox.set_border_width (2); bottom_hbox.set_spacing (3); - route_display_model = ListStore::create(route_display_columns); - route_list_display.set_model (route_display_model); - 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)); - route_list_display.set_headers_visible (true); - route_list_display.set_name ("TrackListDisplay"); - route_list_display.get_selection()->set_mode (SELECTION_SINGLE); - route_list_display.set_reorderable (true); - route_list_display.set_size_request (100,-1); - route_list_display.add_object_drag (route_display_columns.route.index(), "routes"); - - CellRendererToggle* route_list_visible_cell = dynamic_cast(route_list_display.get_column_cell_renderer (0)); - route_list_visible_cell->property_activatable() = true; - route_list_visible_cell->property_radio() = false; - - route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete)); - route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change)); - - route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false); - - route_list_scroller.add (route_list_display); - route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC); - - group_model = ListStore::create(group_columns); - 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 (_("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)); - edit_group_display.get_column (0)->set_expand (true); - edit_group_display.get_column (1)->set_expand (false); - edit_group_display.get_column (2)->set_expand (false); - edit_group_display.set_headers_visible (true); - - /* name is directly editable */ - - CellRendererText* name_cell = dynamic_cast(edit_group_display.get_column_cell_renderer (0)); - name_cell->property_editable() = true; - name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit)); - - /* use checkbox for the active + visible columns */ - - CellRendererToggle* active_cell = dynamic_cast(edit_group_display.get_column_cell_renderer (1)); - active_cell->property_activatable() = true; - active_cell->property_radio() = false; - - active_cell = dynamic_cast(edit_group_display.get_column_cell_renderer (1)); - active_cell->property_activatable() = true; - active_cell->property_radio() = false; - - 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 (true); - edit_group_display.set_reorderable (false); - edit_group_display.set_rules_hint (true); - edit_group_display.set_size_request (75, -1); - - edit_group_display_scroller.add (edit_group_display); - edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC); - - 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()); - 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 ()); - Button* edit_group_remove_button = manage (new Button ()); - - Widget* w; - - w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON)); - w->show(); - edit_group_add_button->add (*w); - - w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON)); - w->show(); - edit_group_remove_button->add (*w); - - edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group)); - edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group)); - - edit_group_display_button_box->pack_start (*edit_group_add_button); - edit_group_display_button_box->pack_start (*edit_group_remove_button); - - edit_group_display_packer->pack_start (edit_group_display_scroller, true, true); - edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false); - - 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)); - region_list_model->set_sort_column (0, SORT_ASCENDING); - - 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); - - CellRendererText* region_name_cell = dynamic_cast(region_list_display.get_column_cell_renderer (0)); - region_name_cell->property_editable() = true; - region_name_cell->signal_edited().connect (mem_fun (*this, &Editor::region_name_edit)); - - region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter)); - - TreeViewColumn* tv_col = region_list_display.get_column(0); - CellRendererText* renderer = dynamic_cast(region_list_display.get_column_cell_renderer (0)); - tv_col->add_attribute(renderer->property_text(), region_list_columns.name); - tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_); - - 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; - - region_list_target_table.push_back (TargetEntry ("text/plain")); - region_list_target_table.push_back (TargetEntry ("text/uri-list")); - region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop")); - - region_list_display.add_drop_targets (region_list_target_table); - 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_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); - region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release)); - 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)); - - named_selection_scroller.add (named_selection_display); - named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC); - - named_selection_model = TreeStore::create (named_selection_columns); - named_selection_display.set_model (named_selection_model); - 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 ("NamedSelectionDisplay"); - - named_selection_display.get_selection()->set_mode (SELECTION_SINGLE); - named_selection_display.set_size_request (100, -1); - 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 */ - - 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 ("SnapshotDisplay"); - snapshot_display.set_size_request (75, -1); - snapshot_display.set_headers_visible (false); - snapshot_display.set_reorderable (false); - snapshot_display_scroller.add (snapshot_display); - snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - - snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed)); - snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false); + _route_groups = new EditorRouteGroups (this); + _routes = new EditorRoutes (this); + _regions = new EditorRegions (this); + _snapshots = new EditorSnapshots (this); + _locations = new EditorLocations (this); Gtk::Label* nlabel; nlabel = manage (new Label (_("Regions"))); nlabel->set_angle (-90); - the_notebook.append_page (region_list_scroller, *nlabel); + the_notebook.append_page (_regions->widget (), *nlabel); nlabel = manage (new Label (_("Tracks/Busses"))); nlabel->set_angle (-90); - the_notebook.append_page (route_list_scroller, *nlabel); + the_notebook.append_page (_routes->widget (), *nlabel); nlabel = manage (new Label (_("Snapshots"))); nlabel->set_angle (-90); - the_notebook.append_page (snapshot_display_scroller, *nlabel); - nlabel = manage (new Label (_("Edit Groups"))); + the_notebook.append_page (_snapshots->widget (), *nlabel); + nlabel = manage (new Label (_("Route Groups"))); nlabel->set_angle (-90); - the_notebook.append_page (*edit_group_display_packer, *nlabel); - - if (!Profile->get_sae()) { - nlabel = manage (new Label (_("Chunks"))); - nlabel->set_angle (-90); - the_notebook.append_page (named_selection_scroller, *nlabel); - } + the_notebook.append_page (_route_groups->widget (), *nlabel); + nlabel = manage (new Label (_("Ranges & Marks"))); + nlabel->set_angle (-90); + the_notebook.append_page (_locations->widget (), *nlabel); the_notebook.set_show_tabs (true); the_notebook.set_scrollable (true); - the_notebook.popup_enable (); + the_notebook.popup_disable (); the_notebook.set_tab_pos (Gtk::POS_RIGHT); - + the_notebook.show_all (); + post_maximal_editor_width = 0; post_maximal_pane_position = 0; - edit_pane.pack1 (edit_packer, true, true); - edit_pane.pack2 (the_notebook, false, true); + + VPaned *editor_summary_pane = manage(new VPaned()); + editor_summary_pane->pack1(edit_packer); + + Button* summary_arrows_left_left = manage (new Button); + summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE))); + summary_arrows_left_left->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left)); + Button* summary_arrows_left_right = manage (new Button); + summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE))); + summary_arrows_left_right->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right)); + VBox* summary_arrows_left = manage (new VBox); + summary_arrows_left->pack_start (*summary_arrows_left_left); + summary_arrows_left->pack_start (*summary_arrows_left_right); + + Button* summary_arrows_right_left = manage (new Button); + summary_arrows_right_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE))); + summary_arrows_right_left->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left)); + Button* summary_arrows_right_right = manage (new Button); + summary_arrows_right_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE))); + summary_arrows_right_right->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right)); + VBox* summary_arrows_right = manage (new VBox); + summary_arrows_right->pack_start (*summary_arrows_right_left); + summary_arrows_right->pack_start (*summary_arrows_right_right); + + Frame* summary_frame = manage (new Frame); + summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN); + summary_frame->add (*_summary); + summary_frame->show (); + + _summary_hbox.pack_start (*summary_arrows_left, false, false); + _summary_hbox.pack_start (*summary_frame, true, true); + _summary_hbox.pack_start (*summary_arrows_right, false, false); - edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast (&edit_pane))); + editor_summary_pane->pack2 (_summary_hbox); + + edit_pane.pack1 (*editor_summary_pane, true, true); + edit_pane.pack2 (the_notebook, false, true); + + edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast (&edit_pane))); top_hbox.pack_start (toolbar_frame, false, true); - top_hbox.pack_start (midi_toolbar_frame, false, true); HBox *hbox = manage (new HBox); hbox->pack_start (edit_pane, true, true); @@ -744,27 +607,27 @@ Editor::Editor () vpacker.pack_end (status_bar_hpacker, false, false); vpacker.pack_end (global_hpacker, true, true); - edit_controls_vbox.show (); - controls_layout.show (); - the_notebook.show_all (); - /* register actions now so that set_state() can find them and set toggles/checks etc */ - + register_actions (); - snap_type = SnapToBeat; - set_snap_to (snap_type); - snap_mode = SnapOff; - set_snap_mode (snap_mode); + setup_toolbar (); + setup_midi_toolbar (); + + _snap_type = SnapToBeat; + set_snap_to (_snap_type); + _snap_mode = SnapOff; + set_snap_mode (_snap_mode); + set_mouse_mode (MouseObject, true); set_edit_point_preference (EditAtMouse, true); XMLNode* node = ARDOUR_UI::instance()->editor_settings(); - set_state (*node); + set_state (*node, Stateful::loading_state_version); _playlist_selector = new PlaylistSelector(); - _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast (_playlist_selector))); + _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast (_playlist_selector))); - RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview)); + RegionView::RegionViewGoingAway.connect (*this, ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context()); /* nudge stuff */ @@ -809,19 +672,26 @@ Editor::Editor () add (vpacker); add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); - signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler)); - signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close)); + signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler)); + signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close)); /* allow external control surfaces/protocols to do various things */ - ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session)); - 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)); + ControlProtocol::ZoomToSession.connect (*this, boost::bind (&Editor::temporal_zoom_session, this), gui_context()); + ControlProtocol::ZoomIn.connect (*this, boost::bind (&Editor::temporal_zoom_step, this, false), gui_context()); + ControlProtocol::ZoomOut.connect (*this, boost::bind (&Editor::temporal_zoom_step, this, true), gui_context()); + ControlProtocol::ScrollTimeline.connect (*this, ui_bind (&Editor::control_scroll, this, _1), gui_context()); + BasicUI::AccessAction.connect (*this, ui_bind (&Editor::access_action, this, _1, _2), gui_context()); + + /* problematic: has to return a value and thus cannot be x-thread */ + + Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1)); + + Config->ParameterChanged.connect (*this, ui_bind (&Editor::parameter_changed, this, _1), gui_context()); - Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed)); - Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys)); + TimeAxisView::CatchDeletion.connect (*this, ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context()); + + _last_normalization_value = 0; constructed = true; instant_save (); @@ -835,16 +705,16 @@ Editor::~Editor() { image_socket_listener->close_connection() ; } - + delete image_socket_listener ; image_socket_listener = 0 ; } #endif - if (track_canvas) { - delete track_canvas; - track_canvas = 0; - } + delete _routes; + delete _route_groups; + delete track_canvas; + delete _drags; } void @@ -861,6 +731,10 @@ Editor::catch_vanishing_regionview (RegionView *rv) audioregionview by itself. */ + if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) { + _drags->abort (); + } + if (clicked_regionview == rv) { clicked_regionview = 0; } @@ -901,20 +775,27 @@ Editor::set_entered_track (TimeAxisView* tav) void Editor::show_window () { - show_all_children (); - - /* re-hide editor list if necessary */ - editor_list_button_toggled (); + if (! is_visible ()) { + show_all (); - /* now reset all audio_time_axis heights, because widgets might need - to be re-hidden - */ - - TimeAxisView *tv; - - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - tv = (static_cast(*i)); - tv->reset_height (); + /* re-hide editor list if necessary */ + editor_list_button_toggled (); + + /* re-hide summary widget if necessary */ + parameter_changed ("show-summary"); + + parameter_changed ("show-edit-group-tabs"); + + /* now reset all audio_time_axis heights, because widgets might need + to be re-hidden + */ + + TimeAxisView *tv; + + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + tv = (static_cast(*i)); + tv->reset_height (); + } } present (); @@ -927,60 +808,39 @@ Editor::instant_save () return; } - if (session) { - session->add_instant_xml(get_state()); + if (_session) { + _session->add_instant_xml(get_state()); } else { Config->add_instant_xml(get_state()); } } -void -Editor::edit_point_clock_changed() -{ - if (_dragging_edit_point) { - return; - } - - if (selection->markers.empty()) { - return; - } - - bool ignored; - Location* loc = find_location_from_marker (selection->markers.front(), ignored); - - if (!loc) { - return; - } - - loc->move_to (edit_point_clock.current_time()); -} - void Editor::zoom_adjustment_changed () { - if (session == 0) { + if (_session == 0) { return; } - double fpu = zoom_range_clock.current_duration() / canvas_width; + double fpu = zoom_range_clock.current_duration() / _canvas_width; if (fpu < 1.0) { fpu = 1.0; - 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 ((nframes64_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 ((nframes64_t) floor (fpu * _canvas_width)); } - + temporal_zoom (fpu); } void Editor::control_scroll (float fraction) { - ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction)); + ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction) - if (!session) { + if (!_session) { return; } @@ -988,7 +848,7 @@ Editor::control_scroll (float fraction) /* _control_scroll_target is an optional - + 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 @@ -998,7 +858,7 @@ Editor::control_scroll (float fraction) */ if (!_control_scroll_target) { - _control_scroll_target = session->transport_frame(); + _control_scroll_target = _session->transport_frame(); _dragging_playhead = true; } @@ -1014,7 +874,7 @@ Editor::control_scroll (float fraction) playhead_cursor->set_position (*_control_scroll_target); UpdateAllTransportClocks (*_control_scroll_target); - + if (*_control_scroll_target > (current_page_frames() / 2)) { /* try to center PH in window */ reset_x_origin (*_control_scroll_target - (current_page_frames()/2)); @@ -1034,13 +894,13 @@ Editor::control_scroll (float fraction) /* add the next timeout */ - control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250); + control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250); } bool -Editor::deferred_control_scroll (nframes64_t target) +Editor::deferred_control_scroll (nframes64_t /*target*/) { - session->request_locate (*_control_scroll_target, session->transport_rolling()); + _session->request_locate (*_control_scroll_target, _session->transport_rolling()); // reset for next stream _control_scroll_target = boost::none; _dragging_playhead = false; @@ -1050,13 +910,11 @@ Editor::deferred_control_scroll (nframes64_t target) void Editor::access_action (std::string action_group, std::string action_item) { - if (!session) { + if (!_session) { return; } - ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::access_action), action_group, action_item)); - - cout<< "OSC: Recieved: "<< action_item << endl; + ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item) RefPtr act; act = ActionManager::get_action( action_group.c_str(), action_item.c_str() ); @@ -1064,7 +922,7 @@ Editor::access_action (std::string action_group, std::string action_item) if (act) { act->activate(); } - + } @@ -1078,8 +936,8 @@ Editor::on_realize () void Editor::start_scrolling () { - scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect - (mem_fun(*this, &Editor::update_current_screen)); + scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect + (sigc::mem_fun(*this, &Editor::update_current_screen)); } @@ -1092,24 +950,24 @@ Editor::stop_scrolling () void Editor::map_position_change (nframes64_t frame) { - ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame)); + ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame) - if (session == 0 || !_follow_playhead) { + if (_session == 0 || !_follow_playhead) { return; } center_screen (frame); playhead_cursor->set_position (frame); -} +} void Editor::center_screen (nframes64_t frame) { - double page = canvas_width * frames_per_unit; + double page = _canvas_width * frames_per_unit; /* if we're off the page, then scroll. */ - + if (frame < leftmost_frame || frame >= leftmost_frame + page) { center_screen_internal (frame, page); } @@ -1119,7 +977,7 @@ void Editor::center_screen_internal (nframes64_t frame, float page) { page /= 2; - + if (frame > page) { frame -= (nframes64_t) page; } else { @@ -1132,42 +990,36 @@ Editor::center_screen_internal (nframes64_t frame, float page) void Editor::handle_new_duration () { - ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration)); - - 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 (); + if (!_session) { + return; } - 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 -} + ENSURE_GUI_THREAD (*this, &Editor::handle_new_duration) + nframes64_t new_end = _session->current_end_frame() + (nframes64_t) floorf (current_page_frames() * 0.10f); -void -Editor::update_title_s (const string & snap_name) -{ - ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name)); - - update_title (); + horizontal_adjustment.set_upper (new_end / frames_per_unit); + horizontal_adjustment.set_page_size (current_page_frames()/frames_per_unit); + + if (horizontal_adjustment.get_value() + _canvas_width > horizontal_adjustment.get_upper()) { + horizontal_adjustment.set_value (horizontal_adjustment.get_upper() - _canvas_width); + } + //cerr << "Editor::handle_new_duration () called ha v:l:u:ps:lcf = " << horizontal_adjustment.get_value() << ":" << horizontal_adjustment.get_lower() << ":" << horizontal_adjustment.get_upper() << ":" << horizontal_adjustment.get_page_size() << ":" << endl;//DEBUG } void Editor::update_title () { - ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title)); + ENSURE_GUI_THREAD (*this, &Editor::update_title) - if (session) { - bool dirty = session->dirty(); + if (_session) { + bool dirty = _session->dirty(); string session_name; - if (session->snap_name() != session->name()) { - session_name = session->snap_name(); + if (_session->snap_name() != _session->name()) { + session_name = _session->snap_name(); } else { - session_name = session->name(); + session_name = _session->name(); } if (dirty) { @@ -1181,155 +1033,133 @@ Editor::update_title () } void -Editor::connect_to_session (Session *t) +Editor::set_session (Session *t) { - session = t; + SessionHandlePtr::set_session (t); + + if (!_session) { + return; + } + + zoom_range_clock.set_session (_session); + _playlist_selector->set_session (_session); + nudge_clock.set_session (_session); + _summary->set_session (_session); + _group_tabs->set_session (_session); + _route_groups->set_session (_session); + _regions->set_session (_session); + _snapshots->set_session (_session); + _routes->set_session (_session); + _locations->set_session (_session); + + if (rhythm_ferret) { + rhythm_ferret->set_session (_session); + } + + if (analysis_window) { + analysis_window->set_session (_session); + } + + if (sfbrowser) { + sfbrowser->set_session (_session); + } + + compute_fixed_ruler_scale (); /* there are never any selected regions at startup */ sensitize_the_right_region_actions (false); XMLNode* node = ARDOUR_UI::instance()->editor_settings(); - set_state (*node); + set_state (*node, Stateful::loading_state_version); /* catch up with the playhead */ - session->request_locate (playhead_cursor->current_frame); - - if (first_action_message) { - first_action_message->hide(); - } + _session->request_locate (playhead_cursor->current_frame); 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, but use Gtkmm2ext::UI::instance()->call_slot(); */ - session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state))); - session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change))); - session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route))); - session_connections.push_back (session->RegionsAdded.connect (mem_fun(*this, &Editor::handle_new_regions))); - session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed))); - session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration))); - session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group))); - session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed))); - session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection))); - session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection))); - session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title))); - session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s))); - session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog))); - session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden))); - - session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte))); - - session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed))); - - edit_groups_changed (); - - edit_point_clock.set_session (session); - 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 + _session->TransportStateChange.connect (_session_connections, boost::bind (&Editor::map_transport_state, this), gui_context()); + _session->PositionChanged.connect (_session_connections, ui_bind (&Editor::map_position_change, this, _1), gui_context()); + _session->RouteAdded.connect (_session_connections, ui_bind (&Editor::handle_new_route, this, _1), gui_context()); + _session->DurationChanged.connect (_session_connections, boost::bind (&Editor::handle_new_duration, this), gui_context()); + _session->DirtyChanged.connect (_session_connections, boost::bind (&Editor::update_title, this), gui_context()); + _session->TimecodeOffsetChanged.connect (_session_connections, boost::bind (&Editor::update_just_timecode, this), gui_context()); + _session->tempo_map().StateChanged.connect (_session_connections, ui_bind (&Editor::tempo_map_changed, this, _1), gui_context()); + _session->Located.connect (_session_connections, boost::bind (&Editor::located, this), gui_context()); + _session->config.ParameterChanged.connect (_session_connections, ui_bind (&Editor::parameter_changed, this, _1), gui_context()); + _session->StateSaved.connect (_session_connections, ui_bind (&Editor::session_state_saved, this, _1), gui_context()); + _session->locations()->added.connect (_session_connections, ui_bind (&Editor::add_new_location, this, _1), gui_context()); + _session->locations()->removed.connect (_session_connections, ui_bind (&Editor::location_gone, this, _1), gui_context()); + _session->locations()->changed.connect (_session_connections, boost::bind (&Editor::refresh_location_display, this), gui_context()); + _session->locations()->StateChanged.connect (_session_connections, ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context()); + _session->locations()->end_location()->changed.connect (_session_connections, ui_bind (&Editor::end_location_changed, this, _1), gui_context()); + _session->history().Changed.connect (_session_connections, boost::bind (&Editor::history_changed, this), gui_context()); + + if (Profile->get_sae()) { + BBT_Time bbt; + bbt.bars = 0; + bbt.beats = 0; + bbt.ticks = 120; + nframes_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1); + nudge_clock.set_mode(AudioClock::BBT); + nudge_clock.set (pos, true, 0, AudioClock::BBT); - if (rhythm_ferret) { - rhythm_ferret->set_session (session); + } else { + nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds } -#ifdef FFT_ANALYSIS - if (analysis_window != 0) - analysis_window->set_session (session); -#endif + playhead_cursor->canvas_item.show (); - Location* loc = session->locations()->auto_loop_location(); + Location* loc = _session->locations()->auto_loop_location(); if (loc == 0) { - loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden)); + loc = new Location (0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden)); if (loc->start() == loc->end()) { loc->set_end (loc->start() + 1); } - session->locations()->add (loc, false); - session->set_auto_loop_location (loc); + _session->locations()->add (loc, false); + _session->set_auto_loop_location (loc); } else { // force name loc->set_name (_("Loop")); } - - loc = session->locations()->auto_punch_location(); + + loc = _session->locations()->auto_punch_location(); if (loc == 0) { - loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden)); + loc = new Location (0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden)); if (loc->start() == loc->end()) { loc->set_end (loc->start() + 1); } - session->locations()->add (loc, false); - session->set_auto_punch_location (loc); + _session->locations()->add (loc, false); + _session->set_auto_punch_location (loc); } else { // force name loc->set_name (_("Punch")); } - Config->map_parameters (mem_fun (*this, &Editor::parameter_changed)); - - session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved)); - - refresh_location_display (); - session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location)); - session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone)); - session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display)); - session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s)); - session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed)); - - if (sfbrowser) { - sfbrowser->set_session (session); - } + boost::function pc (boost::bind (&Editor::parameter_changed, this, _1)); + Config->map_parameters (pc); + _session->config.map_parameters (pc); + refresh_location_display (); handle_new_duration (); - redisplay_regions (); - redisplay_named_selections (); - redisplay_snapshots (); - - initial_route_list_display (); + restore_ruler_visibility (); + //tempo_map_changed (Change (0)); + _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { (static_cast(*i))->set_samples_per_unit (frames_per_unit); } - restore_ruler_visibility (); - //tempo_map_changed (Change (0)); - session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); - start_scrolling (); - /* don't show master bus in a new session */ - - if (ARDOUR_UI::instance()->session_is_new ()) { - - TreeModel::Children rows = route_display_model->children(); - TreeModel::Children::iterator i; - - no_route_list_redisplay = true; - - for (i = rows.begin(); i != rows.end(); ++i) { - TimeAxisView *tv = (*i)[route_display_columns.tv]; - RouteTimeAxisView *rtv; - - if ((rtv = dynamic_cast(tv)) != 0) { - if (rtv->route()->is_master()) { - route_list_display.get_selection()->unselect (i); - } - } - } - - no_route_list_redisplay = false; - redisplay_route_list (); - } - - switch (snap_type) { + switch (_snap_type) { case SnapToRegionStart: case SnapToRegionEnd: case SnapToRegionSync: @@ -1342,7 +1172,7 @@ Editor::connect_to_session (Session *t) } /* register for undo history */ - session->register_with_memento_command_factory(_id, this); + _session->register_with_memento_command_factory(_id, this); start_updating (); } @@ -1351,7 +1181,7 @@ void Editor::build_cursors () { using namespace Gdk; - + Gdk::Color mbg ("#000000" ); /* Black */ Gdk::Color mfg ("#0000ff" ); /* Blue. */ @@ -1364,23 +1194,23 @@ Editor::build_cursors () Gdk::Color fbg ("#ffffff" ); Gdk::Color ffg ("#000000" ); - + { RefPtr source, mask; - + source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height); mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height); fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot); } - - { + + { RefPtr source, mask; source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height); mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height); speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot); } - - { + + { RefPtr bits; char pix[4] = { 0, 0, 0, 0 }; bits = Bitmap::create (pix, 2, 2); @@ -1388,17 +1218,17 @@ Editor::build_cursors () transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0); } - { + { RefPtr bits; char pix[4] = { 0, 0, 0, 0 }; bits = Bitmap::create (pix, 2, 2); Gdk::Color c; transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0); } - + grabber_cursor = new Gdk::Cursor (HAND2); - + { Glib::RefPtr grabber_edit_point_pixbuf (::get_icon ("grabber_edit_point")); grabber_edit_point_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_edit_point_pixbuf, 5, 17); @@ -1436,22 +1266,22 @@ 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 (*this, &Editor::set_fade_in_active), false))); + items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false))); } else { - items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true))); + items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true))); } - + items.push_back (SeparatorElem()); if (Profile->get_sae()) { - items.push_back (MenuElem (_("Linear"), 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::Fast))); + items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast))); } else { - 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::Fast))); - items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB))); - 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))); + items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast))); + items.push_back (MenuElem (_("Slow"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB))); + items.push_back (MenuElem (_("Fast"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA))); + items.push_back (MenuElem (_("Fastest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow))); } break; @@ -1459,22 +1289,22 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i case FadeOutItem: case FadeOutHandleItem: if (arv->audio_region()->fade_out_active()) { - items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false))); + items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false))); } else { - items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true))); + items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true))); } - + items.push_back (SeparatorElem()); - + if (Profile->get_sae()) { - 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::Slow))); + items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow))); } else { - 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::Slow))); - items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA))); - items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB))); - items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast))); + items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow))); + items.push_back (MenuElem (_("Slow"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA))); + items.push_back (MenuElem (_("Fast"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB))); + items.push_back (MenuElem (_("Fastest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast))); } break; @@ -1534,7 +1364,7 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, menu = (this->*build_menu_function)(frame); menu->set_name ("ArdourContextMenu"); - + /* now handle specific situations */ switch (item_type) { @@ -1579,23 +1409,23 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) { /* Bounce to disk */ - + using namespace Menu_Helpers; MenuList& edit_items = menu->items(); - + edit_items.push_back (SeparatorElem()); switch (clicked_routeview->audio_track()->freeze_state()) { case AudioTrack::NoFreeze: - edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route))); + edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route))); break; case AudioTrack::Frozen: - edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route))); + edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route))); break; - + case AudioTrack::UnFrozen: - edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route))); + edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route))); break; } @@ -1609,7 +1439,7 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, } Menu* -Editor::build_track_context_menu (nframes64_t ignored) +Editor::build_track_context_menu (nframes64_t) { using namespace Menu_Helpers; @@ -1621,7 +1451,7 @@ Editor::build_track_context_menu (nframes64_t ignored) } Menu* -Editor::build_track_bus_context_menu (nframes64_t ignored) +Editor::build_track_bus_context_menu (nframes64_t) { using namespace Menu_Helpers; @@ -1644,16 +1474,16 @@ Editor::build_track_region_context_menu (nframes64_t frame) if (rtv) { boost::shared_ptr ds; boost::shared_ptr pl; - + if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) { Playlist::RegionList* regions = pl->regions_at ((nframes64_t) floor ( (double)frame * ds->speed())); if (selection->regions.size() > 1) { - // there's already a multiple selection: just add a - // single region context menu that will act on all + // 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); + 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); @@ -1697,11 +1527,11 @@ Editor::build_track_crossfade_context_menu (nframes64_t frame) } if (selection->regions.size() > 1) { - // there's already a multiple selection: just add a - // single region context menu that will act on all + // 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); + 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); @@ -1716,22 +1546,21 @@ Editor::build_track_crossfade_context_menu (nframes64_t frame) return &track_crossfade_context_menu; } -#ifdef FFT_ANALYSIS void Editor::analyze_region_selection() { if (analysis_window == 0) { analysis_window = new AnalysisWindow(); - if (session != 0) - analysis_window->set_session(session); + if (_session != 0) + analysis_window->set_session(_session); analysis_window->show_all(); } analysis_window->set_regionmode(); analysis_window->analyze(); - + analysis_window->present(); } @@ -1741,21 +1570,20 @@ Editor::analyze_range_selection() if (analysis_window == 0) { analysis_window = new AnalysisWindow(); - if (session != 0) - analysis_window->set_session(session); + if (_session != 0) + analysis_window->set_session(_session); analysis_window->show_all(); } analysis_window->set_rangemode(); analysis_window->analyze(); - + analysis_window->present(); } -#endif /* FFT_ANALYSIS */ Menu* -Editor::build_track_selection_context_menu (nframes64_t ignored) +Editor::build_track_selection_context_menu (nframes64_t) { using namespace Menu_Helpers; MenuList& edit_items = track_selection_context_menu.items(); @@ -1772,7 +1600,7 @@ Editor::build_track_selection_context_menu (nframes64_t ignored) * @param edit_items List to add the items to. */ void -Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr xfade, Menu_Helpers::MenuList& edit_items, bool many) +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); @@ -1782,22 +1610,22 @@ Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptractive()) { str = _("Mute"); - } else { + } else { str = _("Unmute"); } - 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)))); + items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr (xfade)))); + items.push_back (MenuElem (_("Edit"), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr (xfade)))); if (xfade->can_follow_overlap()) { if (xfade->following_overlap()) { - str = _("Convert to short"); + str = _("Convert to Short"); } else { - str = _("Convert to full"); + str = _("Convert to Full"); } - items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade))); + items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade))); } if (many) { @@ -1828,28 +1656,15 @@ Editor::xfade_edit_right_region () } } -/** Add an element to a menu, settings its sensitivity. - * @param m Menu to add to. - * @param e Element to add. - * @param s true to make sensitive, false to make insensitive - */ -void -Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const -{ - m.push_back (e); - if (!s) { - m.back().set_sensitive (false); - } -} - void Editor::add_region_context_items (StreamView* sv, boost::shared_ptr region, Menu_Helpers::MenuList& edit_items) { using namespace Menu_Helpers; + Gtk::MenuItem* foo_item; Menu *region_menu = manage (new Menu); MenuList& items = region_menu->items(); region_menu->set_name ("ArdourContextMenu"); - + boost::shared_ptr ar; boost::shared_ptr mr; @@ -1857,119 +1672,119 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi ar = boost::dynamic_pointer_cast (region); mr = boost::dynamic_pointer_cast (region); - /* when this particular menu pops up, make the relevant region + /* 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))); - - items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::rename_region))); - items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region))); + sigc::bind (sigc::mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr(region))); + + items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &Editor::rename_region))); + if (mr && internal_editing()) { + items.push_back (MenuElem (_("List editor..."), sigc::mem_fun(*this, &Editor::show_midi_list_editor))); + } else { + items.push_back (MenuElem (_("Region Properties..."), sigc::mem_fun(*this, &Editor::edit_region))); + } } - 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 (MenuElem (_("Raise to Top Layer"), sigc::mem_fun(*this, &Editor::raise_region_to_top))); + items.push_back (MenuElem (_("Lower to Bottom Layer"), sigc::mem_fun (*this, &Editor::lower_region_to_bottom))); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_point))); - items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync))); + items.push_back (MenuElem (_("Define Sync Point"), sigc::mem_fun(*this, &Editor::set_region_sync_from_edit_point))); + if (_edit_point == EditAtMouse) { + items.back ().set_sensitive (false); + } + items.push_back (MenuElem (_("Remove Sync Point"), sigc::mem_fun(*this, &Editor::remove_region_sync))); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::play_selected_region))); - items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region))); - items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection))); + items.push_back (MenuElem (_("Audition"), sigc::mem_fun(*this, &Editor::play_selected_region))); + items.push_back (MenuElem (_("Export"), sigc::mem_fun(*this, &Editor::export_region))); + items.push_back (MenuElem (_("Bounce"), sigc::mem_fun(*this, &Editor::bounce_region_selection))); -#ifdef FFT_ANALYSIS if (ar) { - items.push_back (MenuElem (_("Spectral Analysis"), mem_fun(*this, &Editor::analyze_region_selection))); + items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_region_selection))); } -#endif items.push_back (SeparatorElem()); sigc::connection fooc; + boost::shared_ptr region_to_check; if (region) { - items.push_back (CheckMenuElem (_("Lock"))); - CheckMenuItem* region_lock_item = static_cast(&items.back()); - if (region->locked()) { - region_lock_item->set_active(); - } - region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock)); + region_to_check = region; + } else { + region_to_check = selection->regions.front()->region(); + } - items.push_back (CheckMenuElem (_("Glue to Bars&Beats"))); - CheckMenuItem* bbt_glue_item = static_cast(&items.back()); + items.push_back (CheckMenuElem (_("Lock"))); + CheckMenuItem* region_lock_item = static_cast(&items.back()); + if (region_to_check->locked()) { + region_lock_item->set_active(); + } + region_lock_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_lock)); - switch (region->positional_lock_style()) { - case Region::MusicTime: - bbt_glue_item->set_active (true); - break; - default: - bbt_glue_item->set_active (false); - break; - } + items.push_back (CheckMenuElem (_("Glue to Bars and Beats"))); + CheckMenuItem* bbt_glue_item = static_cast(&items.back()); + + switch (region_to_check->positional_lock_style()) { + case Region::MusicTime: + bbt_glue_item->set_active (true); + break; + default: + bbt_glue_item->set_active (false); + break; + } - bbt_glue_item->signal_activate().connect (bind (mem_fun (*this, &Editor::set_region_lock_style), Region::MusicTime)); + bbt_glue_item->signal_activate().connect (sigc::bind (sigc::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()) { + items.push_back (CheckMenuElem (_("Mute"))); + CheckMenuItem* region_mute_item = static_cast(&items.back()); + fooc = region_mute_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_mute)); + if (region_to_check->muted()) { + fooc.block (true); + region_mute_item->set_active(); + fooc.block (false); + } + + if (!Profile->get_sae()) { + items.push_back (CheckMenuElem (_("Opaque"))); + CheckMenuItem* region_opaque_item = static_cast(&items.back()); + fooc = region_opaque_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_region_opaque)); + if (region_to_check->opaque()) { fooc.block (true); - region_mute_item->set_active(); + region_opaque_item->set_active(); fooc.block (false); } - - if (!Profile->get_sae()) { - 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()) { - fooc.block (true); - region_opaque_item->set_active(); - fooc.block (false); - } - } - } else { - // multiple regions selected - // how should these act? - // here they toggle the property of all selected regions - - items.push_back (MenuElem (_("Lock"), mem_fun(*this, &Editor::toggle_region_lock))); - items.push_back (MenuElem (_("Mute"), mem_fun(*this, &Editor::toggle_region_mute))); - if (!Profile->get_sae()) { - items.push_back (MenuElem (_("Opaque"), mem_fun(*this, &Editor::toggle_region_opaque))); - } } - items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize))); - if (region && region->at_natural_position()) { + items.push_back (CheckMenuElem (_("Original Position"), sigc::mem_fun(*this, &Editor::naturalize))); + if (region_to_check->at_natural_position()) { items.back().set_sensitive (false); } - + items.push_back (SeparatorElem()); - + if (ar) { - + RegionView* rv = sv->find_view (ar); AudioRegionView* arv = dynamic_cast(rv); - + if (!Profile->get_sae()) { - items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes))); + items.push_back (MenuElem (_("Reset Envelope"), sigc::mem_fun(*this, &Editor::reset_region_gain_envelopes))); items.push_back (CheckMenuElem (_("Envelope Visible"))); CheckMenuItem* region_envelope_visible_item = static_cast (&items.back()); - fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility)); + fooc = region_envelope_visible_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_visibility)); if (arv->envelope_visible()) { fooc.block (true); region_envelope_visible_item->set_active (true); fooc.block (false); } - + items.push_back (CheckMenuElem (_("Envelope Active"))); CheckMenuItem* region_envelope_active_item = static_cast (&items.back()); - fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active)); - + fooc = region_envelope_active_item->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_gain_envelope_active)); + if (ar->envelope_active()) { fooc.block (true); region_envelope_active_item->set_active (true); @@ -1979,36 +1794,41 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi items.push_back (SeparatorElem()); } - if (ar->scale_amplitude() != 1.0f) { - items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region))); - } else { - items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region))); + items.push_back (MenuElem (_("Normalize"), sigc::mem_fun(*this, &Editor::normalize_region))); + if (ar->scale_amplitude() != 1) { + items.push_back (MenuElem (_("Reset Gain"), sigc::mem_fun(*this, &Editor::reset_region_scale_amplitude))); } } else if (mr) { - items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_region))); + items.push_back (MenuElem (_("Quantize"), sigc::mem_fun(*this, &Editor::quantize_region))); items.push_back (SeparatorElem()); } - items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region))); + items.push_back (MenuElem (_("Strip Silence..."), sigc::mem_fun (*this, &Editor::strip_region_silence))); + items.push_back (MenuElem (_("Reverse"), sigc::mem_fun(*this, &Editor::reverse_region))); items.push_back (SeparatorElem()); /* 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 Selection"), mem_fun (*this, &Editor::set_selection_from_region))); + items.push_back (MenuElem (_("Add Single Range"), sigc::mem_fun (*this, &Editor::add_location_from_audio_region))); + items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_locations_from_audio_region))); + if (selection->regions.size() < 2) { + items.back().set_sensitive (false); + } + + items.push_back (MenuElem (_("Set Range Selection"), sigc::mem_fun (*this, &Editor::set_selection_from_region))); items.push_back (SeparatorElem()); - + /* Nudge region */ Menu *nudge_menu = manage (new Menu()); MenuList& nudge_items = nudge_menu->items(); nudge_menu->set_name ("ArdourContextMenu"); - - nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false, false)))); - nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false, false)))); - nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset)))); - nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset)))); + + nudge_items.push_back (MenuElem (_("Nudge Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_forward), false, false)))); + nudge_items.push_back (MenuElem (_("Nudge Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_backward), false, false)))); + nudge_items.push_back (MenuElem (_("Nudge Forward by Capture Offset"), (sigc::mem_fun(*this, &Editor::nudge_forward_capture_offset)))); + nudge_items.push_back (MenuElem (_("Nudge Backward by Capture Offset"), (sigc::mem_fun(*this, &Editor::nudge_backward_capture_offset)))); items.push_back (MenuElem (_("Nudge"), *nudge_menu)); items.push_back (SeparatorElem()); @@ -2016,26 +1836,38 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi Menu *trim_menu = manage (new Menu); MenuList& trim_items = trim_menu->items(); trim_menu->set_name ("ArdourContextMenu"); - - trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point))); - trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point))); - trim_items.push_back (MenuElem (_("Trim To Loop"), mem_fun(*this, &Editor::trim_region_to_loop))); - trim_items.push_back (MenuElem (_("Trim To Punch"), mem_fun(*this, &Editor::trim_region_to_punch))); - + + trim_items.push_back (MenuElem (_("Start to Edit Point"), sigc::mem_fun(*this, &Editor::trim_region_from_edit_point))); + foo_item = &trim_items.back(); + if (_edit_point == EditAtMouse) { + foo_item->set_sensitive (false); + } + trim_items.push_back (MenuElem (_("Edit Point to End"), sigc::mem_fun(*this, &Editor::trim_region_to_edit_point))); + foo_item = &trim_items.back(); + if (_edit_point == EditAtMouse) { + foo_item->set_sensitive (false); + } + trim_items.push_back (MenuElem (_("Trim to Loop"), sigc::mem_fun(*this, &Editor::trim_region_to_loop))); + trim_items.push_back (MenuElem (_("Trim to Punch"), sigc::mem_fun(*this, &Editor::trim_region_to_punch))); + items.push_back (MenuElem (_("Trim"), *trim_menu)); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region)))); + items.push_back (MenuElem (_("Split"), (sigc::mem_fun(*this, &Editor::split)))); region_edit_menu_split_item = &items.back(); - items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region)))); + if (_edit_point == EditAtMouse) { + region_edit_menu_split_item->set_sensitive (false); + } + + items.push_back (MenuElem (_("Make Mono Regions"), (sigc::mem_fun(*this, &Editor::split_multichannel_region)))); region_edit_menu_split_multichannel_item = &items.back(); - items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), false)))); - 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 (MenuElem (_("Duplicate"), (sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)))); + items.push_back (MenuElem (_("Multi-Duplicate"), (sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), true)))); + items.push_back (MenuElem (_("Fill Track"), (sigc::mem_fun(*this, &Editor::region_fill_track)))); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions))); + items.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::remove_selected_regions))); /* OK, stick the region submenu at the top of the list, and then add the standard items. @@ -2046,13 +1878,13 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi */ string::size_type pos = 0; - string menu_item_name = (region) ? region->name() : _("Selected regions"); + string menu_item_name = (region) ? region->name() : _("Selected Regions"); while ((pos = menu_item_name.find ("_", pos)) != string::npos) { menu_item_name.replace (pos, 1, "__"); pos += 2; } - + edit_items.push_back (MenuElem (menu_item_name, *region_menu)); edit_items.push_back (SeparatorElem()); } @@ -2064,47 +1896,47 @@ void Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items) { using namespace Menu_Helpers; - Menu *selection_menu = manage (new Menu); - MenuList& items = selection_menu->items(); - selection_menu->set_name ("ArdourContextMenu"); - items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection))); - items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true))); + edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection))); + edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true))); -#ifdef FFT_ANALYSIS - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Spectral Analysis"), mem_fun(*this, &Editor::analyze_range_selection))); -#endif - - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false))); - items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false))); + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection))); - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection))); - items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection))); - - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection))); + if (!selection->regions.empty()) { + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Extend Range to End of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_end_of_region), false))); + edit_items.push_back (MenuElem (_("Extend Range to Start of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_start_of_region), false))); + } - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false))); - items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection))); - - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection))); - 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::create_named_selection))); - items.push_back (SeparatorElem()); - 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_selection))); + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Silence Range"), sigc::mem_fun(*this, &Editor::separate_region_from_selection))); + edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection))); + + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection))); + + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false))); + edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection))); + + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection))); + + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection))); + edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection))); + edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false))); + + edit_items.push_back (SeparatorElem()); + edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false))); + edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true))); + edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false))); + edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true))); + edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_range))); } - + void Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) { @@ -2115,13 +1947,13 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) Menu *play_menu = manage (new Menu); MenuList& play_items = play_menu->items(); play_menu->set_name ("ArdourContextMenu"); - - play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point))); - 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 (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point))); + play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start))); + play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region))); play_items.push_back (SeparatorElem()); - play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region))); - + play_items.push_back (MenuElem (_("Loop Region"), sigc::mem_fun(*this, &Editor::loop_selected_region))); + edit_items.push_back (MenuElem (_("Play"), *play_menu)); /* Selection */ @@ -2129,24 +1961,22 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) Menu *select_menu = manage (new Menu); MenuList& select_items = select_menu->items(); select_menu->set_name ("ArdourContextMenu"); - - select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); - select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set))); - select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track))); - select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection))); - select_items.push_back (SeparatorElem()); - select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop))); - select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch))); - select_items.push_back (SeparatorElem()); - select_items.push_back (MenuElem (_("Select All After Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true))); - select_items.push_back (MenuElem (_("Select All Before Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false))); - select_items.push_back (MenuElem (_("Select All After Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true))); - select_items.push_back (MenuElem (_("Select All Before Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false))); - select_items.push_back (MenuElem (_("Select All Between Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), false))); - select_items.push_back (MenuElem (_("Select All Within Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), true))); - select_items.push_back (MenuElem (_("Select Range Between Playhead & Edit Point"), mem_fun(*this, &Editor::select_range_between))); + select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); + select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set))); + select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track))); + select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection))); select_items.push_back (SeparatorElem()); + select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop))); + select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch))); + select_items.push_back (SeparatorElem()); + select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true))); + select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false))); + select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true))); + select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false))); + select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false))); + select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true))); + select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between))); edit_items.push_back (MenuElem (_("Select"), *select_menu)); @@ -2155,39 +1985,35 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items) Menu *cutnpaste_menu = manage (new Menu); MenuList& cutnpaste_items = cutnpaste_menu->items(); cutnpaste_menu->set_name ("ArdourContextMenu"); - - cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut))); - cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy))); - cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f))); - - cutnpaste_items.push_back (SeparatorElem()); - cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint))); - cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint))); + cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut))); + cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy))); + cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f))); cutnpaste_items.push_back (SeparatorElem()); - cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f))); + cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun(*this, &Editor::align), ARDOUR::SyncPoint))); + cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint))); edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu)); /* Adding new material */ - + 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 Media"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack))); + edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f))); + edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack))); /* Nudge track */ Menu *nudge_menu = manage (new Menu()); MenuList& nudge_items = nudge_menu->items(); nudge_menu->set_name ("ArdourContextMenu"); - + edit_items.push_back (SeparatorElem()); - nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true)))); - nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true)))); - nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false)))); - nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false)))); + nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true)))); + nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true)))); + nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false)))); + nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false)))); edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu)); } @@ -2202,9 +2028,9 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items) Menu *play_menu = manage (new Menu); MenuList& play_items = play_menu->items(); play_menu->set_name ("ArdourContextMenu"); - - play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point))); - play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start))); + + play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point))); + play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start))); edit_items.push_back (MenuElem (_("Play"), *play_menu)); /* Selection */ @@ -2212,16 +2038,16 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items) Menu *select_menu = manage (new Menu); MenuList& select_items = select_menu->items(); select_menu->set_name ("ArdourContextMenu"); - - select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); - select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set))); - select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track))); - select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection))); + + select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set))); + select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set))); + select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track))); + select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection))); select_items.push_back (SeparatorElem()); - select_items.push_back (MenuElem (_("Select all after edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true))); - select_items.push_back (MenuElem (_("Select all before edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false))); - select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true))); - select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false))); + select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true))); + select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false))); + select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true))); + select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false))); edit_items.push_back (MenuElem (_("Select"), *select_menu)); @@ -2230,36 +2056,48 @@ Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items) Menu *cutnpaste_menu = manage (new Menu); MenuList& cutnpaste_items = cutnpaste_menu->items(); cutnpaste_menu->set_name ("ArdourContextMenu"); - - cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut))); - cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy))); - cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f))); + + cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut))); + cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy))); + cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f))); Menu *nudge_menu = manage (new Menu()); MenuList& nudge_items = nudge_menu->items(); nudge_menu->set_name ("ArdourContextMenu"); - + edit_items.push_back (SeparatorElem()); - nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true)))); - nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true)))); - nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false)))); - nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false)))); + nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true)))); + nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true)))); + nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false)))); + nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false)))); edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu)); } +SnapType +Editor::snap_type() const +{ + return _snap_type; +} + +SnapMode +Editor::snap_mode() const +{ + return _snap_mode; +} + void Editor::set_snap_to (SnapType st) { unsigned int snap_ind = (unsigned int)st; - snap_type = st; - + _snap_type = st; + if (snap_ind > snap_type_strings.size() - 1) { snap_ind = 0; - snap_type = (SnapType)snap_ind; + _snap_type = (SnapType)snap_ind; } - + string str = snap_type_strings[snap_ind]; if (str != snap_type_selector.get_active_text()) { @@ -2268,13 +2106,13 @@ Editor::set_snap_to (SnapType st) instant_save (); - switch (snap_type) { + switch (_snap_type) { case SnapToAThirtysecondBeat: case SnapToASixteenthBeat: case SnapToAEighthBeat: case SnapToAQuarterBeat: case SnapToAThirdBeat: - compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + (nframes_t)(edit_packer.get_width() * frames_per_unit)); + compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames()); update_tempo_based_rulers (); break; @@ -2294,7 +2132,7 @@ Editor::set_snap_to (SnapType st) void Editor::set_snap_mode (SnapMode mode) { - snap_mode = mode; + _snap_mode = mode; string str = snap_mode_strings[(int)mode]; if (str != snap_mode_selector.get_active_text ()) { @@ -2321,27 +2159,7 @@ Editor::set_edit_point_preference (EditPoint ep, bool force) return; } - 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; - } - break; - default: - break; - } - - const char* action; + const char* action=NULL; switch (_edit_point) { case EditAtPlayhead: @@ -2373,7 +2191,7 @@ Editor::set_edit_point_preference (EditPoint ep, bool force) } int -Editor::set_state (const XMLNode& node) +Editor::set_state (const XMLNode& node, int /*version*/) { const XMLProperty* prop; XMLNode* geometry; @@ -2384,43 +2202,68 @@ Editor::set_state (const XMLNode& node) _id = prop->value (); } - if ((geometry = find_named_node (node, "geometry")) == 0) { + g.base_width = default_width; + g.base_height = default_height; + x = 1; + y = 1; + xoff = 0; + yoff = 21; - g.base_width = default_width; - g.base_height = default_height; - x = 1; - y = 1; - xoff = 0; - yoff = 21; + if ((geometry = find_named_node (node, "geometry")) != 0) { - } else { + XMLProperty* prop; - g.base_width = atoi(geometry->property("x_size")->value()); - g.base_height = atoi(geometry->property("y_size")->value()); - x = atoi(geometry->property("x_pos")->value()); - y = atoi(geometry->property("y_pos")->value()); - xoff = atoi(geometry->property("x_off")->value()); - yoff = atoi(geometry->property("y_off")->value()); + if ((prop = geometry->property("x_size")) == 0) { + prop = geometry->property ("x-size"); + } + if (prop) { + g.base_width = atoi(prop->value()); + } + if ((prop = geometry->property("y_size")) == 0) { + prop = geometry->property ("y-size"); + } + if (prop) { + g.base_height = atoi(prop->value()); + } + + if ((prop = geometry->property ("x_pos")) == 0) { + prop = geometry->property ("x-pos"); + } + if (prop) { + x = atoi (prop->value()); + + } + if ((prop = geometry->property ("y_pos")) == 0) { + prop = geometry->property ("y-pos"); + } + if (prop) { + y = atoi (prop->value()); + } + + if ((prop = geometry->property ("x_off")) == 0) { + prop = geometry->property ("x-off"); + } + if (prop) { + xoff = atoi (prop->value()); + } + if ((prop = geometry->property ("y_off")) == 0) { + prop = geometry->property ("y-off"); + } + if (prop) { + yoff = atoi (prop->value()); + } } set_default_size (g.base_width, g.base_height); move (x, y); - if (session && (prop = node.property ("playhead"))) { + if (_session && (prop = node.property ("playhead"))) { nframes64_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 ((prop = node.property ("mixer-width"))) { editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width)); } @@ -2441,33 +2284,42 @@ Editor::set_state (const XMLNode& node) set_snap_mode ((SnapMode) atoi (prop->value())); } - if ((prop = node.property ("edit-point"))) { - set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true); - } - if ((prop = node.property ("mouse-mode"))) { MouseMode m = str2mousemode(prop->value()); - mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */ set_mouse_mode (m, true); } else { - mouse_mode = MouseGain; /* lie, to force the mode switch */ set_mouse_mode (MouseObject, true); } - if ((prop = node.property ("show-waveforms"))) { - bool yn = (prop->value() == "yes"); - _show_waveforms = !yn; - RefPtr act = ActionManager::get_action (X_("Editor"), X_("toggle-waveform-visible")); + if ((prop = node.property ("left-frame")) != 0){ + nframes64_t pos; + if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) { + reset_x_origin (pos); + /* this hack prevents the initial call to update_current_screen() from doing re-centering on the playhead */ + last_update_frame = pos; + } + } + + if ((prop = node.property ("internal-edit"))) { + bool yn = string_is_affirmative (prop->value()); + RefPtr act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit")); if (act) { RefPtr tact = RefPtr::cast_dynamic(act); - /* do it twice to force the change */ tact->set_active (!yn); tact->set_active (yn); } } + if ((prop = node.property ("join-object-range"))) { + join_object_range_button.set_active (string_is_affirmative (prop->value ())); + } + + if ((prop = node.property ("edit-point"))) { + set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true); + } + if ((prop = node.property ("show-waveforms-recording"))) { - bool yn = (prop->value() == "yes"); + bool yn = string_is_affirmative (prop->value()); _show_waveforms_recording = !yn; RefPtr act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording")); if (act) { @@ -2477,9 +2329,9 @@ Editor::set_state (const XMLNode& node) tact->set_active (yn); } } - + if ((prop = node.property ("show-measures"))) { - bool yn = (prop->value() == "yes"); + bool yn = string_is_affirmative (prop->value()); _show_measures = !yn; RefPtr act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility")); if (act) { @@ -2491,7 +2343,7 @@ Editor::set_state (const XMLNode& node) } if ((prop = node.property ("follow-playhead"))) { - bool yn = (prop->value() == "yes"); + bool yn = string_is_affirmative (prop->value()); set_follow_playhead (yn); RefPtr act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead")); if (act) { @@ -2503,12 +2355,11 @@ Editor::set_state (const XMLNode& node) } if ((prop = node.property ("region-list-sort-type"))) { - region_list_sort_type = (Editing::RegionListSortType) -1; // force change - reset_region_list_sort_type(str2regionlistsorttype(prop->value())); + _regions->reset_sort_type (str2regionlistsorttype(prop->value()), true); } if ((prop = node.property ("xfades-visible"))) { - bool yn = (prop->value() == "yes"); + bool yn = string_is_affirmative (prop->value()); _xfade_visibility = !yn; // set_xfade_visibility (yn); } @@ -2519,15 +2370,15 @@ Editor::set_state (const XMLNode& node) if (act) { Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); - bool yn = (prop->value() == X_("yes")); + bool yn = string_is_affirmative (prop->value()); /* do it twice to force the change */ - + tact->set_active (!yn); tact->set_active (yn); } } - + if ((prop = node.property ("show-editor-list"))) { Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-list")); @@ -2535,10 +2386,10 @@ Editor::set_state (const XMLNode& node) if (act) { Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); - bool yn = (prop->value() == X_("yes")); + bool yn = string_is_affirmative (prop->value()); /* do it twice to force the change */ - + tact->set_active (!yn); tact->set_active (yn); } @@ -2556,29 +2407,29 @@ Editor::get_state () _id.print (buf, sizeof (buf)); node->add_property ("id", buf); - + if (is_realized()) { Glib::RefPtr win = get_window(); - + int x, y, xoff, yoff, width, height; win->get_root_origin(x, y); win->get_position(xoff, yoff); win->get_size(width, height); - + XMLNode* geometry = new XMLNode ("geometry"); snprintf(buf, sizeof(buf), "%d", width); - geometry->add_property("x_size", string(buf)); + geometry->add_property("x-size", string(buf)); snprintf(buf, sizeof(buf), "%d", height); - geometry->add_property("y_size", string(buf)); + geometry->add_property("y-size", string(buf)); snprintf(buf, sizeof(buf), "%d", x); - geometry->add_property("x_pos", string(buf)); + geometry->add_property("x-pos", string(buf)); snprintf(buf, sizeof(buf), "%d", y); - geometry->add_property("y_pos", string(buf)); + geometry->add_property("y-pos", string(buf)); snprintf(buf, sizeof(buf), "%d", xoff); - geometry->add_property("x_off", string(buf)); + geometry->add_property("x-off", string(buf)); snprintf(buf, sizeof(buf), "%d", yoff); - geometry->add_property("y_off", string(buf)); + geometry->add_property("y-off", string(buf)); snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast(&edit_pane)->gobj())); geometry->add_property("edit_pane_pos", string(buf)); @@ -2586,35 +2437,38 @@ Editor::get_state () } maybe_add_mixer_strip_width (*node); - + snprintf (buf, sizeof(buf), "%d", (int) zoom_focus); node->add_property ("zoom-focus", buf); snprintf (buf, sizeof(buf), "%f", frames_per_unit); node->add_property ("zoom", buf); - snprintf (buf, sizeof(buf), "%d", (int) snap_type); + snprintf (buf, sizeof(buf), "%d", (int) _snap_type); node->add_property ("snap-to", buf); - snprintf (buf, sizeof(buf), "%d", (int) snap_mode); + snprintf (buf, sizeof(buf), "%d", (int) _snap_mode); node->add_property ("snap-mode", buf); node->add_property ("edit-point", enum_2_string (_edit_point)); snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame); node->add_property ("playhead", buf); + snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame); + node->add_property ("left-frame", 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"); node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no"); node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no"); - node->add_property ("region-list-sort-type", enum2str(region_list_sort_type)); + node->add_property ("region-list-sort-type", enum2str (_regions->sort_type ())); node->add_property ("mouse-mode", enum2str(mouse_mode)); - + node->add_property ("internal-edit", _internal_editing ? "yes" : "no"); + node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no"); + Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer")); if (act) { Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no"); } - + act = ActionManager::get_action (X_("Editor"), X_("show-editor-list")); if (act) { Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); @@ -2626,101 +2480,142 @@ Editor::get_state () -TimeAxisView * +/** @param y y offset from the top of all trackviews. + * @return pair: TimeAxisView that y is over, layer index. + * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is + * in stacked region display mode, otherwise 0. + */ +std::pair Editor::trackview_by_y_position (double y) { for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) { - TimeAxisView *tv; - - if ((tv = (*iter)->covers_y_position (y)) != 0) { - return tv; + std::pair const r = (*iter)->covers_y_position (y); + if (r.first) { + return r; } } - return 0; + return std::make_pair ( (TimeAxisView *) 0, 0); } +/** Snap a position to the grid, if appropriate, taking into account current + * grid settings and also the state of any snap modifier keys that may be pressed. + * @param start Position to snap. + * @param event Event to get current key modifier information from, or 0. + */ void -Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) +Editor::snap_to_with_modifier (nframes64_t& start, GdkEvent const * event, int32_t direction, bool for_mark) { - if (!session || snap_mode == SnapOff) { + if (!_session || !event) { return; } - snap_to_internal (start, direction, for_mark); + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { + if (_snap_mode == SnapOff) { + snap_to_internal (start, direction, for_mark); + } + } else { + if (_snap_mode != SnapOff) { + snap_to_internal (start, direction, for_mark); + } + } } void -Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark) +Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark) { - Location* before = 0; - Location* after = 0; + if (!_session || _snap_mode == SnapOff) { + return; + } - 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()); - nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60); - nframes64_t presnap = start; + snap_to_internal (start, direction, for_mark); +} - switch (snap_type) { - case SnapToCDFrame: - 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 = (nframes64_t) floor ((double) start / (one_second / 75)) * (one_second / 75); - } - break; +void +Editor::timecode_snap_to_internal (nframes64_t& start, int32_t direction, bool /*for_mark*/) +{ + const nframes64_t one_timecode_second = (nframes64_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame()); + nframes64_t one_timecode_minute = (nframes64_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60); - case SnapToSMPTEFrame: - 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()); + switch (_snap_type) { + case SnapToTimecodeFrame: + if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) { + start = (nframes64_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame()); } else { - start = (nframes64_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame()); + start = (nframes64_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame()); } break; - case SnapToSMPTESeconds: - if (session->smpte_offset_negative()) + case SnapToTimecodeSeconds: + if (_session->timecode_offset_negative()) { - start += session->smpte_offset (); + start += _session->timecode_offset (); } else { - start -= session->smpte_offset (); - } - 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; + start -= _session->timecode_offset (); + } + if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) { + start = (nframes64_t) ceil ((double) start / one_timecode_second) * one_timecode_second; } else { - start = (nframes64_t) floor ((double) start / one_smpte_second) * one_smpte_second; + start = (nframes64_t) floor ((double) start / one_timecode_second) * one_timecode_second; } - - if (session->smpte_offset_negative()) + + if (_session->timecode_offset_negative()) { - start -= session->smpte_offset (); + start -= _session->timecode_offset (); } else { - start += session->smpte_offset (); + start += _session->timecode_offset (); } break; - - case SnapToSMPTEMinutes: - if (session->smpte_offset_negative()) + + case SnapToTimecodeMinutes: + if (_session->timecode_offset_negative()) { - start += session->smpte_offset (); + start += _session->timecode_offset (); } else { - start -= session->smpte_offset (); + start -= _session->timecode_offset (); } - 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; + if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) { + start = (nframes64_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute; } else { - start = (nframes64_t) floor ((double) start / one_smpte_minute) * one_smpte_minute; + start = (nframes64_t) floor ((double) start / one_timecode_minute) * one_timecode_minute; } - if (session->smpte_offset_negative()) + if (_session->timecode_offset_negative()) { - start -= session->smpte_offset (); + start -= _session->timecode_offset (); } else { - start += session->smpte_offset (); + start += _session->timecode_offset (); } break; - + default: + fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg; + /*NOTREACHED*/ + } +} + +void +Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark) +{ + const nframes64_t one_second = _session->frame_rate(); + const nframes64_t one_minute = _session->frame_rate() * 60; + nframes64_t presnap = start; + nframes64_t before; + nframes64_t after; + + switch (_snap_type) { + case SnapToTimecodeFrame: + case SnapToTimecodeSeconds: + case SnapToTimecodeMinutes: + return timecode_snap_to_internal (start, direction, for_mark); + + case SnapToCDFrame: + 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 = (nframes64_t) floor ((double) start / (one_second / 75)) * (one_second / 75); + } + break; + case SnapToSeconds: if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) { start = (nframes64_t) ceil ((double) start / one_second) * one_second; @@ -2728,7 +2623,7 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark) start = (nframes64_t) floor ((double) start / one_second) * one_second; } break; - + case SnapToMinutes: if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) { start = (nframes64_t) ceil ((double) start / one_minute) * one_minute; @@ -2738,31 +2633,31 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark) break; case SnapToBar: - start = session->tempo_map().round_to_bar (start, direction); + start = _session->tempo_map().round_to_bar (start, direction); break; case SnapToBeat: - start = session->tempo_map().round_to_beat (start, direction); + start = _session->tempo_map().round_to_beat (start, direction); break; case SnapToAThirtysecondBeat: - start = session->tempo_map().round_to_beat_subdivision (start, 32); + start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction); break; case SnapToASixteenthBeat: - start = session->tempo_map().round_to_beat_subdivision (start, 16); + start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction); break; case SnapToAEighthBeat: - start = session->tempo_map().round_to_beat_subdivision (start, 8); + start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction); break; case SnapToAQuarterBeat: - start = session->tempo_map().round_to_beat_subdivision (start, 4); + start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction); break; case SnapToAThirdBeat: - start = session->tempo_map().round_to_beat_subdivision (start, 3); + start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction); break; case SnapToMark: @@ -2770,39 +2665,21 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark) return; } - before = session->locations()->first_location_before (start); - after = session->locations()->first_location_after (start); + _session->locations()->marks_either_side (start, before, after); - if (direction < 0) { - if (before) { - start = before->start(); + if (before == max_frames) { + start = after; + } else if (after == max_frames) { + start = before; + } else if (before != max_frames && after != max_frames) { + /* have before and after */ + if ((start - before) < (after - start)) { + start = before; } else { - start = 0; - } - } else if (direction > 0) { - if (after) { - start = after->start(); - } else { - start = session->current_end_frame(); - } - } else { - if (before) { - if (after) { - /* find nearest of the two */ - if ((start - before->start()) < (after->start() - start)) { - start = before->start(); - } else { - start = after->start(); - } - } else { - start = before->start(); - } - } else if (after) { - start = after->start(); - } else { - /* relax */ + start = after; } } + break; case SnapToRegionStart: @@ -2810,196 +2687,158 @@ Editor::snap_to_internal (nframes64_t& start, int32_t direction, bool for_mark) case SnapToRegionSync: case SnapToRegionBoundary: if (!region_boundary_cache.empty()) { - vector::iterator i; + + vector::iterator prev = region_boundary_cache.end (); + vector::iterator next = region_boundary_cache.end (); if (direction > 0) { - i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start); + next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start); } else { - i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start); + next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start); } - - 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; - } + if (next != region_boundary_cache.begin ()) { + prev = next; + prev--; + } - start = *i; + nframes64_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev; + nframes64_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next; + if (start > (p + n) / 2) { + start = n; } else { - start = region_boundary_cache.back(); + start = p; } - } + } break; } - switch (snap_mode) { + switch (_snap_mode) { case SnapNormal: - return; - + return; + case SnapMagnetic: - + if (presnap > start) { if (presnap > (start + unit_to_frame(snap_threshold))) { start = presnap; } - + } else if (presnap < start) { if (presnap < (start - unit_to_frame(snap_threshold))) { start = presnap; } } - + default: /* handled at entry */ return; - - } -} - -double -Editor::snap_length_beats (nframes64_t start) -{ - if (!session) { - return 1.0; - } - - /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */ - - switch (snap_type) { - case SnapToBar: - return session->tempo_map().meter_at(start).beats_per_bar(); - - case SnapToBeat: - return 1.0; - - case SnapToAThirtysecondBeat: - return 1.0 / (double)32.0; - break; - - case SnapToASixteenthBeat: - return 1.0 / (double)16.0; - break; - - case SnapToAEighthBeat: - return 1.0 / (double)8.0; - break; - - case SnapToAQuarterBeat: - return 1.0 / (double)4.0; - break; - - case SnapToAThirdBeat: - return 1.0 / (double)3.0; - default: - return 1.0; } } + void Editor::setup_toolbar () { string pixmap_path; -#ifdef GTKOSX - const guint32 FUDGE = 38; // Combo's are stupid - they steal space from the entry for the button -#else - const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button -#endif - /* Mode Buttons (tool selection) */ - vector mouse_mode_buttons; - - mouse_move_button.add (*(manage (new Image (::get_icon("tool_object"))))); mouse_move_button.set_relief(Gtk::RELIEF_NONE); - mouse_mode_buttons.push_back (&mouse_move_button); - - if (!Profile->get_sae()) { - mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm"))))); - mouse_select_button.set_relief(Gtk::RELIEF_NONE); - mouse_mode_buttons.push_back (&mouse_select_button); - - mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain"))))); - mouse_gain_button.set_relief(Gtk::RELIEF_NONE); - mouse_mode_buttons.push_back (&mouse_gain_button); - } - - mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom"))))); + mouse_select_button.set_relief(Gtk::RELIEF_NONE); + mouse_gain_button.set_relief(Gtk::RELIEF_NONE); mouse_zoom_button.set_relief(Gtk::RELIEF_NONE); - mouse_mode_buttons.push_back (&mouse_zoom_button); - mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch"))))); mouse_timefx_button.set_relief(Gtk::RELIEF_NONE); - mouse_mode_buttons.push_back (&mouse_timefx_button); - mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition"))))); mouse_audition_button.set_relief(Gtk::RELIEF_NONE); - mouse_note_button.add (*(manage (new Image (::get_icon("tool_note"))))); - mouse_note_button.set_relief(Gtk::RELIEF_NONE); - mouse_mode_buttons.push_back (&mouse_note_button); - mouse_mode_buttons.push_back (&mouse_audition_button); - - mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons); + // internal_edit_button.set_relief(Gtk::RELIEF_NONE); + join_object_range_button.set_relief(Gtk::RELIEF_NONE); HBox* mode_box = manage(new HBox); mode_box->set_border_width (2); mode_box->set_spacing(4); - mouse_mode_button_box.set_spacing(1); - mouse_mode_button_box.pack_start(mouse_move_button, true, true); - if (!Profile->get_sae()) { - mouse_mode_button_box.pack_start(mouse_select_button, true, true); + + /* table containing mode buttons */ + + Table* mouse_mode_button_table = manage (new Table (Profile->get_sae() ? 4 : 6, 2)); + + int c = 0; + + if (Profile->get_sae()) { + mouse_mode_button_table->attach (mouse_move_button, c, c + 1, 0, 1); + ++c; + } else { + mouse_mode_button_table->attach (mouse_move_button, c, c + 1, 0, 1); + mouse_mode_button_table->attach (mouse_select_button, c + 1, c + 2, 0, 1); + mouse_mode_button_table->attach (join_object_range_button, c, c + 2, 1, 2); + c += 2; } - mouse_mode_button_box.pack_start(mouse_zoom_button, true, true); + + mouse_mode_button_table->attach (mouse_zoom_button, c, c + 1, 0, 1); + ++c; + if (!Profile->get_sae()) { - mouse_mode_button_box.pack_start(mouse_gain_button, true, true); + mouse_mode_button_table->attach (mouse_gain_button, c, c + 1, 0, 1); + ++c; } - mouse_mode_button_box.pack_start(mouse_timefx_button, true, true); - mouse_mode_button_box.pack_start(mouse_audition_button, true, true); - mouse_mode_button_box.pack_start(mouse_note_button, true, true); - mouse_mode_button_box.set_homogeneous(true); - + + mouse_mode_button_table->attach (mouse_timefx_button, c, c + 1, 0, 1); + ++c; + + mouse_mode_button_table->attach (mouse_audition_button, c, c + 1, 0, 1); + ++c; + + mouse_mode_button_table->attach (internal_edit_button, c, c + 1, 0, 1); + ++c; + vector edit_mode_strings; edit_mode_strings.push_back (edit_mode_to_string (Slide)); - edit_mode_strings.push_back (edit_mode_to_string (Splice)); + if (!Profile->get_sae()) { + edit_mode_strings.push_back (edit_mode_to_string (Splice)); + } edit_mode_strings.push_back (edit_mode_to_string (Lock)); edit_mode_selector.set_name ("EditModeSelector"); - Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10); - set_popdown_strings (edit_mode_selector, edit_mode_strings); - edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done)); + set_popdown_strings (edit_mode_selector, edit_mode_strings, true); + edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done)); + + mode_box->pack_start (edit_mode_selector); + mode_box->pack_start (*mouse_mode_button_table); - mode_box->pack_start(edit_mode_selector); - mode_box->pack_start(mouse_mode_button_box); - mouse_mode_tearoff = manage (new TearOff (*mode_box)); mouse_mode_tearoff->set_name ("MouseModeBase"); + mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &mouse_mode_tearoff->tearoff_window()), false); + + if (Profile->get_sae()) { + mouse_mode_tearoff->set_can_be_torn_off (false); + } - mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), &mouse_mode_tearoff->tearoff_window())); - mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), &mouse_mode_tearoff->tearoff_window(), 1)); - mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), &mouse_mode_tearoff->tearoff_window())); - mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), &mouse_mode_tearoff->tearoff_window(), 1)); + mouse_move_button.set_mode (false); + mouse_select_button.set_mode (false); + mouse_gain_button.set_mode (false); + mouse_zoom_button.set_mode (false); + mouse_timefx_button.set_mode (false); + mouse_audition_button.set_mode (false); + join_object_range_button.set_mode (false); + mouse_move_button.set_name ("MouseModeButton"); mouse_select_button.set_name ("MouseModeButton"); mouse_gain_button.set_name ("MouseModeButton"); mouse_zoom_button.set_name ("MouseModeButton"); mouse_timefx_button.set_name ("MouseModeButton"); mouse_audition_button.set_name ("MouseModeButton"); - mouse_note_button.set_name ("MouseModeButton"); - - ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes")); + internal_edit_button.set_name ("MouseModeButton"); + join_object_range_button.set_name ("MouseModeButton"); mouse_move_button.unset_flags (CAN_FOCUS); mouse_select_button.unset_flags (CAN_FOCUS); @@ -3007,77 +2846,81 @@ Editor::setup_toolbar () mouse_zoom_button.unset_flags (CAN_FOCUS); mouse_timefx_button.unset_flags (CAN_FOCUS); mouse_audition_button.unset_flags (CAN_FOCUS); - mouse_note_button.unset_flags (CAN_FOCUS); - - mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange)); - mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release)); - - mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject)); - mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain)); - mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom)); - mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX)); - mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition)); - mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote)); - - // mouse_move_button.set_active (true); - + internal_edit_button.unset_flags (CAN_FOCUS); + join_object_range_button.unset_flags (CAN_FOCUS); /* Zoom */ - + zoom_box.set_spacing (1); zoom_box.set_border_width (0); 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)); + zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_BUTTON)))); + zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false)); ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In")); - + zoom_out_button.set_name ("EditorTimeButton"); - zoom_out_button.set_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)); + zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_BUTTON)))); + zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true)); ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out")); zoom_out_full_button.set_name ("EditorTimeButton"); - zoom_out_full_button.set_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)); + zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_BUTTON)))); + zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session)); ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session")); zoom_focus_selector.set_name ("ZoomFocusSelector"); - Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, _("Playhead"), 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)); + set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true); + zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done)); ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus")); - zoom_box.pack_start (zoom_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); + /* Track zoom buttons */ + tav_expand_button.set_name ("TrackHeightButton"); + tav_expand_button.set_size_request(-1,20); + tav_expand_button.add (*(manage (new Image (::get_icon("tav_exp"))))); + tav_expand_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), true)); + ARDOUR_UI::instance()->tooltips().set_tip (tav_expand_button, _("Expand Tracks")); + + tav_shrink_button.set_name ("TrackHeightButton"); + tav_shrink_button.set_size_request(-1,20); + tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink"))))); + tav_shrink_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), false)); + ARDOUR_UI::instance()->tooltips().set_tip (tav_shrink_button, _("Shrink Tracks")); + + track_zoom_box.set_spacing (1); + track_zoom_box.set_border_width (0); + + track_zoom_box.pack_start (tav_shrink_button, false, false); + track_zoom_box.pack_start (tav_expand_button, false, false); + + HBox* zbc = manage (new HBox); + zbc->pack_start (zoom_focus_selector, PACK_SHRINK); + zoom_vbox.pack_start (*zbc, PACK_SHRINK); + zoom_vbox.pack_start (zoom_box, PACK_SHRINK); + zoom_vbox.pack_start (track_zoom_box, PACK_SHRINK); + snap_box.set_spacing (1); snap_box.set_border_width (2); snap_type_selector.set_name ("SnapTypeSelector"); - Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, _("SMPTE Seconds"), 2+FUDGE, 10); - set_popdown_strings (snap_type_selector, snap_type_strings); - snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done)); + set_popdown_strings (snap_type_selector, snap_type_strings, true); + snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done)); ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units")); snap_mode_selector.set_name ("SnapModeSelector"); - Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, _("Magnetic Snap"), 2+FUDGE, 10); - set_popdown_strings (snap_mode_selector, snap_mode_strings); - snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done)); + set_popdown_strings (snap_mode_selector, snap_mode_strings, true); + snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done)); ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode")); - edit_point_selector.set_name ("SnapModeSelector"); - Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, _("Playhead"), 2+FUDGE, 10); - set_popdown_strings (edit_point_selector, edit_point_strings); - edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done)); + edit_point_selector.set_name ("EditPointSelector"); + set_popdown_strings (edit_point_selector, edit_point_strings, true); + edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done)); ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point")); - snap_box.pack_start (edit_point_clock, false, false); snap_box.pack_start (snap_mode_selector, false, false); snap_box.pack_start (snap_type_selector, false, false); snap_box.pack_start (edit_point_selector, false, false); @@ -3088,8 +2931,8 @@ Editor::setup_toolbar () nudge_box->set_spacing(1); nudge_box->set_border_width (2); - nudge_forward_button.signal_button_release_event().connect (mem_fun(*this, &Editor::nudge_forward_release), false); - nudge_backward_button.signal_button_release_event().connect (mem_fun(*this, &Editor::nudge_backward_release), false); + nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false); + nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false); nudge_box->pack_start (nudge_backward_button, false, false); nudge_box->pack_start (nudge_forward_button, false, false); @@ -3103,14 +2946,19 @@ Editor::setup_toolbar () tools_tearoff = manage (new TearOff (*hbox)); tools_tearoff->set_name ("MouseModeBase"); + tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &tools_tearoff->tearoff_window()), false); + + if (Profile->get_sae()) { + tools_tearoff->set_can_be_torn_off (false); + } - tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), &tools_tearoff->tearoff_window())); - tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), &tools_tearoff->tearoff_window(), 0)); - tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), &tools_tearoff->tearoff_window())); - tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), &tools_tearoff->tearoff_window(), 0)); toolbar_hbox.set_spacing (10); @@ -3119,13 +2967,12 @@ Editor::setup_toolbar () toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false); toolbar_hbox.pack_start (*tools_tearoff, false, false); - hbox->pack_start (snap_box, false, false); - // hbox->pack_start (zoom_box, false, false); hbox->pack_start (*nudge_box, false, false); + hbox->pack_start (panic_box, false, false); hbox->show_all (); - + toolbar_base.set_name ("ToolBarBase"); toolbar_base.add (toolbar_hbox); @@ -3134,109 +2981,49 @@ Editor::setup_toolbar () toolbar_frame.add (toolbar_base); } - void -Editor::setup_midi_toolbar () +Editor::midi_panic () { - string pixmap_path; - - /* Mode Buttons (tool selection) */ + cerr << "MIDI panic\n"; - vector midi_tool_buttons; - - midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil"))))); - midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE); - midi_tool_buttons.push_back (&midi_tool_pencil_button); - 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); - - midi_tool_pencil_button.set_active(true); - - midi_tool_button_set = new GroupedButtons (midi_tool_buttons); - - midi_tool_button_box.set_border_width (2); - 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)); - - /* Pack everything in... */ - - midi_tools_tearoff = manage (new TearOff (midi_tool_button_box)); - midi_tools_tearoff->set_name ("MouseModeBase"); + if (_session) { + _session->midi_panic(); + } +} - /* - midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&midi_toolbar_hbox), - &midi_tools_tearoff->tearoff_window())); - midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&midi_toolbar_hbox), - &midi_tools_tearoff->tearoff_window(), 0)); - midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&midi_toolbar_hbox), - &midi_tools_tearoff->tearoff_window())); - midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&midi_toolbar_hbox), - &midi_tools_tearoff->tearoff_window(), 0)); - */ +void +Editor::setup_midi_toolbar () +{ + RefPtr act; - midi_toolbar_hbox.set_spacing (10); - midi_toolbar_hbox.set_border_width (1); + /* Midi sound notes */ + midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes"))))); + midi_sound_notes.set_relief(Gtk::RELIEF_NONE); + ARDOUR_UI::instance()->tooltips().set_tip (midi_sound_notes, _("Sound Notes")); + midi_sound_notes.unset_flags (CAN_FOCUS); - midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true); + /* Panic */ - midi_tool_button_box.show_all (); - midi_toolbar_hbox.show_all(); - midi_tools_tearoff->show_all(); - - midi_toolbar_base.set_name ("ToolBarBase"); - midi_toolbar_base.add (midi_toolbar_hbox); + act = ActionManager::get_action (X_("MIDI"), X_("panic")); + midi_panic_button.set_name("MidiPanicButton"); + ARDOUR_UI::instance()->tooltips().set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels")); + act->connect_proxy (midi_panic_button); - midi_toolbar_frame.set_shadow_type (SHADOW_OUT); - midi_toolbar_frame.set_name ("BaseFrame"); - midi_toolbar_frame.add (midi_toolbar_base); + panic_box.pack_start (midi_sound_notes , true, true); + panic_box.pack_start (midi_panic_button, true, true); } int -Editor::convert_drop_to_paths (vector& paths, - const RefPtr& context, - gint x, - gint y, - const SelectionData& data, - guint info, - guint time) - -{ - if (session == 0) { +Editor::convert_drop_to_paths ( + vector& paths, + const RefPtr& /*context*/, + gint /*x*/, + gint /*y*/, + const SelectionData& data, + guint /*info*/, + guint /*time*/) +{ + if (_session == 0) { return -1; } @@ -3251,31 +3038,39 @@ Editor::convert_drop_to_paths (vector& paths, if (data.get_target() != "text/plain") { return -1; } - - /* Parse the "uri-list" format that Nautilus provides, - where each pathname is delimited by \r\n + + /* Parse the "uri-list" format that Nautilus provides, + where each pathname is delimited by \r\n. + + THERE MAY BE NO NULL TERMINATING CHAR!!! */ - - const char* p = data.get_text().c_str(); + + ustring txt = data.get_text(); + const char* p; const char* q; + p = (const char *) malloc (txt.length() + 1); + txt.copy ((char *) p, txt.length(), 0); + ((char*)p)[txt.length()] = '\0'; + while (p) { if (*p != '#') { while (g_ascii_isspace (*p)) p++; - + q = p; - while (*q && (*q != '\n') && (*q != '\r')) + while (*q && (*q != '\n') && (*q != '\r')) { q++; - + } + if (q > p) { q--; while (q > p && g_ascii_isspace (*q)) q--; - + if (q > p) { uris.push_back (ustring (p, q - p + 1)); @@ -3287,20 +3082,22 @@ Editor::convert_drop_to_paths (vector& paths, p++; } + free ((void*)p); + if (uris.empty()) { return -1; } } - + for (vector::iterator i = uris.begin(); i != uris.end(); ++i) { if ((*i).substr (0,7) == "file://") { - + ustring p = *i; - PBD::url_decode (p); + PBD::url_decode (p); // scan forward past three slashes - + ustring::size_type slashcnt = 0; ustring::size_type n = 0; ustring::iterator x = p.begin(); @@ -3336,9 +3133,9 @@ Editor::new_tempo_section () void Editor::map_transport_state () { - ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state)); + ENSURE_GUI_THREAD (*this, &Editor::map_transport_state) - if (session->transport_stopped()) { + if (_session->transport_stopped()) { have_pending_keyboard_selection = false; } @@ -3357,95 +3154,66 @@ Editor::State::~State () delete selection; } -UndoAction -Editor::get_memento () const -{ - State *state = new State (this); - - store_state (*state); - return bind (mem_fun (*(const_cast(this)), &Editor::restore_state), state); -} - -void -Editor::store_state (State& state) const -{ - *state.selection = *selection; -} - -void -Editor::restore_state (State *state) -{ - if (*selection == *state->selection) { - return; - } - - *selection = *state->selection; - time_selection_changed (); - region_selection_changed (); - - /* XXX other selection change handlers? */ -} - void Editor::begin_reversible_command (string name) { - if (session) { - before = &get_state(); - session->begin_reversible_command (name); + if (_session) { + before = &get_state(); + _session->begin_reversible_command (name); } } void Editor::commit_reversible_command () { - if (session) { - session->commit_reversible_command (new MementoCommand(*this, before, &get_state())); + if (_session) { + _session->commit_reversible_command (new MementoCommand(*this, before, &get_state())); } } void -Editor::set_edit_group_solo (Route& route, bool yn) +Editor::set_route_group_solo (Route& route, bool yn) { - RouteGroup *edit_group; + RouteGroup *route_group; - if ((edit_group = route.edit_group()) != 0) { - edit_group->apply (&Route::set_solo, yn, this); + if ((route_group = route.route_group()) != 0) { + route_group->apply (&Route::set_solo, yn, this); } else { route.set_solo (yn, this); } } void -Editor::set_edit_group_mute (Route& route, bool yn) +Editor::set_route_group_mute (Route& route, bool yn) { - RouteGroup *edit_group = 0; + RouteGroup *route_group = 0; - if ((edit_group == route.edit_group()) != 0) { - edit_group->apply (&Route::set_mute, yn, this); + if ((route_group == route.route_group()) != 0) { + route_group->apply (&Route::set_mute, yn, this); } else { route.set_mute (yn, this); } } - + void Editor::history_changed () { string label; - if (undo_action && session) { - if (session->undo_depth() == 0) { + if (undo_action && _session) { + if (_session->undo_depth() == 0) { label = _("Undo"); } else { - label = string_compose(_("Undo (%1)"), session->next_undo()); + label = string_compose(_("Undo (%1)"), _session->next_undo()); } undo_action->property_label() = label; } - if (redo_action && session) { - if (session->redo_depth() == 0) { + if (redo_action && _session) { + if (_session->redo_depth() == 0) { label = _("Redo"); } else { - label = string_compose(_("Redo (%1)"), session->next_redo()); + label = string_compose(_("Redo (%1)"), _session->next_redo()); } redo_action->property_label() = label; } @@ -3464,7 +3232,7 @@ Editor::duplicate_dialog (bool with_dialog) RegionSelection rs; get_regions_for_action (rs); - + if (mouse_mode != MouseRange) { if (rs.empty()) { @@ -3474,44 +3242,44 @@ Editor::duplicate_dialog (bool with_dialog) if (with_dialog) { - ArdourDialog win ("Duplication Dialog"); + ArdourDialog win ("Duplicate"); Label label (_("Number of Duplications:")); Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0); SpinButton spinner (adjustment, 0.0, 1); HBox hbox; - + win.get_vbox()->set_spacing (12); win.get_vbox()->pack_start (hbox); hbox.set_border_width (6); hbox.pack_start (label, PACK_EXPAND_PADDING, 12); - + /* dialogs have ::add_action_widget() but that puts the spinner in the wrong place, visually. so do this by hand. */ - + hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12); - spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT)); + spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT)); spinner.grab_focus(); hbox.show (); label.show (); spinner.show (); - + win.add_button (Stock::CANCEL, RESPONSE_CANCEL); win.add_button (_("Duplicate"), RESPONSE_ACCEPT); win.set_default_response (RESPONSE_ACCEPT); - + win.set_position (WIN_POS_MOUSE); - + spinner.grab_focus (); - + switch (win.run ()) { case RESPONSE_ACCEPT: break; default: return; } - + times = adjustment.get_value(); } @@ -3543,7 +3311,7 @@ Editor::clamp_verbose_cursor_x (double x) if (x < 0) { x = 0; } else { - x = min (canvas_width - 200.0, x); + x = min (_canvas_width - 200.0, x); } return x; } @@ -3554,11 +3322,29 @@ Editor::clamp_verbose_cursor_y (double y) if (y < canvas_timebars_vsize) { y = canvas_timebars_vsize; } else { - y = min (canvas_height - 50, y); + y = min (_canvas_height - 50, y); } return y; } +void +Editor::show_verbose_canvas_cursor_with (const string & txt) +{ + verbose_canvas_cursor->property_text() = txt.c_str(); + + int x, y; + double wx, wy; + + track_canvas->get_pointer (x, y); + track_canvas->window_to_world (x, y, wx, wy); + + /* don't get too close to the edge */ + verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx); + verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy); + + show_verbose_canvas_cursor (); +} + void Editor::set_verbose_canvas_cursor (const string & txt, double x, double y) { @@ -3585,7 +3371,11 @@ Editor::cycle_edit_mode () { switch (Config->get_edit_mode()) { case Slide: - Config->set_edit_mode (Splice); + if (Profile->get_sae()) { + Config->set_edit_mode (Lock); + } else { + Config->set_edit_mode (Splice); + } break; case Splice: Config->set_edit_mode (Lock); @@ -3599,7 +3389,7 @@ Editor::cycle_edit_mode () void Editor::edit_mode_selection_done () { - if (session == 0) { + if (_session == 0) { return; } @@ -3615,7 +3405,7 @@ Editor::edit_mode_selection_done () } Config->set_edit_mode (mode); -} +} void Editor::snap_type_selection_done () @@ -3649,12 +3439,12 @@ Editor::snap_type_selection_done () snaptype = SnapToRegionSync; } else if (choice == _("CD Frames")) { snaptype = SnapToCDFrame; - } else if (choice == _("SMPTE Frames")) { - snaptype = SnapToSMPTEFrame; - } else if (choice == _("SMPTE Seconds")) { - snaptype = SnapToSMPTESeconds; - } else if (choice == _("SMPTE Minutes")) { - snaptype = SnapToSMPTEMinutes; + } else if (choice == _("Timecode Frames")) { + snaptype = SnapToTimecodeFrame; + } else if (choice == _("Timecode Seconds")) { + snaptype = SnapToTimecodeSeconds; + } else if (choice == _("Timecode Minutes")) { + snaptype = SnapToTimecodeMinutes; } else if (choice == _("Seconds")) { snaptype = SnapToSeconds; } else if (choice == _("Minutes")) { @@ -3665,7 +3455,7 @@ Editor::snap_type_selection_done () if (ract) { ract->set_active (); } -} +} void Editor::snap_mode_selection_done () @@ -3741,24 +3531,20 @@ Editor::zoom_focus_selection_done () focus_type = ZoomFocusRight; } else if (choice == _("Center")) { focus_type = ZoomFocusCenter; - } else if (choice == _("Play")) { + } else if (choice == _("Playhead")) { focus_type = ZoomFocusPlayhead; - } else if (choice == _("Edit")) { - focus_type = ZoomFocusEdit; - } else if (choice == _("Active Mark")) { - focus_type = ZoomFocusEdit; - } else if (choice == _("Active Mark")) { - focus_type = ZoomFocusEdit; - } else { + } else if (choice == _("Mouse")) { focus_type = ZoomFocusMouse; - } - + } else if (choice == _("Edit point")) { + focus_type = ZoomFocusEdit; + } + RefPtr ract = zoom_focus_action (focus_type); if (ract) { ract->set_active (); } -} +} gint Editor::edit_controls_button_release (GdkEventButton* ev) @@ -3781,44 +3567,6 @@ Editor::mouse_select_button_release (GdkEventButton* ev) return true; } -Editor::TrackViewList * -Editor::get_valid_views (TimeAxisView* track, RouteGroup* group) -{ - TrackViewList *v; - TrackViewList::iterator i; - - v = new TrackViewList; - - if (track == 0 && group == 0) { - - /* all views */ - - for (i = track_views.begin(); i != track_views.end (); ++i) { - v->push_back (*i); - } - - } else if ((track != 0 && group == 0) || (track != 0 && group != 0 && !group->is_active())) { - - /* just the view for this track - */ - - v->push_back (track); - - } else { - - /* views for all tracks in the edit group */ - - for (i = track_views.begin(); i != track_views.end (); ++i) { - - if (group == 0 || (*i)->edit_group() == group) { - v->push_back (*i); - } - } - } - - return v; -} - void Editor::set_zoom_focus (ZoomFocus f) { @@ -3827,7 +3575,7 @@ Editor::set_zoom_focus (ZoomFocus f) if (str != zoom_focus_selector.get_active_text()) { zoom_focus_selector.set_active_text (str); } - + if (zoom_focus != f) { zoom_focus = f; @@ -3843,7 +3591,7 @@ Editor::ensure_float (Window& win) win.set_transient_for (*this); } -void +void Editor::pane_allocation_handler (Allocation &alloc, Paned* which) { /* recover or initialize pane positions. do this here rather than earlier because @@ -3858,12 +3606,23 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) static int32_t done; XMLNode* geometry; - if ((geometry = find_named_node (*node, "geometry")) == 0) { - width = default_width; - height = default_height; - } else { - width = atoi(geometry->property("x_size")->value()); - height = atoi(geometry->property("y_size")->value()); + width = default_width; + height = default_height; + + if ((geometry = find_named_node (*node, "geometry")) != 0) { + + if ((prop = geometry->property ("x_size")) == 0) { + prop = geometry->property ("x-size"); + } + if (prop) { + width = atoi (prop->value()); + } + if ((prop = geometry->property ("y_size")) == 0) { + prop = geometry->property ("y-size"); + } + if (prop) { + height = atoi (prop->value()); + } } if (which == static_cast (&edit_pane)) { @@ -3872,14 +3631,14 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) return; } - if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) { + if (!geometry || (prop = geometry->property ("edit-pane-pos")) == 0) { /* initial allocation is 90% to canvas, 10% to notebook */ pos = (int) floor (alloc.get_width() * 0.90f); snprintf (buf, sizeof(buf), "%d", pos); } 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; @@ -3888,17 +3647,20 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which) } void -Editor::detach_tearoff (Box* b, Window* w) +Editor::detach_tearoff (Box* /*b*/, Window* /*w*/) { - if (tools_tearoff->torn_off() && + cerr << "remove tearoff\n"; + + if (tools_tearoff->torn_off() && mouse_mode_tearoff->torn_off()) { top_hbox.remove (toolbar_frame); } } void -Editor::reattach_tearoff (Box* b, Window* w, int32_t n) +Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/) { + cerr << "reattach tearoff\n"; if (toolbar_frame.get_parent() == 0) { top_hbox.pack_end (toolbar_frame); } @@ -3911,6 +3673,8 @@ Editor::set_show_measures (bool yn) hide_measures (); if ((_show_measures = yn) == true) { + if (tempo_lines) + tempo_lines->show(); draw_measures (); } instant_save (); @@ -3966,17 +3730,17 @@ Editor::edit_xfade (boost::weak_ptr wxfade) return; } - CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0); - + CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0); + ensure_float (cew); - + switch (cew.run ()) { case RESPONSE_ACCEPT: break; default: return; } - + cew.apply (); xfade->StateChanged (Change (~0)); } @@ -3987,26 +3751,81 @@ Editor::playlist_selector () const return *_playlist_selector; } -nframes64_t -Editor::get_nudge_distance (nframes64_t pos, nframes64_t& next) +Evoral::MusicalTime +Editor::get_grid_type_as_beats (bool& success, nframes64_t position) { - nframes64_t ret; + success = true; - ret = nudge_clock.current_duration (pos); - next = ret + 1; /* XXXX fix me */ + switch (_snap_type) { + case SnapToBeat: + return 1.0; + break; - return ret; -} + case SnapToAThirtysecondBeat: + return 1.0/32.0; + break; -void -Editor::end_location_changed (Location* location) -{ - ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location)); - //reset_scrolling_region (); - horizontal_adjustment.set_upper ( location->start()); -} + case SnapToASixteenthBeat: + return 1.0/16.0; + break; -int + case SnapToAEighthBeat: + return 1.0/8.0; + break; + + case SnapToAQuarterBeat: + return 1.0/4.0; + break; + + case SnapToAThirdBeat: + return 1.0/3.0; + break; + + case SnapToBar: + if (_session) { + return _session->tempo_map().meter_at (position).beats_per_bar(); + } + break; + + case SnapToCDFrame: + case SnapToTimecodeFrame: + case SnapToTimecodeSeconds: + case SnapToTimecodeMinutes: + case SnapToSeconds: + case SnapToMinutes: + case SnapToRegionStart: + case SnapToRegionEnd: + case SnapToRegionSync: + case SnapToRegionBoundary: + default: + success = false; + break; + } + + return 0.0; +} + +nframes64_t +Editor::get_nudge_distance (nframes64_t pos, nframes64_t& next) +{ + nframes64_t ret; + + ret = nudge_clock.current_duration (pos); + next = ret + 1; /* XXXX fix me */ + + return ret; +} + +void +Editor::end_location_changed (Location* location) +{ + ENSURE_GUI_THREAD (*this, &Editor::end_location_changed, location) + //reset_scrolling_region (); + nframes64_t session_span = location->start() + (nframes64_t) floorf (current_page_frames() * 0.10f); + horizontal_adjustment.set_upper (session_span / frames_per_unit); +} + +int Editor::playlist_deletion_dialog (boost::shared_ptr pl) { ArdourDialog dialog ("playlist deletion dialog"); @@ -4014,7 +3833,7 @@ Editor::playlist_deletion_dialog (boost::shared_ptr pl) "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); @@ -4063,21 +3882,20 @@ Editor::prepare_for_cleanup () selection->clear_regions (); selection->clear_playlists (); - no_region_list_redisplay = true; + _regions->suspend_redisplay (); } void Editor::finish_cleanup () { - no_region_list_redisplay = false; - redisplay_regions (); + _regions->resume_redisplay (); } Location* Editor::transport_loop_location() { - if (session) { - return session->locations()->auto_loop_location(); + if (_session) { + return _session->locations()->auto_loop_location(); } else { return 0; } @@ -4086,8 +3904,8 @@ Editor::transport_loop_location() Location* Editor::transport_punch_location() { - if (session) { - return session->locations()->auto_punch_location(); + if (_session) { + return _session->locations()->auto_punch_location(); } else { return 0; } @@ -4096,6 +3914,10 @@ Editor::transport_punch_location() bool Editor::control_layout_scroll (GdkEventScroll* ev) { + if (Keyboard::some_magic_widget_has_focus()) { + return false; + } + switch (ev->direction) { case GDK_SCROLL_UP: scroll_tracks_up_line (); @@ -4105,7 +3927,7 @@ Editor::control_layout_scroll (GdkEventScroll* ev) case GDK_SCROLL_DOWN: scroll_tracks_down_line (); return true; - + default: /* no left/right handling yet */ break; @@ -4114,168 +3936,18 @@ Editor::control_layout_scroll (GdkEventScroll* ev) return false; } - -/** A new snapshot has been selected. - */ -void -Editor::snapshot_display_selection_changed () -{ - if (snapshot_display.get_selection()->count_selected_rows() > 0) { - - TreeModel::iterator i = snapshot_display.get_selection()->get_selected(); - - Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name]; - - if (snap_name.length() == 0) { - return; - } - - if (session->snap_name() == snap_name) { - return; - } - - ARDOUR_UI::instance()->load_session(session->path(), string (snap_name)); - } -} - -bool -Editor::snapshot_display_button_press (GdkEventButton* ev) -{ - if (ev->button == 3) { - /* Right-click on the snapshot list. Work out which snapshot it - was over. */ - Gtk::TreeModel::Path path; - Gtk::TreeViewColumn* col; - int cx; - int cy; - snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy); - Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path); - if (iter) { - Gtk::TreeModel::Row row = *iter; - popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]); - } - return true; - } - - return false; -} - - -/** Pop up the snapshot display context menu. - * @param button Button used to open the menu. - * @param time Menu open time. - * @snapshot_name Name of the snapshot that the menu click was over. - */ - -void -Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name) -{ - using namespace Menu_Helpers; - - MenuList& items (snapshot_context_menu.items()); - items.clear (); - - const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name); - - add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed); - - add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed); - - snapshot_context_menu.popup (button, time); -} - -void -Editor::rename_snapshot (Glib::ustring old_name) -{ - ArdourPrompter prompter(true); - - string new_name; - - prompter.set_name ("Prompter"); - prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); - prompter.set_prompt (_("New name of snapshot")); - prompter.set_initial_text (old_name); - - if (prompter.run() == RESPONSE_ACCEPT) { - prompter.get_result (new_name); - if (new_name.length()) { - session->rename_state (old_name, new_name); - redisplay_snapshots (); - } - } -} - - -void -Editor::remove_snapshot (Glib::ustring name) -{ - vector choices; - - std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name); - - choices.push_back (_("No, do nothing.")); - choices.push_back (_("Yes, remove it.")); - - Gtkmm2ext::Choice prompter (prompt, choices); - - if (prompter.run () == 1) { - session->remove_state (name); - redisplay_snapshots (); - } -} - -void -Editor::redisplay_snapshots () -{ - if (session == 0) { - return; - } - - vector state_file_paths; - - get_state_files_in_directory (session->session_directory().root_path(), - state_file_paths); - - if (state_file_paths.empty()) return; - - vector state_file_names(get_file_names_no_extension(state_file_paths)); - - snapshot_display_model->clear (); - - for (vector::iterator i = state_file_names.begin(); - i != state_file_names.end(); ++i) - { - string statename = (*i); - TreeModel::Row row = *(snapshot_display_model->append()); - - /* 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; - } -} - void Editor::session_state_saved (string snap_name) { - ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name)); - redisplay_snapshots (); + ENSURE_GUI_THREAD (*this, &Editor::session_state_saved, snap_name); + + update_title (); + _snapshots->redisplay (); } void Editor::maximise_editing_space () { - initial_ruler_update_required = true; - mouse_mode_tearoff->set_visible (false); tools_tearoff->set_visible (false); @@ -4289,7 +3961,7 @@ Editor::maximise_editing_space () fullscreen(); if(post_maximal_editor_width) { - edit_pane.set_position (post_maximal_pane_position - + 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); @@ -4299,9 +3971,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(); } @@ -4312,29 +3983,28 @@ 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)); } /** * Make new playlists for a given track and also any others that belong - * to the same active edit group. + * to the same active route group with the `edit' property. * @param v Track. */ -void +void Editor::new_playlists (TimeAxisView* v) { begin_reversible_command (_("new playlists")); - mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v); + vector > playlists; + _session->playlists->get (playlists); + mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, RouteGroup::Edit); commit_reversible_command (); } /** * Use a copy of the current playlist for a given track and also any others that belong - * to the same active edit group. + * to the same active route group with the `edit' property. * @param v Track. */ @@ -4342,38 +4012,41 @@ void Editor::copy_playlists (TimeAxisView* v) { begin_reversible_command (_("copy playlists")); - mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v); + vector > playlists; + _session->playlists->get (playlists); + mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, RouteGroup::Edit); commit_reversible_command (); } -/** - * Clear the current playlist for a given track and also any others that belong - * to the same active edit group. +/** Clear the current playlist for a given track and also any others that belong + * to the same active route group with the `edit' property. * @param v Track. */ -void +void Editor::clear_playlists (TimeAxisView* v) { begin_reversible_command (_("clear playlists")); - mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v); + vector > playlists; + _session->playlists->get (playlists); + mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, RouteGroup::Edit); commit_reversible_command (); } -void -Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz) +void +Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector > const & playlists) { - atv.use_new_playlist (sz > 1 ? false : true); + atv.use_new_playlist (sz > 1 ? false : true, playlists); } void -Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz) +Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector > const & playlists) { - atv.use_copy_playlist (sz > 1 ? false : true); + atv.use_copy_playlist (sz > 1 ? false : true, playlists); } -void -Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz) +void +Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/) { atv.clear_playlist (); } @@ -4398,6 +4071,12 @@ Editor::reset_x_origin (nframes64_t frame) queue_visual_change (frame); } +void +Editor::reset_y_origin (double y) +{ + queue_visual_change_y (y); +} + void Editor::reset_zoom (double fpu) { @@ -4424,14 +4103,13 @@ Editor::current_visual_state (bool with_tracks) 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; } @@ -4476,6 +4154,8 @@ Editor::use_visual_state (VisualState& vs) { no_save_visual = true; + _routes->suspend_redisplay (); + vertical_adjustment.set_value (vs.y_position); set_zoom_focus (vs.zoom_focus); @@ -4487,14 +4167,17 @@ Editor::use_visual_state (VisualState& vs) /* 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)); + (*t)->set_state (*(i->second), Stateful::loading_state_version); } } + if (!vs.track_states.empty()) { - update_route_visibility (); - } - + _routes->update_visibility (); + } + + _routes->resume_redisplay (); + no_save_visual = false; } @@ -4513,7 +4196,7 @@ Editor::set_frames_per_unit (double fpu) fpu = 2.0; } - + /* don't allow zooms that fit more than the maximum number of frames into an 800 pixel wide space. */ @@ -4522,6 +4205,9 @@ Editor::set_frames_per_unit (double fpu) return; } + if (tempo_lines) + tempo_lines->tempo_map_changed(); + frames_per_unit = fpu; post_zoom (); } @@ -4529,61 +4215,85 @@ Editor::set_frames_per_unit (double fpu) void Editor::post_zoom () { + nframes64_t cef = 0; + // convert fpu to frame count - nframes64_t frames = (nframes64_t) floor (frames_per_unit * canvas_width); + 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); } 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); - } + for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { + (*i)->reshow_selection (selection->time); } } + leftmost_frame = (nframes64_t) floor (horizontal_adjustment.get_value() * frames_per_unit); + ZoomChanged (); /* EMIT_SIGNAL */ - reset_hscrollbar_stepping (); + if (_session) { + cef = _session->current_end_frame() + (current_page_frames() / 10);// Add a little extra so we can see the end marker + } + horizontal_adjustment.set_upper (cef / frames_per_unit); + //reset_scrolling_region (); if (playhead_cursor) { playhead_cursor->set_position (playhead_cursor->current_frame); } + refresh_location_display(); + _summary->set_overlays_dirty (); + instant_save (); } void 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.add (VisualChange::TimeOrigin); - 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); + /* if we're moving beyond the end, make sure the upper limit of the horizontal adjustment + can reach. + */ + + if (_session && (where > _session->current_end_frame())) { + horizontal_adjustment.set_upper ((where + current_page_frames()) / frames_per_unit); } + + pending_visual_change.time_origin = where; + + ensure_visual_change_idle_handler (); } void Editor::queue_visual_change (double fpu) { - pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel); + pending_visual_change.add (VisualChange::ZoomLevel); pending_visual_change.frames_per_unit = fpu; + ensure_visual_change_idle_handler (); +} + +void +Editor::queue_visual_change_y (double y) +{ + pending_visual_change.add (VisualChange::YOrigin); + pending_visual_change.y_origin = y; + + ensure_visual_change_idle_handler (); +} + +void +Editor::ensure_visual_change_idle_handler () +{ if (pending_visual_change.idle_handler_id < 0) { - pending_visual_change.idle_handler_id = g_idle_add ( _idle_visual_changer, this); + pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this); } - } int @@ -4598,50 +4308,44 @@ Editor::idle_visual_changer () VisualChange::Type p = pending_visual_change.pending; pending_visual_change.pending = (VisualChange::Type) 0; + double last_time_origin = horizontal_adjustment.get_value(); + 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)(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)); + compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames()); + compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames()); update_tempo_based_rulers (); } if (p & VisualChange::TimeOrigin) { + horizontal_adjustment.set_value (pending_visual_change.time_origin / frames_per_unit); + } + if (p & VisualChange::YOrigin) { + vertical_adjustment.set_value (pending_visual_change.y_origin); + } - 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 (last_time_origin == horizontal_adjustment.get_value()) { + /* changed signal not emitted */ + update_fixed_rulers (); + redisplay_tempo (true); + } - /* if we seek beyond the current end of the canvas, move the end */ + _summary->set_overlays_dirty (); - 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 + // 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 */ } struct EditorOrderTimeAxisSorter { bool operator() (const TimeAxisView* a, const TimeAxisView* b) const { - return a->order < b->order; + return a->order () < b->order (); } }; - + void -Editor::sort_track_selection (TrackSelection* sel) +Editor::sort_track_selection (TrackViewList* sel) { EditorOrderTimeAxisSorter cmp; @@ -4669,9 +4373,9 @@ Editor::get_preferred_edit_position (bool ignore_playhead) switch (ep) { case EditAtPlayhead: - where = session->audible_frame(); + where = _session->audible_frame(); break; - + case EditAtSelectedMarker: if (!selection->markers.empty()) { bool is_start; @@ -4684,9 +4388,9 @@ Editor::get_preferred_edit_position (bool ignore_playhead) } break; } - } + } /* fallthru */ - + default: case EditAtMouse: if (!mouse_frame (where, ignored)) { @@ -4703,62 +4407,67 @@ Editor::get_preferred_edit_position (bool ignore_playhead) void Editor::set_loop_range (nframes64_t start, nframes64_t end, string cmd) { - if (!session) return; + if (!_session) return; begin_reversible_command (cmd); - + Location* tll; if ((tll = transport_loop_location()) == 0) { Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop); - XMLNode &before = session->locations()->get_state(); - session->locations()->add (loc, true); - session->set_auto_loop_location (loc); - XMLNode &after = session->locations()->get_state(); - session->add_command (new MementoCommand(*(session->locations()), &before, &after)); + XMLNode &before = _session->locations()->get_state(); + _session->locations()->add (loc, true); + _session->set_auto_loop_location (loc); + XMLNode &after = _session->locations()->get_state(); + _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); } else { - XMLNode &before = tll->get_state(); + XMLNode &before = tll->get_state(); tll->set_hidden (false, this); tll->set (start, end); - XMLNode &after = tll->get_state(); - session->add_command (new MementoCommand(*tll, &before, &after)); + XMLNode &after = tll->get_state(); + _session->add_command (new MementoCommand(*tll, &before, &after)); } - + commit_reversible_command (); } void Editor::set_punch_range (nframes64_t start, nframes64_t end, string cmd) { - if (!session) return; + if (!_session) return; begin_reversible_command (cmd); - + Location* tpl; if ((tpl = transport_punch_location()) == 0) { Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch); - XMLNode &before = session->locations()->get_state(); - session->locations()->add (loc, true); - session->set_auto_loop_location (loc); - XMLNode &after = session->locations()->get_state(); - session->add_command (new MementoCommand(*(session->locations()), &before, &after)); + XMLNode &before = _session->locations()->get_state(); + _session->locations()->add (loc, true); + _session->set_auto_loop_location (loc); + XMLNode &after = _session->locations()->get_state(); + _session->add_command (new MementoCommand(*(_session->locations()), &before, &after)); } else { - XMLNode &before = tpl->get_state(); + XMLNode &before = tpl->get_state(); tpl->set_hidden (false, this); tpl->set (start, end); - XMLNode &after = tpl->get_state(); - session->add_command (new MementoCommand(*tpl, &before, &after)); + XMLNode &after = tpl->get_state(); + _session->add_command (new MementoCommand(*tpl, &before, &after)); } - + commit_reversible_command (); } +/** Find regions which exist at a given time, and optionally on a given list of tracks. + * @param rs List to which found regions are added. + * @param where Time to look at. + * @param ts Tracks to look on; if this is empty, all tracks are examined. + */ void -Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackSelection& ts) const +Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackViewList& ts) const { - const TrackSelection* tracks; + const TrackViewList* tracks; if (ts.empty()) { tracks = &track_views; @@ -4766,22 +4475,19 @@ Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackSelec tracks = &ts; } - for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) { - - AudioTimeAxisView* atv = dynamic_cast(*t); - - if (atv) { + for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) { + RouteTimeAxisView* rtv = dynamic_cast(*t); + if (rtv) { boost::shared_ptr ds; boost::shared_ptr pl; - - if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) { - Playlist::RegionList* regions = pl->regions_at ((nframes64_t) floor ( (double)where * ds->speed())); + if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) { - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - - RegionView* rv = atv->audio_view()->find_view (*i); + 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 = rtv->view()->find_view (*i); if (rv) { rs.add (rv); } @@ -4794,9 +4500,9 @@ Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackSelec } void -Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSelection& ts) const +Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackViewList& ts) const { - const TrackSelection* tracks; + const TrackViewList* tracks; if (ts.empty()) { tracks = &track_views; @@ -4804,21 +4510,20 @@ Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSe tracks = &ts; } - for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) { - - AudioTimeAxisView* atv = dynamic_cast(*t); - - if (atv) { + for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) { + RouteTimeAxisView* rtv = dynamic_cast(*t); + if (rtv) { boost::shared_ptr ds; boost::shared_ptr pl; - - if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) { - Playlist::RegionList* regions = pl->regions_touched ((nframes64_t) floor ( (double)where * ds->speed()), max_frames); + if ((ds = rtv->get_diskstream()) && ((pl = ds->playlist()))) { + + 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) { - RegionView* rv = atv->audio_view()->find_view (*i); + RegionView* rv = rtv->view()->find_view (*i); if (rv) { rs.push_back (rv); @@ -4831,97 +4536,81 @@ Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSe } } +/** Find all regions which are either: + * - selected or + * - the entered_regionview (if allow_entered == true) or + * - under the preferred edit position AND on a selected track, or on a track + * which is in the same active edit-enable route group as a selected region (if allow_edit_position == true) + * @param rs Returned region list. + * @param allow_entered true to include the entered_regionview in the list. + */ void -Editor::get_regions_for_action (RegionSelection& rs, bool allow_entered) +Editor::get_regions_for_action (RegionSelection& rs, bool allow_entered, bool allow_edit_position) { - if (selection->regions.empty()) { - - if (selection->tracks.empty()) { - - /* no regions or tracks selected - */ - - 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); - } + /* Start with selected regions */ + rs = selection->regions; - return; - - } else { + /* Add the entered_regionview, if requested */ + if (allow_entered && entered_regionview) { + rs.add (entered_regionview); + } - /* no regions selected, so get all regions at the edit point across - all selected tracks. - */ + if (allow_edit_position) { - nframes64_t where = get_preferred_edit_position(); - get_regions_at (rs, where, selection->tracks); + TrackViewList tracks = selection->tracks; - /* if the entered regionview wasn't selected and neither was its track - then add it. - */ + /* tracks is currently the set of selected tracks; add any other tracks that + * have regions that are in the same edit-activated route group as one of + * our regions */ + for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) { - if (entered_regionview != 0 && - !selection->selected (entered_regionview) && - !selection->selected (&entered_regionview->get_time_axis_view())) { - rs.add (entered_regionview); - } + RouteGroup* g = (*i)->get_time_axis_view().route_group (); + if (g && g->active_property (RouteGroup::Edit)) { + tracks.add (axis_views_from_routes (g->route_list())); + } + } - } else { - - /* just use the selected regions */ - - rs = selection->regions; - - /* if the entered regionview wasn't selected and we allow this sort of thing, - then add it. - */ - - if (allow_entered && entered_regionview && !selection->selected (entered_regionview)) { - rs.add (entered_regionview); + if (!tracks.empty()) { + /* now find regions that are at the edit position on those tracks */ + nframes64_t const where = get_preferred_edit_position (); + get_regions_at (rs, where, tracks); } - } } void Editor::get_regions_corresponding_to (boost::shared_ptr region, vector& regions) { - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - + RouteTimeAxisView* tatv; - + if ((tatv = dynamic_cast (*i)) != 0) { - + boost::shared_ptr pl; vector > results; RegionView* marv; boost::shared_ptr ds; - + if ((ds = tatv->get_diskstream()) == 0) { /* bus */ continue; } - + if ((pl = (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) { regions.push_back (marv); } } - + } } -} +} void Editor::show_rhythm_ferret () @@ -4930,18 +4619,28 @@ Editor::show_rhythm_ferret () rhythm_ferret = new RhythmFerret(*this); } - rhythm_ferret->set_session (session); + rhythm_ferret->set_session (_session); rhythm_ferret->show (); rhythm_ferret->present (); } +void +Editor::show_global_port_matrix (ARDOUR::DataType t) +{ + if (_global_port_matrix[t] == 0) { + _global_port_matrix[t] = new GlobalPortMatrixWindow (_session, t); + } + + _global_port_matrix[t]->show (); +} + void Editor::first_idle () { MessageDialog* dialog = 0; - if (track_views.size() > 1) { - dialog = new MessageDialog (*this, + if (track_views.size() > 1) { + dialog = new MessageDialog (*this, _("Please wait while Ardour loads visual data"), true, Gtk::MESSAGE_INFO, @@ -4953,179 +4652,373 @@ Editor::first_idle () for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) { (*t)->first_idle(); } - - if (dialog) { - delete dialog; - } + + // first idle adds route children (automation tracks), so we need to redisplay here + _routes->redisplay (); + + delete dialog; _have_idled = true; } +static gboolean +_idle_resizer (gpointer arg) +{ + return ((Editor*)arg)->idle_resize (); +} + +void +Editor::add_to_idle_resize (TimeAxisView* view, int32_t h) +{ + if (resize_idle_id < 0) { + resize_idle_id = g_idle_add (_idle_resizer, this); + _pending_resize_amount = 0; + } + + /* make a note of the smallest resulting height, so that we can clamp the + lower limit at TimeAxisView::hSmall */ + + int32_t min_resulting = INT32_MAX; + + _pending_resize_amount += h; + _pending_resize_view = view; + + min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount); + + if (selection->tracks.contains (_pending_resize_view)) { + for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { + min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount); + } + } + + if (min_resulting < 0) { + min_resulting = 0; + } + + /* clamp */ + if (uint32_t (min_resulting) < TimeAxisView::hSmall) { + _pending_resize_amount += TimeAxisView::hSmall - min_resulting; + } +} + +/** Handle pending resizing of tracks */ +bool +Editor::idle_resize () +{ + _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount); + + if (dynamic_cast (_pending_resize_view) == 0 && + selection->tracks.contains (_pending_resize_view)) { + + for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { + if (*i != _pending_resize_view) { + (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount); + } + } + } + + flush_canvas (); + _group_tabs->set_dirty (); + resize_idle_id = -1; + + return false; +} + void -Editor::start_resize_line_ops () +Editor::located () { -#if 0 - old_resize_line_y = -1; - resize_line_y = -1; - need_resize_line = true; -#endif + ENSURE_GUI_THREAD (*this, &Editor::located); + + _pending_locate_request = false; } void -Editor::end_resize_line_ops () +Editor::region_view_added (RegionView *) { -#if 0 - need_resize_line = false; + _summary->set_dirty (); +} - 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); +void +Editor::streamview_height_changed () +{ + _summary->set_dirty (); +} + +TimeAxisView* +Editor::axis_view_from_route (boost::shared_ptr r) const +{ + TrackViewList::const_iterator j = track_views.begin (); + while (j != track_views.end()) { + RouteTimeAxisView* rtv = dynamic_cast (*j); + if (rtv && rtv->route() == r) { + return rtv; + } + ++j; } -#endif + + return 0; +} + + +TrackViewList +Editor::axis_views_from_routes (boost::shared_ptr r) const +{ + TrackViewList t; + + for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) { + TimeAxisView* tv = axis_view_from_route (*i); + if (tv) { + t.push_back (tv); + } + } + + return t; } + void -Editor::queue_draw_resize_line (int at) +Editor::handle_new_route (RouteList& routes) { -#if 0 - Glib::RefPtr win = get_window(); + ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes) - resize_line_y = at; + RouteTimeAxisView *rtv; + list new_views; - if (win && canvas_width) { + for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { + boost::shared_ptr route = (*x); - int controls_width = controls_layout.get_width(); - int xroot, discard; - - controls_layout.get_window()->get_origin (xroot, discard); + if (route->is_hidden()) { + continue; + } - 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"; + DataType dt = route->input()->default_type(); + + if (dt == ARDOUR::DataType::AUDIO) { + rtv = new AudioTimeAxisView (*this, _session, route, *track_canvas); + } else if (dt == ARDOUR::DataType::MIDI) { + rtv = new MidiTimeAxisView (*this, _session, route, *track_canvas); + } else { + throw unknown_type(); } - /* draw where it is */ + new_views.push_back (rtv); + track_views.push_back (rtv); + + rtv->effective_gain_display (); - Gdk::Rectangle r (0, at - 1, controls_width + (int) canvas_width, 3); - win->invalidate_rect (r, true); + rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added)); + rtv->view()->HeightChanged.connect (sigc::mem_fun (*this, &Editor::streamview_height_changed)); } -#endif + + _routes->routes_added (new_views); + + if (show_editor_mixer_when_tracks_arrive) { + show_editor_mixer (true); + } + + editor_list_button.set_sensitive (true); + + _summary->set_dirty (); } -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); +void +Editor::timeaxisview_deleted (TimeAxisView *tv) +{ + if (_session && _session->deletion_in_progress()) { + /* the situation is under control */ + return; + } -#if 0 - if (need_resize_line) { + ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv); - 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. - */ + _routes->route_removed (tv); - get_window()->get_origin (discard, yroot); - controls_layout.get_window()->get_origin (xroot, discard); - controls_width = controls_layout.get_width(); - - GdkRectangle lr; - GdkRectangle intersection; + if (tv == entered_track) { + entered_track = 0; + } + + /* remove it from the list of track views */ - lr.x = 0; - lr.y = resize_line_y; - lr.width = controls_width + (int) canvas_width; - lr.height = 3; + TrackViewList::iterator i; - 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); + if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) { + i = track_views.erase (i); + } - /* draw on root window */ + /* update whatever the current mixer strip is displaying, if revelant */ - 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; + boost::shared_ptr route; + RouteTimeAxisView* rtav = dynamic_cast (tv); + + if (rtav) { + route = rtav->route (); + } + + if (current_mixer_strip && current_mixer_strip->route() == route) { + + TimeAxisView* next_tv; + + if (track_views.empty()) { + next_tv = 0; + } else if (i == track_views.end()) { + next_tv = track_views.front(); } else { - cerr << "no intersect with " - << lr.x << ',' << lr.y - << ' ' - << lr.width << " x " << lr.height - << endl; + next_tv = (*i); } - } + + + if (next_tv) { + set_selected_mixer_strip (*next_tv); + } else { + /* make the editor mixer strip go away setting the + * button to inactive (which also unticks the menu option) + */ + + ActionManager::uncheck_toggleaction ("/Editor/show-editor-mixer"); + } + } +} - //cerr << "--- editor expose\n"; -#endif +void +Editor::hide_track_in_display (TimeAxisView& tv, bool /*temponly*/) +{ + RouteTimeAxisView* rtv = dynamic_cast (&tv); - return ret; + if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) { + // this will hide the mixer strip + set_selected_mixer_strip (tv); + } + + _routes->hide_track_in_display (tv); } -static gboolean -_idle_resizer (gpointer arg) +bool +Editor::sync_track_view_list_and_routes () { - return ((Editor*)arg)->idle_resize (); + track_views = TrackViewList (_routes->views ()); + + _summary->set_dirty (); + _group_tabs->set_dirty (); + + return false; // do not call again (until needed) } void -Editor::add_to_idle_resize (TimeAxisView* view, uint32_t h) +Editor::foreach_time_axis_view (sigc::slot theslot) { - if (resize_idle_id < 0) { - resize_idle_id = g_idle_add (_idle_resizer, this); + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + theslot (**i); } +} + +RouteTimeAxisView* +Editor::get_route_view_by_id (PBD::ID& id) +{ + RouteTimeAxisView* v; + + for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + if((v = dynamic_cast(*i)) != 0) { + if(v->route()->id() == id) { + return v; + } + } + } + + return 0; +} - resize_idle_target = h; +void +Editor::fit_route_group (RouteGroup *g) +{ + TrackViewList ts = axis_views_from_routes (g->route_list ()); + fit_tracks (ts); +} + +void +Editor::consider_auditioning (boost::shared_ptr region) +{ + boost::shared_ptr r = boost::dynamic_pointer_cast (region); - pending_resizes.push_back (view); + if (r == 0) { + _session->cancel_audition (); + return; + } - if (selection->selected (view) && !selection->tracks.empty()) { - pending_resizes.insert (pending_resizes.end(), selection->tracks.begin(), selection->tracks.end()); + if (_session->is_auditioning()) { + _session->cancel_audition (); + if (r == last_audition_region) { + return; + } } + + _session->audition_region (r); + last_audition_region = r; +} + + +void +Editor::hide_a_region (boost::shared_ptr r) +{ + r->set_hidden (true); +} + +void +Editor::remove_a_region (boost::shared_ptr r) +{ + _session->remove_region_from_region_list (r); +} + +void +Editor::audition_region_from_region_list () +{ + _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning)); +} + +void +Editor::hide_region_from_region_list () +{ + _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region)); +} + +void +Editor::start_step_editing () +{ + step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20); +} + +void +Editor::stop_step_editing () +{ + step_edit_connection.disconnect (); } bool -Editor::idle_resize () +Editor::check_step_edit () { - for (vector::iterator i = pending_resizes.begin(); i != pending_resizes.end(); ++i) { - (*i)->idle_resize (resize_idle_target); + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + MidiTimeAxisView* mtv = dynamic_cast (*i); + if (mtv) { + mtv->check_step_edit (); + } } - pending_resizes.clear(); - resize_idle_id = -1; - return false; + + return true; // do it again, till we stop +} + +void +Editor::horizontal_scroll_left () +{ + double x = leftmost_position() - current_page_frames() / 5; + if (x < 0) { + x = 0; + } + + reset_x_origin (x); +} + +void +Editor::horizontal_scroll_right () +{ + reset_x_origin (leftmost_position() + current_page_frames() / 5); }