2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
47 #include <glibmm/miscutils.h>
48 #include <gtkmm/image.h>
49 #include <gdkmm/color.h>
50 #include <gdkmm/bitmap.h>
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/grouped_buttons.h"
54 #include "gtkmm2ext/gtk_ui.h"
55 #include "gtkmm2ext/tearoff.h"
56 #include "gtkmm2ext/utils.h"
57 #include "gtkmm2ext/window_title.h"
58 #include "gtkmm2ext/choice.h"
59 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
61 #include "ardour/audio_track.h"
62 #include "ardour/audioplaylist.h"
63 #include "ardour/audioregion.h"
64 #include "ardour/location.h"
65 #include "ardour/midi_region.h"
66 #include "ardour/plugin_manager.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_directory.h"
70 #include "ardour/session_route.h"
71 #include "ardour/session_state_utils.h"
72 #include "ardour/tempo.h"
73 #include "ardour/utils.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/audioengine.h"
77 #include "control_protocol/control_protocol.h"
81 #include "analysis_window.h"
82 #include "audio_clock.h"
83 #include "audio_region_view.h"
84 #include "audio_streamview.h"
85 #include "audio_time_axis.h"
86 #include "automation_time_axis.h"
87 #include "bundle_manager.h"
88 #include "canvas-noevent-text.h"
89 #include "canvas_impl.h"
90 #include "crossfade_edit.h"
91 #include "crossfade_view.h"
95 #include "editor_cursors.h"
96 #include "editor_drag.h"
97 #include "editor_group_tabs.h"
98 #include "editor_locations.h"
99 #include "editor_regions.h"
100 #include "editor_route_groups.h"
101 #include "editor_routes.h"
102 #include "editor_snapshots.h"
103 #include "editor_summary.h"
104 #include "global_port_matrix.h"
105 #include "gui_object.h"
106 #include "gui_thread.h"
107 #include "keyboard.h"
109 #include "midi_time_axis.h"
110 #include "mixer_strip.h"
111 #include "mixer_ui.h"
112 #include "mouse_cursors.h"
113 #include "playlist_selector.h"
114 #include "public_editor.h"
115 #include "region_layering_order_editor.h"
116 #include "rgb_macros.h"
117 #include "rhythm_ferret.h"
118 #include "selection.h"
120 #include "simpleline.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
128 #include "imageframe_socket_handler.h"
132 using namespace ARDOUR;
135 using namespace Glib;
136 using namespace Gtkmm2ext;
137 using namespace Editing;
139 using PBD::internationalize;
141 using Gtkmm2ext::Keyboard;
143 const double Editor::timebar_height = 15.0;
145 static const gchar *_snap_type_strings[] = {
147 N_("Timecode Frames"),
148 N_("Timecode Seconds"),
149 N_("Timecode Minutes"),
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_zoom_focus_strings[] = {
201 #ifdef USE_RUBBERBAND
202 static const gchar *_rb_opt_strings[] = {
205 N_("Balanced multitimbral mixture"),
206 N_("Unpitched percussion with stable notes"),
207 N_("Crisp monophonic instrumental"),
208 N_("Unpitched solo percussion"),
209 N_("Resample without preserving pitch"),
215 show_me_the_size (Requisition* r, const char* what)
217 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
222 pane_size_watcher (Paned* pane)
224 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
225 it is no longer accessible. so stop that. this doesn't happen on X11,
226 just the quartz backend.
231 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
233 gint pos = pane->get_position ();
235 if (pos > max_width_of_lhs) {
236 pane->set_position (max_width_of_lhs);
242 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
244 /* time display buttons */
245 , minsec_label (_("Mins:Secs"))
246 , bbt_label (_("Bars:Beats"))
247 , timecode_label (_("Timecode"))
248 , samples_label (_("Samples"))
249 , tempo_label (_("Tempo"))
250 , meter_label (_("Meter"))
251 , mark_label (_("Location Markers"))
252 , range_mark_label (_("Range Markers"))
253 , transport_mark_label (_("Loop/Punch Ranges"))
254 , cd_mark_label (_("CD Markers"))
255 , edit_packer (4, 4, true)
257 /* the values here don't matter: layout widgets
258 reset them as needed.
261 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
263 /* tool bar related */
265 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
267 , toolbar_selection_clock_table (2,3)
269 , automation_mode_button (_("mode"))
271 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
274 , image_socket_listener(0)
279 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
280 , meters_running(false)
281 , _pending_locate_request (false)
282 , _pending_initial_locate (false)
283 , _last_cut_copy_source_track (0)
285 , _region_selection_change_updates_region_list (true)
286 , _following_mixer_selection (false)
290 /* we are a singleton */
292 PublicEditor::_instance = this;
296 selection = new Selection (this);
297 cut_buffer = new Selection (this);
299 clicked_regionview = 0;
300 clicked_axisview = 0;
301 clicked_routeview = 0;
302 clicked_crossfadeview = 0;
303 clicked_control_point = 0;
304 last_update_frame = 0;
305 pre_press_cursor = 0;
306 _drags = new DragManager (this);
307 current_mixer_strip = 0;
308 current_bbt_points = 0;
311 snap_type_strings = I18N (_snap_type_strings);
312 snap_mode_strings = I18N (_snap_mode_strings);
313 zoom_focus_strings = I18N (_zoom_focus_strings);
314 edit_point_strings = I18N (_edit_point_strings);
315 #ifdef USE_RUBBERBAND
316 rb_opt_strings = I18N (_rb_opt_strings);
320 snap_threshold = 5.0;
321 bbt_beat_subdivision = 4;
324 last_autoscroll_x = 0;
325 last_autoscroll_y = 0;
326 autoscroll_active = false;
327 autoscroll_timeout_tag = -1;
332 current_interthread_info = 0;
333 _show_measures = true;
334 show_gain_after_trim = false;
336 have_pending_keyboard_selection = false;
337 _follow_playhead = true;
338 _stationary_playhead = false;
339 _xfade_visibility = true;
340 editor_ruler_menu = 0;
341 no_ruler_shown_update = false;
343 range_marker_menu = 0;
344 marker_menu_item = 0;
345 tempo_or_meter_marker_menu = 0;
346 transport_marker_menu = 0;
347 new_transport_marker_menu = 0;
348 editor_mixer_strip_width = Wide;
349 show_editor_mixer_when_tracks_arrive = false;
350 region_edit_menu_split_multichannel_item = 0;
351 region_edit_menu_split_item = 0;
354 current_stepping_trackview = 0;
356 entered_regionview = 0;
358 clear_entered_track = false;
361 button_release_can_deselect = true;
362 _dragging_playhead = false;
363 _dragging_edit_point = false;
364 select_new_marker = false;
366 layering_order_editor = 0;
367 no_save_visual = false;
370 scrubbing_direction = 0;
374 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
375 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
376 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
377 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
378 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
380 _edit_point = EditAtMouse;
381 _internal_editing = false;
382 current_canvas_cursor = 0;
384 frames_per_unit = 2048; /* too early to use reset_zoom () */
386 _scroll_callbacks = 0;
388 zoom_focus = ZoomFocusLeft;
389 set_zoom_focus (ZoomFocusLeft);
390 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
392 bbt_label.set_name ("EditorTimeButton");
393 bbt_label.set_size_request (-1, (int)timebar_height);
394 bbt_label.set_alignment (1.0, 0.5);
395 bbt_label.set_padding (5,0);
397 bbt_label.set_no_show_all();
398 minsec_label.set_name ("EditorTimeButton");
399 minsec_label.set_size_request (-1, (int)timebar_height);
400 minsec_label.set_alignment (1.0, 0.5);
401 minsec_label.set_padding (5,0);
402 minsec_label.hide ();
403 minsec_label.set_no_show_all();
404 timecode_label.set_name ("EditorTimeButton");
405 timecode_label.set_size_request (-1, (int)timebar_height);
406 timecode_label.set_alignment (1.0, 0.5);
407 timecode_label.set_padding (5,0);
408 timecode_label.hide ();
409 timecode_label.set_no_show_all();
410 samples_label.set_name ("EditorTimeButton");
411 samples_label.set_size_request (-1, (int)timebar_height);
412 samples_label.set_alignment (1.0, 0.5);
413 samples_label.set_padding (5,0);
414 samples_label.hide ();
415 samples_label.set_no_show_all();
417 tempo_label.set_name ("EditorTimeButton");
418 tempo_label.set_size_request (-1, (int)timebar_height);
419 tempo_label.set_alignment (1.0, 0.5);
420 tempo_label.set_padding (5,0);
422 tempo_label.set_no_show_all();
424 meter_label.set_name ("EditorTimeButton");
425 meter_label.set_size_request (-1, (int)timebar_height);
426 meter_label.set_alignment (1.0, 0.5);
427 meter_label.set_padding (5,0);
429 meter_label.set_no_show_all();
431 mark_label.set_name ("EditorTimeButton");
432 mark_label.set_size_request (-1, (int)timebar_height);
433 mark_label.set_alignment (1.0, 0.5);
434 mark_label.set_padding (5,0);
436 mark_label.set_no_show_all();
438 cd_mark_label.set_name ("EditorTimeButton");
439 cd_mark_label.set_size_request (-1, (int)timebar_height);
440 cd_mark_label.set_alignment (1.0, 0.5);
441 cd_mark_label.set_padding (5,0);
442 cd_mark_label.hide();
443 cd_mark_label.set_no_show_all();
445 range_mark_label.set_name ("EditorTimeButton");
446 range_mark_label.set_size_request (-1, (int)timebar_height);
447 range_mark_label.set_alignment (1.0, 0.5);
448 range_mark_label.set_padding (5,0);
449 range_mark_label.hide();
450 range_mark_label.set_no_show_all();
452 transport_mark_label.set_name ("EditorTimeButton");
453 transport_mark_label.set_size_request (-1, (int)timebar_height);
454 transport_mark_label.set_alignment (1.0, 0.5);
455 transport_mark_label.set_padding (5,0);
456 transport_mark_label.hide();
457 transport_mark_label.set_no_show_all();
459 initialize_rulers ();
460 initialize_canvas ();
462 _summary = new EditorSummary (this);
464 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
465 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
467 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
469 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
470 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
472 edit_controls_vbox.set_spacing (0);
473 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
474 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
476 HBox* h = manage (new HBox);
477 _group_tabs = new EditorGroupTabs (this);
478 h->pack_start (*_group_tabs, PACK_SHRINK);
479 h->pack_start (edit_controls_vbox);
480 controls_layout.add (*h);
482 controls_layout.set_name ("EditControlsBase");
483 controls_layout.add_events (Gdk::SCROLL_MASK);
484 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
486 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
487 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
489 _cursors = new MouseCursors;
491 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
492 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
493 0.0, 1.0, 100.0, 1.0));
495 pad_line_1->property_color_rgba() = 0xFF0000FF;
500 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
501 time_canvas_vbox.set_size_request (-1, -1);
503 ruler_label_event_box.add (ruler_label_vbox);
504 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
505 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
507 time_button_event_box.add (time_button_vbox);
508 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
509 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
511 /* these enable us to have a dedicated window (for cursor setting, etc.)
512 for the canvas areas.
515 track_canvas_event_box.add (*track_canvas);
517 time_canvas_event_box.add (time_canvas_vbox);
518 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
520 edit_packer.set_col_spacings (0);
521 edit_packer.set_row_spacings (0);
522 edit_packer.set_homogeneous (false);
523 edit_packer.set_border_width (0);
524 edit_packer.set_name ("EditorWindow");
526 /* labels for the rulers */
527 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
528 /* labels for the marker "tracks" */
529 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
531 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
533 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
535 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
537 bottom_hbox.set_border_width (2);
538 bottom_hbox.set_spacing (3);
540 _route_groups = new EditorRouteGroups (this);
541 _routes = new EditorRoutes (this);
542 _regions = new EditorRegions (this);
543 _snapshots = new EditorSnapshots (this);
544 _locations = new EditorLocations (this);
546 add_notebook_page (_("Regions"), _regions->widget ());
547 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
548 add_notebook_page (_("Snapshots"), _snapshots->widget ());
549 add_notebook_page (_("Route Groups"), _route_groups->widget ());
550 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
552 _the_notebook.set_show_tabs (true);
553 _the_notebook.set_scrollable (true);
554 _the_notebook.popup_disable ();
555 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
556 _the_notebook.show_all ();
558 post_maximal_editor_width = 0;
559 post_maximal_horizontal_pane_position = 0;
560 post_maximal_editor_height = 0;
561 post_maximal_vertical_pane_position = 0;
562 _notebook_shrunk = false;
564 editor_summary_pane.pack1(edit_packer);
566 Button* summary_arrows_left_left = manage (new Button);
567 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
568 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
569 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
571 Button* summary_arrows_left_right = manage (new Button);
572 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
573 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
574 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
576 VBox* summary_arrows_left = manage (new VBox);
577 summary_arrows_left->pack_start (*summary_arrows_left_left);
578 summary_arrows_left->pack_start (*summary_arrows_left_right);
580 Button* summary_arrows_right_up = manage (new Button);
581 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
582 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
583 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
585 Button* summary_arrows_right_down = manage (new Button);
586 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
587 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
588 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
590 VBox* summary_arrows_right = manage (new VBox);
591 summary_arrows_right->pack_start (*summary_arrows_right_up);
592 summary_arrows_right->pack_start (*summary_arrows_right_down);
594 Frame* summary_frame = manage (new Frame);
595 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
597 summary_frame->add (*_summary);
598 summary_frame->show ();
600 _summary_hbox.pack_start (*summary_arrows_left, false, false);
601 _summary_hbox.pack_start (*summary_frame, true, true);
602 _summary_hbox.pack_start (*summary_arrows_right, false, false);
604 editor_summary_pane.pack2 (_summary_hbox);
606 edit_pane.pack1 (editor_summary_pane, true, true);
607 edit_pane.pack2 (_the_notebook, false, true);
609 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
611 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
613 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
615 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
616 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
618 top_hbox.pack_start (toolbar_frame);
620 HBox *hbox = manage (new HBox);
621 hbox->pack_start (edit_pane, true, true);
623 global_vpacker.pack_start (top_hbox, false, false);
624 global_vpacker.pack_start (*hbox, true, true);
626 global_hpacker.pack_start (global_vpacker, true, true);
628 set_name ("EditorWindow");
629 add_accel_group (ActionManager::ui_manager->get_accel_group());
631 status_bar_hpacker.show ();
633 vpacker.pack_end (status_bar_hpacker, false, false);
634 vpacker.pack_end (global_hpacker, true, true);
636 /* register actions now so that set_state() can find them and set toggles/checks etc */
639 /* when we start using our own keybinding system for the editor, this
640 * will be uncommented
646 _snap_type = SnapToBeat;
647 set_snap_to (_snap_type);
648 _snap_mode = SnapOff;
649 set_snap_mode (_snap_mode);
650 set_mouse_mode (MouseObject, true);
651 pre_internal_mouse_mode = MouseObject;
652 set_edit_point_preference (EditAtMouse, true);
654 _playlist_selector = new PlaylistSelector();
655 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
657 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
661 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
662 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
664 nudge_forward_button.set_name ("TransportButton");
665 nudge_backward_button.set_name ("TransportButton");
667 fade_context_menu.set_name ("ArdourContextMenu");
669 /* icons, titles, WM stuff */
671 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
672 Glib::RefPtr<Gdk::Pixbuf> icon;
674 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
675 window_icons.push_back (icon);
677 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
678 window_icons.push_back (icon);
680 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
681 window_icons.push_back (icon);
683 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
684 window_icons.push_back (icon);
686 if (!window_icons.empty()) {
687 // set_icon_list (window_icons);
688 set_default_icon_list (window_icons);
691 WindowTitle title(Glib::get_application_name());
692 title += _("Editor");
693 set_title (title.get_string());
694 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
697 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
699 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
700 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
702 /* allow external control surfaces/protocols to do various things */
704 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
705 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
706 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
707 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
708 ControlProtocol::SelectByRID.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1), gui_context());
709 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
711 /* problematic: has to return a value and thus cannot be x-thread */
713 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
715 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
717 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
719 _ignore_region_action = false;
720 _last_region_menu_was_main = false;
721 _popup_region_menu_item = 0;
723 _show_marker_lines = false;
724 _over_region_trim_target = false;
726 /* Button bindings */
728 button_bindings = new Bindings;
730 XMLNode* node = button_settings();
732 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
733 button_bindings->load (**i);
740 setup_fade_images ();
746 if(image_socket_listener) {
747 if(image_socket_listener->is_connected())
749 image_socket_listener->close_connection() ;
752 delete image_socket_listener ;
753 image_socket_listener = 0 ;
757 delete button_bindings;
759 delete _route_groups;
765 Editor::button_settings () const
767 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
768 XMLNode* node = find_named_node (*settings, X_("Buttons"));
771 cerr << "new empty Button node\n";
772 node = new XMLNode (X_("Buttons"));
779 Editor::add_toplevel_controls (Container& cont)
781 vpacker.pack_start (cont, false, false);
786 Editor::catch_vanishing_regionview (RegionView *rv)
788 /* note: the selection will take care of the vanishing
789 audioregionview by itself.
792 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
796 if (clicked_regionview == rv) {
797 clicked_regionview = 0;
800 if (entered_regionview == rv) {
801 set_entered_regionview (0);
804 if (!_all_region_actions_sensitized) {
805 sensitize_all_region_actions (true);
808 _over_region_trim_target = false;
812 Editor::set_entered_regionview (RegionView* rv)
814 if (rv == entered_regionview) {
818 if (entered_regionview) {
819 entered_regionview->exited ();
822 if ((entered_regionview = rv) != 0) {
823 entered_regionview->entered (internal_editing ());
826 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
827 /* This RegionView entry might have changed what region actions
828 are allowed, so sensitize them all in case a key is pressed.
830 sensitize_all_region_actions (true);
835 Editor::set_entered_track (TimeAxisView* tav)
838 entered_track->exited ();
841 if ((entered_track = tav) != 0) {
842 entered_track->entered ();
847 Editor::show_window ()
849 if (!is_visible ()) {
852 /* XXX: this is a bit unfortunate; it would probably
853 be nicer if we could just call show () above rather
854 than needing the show_all ()
857 /* re-hide stuff if necessary */
858 editor_list_button_toggled ();
859 parameter_changed ("show-summary");
860 parameter_changed ("show-group-tabs");
861 parameter_changed ("show-zoom-tools");
863 /* now reset all audio_time_axis heights, because widgets might need
869 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
870 tv = (static_cast<TimeAxisView*>(*i));
874 if (current_mixer_strip) {
875 current_mixer_strip->hide_things ();
876 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
884 Editor::instant_save ()
886 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
891 _session->add_instant_xml(get_state());
893 Config->add_instant_xml(get_state());
898 Editor::zoom_adjustment_changed ()
904 double fpu = zoom_range_clock->current_duration() / _canvas_width;
908 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
909 } else if (fpu > _session->current_end_frame() / _canvas_width) {
910 fpu = _session->current_end_frame() / _canvas_width;
911 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
918 Editor::control_select (uint32_t rid)
920 /* handles the (static) signal from the ControlProtocol class that
921 * requests setting the selected track to a given RID
928 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
934 TimeAxisView* tav = axis_view_from_route (r);
937 selection->set (tav);
939 selection->clear_tracks ();
944 Editor::control_scroll (float fraction)
946 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
952 double step = fraction * current_page_frames();
955 _control_scroll_target is an optional<T>
957 it acts like a pointer to an framepos_t, with
958 a operator conversion to boolean to check
959 that it has a value could possibly use
960 playhead_cursor->current_frame to store the
961 value and a boolean in the class to know
962 when it's out of date
965 if (!_control_scroll_target) {
966 _control_scroll_target = _session->transport_frame();
967 _dragging_playhead = true;
970 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
971 *_control_scroll_target = 0;
972 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
973 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
975 *_control_scroll_target += (framepos_t) floor (step);
978 /* move visuals, we'll catch up with it later */
980 playhead_cursor->set_position (*_control_scroll_target);
981 UpdateAllTransportClocks (*_control_scroll_target);
983 if (*_control_scroll_target > (current_page_frames() / 2)) {
984 /* try to center PH in window */
985 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
991 Now we do a timeout to actually bring the session to the right place
992 according to the playhead. This is to avoid reading disk buffers on every
993 call to control_scroll, which is driven by ScrollTimeline and therefore
994 probably by a control surface wheel which can generate lots of events.
996 /* cancel the existing timeout */
998 control_scroll_connection.disconnect ();
1000 /* add the next timeout */
1002 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1006 Editor::deferred_control_scroll (framepos_t /*target*/)
1008 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1009 // reset for next stream
1010 _control_scroll_target = boost::none;
1011 _dragging_playhead = false;
1016 Editor::access_action (std::string action_group, std::string action_item)
1022 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1025 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1033 Editor::on_realize ()
1035 Window::on_realize ();
1040 Editor::map_position_change (framepos_t frame)
1042 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1044 if (_session == 0) {
1048 if (_follow_playhead) {
1049 center_screen (frame);
1052 playhead_cursor->set_position (frame);
1056 Editor::center_screen (framepos_t frame)
1058 double page = _canvas_width * frames_per_unit;
1060 /* if we're off the page, then scroll.
1063 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1064 center_screen_internal (frame, page);
1069 Editor::center_screen_internal (framepos_t frame, float page)
1074 frame -= (framepos_t) page;
1079 reset_x_origin (frame);
1084 Editor::update_title ()
1086 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1089 bool dirty = _session->dirty();
1091 string session_name;
1093 if (_session->snap_name() != _session->name()) {
1094 session_name = _session->snap_name();
1096 session_name = _session->name();
1100 session_name = "*" + session_name;
1103 WindowTitle title(session_name);
1104 title += Glib::get_application_name();
1105 set_title (title.get_string());
1110 Editor::set_session (Session *t)
1112 SessionHandlePtr::set_session (t);
1118 zoom_range_clock->set_session (_session);
1119 _playlist_selector->set_session (_session);
1120 nudge_clock->set_session (_session);
1121 _summary->set_session (_session);
1122 _group_tabs->set_session (_session);
1123 _route_groups->set_session (_session);
1124 _regions->set_session (_session);
1125 _snapshots->set_session (_session);
1126 _routes->set_session (_session);
1127 _locations->set_session (_session);
1129 if (rhythm_ferret) {
1130 rhythm_ferret->set_session (_session);
1133 if (analysis_window) {
1134 analysis_window->set_session (_session);
1138 sfbrowser->set_session (_session);
1141 compute_fixed_ruler_scale ();
1143 /* Make sure we have auto loop and auto punch ranges */
1145 Location* loc = _session->locations()->auto_loop_location();
1147 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1149 if (loc->start() == loc->end()) {
1150 loc->set_end (loc->start() + 1);
1153 _session->locations()->add (loc, false);
1154 _session->set_auto_loop_location (loc);
1157 loc->set_name (_("Loop"));
1160 loc = _session->locations()->auto_punch_location();
1163 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1165 if (loc->start() == loc->end()) {
1166 loc->set_end (loc->start() + 1);
1169 _session->locations()->add (loc, false);
1170 _session->set_auto_punch_location (loc);
1173 loc->set_name (_("Punch"));
1176 refresh_location_display ();
1178 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1179 the selected Marker; this needs the LocationMarker list to be available.
1181 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1182 set_state (*node, Stateful::loading_state_version);
1184 /* catch up with the playhead */
1186 _session->request_locate (playhead_cursor->current_frame);
1187 _pending_initial_locate = true;
1191 /* These signals can all be emitted by a non-GUI thread. Therefore the
1192 handlers for them must not attempt to directly interact with the GUI,
1193 but use Gtkmm2ext::UI::instance()->call_slot();
1196 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1197 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1198 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1199 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1200 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1201 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1202 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1203 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1204 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1205 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1206 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1207 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1208 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display, this), gui_context());
1209 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1211 if (Profile->get_sae()) {
1212 Timecode::BBT_Time bbt;
1216 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1217 nudge_clock->set_mode(AudioClock::BBT);
1218 nudge_clock->set (pos, true);
1221 nudge_clock->set_mode (AudioClock::Timecode);
1222 nudge_clock->set (_session->frame_rate() * 5, true);
1225 playhead_cursor->canvas_item.show ();
1227 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1228 Config->map_parameters (pc);
1229 _session->config.map_parameters (pc);
1231 restore_ruler_visibility ();
1232 //tempo_map_changed (PropertyChange (0));
1233 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1235 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1236 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1239 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1240 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1243 switch (_snap_type) {
1244 case SnapToRegionStart:
1245 case SnapToRegionEnd:
1246 case SnapToRegionSync:
1247 case SnapToRegionBoundary:
1248 build_region_boundary_cache ();
1255 /* register for undo history */
1256 _session->register_with_memento_command_factory(id(), this);
1258 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1260 start_updating_meters ();
1264 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1266 if (a->get_name() == "RegionMenu") {
1267 /* When the main menu's region menu is opened, we setup the actions so that they look right
1268 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1269 so we resensitize all region actions when the entered regionview or the region selection
1270 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1271 happens after the region context menu is opened. So we set a flag here, too.
1275 sensitize_the_right_region_actions ();
1276 _last_region_menu_was_main = true;
1280 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1282 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1284 using namespace Menu_Helpers;
1285 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1288 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1292 MenuList& items (fade_context_menu.items());
1296 switch (item_type) {
1298 case FadeInHandleItem:
1299 if (arv->audio_region()->fade_in_active()) {
1300 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1302 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1305 items.push_back (SeparatorElem());
1307 if (Profile->get_sae()) {
1309 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1310 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1317 *_fade_in_images[FadeLinear],
1318 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1322 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1327 *_fade_in_images[FadeFast],
1328 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1331 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1336 *_fade_in_images[FadeLogB],
1337 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1340 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1345 *_fade_in_images[FadeLogA],
1346 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1349 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1354 *_fade_in_images[FadeSlow],
1355 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1358 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1364 case FadeOutHandleItem:
1365 if (arv->audio_region()->fade_out_active()) {
1366 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1368 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1371 items.push_back (SeparatorElem());
1373 if (Profile->get_sae()) {
1374 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1375 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1381 *_fade_out_images[FadeLinear],
1382 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1386 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1391 *_fade_out_images[FadeFast],
1392 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1395 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1400 *_fade_out_images[FadeLogB],
1401 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1409 *_fade_out_images[FadeLogA],
1410 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1413 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1418 *_fade_out_images[FadeSlow],
1419 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1422 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1428 fatal << _("programming error: ")
1429 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1434 fade_context_menu.popup (button, time);
1438 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1440 using namespace Menu_Helpers;
1441 Menu* (Editor::*build_menu_function)();
1444 switch (item_type) {
1446 case RegionViewName:
1447 case RegionViewNameHighlight:
1448 case LeftFrameHandle:
1449 case RightFrameHandle:
1450 if (with_selection) {
1451 build_menu_function = &Editor::build_track_selection_context_menu;
1453 build_menu_function = &Editor::build_track_region_context_menu;
1458 if (with_selection) {
1459 build_menu_function = &Editor::build_track_selection_context_menu;
1461 build_menu_function = &Editor::build_track_context_menu;
1465 case CrossfadeViewItem:
1466 build_menu_function = &Editor::build_track_crossfade_context_menu;
1470 if (clicked_routeview->track()) {
1471 build_menu_function = &Editor::build_track_context_menu;
1473 build_menu_function = &Editor::build_track_bus_context_menu;
1478 /* probably shouldn't happen but if it does, we don't care */
1482 menu = (this->*build_menu_function)();
1483 menu->set_name ("ArdourContextMenu");
1485 /* now handle specific situations */
1487 switch (item_type) {
1489 case RegionViewName:
1490 case RegionViewNameHighlight:
1491 case LeftFrameHandle:
1492 case RightFrameHandle:
1493 if (!with_selection) {
1494 if (region_edit_menu_split_item) {
1495 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1496 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1498 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1501 if (region_edit_menu_split_multichannel_item) {
1502 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1503 region_edit_menu_split_multichannel_item->set_sensitive (true);
1505 region_edit_menu_split_multichannel_item->set_sensitive (false);
1514 case CrossfadeViewItem:
1521 /* probably shouldn't happen but if it does, we don't care */
1525 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1527 /* Bounce to disk */
1529 using namespace Menu_Helpers;
1530 MenuList& edit_items = menu->items();
1532 edit_items.push_back (SeparatorElem());
1534 switch (clicked_routeview->audio_track()->freeze_state()) {
1535 case AudioTrack::NoFreeze:
1536 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1539 case AudioTrack::Frozen:
1540 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1543 case AudioTrack::UnFrozen:
1544 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1550 if (item_type == StreamItem && clicked_routeview) {
1551 clicked_routeview->build_underlay_menu(menu);
1554 /* When the region menu is opened, we setup the actions so that they look right
1557 sensitize_the_right_region_actions ();
1558 _last_region_menu_was_main = false;
1560 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1561 menu->popup (button, time);
1565 Editor::build_track_context_menu ()
1567 using namespace Menu_Helpers;
1569 MenuList& edit_items = track_context_menu.items();
1572 add_dstream_context_items (edit_items);
1573 return &track_context_menu;
1577 Editor::build_track_bus_context_menu ()
1579 using namespace Menu_Helpers;
1581 MenuList& edit_items = track_context_menu.items();
1584 add_bus_context_items (edit_items);
1585 return &track_context_menu;
1589 Editor::build_track_region_context_menu ()
1591 using namespace Menu_Helpers;
1592 MenuList& edit_items = track_region_context_menu.items();
1595 /* we've just cleared the track region context menu, so the menu that these
1596 two items were on will have disappeared; stop them dangling.
1598 region_edit_menu_split_item = 0;
1599 region_edit_menu_split_multichannel_item = 0;
1601 /* we might try to use items that are currently attached to a crossfade menu,
1604 track_crossfade_context_menu.items().clear ();
1606 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1609 boost::shared_ptr<Track> tr;
1610 boost::shared_ptr<Playlist> pl;
1612 if ((tr = rtv->track())) {
1613 add_region_context_items (edit_items, tr);
1617 add_dstream_context_items (edit_items);
1619 return &track_region_context_menu;
1623 Editor::build_track_crossfade_context_menu ()
1625 using namespace Menu_Helpers;
1626 MenuList& edit_items = track_crossfade_context_menu.items();
1627 edit_items.clear ();
1629 /* we might try to use items that are currently attached to a crossfade menu,
1632 track_region_context_menu.items().clear ();
1634 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1637 boost::shared_ptr<Track> tr;
1638 boost::shared_ptr<Playlist> pl;
1639 boost::shared_ptr<AudioPlaylist> apl;
1641 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1643 AudioPlaylist::Crossfades xfades;
1647 /* The xfade menu is a bit of a special case, as we always use the mouse position
1648 to decide whether or not to display it (rather than the edit point). No particularly
1649 strong reasons for this, other than it is a bit surprising to right-click on a xfade
1652 mouse_frame (where, ignored);
1653 apl->crossfades_at (where, xfades);
1655 bool const many = xfades.size() > 1;
1657 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1658 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1661 add_region_context_items (edit_items, tr);
1665 add_dstream_context_items (edit_items);
1667 return &track_crossfade_context_menu;
1671 Editor::analyze_region_selection ()
1673 if (analysis_window == 0) {
1674 analysis_window = new AnalysisWindow();
1677 analysis_window->set_session(_session);
1679 analysis_window->show_all();
1682 analysis_window->set_regionmode();
1683 analysis_window->analyze();
1685 analysis_window->present();
1689 Editor::analyze_range_selection()
1691 if (analysis_window == 0) {
1692 analysis_window = new AnalysisWindow();
1695 analysis_window->set_session(_session);
1697 analysis_window->show_all();
1700 analysis_window->set_rangemode();
1701 analysis_window->analyze();
1703 analysis_window->present();
1707 Editor::build_track_selection_context_menu ()
1709 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_selection_context_menu.items();
1711 edit_items.clear ();
1713 add_selection_context_items (edit_items);
1714 // edit_items.push_back (SeparatorElem());
1715 // add_dstream_context_items (edit_items);
1717 return &track_selection_context_menu;
1720 /** Add context menu items relevant to crossfades.
1721 * @param edit_items List to add the items to.
1724 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1726 using namespace Menu_Helpers;
1727 Menu *xfade_menu = manage (new Menu);
1728 MenuList& items = xfade_menu->items();
1729 xfade_menu->set_name ("ArdourContextMenu");
1732 if (xfade->active()) {
1738 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1739 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1741 if (xfade->can_follow_overlap()) {
1743 if (xfade->following_overlap()) {
1744 str = _("Convert to Short");
1746 str = _("Convert to Full");
1749 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1753 str = xfade->out()->name();
1755 str += xfade->in()->name();
1757 str = _("Crossfade");
1760 edit_items.push_back (MenuElem (str, *xfade_menu));
1761 edit_items.push_back (SeparatorElem());
1765 Editor::xfade_edit_left_region ()
1767 if (clicked_crossfadeview) {
1768 clicked_crossfadeview->left_view.show_region_editor ();
1773 Editor::xfade_edit_right_region ()
1775 if (clicked_crossfadeview) {
1776 clicked_crossfadeview->right_view.show_region_editor ();
1781 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1783 using namespace Menu_Helpers;
1785 /* OK, stick the region submenu at the top of the list, and then add
1789 RegionSelection rs = get_regions_from_selection_and_entered ();
1791 string::size_type pos = 0;
1792 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1794 /* we have to hack up the region name because "_" has a special
1795 meaning for menu titles.
1798 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1799 menu_item_name.replace (pos, 1, "__");
1803 if (_popup_region_menu_item == 0) {
1804 _popup_region_menu_item = new MenuItem (menu_item_name);
1805 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1806 _popup_region_menu_item->show ();
1808 _popup_region_menu_item->set_label (menu_item_name);
1811 /* Use the mouse position rather than the edit point to decide whether to show the `choose top region'
1812 dialogue. If we use the edit point it gets a bit messy because the user still has to click over
1813 *some* region in order to get the region context menu stuff to be displayed at all.
1818 mouse_frame (mouse, ignored);
1820 edit_items.push_back (*_popup_region_menu_item);
1821 if (track->playlist()->count_regions_at (mouse) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1822 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1824 edit_items.push_back (SeparatorElem());
1827 /** Add context menu items relevant to selection ranges.
1828 * @param edit_items List to add the items to.
1831 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1833 using namespace Menu_Helpers;
1835 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1836 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1838 edit_items.push_back (SeparatorElem());
1839 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1841 edit_items.push_back (SeparatorElem());
1843 edit_items.push_back (
1845 _("Move Range Start to Previous Region Boundary"),
1846 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1850 edit_items.push_back (
1852 _("Move Range Start to Next Region Boundary"),
1853 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1857 edit_items.push_back (
1859 _("Move Range End to Previous Region Boundary"),
1860 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1864 edit_items.push_back (
1866 _("Move Range End to Next Region Boundary"),
1867 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1871 edit_items.push_back (SeparatorElem());
1872 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1873 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1878 edit_items.push_back (SeparatorElem());
1879 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1880 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1882 edit_items.push_back (SeparatorElem());
1883 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1885 edit_items.push_back (SeparatorElem());
1886 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1887 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1888 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1890 edit_items.push_back (SeparatorElem());
1891 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1892 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1893 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1894 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1895 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1900 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1902 using namespace Menu_Helpers;
1906 Menu *play_menu = manage (new Menu);
1907 MenuList& play_items = play_menu->items();
1908 play_menu->set_name ("ArdourContextMenu");
1910 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1911 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1912 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1913 play_items.push_back (SeparatorElem());
1914 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1916 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1920 Menu *select_menu = manage (new Menu);
1921 MenuList& select_items = select_menu->items();
1922 select_menu->set_name ("ArdourContextMenu");
1924 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1925 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1926 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1927 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1928 select_items.push_back (SeparatorElem());
1929 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1930 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1931 select_items.push_back (SeparatorElem());
1932 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1933 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1934 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1935 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1936 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1937 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1938 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1940 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1944 Menu *cutnpaste_menu = manage (new Menu);
1945 MenuList& cutnpaste_items = cutnpaste_menu->items();
1946 cutnpaste_menu->set_name ("ArdourContextMenu");
1948 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1949 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1950 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1952 cutnpaste_items.push_back (SeparatorElem());
1954 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1955 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1957 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1959 /* Adding new material */
1961 edit_items.push_back (SeparatorElem());
1962 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1963 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1967 Menu *nudge_menu = manage (new Menu());
1968 MenuList& nudge_items = nudge_menu->items();
1969 nudge_menu->set_name ("ArdourContextMenu");
1971 edit_items.push_back (SeparatorElem());
1972 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1973 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1974 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1975 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1977 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1981 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1983 using namespace Menu_Helpers;
1987 Menu *play_menu = manage (new Menu);
1988 MenuList& play_items = play_menu->items();
1989 play_menu->set_name ("ArdourContextMenu");
1991 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1992 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1993 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1997 Menu *select_menu = manage (new Menu);
1998 MenuList& select_items = select_menu->items();
1999 select_menu->set_name ("ArdourContextMenu");
2001 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2002 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2003 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2004 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2005 select_items.push_back (SeparatorElem());
2006 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2007 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2008 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2009 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2011 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2015 Menu *cutnpaste_menu = manage (new Menu);
2016 MenuList& cutnpaste_items = cutnpaste_menu->items();
2017 cutnpaste_menu->set_name ("ArdourContextMenu");
2019 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2020 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2021 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
2023 Menu *nudge_menu = manage (new Menu());
2024 MenuList& nudge_items = nudge_menu->items();
2025 nudge_menu->set_name ("ArdourContextMenu");
2027 edit_items.push_back (SeparatorElem());
2028 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2029 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2030 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2031 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2033 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2037 Editor::snap_type() const
2043 Editor::snap_mode() const
2049 Editor::set_snap_to (SnapType st)
2051 unsigned int snap_ind = (unsigned int)st;
2055 if (snap_ind > snap_type_strings.size() - 1) {
2057 _snap_type = (SnapType)snap_ind;
2060 string str = snap_type_strings[snap_ind];
2062 if (str != snap_type_selector.get_active_text()) {
2063 snap_type_selector.set_active_text (str);
2068 switch (_snap_type) {
2069 case SnapToBeatDiv32:
2070 case SnapToBeatDiv28:
2071 case SnapToBeatDiv24:
2072 case SnapToBeatDiv20:
2073 case SnapToBeatDiv16:
2074 case SnapToBeatDiv14:
2075 case SnapToBeatDiv12:
2076 case SnapToBeatDiv10:
2077 case SnapToBeatDiv8:
2078 case SnapToBeatDiv7:
2079 case SnapToBeatDiv6:
2080 case SnapToBeatDiv5:
2081 case SnapToBeatDiv4:
2082 case SnapToBeatDiv3:
2083 case SnapToBeatDiv2:
2084 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2085 update_tempo_based_rulers ();
2088 case SnapToRegionStart:
2089 case SnapToRegionEnd:
2090 case SnapToRegionSync:
2091 case SnapToRegionBoundary:
2092 build_region_boundary_cache ();
2100 SnapChanged (); /* EMIT SIGNAL */
2104 Editor::set_snap_mode (SnapMode mode)
2107 string str = snap_mode_strings[(int)mode];
2109 if (str != snap_mode_selector.get_active_text ()) {
2110 snap_mode_selector.set_active_text (str);
2116 Editor::set_edit_point_preference (EditPoint ep, bool force)
2118 bool changed = (_edit_point != ep);
2121 string str = edit_point_strings[(int)ep];
2123 if (str != edit_point_selector.get_active_text ()) {
2124 edit_point_selector.set_active_text (str);
2127 set_canvas_cursor ();
2129 if (!force && !changed) {
2133 const char* action=NULL;
2135 switch (_edit_point) {
2136 case EditAtPlayhead:
2137 action = "edit-at-playhead";
2139 case EditAtSelectedMarker:
2140 action = "edit-at-marker";
2143 action = "edit-at-mouse";
2147 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2149 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2153 bool in_track_canvas;
2155 if (!mouse_frame (foo, in_track_canvas)) {
2156 in_track_canvas = false;
2159 reset_canvas_action_sensitivity (in_track_canvas);
2165 Editor::set_state (const XMLNode& node, int /*version*/)
2167 const XMLProperty* prop;
2174 g.base_width = default_width;
2175 g.base_height = default_height;
2179 if ((geometry = find_named_node (node, "geometry")) != 0) {
2183 if ((prop = geometry->property("x_size")) == 0) {
2184 prop = geometry->property ("x-size");
2187 g.base_width = atoi(prop->value());
2189 if ((prop = geometry->property("y_size")) == 0) {
2190 prop = geometry->property ("y-size");
2193 g.base_height = atoi(prop->value());
2196 if ((prop = geometry->property ("x_pos")) == 0) {
2197 prop = geometry->property ("x-pos");
2200 x = atoi (prop->value());
2203 if ((prop = geometry->property ("y_pos")) == 0) {
2204 prop = geometry->property ("y-pos");
2207 y = atoi (prop->value());
2211 set_default_size (g.base_width, g.base_height);
2214 if (_session && (prop = node.property ("playhead"))) {
2216 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2217 playhead_cursor->set_position (pos);
2219 playhead_cursor->set_position (0);
2222 if ((prop = node.property ("mixer-width"))) {
2223 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2226 if ((prop = node.property ("zoom-focus"))) {
2227 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2230 if ((prop = node.property ("zoom"))) {
2231 reset_zoom (PBD::atof (prop->value()));
2233 reset_zoom (frames_per_unit);
2236 if ((prop = node.property ("snap-to"))) {
2237 set_snap_to ((SnapType) atoi (prop->value()));
2240 if ((prop = node.property ("snap-mode"))) {
2241 set_snap_mode ((SnapMode) atoi (prop->value()));
2244 if ((prop = node.property ("mouse-mode"))) {
2245 MouseMode m = str2mousemode(prop->value());
2246 set_mouse_mode (m, true);
2248 set_mouse_mode (MouseObject, true);
2251 if ((prop = node.property ("left-frame")) != 0) {
2253 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2254 reset_x_origin (pos);
2258 if ((prop = node.property ("y-origin")) != 0) {
2259 reset_y_origin (atof (prop->value ()));
2262 if ((prop = node.property ("internal-edit"))) {
2263 bool yn = string_is_affirmative (prop->value());
2264 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2266 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2267 tact->set_active (!yn);
2268 tact->set_active (yn);
2272 if ((prop = node.property ("join-object-range"))) {
2273 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2276 if ((prop = node.property ("edit-point"))) {
2277 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2280 if ((prop = node.property ("show-measures"))) {
2281 bool yn = string_is_affirmative (prop->value());
2282 _show_measures = yn;
2283 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2285 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2286 /* do it twice to force the change */
2287 tact->set_active (!yn);
2288 tact->set_active (yn);
2292 if ((prop = node.property ("follow-playhead"))) {
2293 bool yn = string_is_affirmative (prop->value());
2294 set_follow_playhead (yn);
2295 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2297 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2298 if (tact->get_active() != yn) {
2299 tact->set_active (yn);
2304 if ((prop = node.property ("stationary-playhead"))) {
2305 bool yn = string_is_affirmative (prop->value());
2306 set_stationary_playhead (yn);
2307 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2309 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2310 if (tact->get_active() != yn) {
2311 tact->set_active (yn);
2316 if ((prop = node.property ("region-list-sort-type"))) {
2317 RegionListSortType st;
2318 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2321 if ((prop = node.property ("xfades-visible"))) {
2322 bool yn = string_is_affirmative (prop->value());
2323 _xfade_visibility = !yn;
2324 // set_xfade_visibility (yn);
2327 if ((prop = node.property ("show-editor-mixer"))) {
2329 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2332 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2333 bool yn = string_is_affirmative (prop->value());
2335 /* do it twice to force the change */
2337 tact->set_active (!yn);
2338 tact->set_active (yn);
2341 if ((prop = node.property ("show-editor-list"))) {
2343 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2346 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2347 bool yn = string_is_affirmative (prop->value());
2349 /* do it twice to force the change */
2351 tact->set_active (!yn);
2352 tact->set_active (yn);
2355 if ((prop = node.property (X_("editor-list-page")))) {
2356 _the_notebook.set_current_page (atoi (prop->value ()));
2359 if ((prop = node.property (X_("show-marker-lines")))) {
2360 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2362 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2363 bool yn = string_is_affirmative (prop->value ());
2365 tact->set_active (!yn);
2366 tact->set_active (yn);
2369 XMLNodeList children = node.children ();
2370 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2371 selection->set_state (**i, Stateful::current_state_version);
2372 _regions->set_state (**i);
2379 Editor::get_state ()
2381 XMLNode* node = new XMLNode ("Editor");
2384 id().print (buf, sizeof (buf));
2385 node->add_property ("id", buf);
2387 if (is_realized()) {
2388 Glib::RefPtr<Gdk::Window> win = get_window();
2390 int x, y, width, height;
2391 win->get_root_origin(x, y);
2392 win->get_size(width, height);
2394 XMLNode* geometry = new XMLNode ("geometry");
2396 snprintf(buf, sizeof(buf), "%d", width);
2397 geometry->add_property("x-size", string(buf));
2398 snprintf(buf, sizeof(buf), "%d", height);
2399 geometry->add_property("y-size", string(buf));
2400 snprintf(buf, sizeof(buf), "%d", x);
2401 geometry->add_property("x-pos", string(buf));
2402 snprintf(buf, sizeof(buf), "%d", y);
2403 geometry->add_property("y-pos", string(buf));
2404 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2405 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2406 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2407 snprintf(buf,sizeof(buf), "%d",pre_maximal_horizontal_pane_position);
2408 geometry->add_property("pre-maximal-horizontal-pane-position", string(buf));
2409 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2410 geometry->add_property("edit-vertical-pane-pos", string(buf));
2412 node->add_child_nocopy (*geometry);
2415 maybe_add_mixer_strip_width (*node);
2417 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2418 node->add_property ("zoom-focus", buf);
2419 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2420 node->add_property ("zoom", buf);
2421 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2422 node->add_property ("snap-to", buf);
2423 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2424 node->add_property ("snap-mode", buf);
2426 node->add_property ("edit-point", enum_2_string (_edit_point));
2428 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2429 node->add_property ("playhead", buf);
2430 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2431 node->add_property ("left-frame", buf);
2432 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2433 node->add_property ("y-origin", buf);
2435 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2436 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2437 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2438 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2439 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2440 node->add_property ("mouse-mode", enum2str(mouse_mode));
2441 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2442 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2444 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2446 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2447 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2450 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2452 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2453 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2456 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2457 node->add_property (X_("editor-list-page"), buf);
2459 if (button_bindings) {
2460 XMLNode* bb = new XMLNode (X_("Buttons"));
2461 button_bindings->save (*bb);
2462 node->add_child_nocopy (*bb);
2465 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2467 node->add_child_nocopy (selection->get_state ());
2468 node->add_child_nocopy (_regions->get_state ());
2475 /** @param y y offset from the top of all trackviews.
2476 * @return pair: TimeAxisView that y is over, layer index.
2477 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2478 * in stacked region display mode, otherwise 0.
2480 std::pair<TimeAxisView *, layer_t>
2481 Editor::trackview_by_y_position (double y)
2483 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2485 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2491 return std::make_pair ( (TimeAxisView *) 0, 0);
2494 /** Snap a position to the grid, if appropriate, taking into account current
2495 * grid settings and also the state of any snap modifier keys that may be pressed.
2496 * @param start Position to snap.
2497 * @param event Event to get current key modifier information from, or 0.
2500 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2502 if (!_session || !event) {
2506 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2507 if (_snap_mode == SnapOff) {
2508 snap_to_internal (start, direction, for_mark);
2511 if (_snap_mode != SnapOff) {
2512 snap_to_internal (start, direction, for_mark);
2518 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2520 if (!_session || _snap_mode == SnapOff) {
2524 snap_to_internal (start, direction, for_mark);
2528 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2530 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2531 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2533 switch (_snap_type) {
2534 case SnapToTimecodeFrame:
2535 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2536 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2538 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2542 case SnapToTimecodeSeconds:
2543 if (_session->config.get_timecode_offset_negative()) {
2544 start += _session->config.get_timecode_offset ();
2546 start -= _session->config.get_timecode_offset ();
2548 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2549 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2551 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2554 if (_session->config.get_timecode_offset_negative()) {
2555 start -= _session->config.get_timecode_offset ();
2557 start += _session->config.get_timecode_offset ();
2561 case SnapToTimecodeMinutes:
2562 if (_session->config.get_timecode_offset_negative()) {
2563 start += _session->config.get_timecode_offset ();
2565 start -= _session->config.get_timecode_offset ();
2567 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2568 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2570 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2572 if (_session->config.get_timecode_offset_negative()) {
2573 start -= _session->config.get_timecode_offset ();
2575 start += _session->config.get_timecode_offset ();
2579 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2585 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2587 const framepos_t one_second = _session->frame_rate();
2588 const framepos_t one_minute = _session->frame_rate() * 60;
2589 framepos_t presnap = start;
2593 switch (_snap_type) {
2594 case SnapToTimecodeFrame:
2595 case SnapToTimecodeSeconds:
2596 case SnapToTimecodeMinutes:
2597 return timecode_snap_to_internal (start, direction, for_mark);
2600 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2601 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2603 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2608 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2609 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2611 start = (framepos_t) floor ((double) start / one_second) * one_second;
2616 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2617 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2619 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2624 start = _session->tempo_map().round_to_bar (start, direction);
2628 start = _session->tempo_map().round_to_beat (start, direction);
2631 case SnapToBeatDiv32:
2632 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2634 case SnapToBeatDiv28:
2635 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2637 case SnapToBeatDiv24:
2638 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2640 case SnapToBeatDiv20:
2641 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2643 case SnapToBeatDiv16:
2644 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2646 case SnapToBeatDiv14:
2647 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2649 case SnapToBeatDiv12:
2650 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2652 case SnapToBeatDiv10:
2653 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2655 case SnapToBeatDiv8:
2656 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2658 case SnapToBeatDiv7:
2659 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2661 case SnapToBeatDiv6:
2662 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2664 case SnapToBeatDiv5:
2665 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2667 case SnapToBeatDiv4:
2668 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2670 case SnapToBeatDiv3:
2671 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2673 case SnapToBeatDiv2:
2674 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2682 _session->locations()->marks_either_side (start, before, after);
2684 if (before == max_framepos) {
2686 } else if (after == max_framepos) {
2688 } else if (before != max_framepos && after != max_framepos) {
2689 /* have before and after */
2690 if ((start - before) < (after - start)) {
2699 case SnapToRegionStart:
2700 case SnapToRegionEnd:
2701 case SnapToRegionSync:
2702 case SnapToRegionBoundary:
2703 if (!region_boundary_cache.empty()) {
2705 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2706 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2708 if (direction > 0) {
2709 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2711 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2714 if (next != region_boundary_cache.begin ()) {
2719 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2720 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2722 if (start > (p + n) / 2) {
2731 switch (_snap_mode) {
2737 if (presnap > start) {
2738 if (presnap > (start + unit_to_frame(snap_threshold))) {
2742 } else if (presnap < start) {
2743 if (presnap < (start - unit_to_frame(snap_threshold))) {
2749 /* handled at entry */
2757 Editor::setup_toolbar ()
2759 HBox* mode_box = manage(new HBox);
2760 mode_box->set_border_width (2);
2761 mode_box->set_spacing(4);
2763 /* table containing mode buttons */
2765 HBox* mouse_mode_button_box = manage (new HBox ());
2766 mouse_mode_button_box->set_spacing (2);
2768 if (Profile->get_sae()) {
2769 mouse_mode_button_box->pack_start (mouse_move_button);
2771 mouse_mode_button_box->pack_start (mouse_move_button);
2772 mouse_mode_button_box->pack_start (join_object_range_button);
2773 mouse_mode_button_box->pack_start (mouse_select_button);
2776 mouse_mode_button_box->pack_start (mouse_zoom_button);
2778 if (!Profile->get_sae()) {
2779 mouse_mode_button_box->pack_start (mouse_gain_button);
2782 mouse_mode_button_box->pack_start (mouse_timefx_button);
2783 mouse_mode_button_box->pack_start (mouse_audition_button);
2784 mouse_mode_button_box->pack_start (internal_edit_button);
2786 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2787 if (!Profile->get_sae()) {
2788 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2790 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2792 edit_mode_selector.set_name ("EditModeSelector");
2793 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2794 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2796 mode_box->pack_start (edit_mode_selector, false, false);
2797 mode_box->pack_start (*mouse_mode_button_box, false, false);
2799 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2800 _mouse_mode_tearoff->set_name ("MouseModeBase");
2801 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2803 if (Profile->get_sae()) {
2804 _mouse_mode_tearoff->set_can_be_torn_off (false);
2807 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2808 &_mouse_mode_tearoff->tearoff_window()));
2809 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2810 &_mouse_mode_tearoff->tearoff_window(), 1));
2811 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2812 &_mouse_mode_tearoff->tearoff_window()));
2813 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2814 &_mouse_mode_tearoff->tearoff_window(), 1));
2818 _zoom_box.set_spacing (2);
2819 _zoom_box.set_border_width (2);
2823 zoom_in_button.set_name ("zoom button");
2824 zoom_in_button.set_image (::get_icon ("zoom_in"));
2825 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2826 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2827 zoom_in_button.set_related_action (act);
2829 zoom_out_button.set_name ("zoom button");
2830 zoom_out_button.set_image (::get_icon ("zoom_out"));
2831 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2832 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2833 zoom_out_button.set_related_action (act);
2835 zoom_out_full_button.set_name ("zoom button");
2836 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2837 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2838 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2839 zoom_out_full_button.set_related_action (act);
2841 zoom_focus_selector.set_name ("ZoomFocusSelector");
2842 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2843 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2845 _zoom_box.pack_start (zoom_out_button, false, false);
2846 _zoom_box.pack_start (zoom_in_button, false, false);
2847 _zoom_box.pack_start (zoom_out_full_button, false, false);
2849 _zoom_box.pack_start (zoom_focus_selector, false, false);
2851 /* Track zoom buttons */
2852 tav_expand_button.set_name ("TrackHeightButton");
2853 tav_expand_button.set_size_request (-1, 20);
2854 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2855 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2856 act->connect_proxy (tav_expand_button);
2858 tav_shrink_button.set_name ("TrackHeightButton");
2859 tav_shrink_button.set_size_request (-1, 20);
2860 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2861 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2862 act->connect_proxy (tav_shrink_button);
2864 _zoom_box.pack_start (tav_shrink_button);
2865 _zoom_box.pack_start (tav_expand_button);
2867 _zoom_tearoff = manage (new TearOff (_zoom_box));
2869 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2870 &_zoom_tearoff->tearoff_window()));
2871 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2872 &_zoom_tearoff->tearoff_window(), 0));
2873 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2874 &_zoom_tearoff->tearoff_window()));
2875 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2876 &_zoom_tearoff->tearoff_window(), 0));
2878 snap_box.set_spacing (1);
2879 snap_box.set_border_width (2);
2881 snap_type_selector.set_name ("SnapTypeSelector");
2882 set_popdown_strings (snap_type_selector, snap_type_strings);
2883 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2885 snap_mode_selector.set_name ("SnapModeSelector");
2886 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2887 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2889 edit_point_selector.set_name ("EditPointSelector");
2890 set_popdown_strings (edit_point_selector, edit_point_strings);
2891 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2893 snap_box.pack_start (snap_mode_selector, false, false);
2894 snap_box.pack_start (snap_type_selector, false, false);
2895 snap_box.pack_start (edit_point_selector, false, false);
2899 HBox *nudge_box = manage (new HBox);
2900 nudge_box->set_spacing (2);
2901 nudge_box->set_border_width (2);
2903 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2904 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2906 nudge_box->pack_start (nudge_backward_button, false, false);
2907 nudge_box->pack_start (nudge_forward_button, false, false);
2908 nudge_box->pack_start (*nudge_clock, false, false);
2911 /* Pack everything in... */
2913 HBox* hbox = manage (new HBox);
2914 hbox->set_spacing(10);
2916 _tools_tearoff = manage (new TearOff (*hbox));
2917 _tools_tearoff->set_name ("MouseModeBase");
2918 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2920 if (Profile->get_sae()) {
2921 _tools_tearoff->set_can_be_torn_off (false);
2924 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2925 &_tools_tearoff->tearoff_window()));
2926 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2927 &_tools_tearoff->tearoff_window(), 0));
2928 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929 &_tools_tearoff->tearoff_window()));
2930 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931 &_tools_tearoff->tearoff_window(), 0));
2933 toolbar_hbox.set_spacing (10);
2934 toolbar_hbox.set_border_width (1);
2936 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2937 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2938 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2940 hbox->pack_start (snap_box, false, false);
2941 if (!Profile->get_small_screen()) {
2942 hbox->pack_start (*nudge_box, false, false);
2944 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2946 hbox->pack_start (panic_box, false, false);
2950 toolbar_base.set_name ("ToolBarBase");
2951 toolbar_base.add (toolbar_hbox);
2953 _toolbar_viewport.add (toolbar_base);
2954 /* stick to the required height but allow width to vary if there's not enough room */
2955 _toolbar_viewport.set_size_request (1, -1);
2957 toolbar_frame.set_shadow_type (SHADOW_OUT);
2958 toolbar_frame.set_name ("BaseFrame");
2959 toolbar_frame.add (_toolbar_viewport);
2963 Editor::setup_tooltips ()
2965 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2966 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2967 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2968 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2969 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2970 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2971 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2972 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2973 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2974 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2975 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2976 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2977 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2978 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2979 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2980 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2981 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2982 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2983 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2984 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2988 Editor::convert_drop_to_paths (
2989 vector<string>& paths,
2990 const RefPtr<Gdk::DragContext>& /*context*/,
2993 const SelectionData& data,
2997 if (_session == 0) {
3001 vector<string> uris = data.get_uris();
3005 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3006 are actually URI lists. So do it by hand.
3009 if (data.get_target() != "text/plain") {
3013 /* Parse the "uri-list" format that Nautilus provides,
3014 where each pathname is delimited by \r\n.
3016 THERE MAY BE NO NULL TERMINATING CHAR!!!
3019 string txt = data.get_text();
3023 p = (const char *) malloc (txt.length() + 1);
3024 txt.copy ((char *) p, txt.length(), 0);
3025 ((char*)p)[txt.length()] = '\0';
3031 while (g_ascii_isspace (*p))
3035 while (*q && (*q != '\n') && (*q != '\r')) {
3042 while (q > p && g_ascii_isspace (*q))
3047 uris.push_back (string (p, q - p + 1));
3051 p = strchr (p, '\n');
3063 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3065 if ((*i).substr (0,7) == "file://") {
3068 PBD::url_decode (p);
3070 // scan forward past three slashes
3072 string::size_type slashcnt = 0;
3073 string::size_type n = 0;
3074 string::iterator x = p.begin();
3076 while (slashcnt < 3 && x != p.end()) {
3079 } else if (slashcnt == 3) {
3086 if (slashcnt != 3 || x == p.end()) {
3087 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3091 paths.push_back (p.substr (n - 1));
3099 Editor::new_tempo_section ()
3105 Editor::map_transport_state ()
3107 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3109 if (_session && _session->transport_stopped()) {
3110 have_pending_keyboard_selection = false;
3113 update_loop_range_view (true);
3118 Editor::State::State (PublicEditor const * e)
3120 selection = new Selection (e);
3123 Editor::State::~State ()
3129 Editor::begin_reversible_command (string name)
3132 _session->begin_reversible_command (name);
3137 Editor::begin_reversible_command (GQuark q)
3140 _session->begin_reversible_command (q);
3145 Editor::commit_reversible_command ()
3148 _session->commit_reversible_command ();
3153 Editor::history_changed ()
3157 if (undo_action && _session) {
3158 if (_session->undo_depth() == 0) {
3159 label = S_("Command|Undo");
3161 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3163 undo_action->property_label() = label;
3166 if (redo_action && _session) {
3167 if (_session->redo_depth() == 0) {
3170 label = string_compose(_("Redo (%1)"), _session->next_redo());
3172 redo_action->property_label() = label;
3177 Editor::duplicate_dialog (bool with_dialog)
3181 if (mouse_mode == MouseRange) {
3182 if (selection->time.length() == 0) {
3187 RegionSelection rs = get_regions_from_selection_and_entered ();
3189 if (mouse_mode != MouseRange && rs.empty()) {
3195 ArdourDialog win (_("Duplicate"));
3196 Label label (_("Number of duplications:"));
3197 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3198 SpinButton spinner (adjustment, 0.0, 1);
3201 win.get_vbox()->set_spacing (12);
3202 win.get_vbox()->pack_start (hbox);
3203 hbox.set_border_width (6);
3204 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3206 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3207 place, visually. so do this by hand.
3210 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3211 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3212 spinner.grab_focus();
3218 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3219 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3220 win.set_default_response (RESPONSE_ACCEPT);
3222 win.set_position (WIN_POS_MOUSE);
3224 spinner.grab_focus ();
3226 switch (win.run ()) {
3227 case RESPONSE_ACCEPT:
3233 times = adjustment.get_value();
3236 if (mouse_mode == MouseRange) {
3237 duplicate_selection (times);
3239 duplicate_some_regions (rs, times);
3244 Editor::set_edit_mode (EditMode m)
3246 Config->set_edit_mode (m);
3250 Editor::cycle_edit_mode ()
3252 switch (Config->get_edit_mode()) {
3254 if (Profile->get_sae()) {
3255 Config->set_edit_mode (Lock);
3257 Config->set_edit_mode (Splice);
3261 Config->set_edit_mode (Lock);
3264 Config->set_edit_mode (Slide);
3270 Editor::edit_mode_selection_done ()
3272 string s = edit_mode_selector.get_active_text ();
3275 Config->set_edit_mode (string_to_edit_mode (s));
3280 Editor::snap_type_selection_done ()
3282 string choice = snap_type_selector.get_active_text();
3283 SnapType snaptype = SnapToBeat;
3285 if (choice == _("Beats/2")) {
3286 snaptype = SnapToBeatDiv2;
3287 } else if (choice == _("Beats/3")) {
3288 snaptype = SnapToBeatDiv3;
3289 } else if (choice == _("Beats/4")) {
3290 snaptype = SnapToBeatDiv4;
3291 } else if (choice == _("Beats/5")) {
3292 snaptype = SnapToBeatDiv5;
3293 } else if (choice == _("Beats/6")) {
3294 snaptype = SnapToBeatDiv6;
3295 } else if (choice == _("Beats/7")) {
3296 snaptype = SnapToBeatDiv7;
3297 } else if (choice == _("Beats/8")) {
3298 snaptype = SnapToBeatDiv8;
3299 } else if (choice == _("Beats/10")) {
3300 snaptype = SnapToBeatDiv10;
3301 } else if (choice == _("Beats/12")) {
3302 snaptype = SnapToBeatDiv12;
3303 } else if (choice == _("Beats/14")) {
3304 snaptype = SnapToBeatDiv14;
3305 } else if (choice == _("Beats/16")) {
3306 snaptype = SnapToBeatDiv16;
3307 } else if (choice == _("Beats/20")) {
3308 snaptype = SnapToBeatDiv20;
3309 } else if (choice == _("Beats/24")) {
3310 snaptype = SnapToBeatDiv24;
3311 } else if (choice == _("Beats/28")) {
3312 snaptype = SnapToBeatDiv28;
3313 } else if (choice == _("Beats/32")) {
3314 snaptype = SnapToBeatDiv32;
3315 } else if (choice == _("Beats")) {
3316 snaptype = SnapToBeat;
3317 } else if (choice == _("Bars")) {
3318 snaptype = SnapToBar;
3319 } else if (choice == _("Marks")) {
3320 snaptype = SnapToMark;
3321 } else if (choice == _("Region starts")) {
3322 snaptype = SnapToRegionStart;
3323 } else if (choice == _("Region ends")) {
3324 snaptype = SnapToRegionEnd;
3325 } else if (choice == _("Region bounds")) {
3326 snaptype = SnapToRegionBoundary;
3327 } else if (choice == _("Region syncs")) {
3328 snaptype = SnapToRegionSync;
3329 } else if (choice == _("CD Frames")) {
3330 snaptype = SnapToCDFrame;
3331 } else if (choice == _("Timecode Frames")) {
3332 snaptype = SnapToTimecodeFrame;
3333 } else if (choice == _("Timecode Seconds")) {
3334 snaptype = SnapToTimecodeSeconds;
3335 } else if (choice == _("Timecode Minutes")) {
3336 snaptype = SnapToTimecodeMinutes;
3337 } else if (choice == _("Seconds")) {
3338 snaptype = SnapToSeconds;
3339 } else if (choice == _("Minutes")) {
3340 snaptype = SnapToMinutes;
3343 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3345 ract->set_active ();
3350 Editor::snap_mode_selection_done ()
3352 string choice = snap_mode_selector.get_active_text();
3353 SnapMode mode = SnapNormal;
3355 if (choice == _("No Grid")) {
3357 } else if (choice == _("Grid")) {
3359 } else if (choice == _("Magnetic")) {
3360 mode = SnapMagnetic;
3363 RefPtr<RadioAction> ract = snap_mode_action (mode);
3366 ract->set_active (true);
3371 Editor::cycle_edit_point (bool with_marker)
3373 switch (_edit_point) {
3375 set_edit_point_preference (EditAtPlayhead);
3377 case EditAtPlayhead:
3379 set_edit_point_preference (EditAtSelectedMarker);
3381 set_edit_point_preference (EditAtMouse);
3384 case EditAtSelectedMarker:
3385 set_edit_point_preference (EditAtMouse);
3391 Editor::edit_point_selection_done ()
3393 string choice = edit_point_selector.get_active_text();
3394 EditPoint ep = EditAtSelectedMarker;
3396 if (choice == _("Marker")) {
3397 set_edit_point_preference (EditAtSelectedMarker);
3398 } else if (choice == _("Playhead")) {
3399 set_edit_point_preference (EditAtPlayhead);
3401 set_edit_point_preference (EditAtMouse);
3404 RefPtr<RadioAction> ract = edit_point_action (ep);
3407 ract->set_active (true);
3412 Editor::zoom_focus_selection_done ()
3414 string choice = zoom_focus_selector.get_active_text();
3415 ZoomFocus focus_type = ZoomFocusLeft;
3417 if (choice == _("Left")) {
3418 focus_type = ZoomFocusLeft;
3419 } else if (choice == _("Right")) {
3420 focus_type = ZoomFocusRight;
3421 } else if (choice == _("Center")) {
3422 focus_type = ZoomFocusCenter;
3423 } else if (choice == _("Playhead")) {
3424 focus_type = ZoomFocusPlayhead;
3425 } else if (choice == _("Mouse")) {
3426 focus_type = ZoomFocusMouse;
3427 } else if (choice == _("Edit point")) {
3428 focus_type = ZoomFocusEdit;
3431 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3434 ract->set_active ();
3439 Editor::edit_controls_button_release (GdkEventButton* ev)
3441 if (Keyboard::is_context_menu_event (ev)) {
3442 ARDOUR_UI::instance()->add_route (this);
3443 } else if (ev->button == 1) {
3444 selection->clear_tracks ();
3451 Editor::mouse_select_button_release (GdkEventButton* ev)
3453 /* this handles just right-clicks */
3455 if (ev->button != 3) {
3463 Editor::set_zoom_focus (ZoomFocus f)
3465 string str = zoom_focus_strings[(int)f];
3467 if (str != zoom_focus_selector.get_active_text()) {
3468 zoom_focus_selector.set_active_text (str);
3471 if (zoom_focus != f) {
3478 Editor::ensure_float (Window& win)
3480 win.set_transient_for (*this);
3484 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3486 /* recover or initialize pane positions. do this here rather than earlier because
3487 we don't want the positions to change the child allocations, which they seem to do.
3493 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3502 XMLNode* geometry = find_named_node (*node, "geometry");
3504 if (which == static_cast<Paned*> (&edit_pane)) {
3506 if (done & Horizontal) {
3510 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3511 _notebook_shrunk = string_is_affirmative (prop->value ());
3514 if (geometry && (prop = geometry->property ("pre-maximal-horizontal-pane-position"))) {
3515 pre_maximal_horizontal_pane_position = atoi (prop->value ());
3518 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3519 /* initial allocation is 90% to canvas, 10% to notebook */
3520 pos = (int) floor (alloc.get_width() * 0.90f);
3521 snprintf (buf, sizeof(buf), "%d", pos);
3523 pos = atoi (prop->value());
3526 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3527 edit_pane.set_position (pos);
3528 if (pre_maximal_horizontal_pane_position == 0) {
3529 pre_maximal_horizontal_pane_position = pos;
3533 done = (Pane) (done | Horizontal);
3535 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3537 if (done & Vertical) {
3541 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3542 /* initial allocation is 90% to canvas, 10% to summary */
3543 pos = (int) floor (alloc.get_height() * 0.90f);
3544 snprintf (buf, sizeof(buf), "%d", pos);
3546 pos = atoi (prop->value());
3549 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3550 editor_summary_pane.set_position (pos);
3551 pre_maximal_vertical_pane_position = pos;
3554 done = (Pane) (done | Vertical);
3559 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3561 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3562 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3563 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3564 top_hbox.remove (toolbar_frame);
3569 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3571 if (toolbar_frame.get_parent() == 0) {
3572 top_hbox.pack_end (toolbar_frame);
3577 Editor::set_show_measures (bool yn)
3579 if (_show_measures != yn) {
3582 if ((_show_measures = yn) == true) {
3584 tempo_lines->show();
3592 Editor::toggle_follow_playhead ()
3594 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3596 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3597 set_follow_playhead (tact->get_active());
3601 /** @param yn true to follow playhead, otherwise false.
3602 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3605 Editor::set_follow_playhead (bool yn, bool catch_up)
3607 if (_follow_playhead != yn) {
3608 if ((_follow_playhead = yn) == true && catch_up) {
3610 reset_x_origin_to_follow_playhead ();
3617 Editor::toggle_stationary_playhead ()
3619 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3621 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3622 set_stationary_playhead (tact->get_active());
3627 Editor::set_stationary_playhead (bool yn)
3629 if (_stationary_playhead != yn) {
3630 if ((_stationary_playhead = yn) == true) {
3632 // FIXME need a 3.0 equivalent of this 2.X call
3633 // update_current_screen ();
3640 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3642 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3644 xfade->set_active (!xfade->active());
3649 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3651 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3653 xfade->set_follow_overlap (!xfade->following_overlap());
3658 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3660 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3666 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3670 switch (cew.run ()) {
3671 case RESPONSE_ACCEPT:
3678 PropertyChange all_crossfade_properties;
3679 all_crossfade_properties.add (ARDOUR::Properties::active);
3680 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3681 xfade->PropertyChanged (all_crossfade_properties);
3685 Editor::playlist_selector () const
3687 return *_playlist_selector;
3691 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3695 switch (_snap_type) {
3700 case SnapToBeatDiv32:
3703 case SnapToBeatDiv28:
3706 case SnapToBeatDiv24:
3709 case SnapToBeatDiv20:
3712 case SnapToBeatDiv16:
3715 case SnapToBeatDiv14:
3718 case SnapToBeatDiv12:
3721 case SnapToBeatDiv10:
3724 case SnapToBeatDiv8:
3727 case SnapToBeatDiv7:
3730 case SnapToBeatDiv6:
3733 case SnapToBeatDiv5:
3736 case SnapToBeatDiv4:
3739 case SnapToBeatDiv3:
3742 case SnapToBeatDiv2:
3748 return _session->tempo_map().meter_at (position).divisions_per_bar();
3753 case SnapToTimecodeFrame:
3754 case SnapToTimecodeSeconds:
3755 case SnapToTimecodeMinutes:
3758 case SnapToRegionStart:
3759 case SnapToRegionEnd:
3760 case SnapToRegionSync:
3761 case SnapToRegionBoundary:
3771 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3775 ret = nudge_clock->current_duration (pos);
3776 next = ret + 1; /* XXXX fix me */
3782 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3784 ArdourDialog dialog (_("Playlist Deletion"));
3785 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3786 "If it is kept, its audio files will not be cleaned.\n"
3787 "If it is deleted, audio files used by it alone will be cleaned."),
3790 dialog.set_position (WIN_POS_CENTER);
3791 dialog.get_vbox()->pack_start (label);
3795 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3796 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3797 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3799 switch (dialog.run ()) {
3800 case RESPONSE_ACCEPT:
3801 /* delete the playlist */
3805 case RESPONSE_REJECT:
3806 /* keep the playlist */
3818 Editor::audio_region_selection_covers (framepos_t where)
3820 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3821 if ((*a)->region()->covers (where)) {
3830 Editor::prepare_for_cleanup ()
3832 cut_buffer->clear_regions ();
3833 cut_buffer->clear_playlists ();
3835 selection->clear_regions ();
3836 selection->clear_playlists ();
3838 _regions->suspend_redisplay ();
3842 Editor::finish_cleanup ()
3844 _regions->resume_redisplay ();
3848 Editor::transport_loop_location()
3851 return _session->locations()->auto_loop_location();
3858 Editor::transport_punch_location()
3861 return _session->locations()->auto_punch_location();
3868 Editor::control_layout_scroll (GdkEventScroll* ev)
3870 if (Keyboard::some_magic_widget_has_focus()) {
3874 switch (ev->direction) {
3876 scroll_tracks_up_line ();
3880 case GDK_SCROLL_DOWN:
3881 scroll_tracks_down_line ();
3885 /* no left/right handling yet */
3893 Editor::session_state_saved (string)
3896 _snapshots->redisplay ();
3900 Editor::maximise_editing_space ()
3902 /* these calls will leave each tearoff visible *if* it is torn off
3905 _mouse_mode_tearoff->set_visible (false);
3906 _tools_tearoff->set_visible (false);
3907 _zoom_tearoff->set_visible (false);
3909 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
3910 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
3911 pre_maximal_editor_width = this->get_width ();
3912 pre_maximal_editor_height = this->get_height ();
3914 if (post_maximal_horizontal_pane_position == 0) {
3915 post_maximal_horizontal_pane_position = edit_pane.get_width();
3918 if (post_maximal_vertical_pane_position == 0) {
3919 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
3924 if (post_maximal_editor_width) {
3925 edit_pane.set_position (post_maximal_horizontal_pane_position -
3926 abs(post_maximal_editor_width - pre_maximal_editor_width));
3928 edit_pane.set_position (post_maximal_horizontal_pane_position);
3931 /* Hack: we must do this in an idle handler for it to work; see comment in
3932 restore_editing_space()
3935 Glib::signal_idle().connect (
3937 sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position),
3938 post_maximal_vertical_pane_position
3942 if (Config->get_keep_tearoffs()) {
3943 _mouse_mode_tearoff->set_visible (true);
3944 _tools_tearoff->set_visible (true);
3945 if (Config->get_show_zoom_tools ()) {
3946 _zoom_tearoff->set_visible (true);
3953 Editor::idle_reset_vertical_pane_position (int p)
3955 editor_summary_pane.set_position (p);
3960 Editor::restore_editing_space ()
3962 // user changed width/height of panes during fullscreen
3964 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
3965 post_maximal_horizontal_pane_position = edit_pane.get_position();
3968 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
3969 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
3974 _mouse_mode_tearoff->set_visible (true);
3975 _tools_tearoff->set_visible (true);
3976 if (Config->get_show_zoom_tools ()) {
3977 _zoom_tearoff->set_visible (true);
3979 post_maximal_editor_width = this->get_width();
3980 post_maximal_editor_height = this->get_height();
3982 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
3984 /* This is a bit of a hack, but it seems that if you set the vertical pane position
3985 here it gets reset to some wrong value after this method has finished. Doing
3986 the setup in an idle callback seems to work.
3988 Glib::signal_idle().connect (
3990 sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position),
3991 pre_maximal_vertical_pane_position
3997 * Make new playlists for a given track and also any others that belong
3998 * to the same active route group with the `edit' property.
4003 Editor::new_playlists (TimeAxisView* v)
4005 begin_reversible_command (_("new playlists"));
4006 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4007 _session->playlists->get (playlists);
4008 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4009 commit_reversible_command ();
4013 * Use a copy of the current playlist for a given track and also any others that belong
4014 * to the same active route group with the `edit' property.
4019 Editor::copy_playlists (TimeAxisView* v)
4021 begin_reversible_command (_("copy playlists"));
4022 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4023 _session->playlists->get (playlists);
4024 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4025 commit_reversible_command ();
4028 /** Clear the current playlist for a given track and also any others that belong
4029 * to the same active route group with the `edit' property.
4034 Editor::clear_playlists (TimeAxisView* v)
4036 begin_reversible_command (_("clear playlists"));
4037 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4038 _session->playlists->get (playlists);
4039 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4040 commit_reversible_command ();
4044 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4046 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4050 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4052 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4056 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4058 atv.clear_playlist ();
4062 Editor::on_key_press_event (GdkEventKey* ev)
4064 return key_press_focus_accelerator_handler (*this, ev);
4068 Editor::on_key_release_event (GdkEventKey* ev)
4070 return Gtk::Window::on_key_release_event (ev);
4071 // return key_press_focus_accelerator_handler (*this, ev);
4074 /** Queue up a change to the viewport x origin.
4075 * @param frame New x origin.
4078 Editor::reset_x_origin (framepos_t frame)
4080 queue_visual_change (frame);
4084 Editor::reset_y_origin (double y)
4086 queue_visual_change_y (y);
4090 Editor::reset_zoom (double fpu)
4092 queue_visual_change (fpu);
4096 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4098 reset_x_origin (frame);
4101 if (!no_save_visual) {
4102 undo_visual_stack.push_back (current_visual_state(false));
4106 Editor::VisualState::VisualState ()
4107 : gui_state (new GUIObjectState)
4111 Editor::VisualState::~VisualState ()
4116 Editor::VisualState*
4117 Editor::current_visual_state (bool with_tracks)
4119 VisualState* vs = new VisualState;
4120 vs->y_position = vertical_adjustment.get_value();
4121 vs->frames_per_unit = frames_per_unit;
4122 vs->leftmost_frame = leftmost_frame;
4123 vs->zoom_focus = zoom_focus;
4126 *(vs->gui_state) = *ARDOUR_UI::instance()->gui_object_state;
4133 Editor::undo_visual_state ()
4135 if (undo_visual_stack.empty()) {
4139 redo_visual_stack.push_back (current_visual_state());
4141 VisualState* vs = undo_visual_stack.back();
4142 undo_visual_stack.pop_back();
4143 use_visual_state (*vs);
4147 Editor::redo_visual_state ()
4149 if (redo_visual_stack.empty()) {
4153 undo_visual_stack.push_back (current_visual_state());
4155 VisualState* vs = redo_visual_stack.back();
4156 redo_visual_stack.pop_back();
4157 use_visual_state (*vs);
4161 Editor::swap_visual_state ()
4163 if (undo_visual_stack.empty()) {
4164 redo_visual_state ();
4166 undo_visual_state ();
4171 Editor::use_visual_state (VisualState& vs)
4173 no_save_visual = true;
4175 _routes->suspend_redisplay ();
4177 vertical_adjustment.set_value (vs.y_position);
4179 set_zoom_focus (vs.zoom_focus);
4180 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4182 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4184 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4185 (*i)->reset_visual_state ();
4188 _routes->update_visibility ();
4189 _routes->resume_redisplay ();
4191 no_save_visual = false;
4195 Editor::set_frames_per_unit (double fpu)
4197 /* this is the core function that controls the zoom level of the canvas. it is called
4198 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4201 if (fpu == frames_per_unit) {
4210 /* don't allow zooms that fit more than the maximum number
4211 of frames into an 800 pixel wide space.
4214 if (max_framepos / fpu < 800.0) {
4219 tempo_lines->tempo_map_changed();
4221 frames_per_unit = fpu;
4226 Editor::post_zoom ()
4228 // convert fpu to frame count
4230 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4232 if (frames_per_unit != zoom_range_clock->current_duration()) {
4233 zoom_range_clock->set (frames);
4236 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4237 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4238 (*i)->reshow_selection (selection->time);
4242 ZoomChanged (); /* EMIT_SIGNAL */
4244 //reset_scrolling_region ();
4246 if (playhead_cursor) {
4247 playhead_cursor->set_position (playhead_cursor->current_frame);
4250 refresh_location_display();
4251 _summary->set_overlays_dirty ();
4253 update_marker_labels ();
4259 Editor::queue_visual_change (framepos_t where)
4261 pending_visual_change.add (VisualChange::TimeOrigin);
4262 pending_visual_change.time_origin = where;
4263 ensure_visual_change_idle_handler ();
4267 Editor::queue_visual_change (double fpu)
4269 pending_visual_change.add (VisualChange::ZoomLevel);
4270 pending_visual_change.frames_per_unit = fpu;
4272 ensure_visual_change_idle_handler ();
4276 Editor::queue_visual_change_y (double y)
4278 pending_visual_change.add (VisualChange::YOrigin);
4279 pending_visual_change.y_origin = y;
4281 ensure_visual_change_idle_handler ();
4285 Editor::ensure_visual_change_idle_handler ()
4287 if (pending_visual_change.idle_handler_id < 0) {
4288 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4293 Editor::_idle_visual_changer (void* arg)
4295 return static_cast<Editor*>(arg)->idle_visual_changer ();
4299 Editor::idle_visual_changer ()
4301 VisualChange::Type p = pending_visual_change.pending;
4302 pending_visual_change.pending = (VisualChange::Type) 0;
4304 double const last_time_origin = horizontal_position ();
4306 if (p & VisualChange::TimeOrigin) {
4307 /* This is a bit of a hack, but set_frames_per_unit
4308 below will (if called) end up with the
4309 CrossfadeViews looking at Editor::leftmost_frame,
4310 and if we're changing origin and zoom in the same
4311 operation it will be the wrong value unless we
4315 leftmost_frame = pending_visual_change.time_origin;
4318 if (p & VisualChange::ZoomLevel) {
4319 set_frames_per_unit (pending_visual_change.frames_per_unit);
4321 compute_fixed_ruler_scale ();
4322 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4323 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4324 update_tempo_based_rulers ();
4326 if (p & VisualChange::TimeOrigin) {
4327 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4329 if (p & VisualChange::YOrigin) {
4330 vertical_adjustment.set_value (pending_visual_change.y_origin);
4333 if (last_time_origin == horizontal_position ()) {
4334 /* changed signal not emitted */
4335 update_fixed_rulers ();
4336 redisplay_tempo (true);
4339 _summary->set_overlays_dirty ();
4341 pending_visual_change.idle_handler_id = -1;
4342 return 0; /* this is always a one-shot call */
4345 struct EditorOrderTimeAxisSorter {
4346 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4347 return a->order () < b->order ();
4352 Editor::sort_track_selection (TrackViewList& sel)
4354 EditorOrderTimeAxisSorter cmp;
4359 Editor::get_preferred_edit_position (bool ignore_playhead)
4362 framepos_t where = 0;
4363 EditPoint ep = _edit_point;
4365 if (entered_marker) {
4366 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4367 return entered_marker->position();
4370 if (ignore_playhead && ep == EditAtPlayhead) {
4371 ep = EditAtSelectedMarker;
4375 case EditAtPlayhead:
4376 where = _session->audible_frame();
4377 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4380 case EditAtSelectedMarker:
4381 if (!selection->markers.empty()) {
4383 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4386 where = loc->start();
4390 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4398 if (!mouse_frame (where, ignored)) {
4399 /* XXX not right but what can we do ? */
4403 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4411 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4413 if (!_session) return;
4415 begin_reversible_command (cmd);
4419 if ((tll = transport_loop_location()) == 0) {
4420 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4421 XMLNode &before = _session->locations()->get_state();
4422 _session->locations()->add (loc, true);
4423 _session->set_auto_loop_location (loc);
4424 XMLNode &after = _session->locations()->get_state();
4425 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4427 XMLNode &before = tll->get_state();
4428 tll->set_hidden (false, this);
4429 tll->set (start, end);
4430 XMLNode &after = tll->get_state();
4431 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4434 commit_reversible_command ();
4438 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4440 if (!_session) return;
4442 begin_reversible_command (cmd);
4446 if ((tpl = transport_punch_location()) == 0) {
4447 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4448 XMLNode &before = _session->locations()->get_state();
4449 _session->locations()->add (loc, true);
4450 _session->set_auto_loop_location (loc);
4451 XMLNode &after = _session->locations()->get_state();
4452 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4455 XMLNode &before = tpl->get_state();
4456 tpl->set_hidden (false, this);
4457 tpl->set (start, end);
4458 XMLNode &after = tpl->get_state();
4459 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4462 commit_reversible_command ();
4465 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4466 * @param rs List to which found regions are added.
4467 * @param where Time to look at.
4468 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4471 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4473 const TrackViewList* tracks;
4476 tracks = &track_views;
4481 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4483 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4486 boost::shared_ptr<Track> tr;
4487 boost::shared_ptr<Playlist> pl;
4489 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4491 Playlist::RegionList* regions = pl->regions_at (
4492 (framepos_t) floor ( (double) where * tr->speed()));
4494 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4495 RegionView* rv = rtv->view()->find_view (*i);
4508 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4510 const TrackViewList* tracks;
4513 tracks = &track_views;
4518 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4519 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4521 boost::shared_ptr<Track> tr;
4522 boost::shared_ptr<Playlist> pl;
4524 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4526 Playlist::RegionList* regions = pl->regions_touched (
4527 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4529 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4531 RegionView* rv = rtv->view()->find_view (*i);
4544 /** Start with regions that are selected. Then add equivalent regions
4545 * on tracks in the same active edit-enabled route group as any of
4546 * the regions that we started with.
4550 Editor::get_regions_from_selection ()
4552 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4555 /** Get regions using the following method:
4557 * Make an initial region list using the selected regions, unless
4558 * the edit point is `mouse' and the mouse is over an unselected
4559 * region. In this case, start with just that region.
4561 * Then, make an initial track list of the tracks that these
4562 * regions are on, and if the edit point is not `mouse', add the
4565 * Look at this track list and add any other tracks that are on the
4566 * same active edit-enabled route group as one of the initial tracks.
4568 * Finally take the initial region list and add any regions that are
4569 * under the edit point on one of the tracks on the track list to get
4570 * the returned region list.
4572 * The rationale here is that the mouse edit point is special in that
4573 * its position describes both a time and a track; the other edit
4574 * modes only describe a time. Hence if the edit point is `mouse' we
4575 * ignore selected tracks, as we assume the user means something by
4576 * pointing at a particular track. Also in this case we take note of
4577 * the region directly under the edit point, as there is always just one
4578 * (rather than possibly several with non-mouse edit points).
4582 Editor::get_regions_from_selection_and_edit_point ()
4584 RegionSelection regions;
4586 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4587 regions.add (entered_regionview);
4589 regions = selection->regions;
4592 TrackViewList tracks;
4594 if (_edit_point != EditAtMouse) {
4595 tracks = selection->tracks;
4598 /* Add any other tracks that have regions that are in the same
4599 edit-activated route group as one of our regions.
4601 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4603 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4605 if (g && g->is_active() && g->is_edit()) {
4606 tracks.add (axis_views_from_routes (g->route_list()));
4610 if (!tracks.empty()) {
4611 /* now find regions that are at the edit position on those tracks */
4612 framepos_t const where = get_preferred_edit_position ();
4613 get_regions_at (regions, where, tracks);
4619 /** Start with regions that are selected, or the entered regionview if none are selected.
4620 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4621 * of the regions that we started with.
4625 Editor::get_regions_from_selection_and_entered ()
4627 RegionSelection regions = selection->regions;
4629 if (regions.empty() && entered_regionview) {
4630 regions.add (entered_regionview);
4633 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4637 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4639 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4641 RouteTimeAxisView* tatv;
4643 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4645 boost::shared_ptr<Playlist> pl;
4646 vector<boost::shared_ptr<Region> > results;
4648 boost::shared_ptr<Track> tr;
4650 if ((tr = tatv->track()) == 0) {
4655 if ((pl = (tr->playlist())) != 0) {
4656 pl->get_region_list_equivalent_regions (region, results);
4659 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4660 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4661 regions.push_back (marv);
4670 Editor::show_rhythm_ferret ()
4672 if (rhythm_ferret == 0) {
4673 rhythm_ferret = new RhythmFerret(*this);
4676 rhythm_ferret->set_session (_session);
4677 rhythm_ferret->show ();
4678 rhythm_ferret->present ();
4682 Editor::first_idle ()
4684 MessageDialog* dialog = 0;
4686 if (track_views.size() > 1) {
4687 dialog = new MessageDialog (
4689 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4693 ARDOUR_UI::instance()->flush_pending ();
4696 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4700 // first idle adds route children (automation tracks), so we need to redisplay here
4701 _routes->redisplay ();
4708 Editor::_idle_resize (gpointer arg)
4710 return ((Editor*)arg)->idle_resize ();
4714 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4716 if (resize_idle_id < 0) {
4717 resize_idle_id = g_idle_add (_idle_resize, this);
4718 _pending_resize_amount = 0;
4721 /* make a note of the smallest resulting height, so that we can clamp the
4722 lower limit at TimeAxisView::hSmall */
4724 int32_t min_resulting = INT32_MAX;
4726 _pending_resize_amount += h;
4727 _pending_resize_view = view;
4729 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4731 if (selection->tracks.contains (_pending_resize_view)) {
4732 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4733 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4737 if (min_resulting < 0) {
4742 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4743 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4747 /** Handle pending resizing of tracks */
4749 Editor::idle_resize ()
4751 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4753 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4754 selection->tracks.contains (_pending_resize_view)) {
4756 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4757 if (*i != _pending_resize_view) {
4758 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4763 _pending_resize_amount = 0;
4765 _group_tabs->set_dirty ();
4766 resize_idle_id = -1;
4774 ENSURE_GUI_THREAD (*this, &Editor::located);
4776 playhead_cursor->set_position (_session->audible_frame ());
4777 if (_follow_playhead && !_pending_initial_locate) {
4778 reset_x_origin_to_follow_playhead ();
4781 _pending_locate_request = false;
4782 _pending_initial_locate = false;
4786 Editor::region_view_added (RegionView *)
4788 _summary->set_dirty ();
4792 Editor::region_view_removed ()
4794 _summary->set_dirty ();
4798 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4800 TrackViewList::const_iterator j = track_views.begin ();
4801 while (j != track_views.end()) {
4802 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4803 if (rtv && rtv->route() == r) {
4814 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4818 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4819 TimeAxisView* tv = axis_view_from_route (*i);
4830 Editor::handle_new_route (RouteList& routes)
4832 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4834 RouteTimeAxisView *rtv;
4835 list<RouteTimeAxisView*> new_views;
4837 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4838 boost::shared_ptr<Route> route = (*x);
4840 if (route->is_hidden() || route->is_monitor()) {
4844 DataType dt = route->input()->default_type();
4846 if (dt == ARDOUR::DataType::AUDIO) {
4847 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4848 rtv->set_route (route);
4849 } else if (dt == ARDOUR::DataType::MIDI) {
4850 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4851 rtv->set_route (route);
4853 throw unknown_type();
4856 new_views.push_back (rtv);
4857 track_views.push_back (rtv);
4859 rtv->effective_gain_display ();
4861 if (internal_editing()) {
4862 rtv->enter_internal_edit_mode ();
4864 rtv->leave_internal_edit_mode ();
4867 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4868 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4871 _routes->routes_added (new_views);
4872 _summary->routes_added (new_views);
4874 if (show_editor_mixer_when_tracks_arrive) {
4875 show_editor_mixer (true);
4878 editor_list_button.set_sensitive (true);
4882 Editor::timeaxisview_deleted (TimeAxisView *tv)
4884 if (_session && _session->deletion_in_progress()) {
4885 /* the situation is under control */
4889 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4891 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4893 _routes->route_removed (tv);
4895 if (tv == entered_track) {
4899 TimeAxisView::Children c = tv->get_child_list ();
4900 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4901 if (entered_track == i->get()) {
4906 /* remove it from the list of track views */
4908 TrackViewList::iterator i;
4910 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4911 i = track_views.erase (i);
4914 /* update whatever the current mixer strip is displaying, if revelant */
4916 boost::shared_ptr<Route> route;
4919 route = rtav->route ();
4922 if (current_mixer_strip && current_mixer_strip->route() == route) {
4924 TimeAxisView* next_tv;
4926 if (track_views.empty()) {
4928 } else if (i == track_views.end()) {
4929 next_tv = track_views.front();
4936 set_selected_mixer_strip (*next_tv);
4938 /* make the editor mixer strip go away setting the
4939 * button to inactive (which also unticks the menu option)
4942 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4948 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4950 if (apply_to_selection) {
4951 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4953 TrackSelection::iterator j = i;
4956 hide_track_in_display (*i, false);
4961 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4963 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4964 // this will hide the mixer strip
4965 set_selected_mixer_strip (*tv);
4968 _routes->hide_track_in_display (*tv);
4973 Editor::sync_track_view_list_and_routes ()
4975 track_views = TrackViewList (_routes->views ());
4977 _summary->set_dirty ();
4978 _group_tabs->set_dirty ();
4980 return false; // do not call again (until needed)
4984 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4986 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4991 /** Find a RouteTimeAxisView by the ID of its route */
4993 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4995 RouteTimeAxisView* v;
4997 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4998 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4999 if(v->route()->id() == id) {
5009 Editor::fit_route_group (RouteGroup *g)
5011 TrackViewList ts = axis_views_from_routes (g->route_list ());
5016 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5018 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5021 _session->cancel_audition ();
5025 if (_session->is_auditioning()) {
5026 _session->cancel_audition ();
5027 if (r == last_audition_region) {
5032 _session->audition_region (r);
5033 last_audition_region = r;
5038 Editor::hide_a_region (boost::shared_ptr<Region> r)
5040 r->set_hidden (true);
5044 Editor::show_a_region (boost::shared_ptr<Region> r)
5046 r->set_hidden (false);
5050 Editor::audition_region_from_region_list ()
5052 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5056 Editor::hide_region_from_region_list ()
5058 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5062 Editor::show_region_in_region_list ()
5064 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5068 Editor::step_edit_status_change (bool yn)
5071 start_step_editing ();
5073 stop_step_editing ();
5078 Editor::start_step_editing ()
5080 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5084 Editor::stop_step_editing ()
5086 step_edit_connection.disconnect ();
5090 Editor::check_step_edit ()
5092 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5093 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5095 mtv->check_step_edit ();
5099 return true; // do it again, till we stop
5103 Editor::scroll_press (Direction dir)
5105 ++_scroll_callbacks;
5107 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5108 /* delay the first auto-repeat */
5114 scroll_backward (1);
5122 scroll_tracks_up_line ();
5126 scroll_tracks_down_line ();
5130 /* do hacky auto-repeat */
5131 if (!_scroll_connection.connected ()) {
5133 _scroll_connection = Glib::signal_timeout().connect (
5134 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5137 _scroll_callbacks = 0;
5144 Editor::scroll_release ()
5146 _scroll_connection.disconnect ();
5149 /** Queue a change for the Editor viewport x origin to follow the playhead */
5151 Editor::reset_x_origin_to_follow_playhead ()
5153 framepos_t const frame = playhead_cursor->current_frame;
5155 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5157 if (_session->transport_speed() < 0) {
5159 if (frame > (current_page_frames() / 2)) {
5160 center_screen (frame-(current_page_frames()/2));
5162 center_screen (current_page_frames()/2);
5167 if (frame < leftmost_frame) {
5170 if (_session->transport_rolling()) {
5171 /* rolling; end up with the playhead at the right of the page */
5172 l = frame - current_page_frames ();
5174 /* not rolling: end up with the playhead 3/4 of the way along the page */
5175 l = frame - (3 * current_page_frames() / 4);
5182 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5185 if (_session->transport_rolling()) {
5186 /* rolling: end up with the playhead on the left of the page */
5187 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5189 /* not rolling: end up with the playhead 1/4 of the way along the page */
5190 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5198 Editor::super_rapid_screen_update ()
5200 if (!_session || !_session->engine().running()) {
5204 /* METERING / MIXER STRIPS */
5206 /* update track meters, if required */
5207 if (is_mapped() && meters_running) {
5208 RouteTimeAxisView* rtv;
5209 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5210 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5211 rtv->fast_update ();
5216 /* and any current mixer strip */
5217 if (current_mixer_strip) {
5218 current_mixer_strip->fast_update ();
5221 /* PLAYHEAD AND VIEWPORT */
5223 framepos_t const frame = _session->audible_frame();
5225 /* There are a few reasons why we might not update the playhead / viewport stuff:
5227 * 1. we don't update things when there's a pending locate request, otherwise
5228 * when the editor requests a locate there is a chance that this method
5229 * will move the playhead before the locate request is processed, causing
5231 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5232 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5235 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5237 last_update_frame = frame;
5239 if (!_dragging_playhead) {
5240 playhead_cursor->set_position (frame);
5243 if (!_stationary_playhead) {
5245 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5246 reset_x_origin_to_follow_playhead ();
5251 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5255 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5256 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5257 if (target <= 0.0) {
5260 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5261 target = (target * 0.15) + (current * 0.85);
5267 set_horizontal_position (current);
5276 Editor::session_going_away ()
5278 _have_idled = false;
5280 _session_connections.drop_connections ();
5282 super_rapid_screen_update_connection.disconnect ();
5284 selection->clear ();
5285 cut_buffer->clear ();
5287 clicked_regionview = 0;
5288 clicked_axisview = 0;
5289 clicked_routeview = 0;
5290 clicked_crossfadeview = 0;
5291 entered_regionview = 0;
5293 last_update_frame = 0;
5296 playhead_cursor->canvas_item.hide ();
5298 /* rip everything out of the list displays */
5302 _route_groups->clear ();
5304 /* do this first so that deleting a track doesn't reset cms to null
5305 and thus cause a leak.
5308 if (current_mixer_strip) {
5309 if (current_mixer_strip->get_parent() != 0) {
5310 global_hpacker.remove (*current_mixer_strip);
5312 delete current_mixer_strip;
5313 current_mixer_strip = 0;
5316 /* delete all trackviews */
5318 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5321 track_views.clear ();
5323 zoom_range_clock->set_session (0);
5324 nudge_clock->set_session (0);
5326 editor_list_button.set_active(false);
5327 editor_list_button.set_sensitive(false);
5329 /* clear tempo/meter rulers */
5330 remove_metric_marks ();
5332 clear_marker_display ();
5334 delete current_bbt_points;
5335 current_bbt_points = 0;
5337 /* get rid of any existing editor mixer strip */
5339 WindowTitle title(Glib::get_application_name());
5340 title += _("Editor");
5342 set_title (title.get_string());
5344 SessionHandlePtr::session_going_away ();
5349 Editor::show_editor_list (bool yn)
5352 _the_notebook.show ();
5354 _the_notebook.hide ();
5359 Editor::change_region_layering_order ()
5361 framepos_t const position = get_preferred_edit_position ();
5363 if (!clicked_routeview) {
5364 if (layering_order_editor) {
5365 layering_order_editor->hide ();
5370 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5376 boost::shared_ptr<Playlist> pl = track->playlist();
5382 if (layering_order_editor == 0) {
5383 layering_order_editor = new RegionLayeringOrderEditor(*this);
5386 layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5387 layering_order_editor->maybe_present ();
5391 Editor::update_region_layering_order_editor ()
5393 if (layering_order_editor && layering_order_editor->is_visible ()) {
5394 change_region_layering_order ();
5399 Editor::setup_fade_images ()
5401 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5402 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5403 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5404 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5405 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5407 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5408 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5409 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5410 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5411 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5415 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5417 Editor::action_menu_item (std::string const & name)
5419 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5422 return *manage (a->create_menu_item ());
5426 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5428 EventBox* b = manage (new EventBox);
5429 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5430 Label* l = manage (new Label (name));
5434 _the_notebook.append_page (widget, *b);
5438 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5440 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5441 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5444 if (ev->type == GDK_2BUTTON_PRESS) {
5446 /* double-click on a notebook tab shrinks or expands the notebook */
5448 if (_notebook_shrunk) {
5449 edit_pane.set_position (pre_maximal_horizontal_pane_position);
5450 _notebook_shrunk = false;
5452 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
5453 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5454 _notebook_shrunk = true;
5462 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5464 using namespace Menu_Helpers;
5466 MenuList& items = _control_point_context_menu.items ();
5469 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5470 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5471 if (!can_remove_control_point (item)) {
5472 items.back().set_sensitive (false);
5475 _control_point_context_menu.popup (event->button.button, event->button.time);