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"
46 #include "pbd/unwind.h"
48 #include <glibmm/miscutils.h>
49 #include <gtkmm/image.h>
50 #include <gdkmm/color.h>
51 #include <gdkmm/bitmap.h>
53 #include "gtkmm2ext/bindings.h"
54 #include "gtkmm2ext/grouped_buttons.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/tearoff.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/window_title.h"
59 #include "gtkmm2ext/choice.h"
60 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioplaylist.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/midi_region.h"
67 #include "ardour/plugin_manager.h"
68 #include "ardour/profile.h"
69 #include "ardour/route_group.h"
70 #include "ardour/session_directory.h"
71 #include "ardour/session_route.h"
72 #include "ardour/session_state_utils.h"
73 #include "ardour/tempo.h"
74 #include "ardour/utils.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/audioengine.h"
78 #include "control_protocol/control_protocol.h"
82 #include "analysis_window.h"
83 #include "audio_clock.h"
84 #include "audio_region_view.h"
85 #include "audio_streamview.h"
86 #include "audio_time_axis.h"
87 #include "automation_time_axis.h"
88 #include "bundle_manager.h"
89 #include "button_joiner.h"
90 #include "canvas-noevent-text.h"
91 #include "canvas_impl.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "simpleline.h"
122 #include "tempo_lines.h"
123 #include "time_axis_view.h"
129 #include "imageframe_socket_handler.h"
133 using namespace ARDOUR;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 const double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
148 N_("Timecode Frames"),
149 N_("Timecode Seconds"),
150 N_("Timecode Minutes"),
180 static const gchar *_snap_mode_strings[] = {
187 static const gchar *_edit_point_strings[] = {
194 static const gchar *_zoom_focus_strings[] = {
204 #ifdef USE_RUBBERBAND
205 static const gchar *_rb_opt_strings[] = {
208 N_("Balanced multitimbral mixture"),
209 N_("Unpitched percussion with stable notes"),
210 N_("Crisp monophonic instrumental"),
211 N_("Unpitched solo percussion"),
212 N_("Resample without preserving pitch"),
218 show_me_the_size (Requisition* r, const char* what)
220 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
225 pane_size_watcher (Paned* pane)
227 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
228 it is no longer accessible. so stop that. this doesn't happen on X11,
229 just the quartz backend.
234 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
236 gint pos = pane->get_position ();
238 if (pos > max_width_of_lhs) {
239 pane->set_position (max_width_of_lhs);
245 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
247 /* time display buttons */
248 , minsec_label (_("Mins:Secs"))
249 , bbt_label (_("Bars:Beats"))
250 , timecode_label (_("Timecode"))
251 , samples_label (_("Samples"))
252 , tempo_label (_("Tempo"))
253 , meter_label (_("Meter"))
254 , mark_label (_("Location Markers"))
255 , range_mark_label (_("Range Markers"))
256 , transport_mark_label (_("Loop/Punch Ranges"))
257 , cd_mark_label (_("CD Markers"))
258 , edit_packer (4, 4, true)
260 /* the values here don't matter: layout widgets
261 reset them as needed.
264 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
266 /* tool bar related */
268 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
270 , toolbar_selection_clock_table (2,3)
272 , automation_mode_button (_("mode"))
274 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
277 , image_socket_listener(0)
282 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
283 , meters_running(false)
284 , _pending_locate_request (false)
285 , _pending_initial_locate (false)
286 , _last_cut_copy_source_track (0)
288 , _region_selection_change_updates_region_list (true)
289 , _following_mixer_selection (false)
293 /* we are a singleton */
295 PublicEditor::_instance = this;
299 selection = new Selection (this);
300 cut_buffer = new Selection (this);
302 clicked_regionview = 0;
303 clicked_axisview = 0;
304 clicked_routeview = 0;
305 clicked_control_point = 0;
306 last_update_frame = 0;
307 pre_press_cursor = 0;
308 _drags = new DragManager (this);
309 current_mixer_strip = 0;
312 snap_type_strings = I18N (_snap_type_strings);
313 snap_mode_strings = I18N (_snap_mode_strings);
314 zoom_focus_strings = I18N (_zoom_focus_strings);
315 edit_point_strings = I18N (_edit_point_strings);
316 #ifdef USE_RUBBERBAND
317 rb_opt_strings = I18N (_rb_opt_strings);
321 snap_threshold = 5.0;
322 bbt_beat_subdivision = 4;
325 last_autoscroll_x = 0;
326 last_autoscroll_y = 0;
327 autoscroll_active = false;
328 autoscroll_timeout_tag = -1;
333 current_interthread_info = 0;
334 _show_measures = true;
336 show_gain_after_trim = false;
338 have_pending_keyboard_selection = false;
339 _follow_playhead = true;
340 _stationary_playhead = false;
341 editor_ruler_menu = 0;
342 no_ruler_shown_update = false;
344 range_marker_menu = 0;
345 marker_menu_item = 0;
346 tempo_or_meter_marker_menu = 0;
347 transport_marker_menu = 0;
348 new_transport_marker_menu = 0;
349 editor_mixer_strip_width = Wide;
350 show_editor_mixer_when_tracks_arrive = false;
351 region_edit_menu_split_multichannel_item = 0;
352 region_edit_menu_split_item = 0;
355 current_stepping_trackview = 0;
357 entered_regionview = 0;
359 clear_entered_track = false;
362 button_release_can_deselect = true;
363 _dragging_playhead = false;
364 _dragging_edit_point = false;
365 select_new_marker = false;
367 layering_order_editor = 0;
368 no_save_visual = false;
370 within_track_canvas = false;
372 scrubbing_direction = 0;
376 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
377 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
378 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
379 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
380 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
382 _edit_point = EditAtMouse;
383 _internal_editing = false;
384 current_canvas_cursor = 0;
386 frames_per_unit = 2048; /* too early to use reset_zoom () */
388 _scroll_callbacks = 0;
390 zoom_focus = ZoomFocusLeft;
391 set_zoom_focus (ZoomFocusLeft);
392 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
394 bbt_label.set_name ("EditorTimeButton");
395 bbt_label.set_size_request (-1, (int)timebar_height);
396 bbt_label.set_alignment (1.0, 0.5);
397 bbt_label.set_padding (5,0);
399 bbt_label.set_no_show_all();
400 minsec_label.set_name ("EditorTimeButton");
401 minsec_label.set_size_request (-1, (int)timebar_height);
402 minsec_label.set_alignment (1.0, 0.5);
403 minsec_label.set_padding (5,0);
404 minsec_label.hide ();
405 minsec_label.set_no_show_all();
406 timecode_label.set_name ("EditorTimeButton");
407 timecode_label.set_size_request (-1, (int)timebar_height);
408 timecode_label.set_alignment (1.0, 0.5);
409 timecode_label.set_padding (5,0);
410 timecode_label.hide ();
411 timecode_label.set_no_show_all();
412 samples_label.set_name ("EditorTimeButton");
413 samples_label.set_size_request (-1, (int)timebar_height);
414 samples_label.set_alignment (1.0, 0.5);
415 samples_label.set_padding (5,0);
416 samples_label.hide ();
417 samples_label.set_no_show_all();
419 tempo_label.set_name ("EditorTimeButton");
420 tempo_label.set_size_request (-1, (int)timebar_height);
421 tempo_label.set_alignment (1.0, 0.5);
422 tempo_label.set_padding (5,0);
424 tempo_label.set_no_show_all();
426 meter_label.set_name ("EditorTimeButton");
427 meter_label.set_size_request (-1, (int)timebar_height);
428 meter_label.set_alignment (1.0, 0.5);
429 meter_label.set_padding (5,0);
431 meter_label.set_no_show_all();
433 mark_label.set_name ("EditorTimeButton");
434 mark_label.set_size_request (-1, (int)timebar_height);
435 mark_label.set_alignment (1.0, 0.5);
436 mark_label.set_padding (5,0);
438 mark_label.set_no_show_all();
440 cd_mark_label.set_name ("EditorTimeButton");
441 cd_mark_label.set_size_request (-1, (int)timebar_height);
442 cd_mark_label.set_alignment (1.0, 0.5);
443 cd_mark_label.set_padding (5,0);
444 cd_mark_label.hide();
445 cd_mark_label.set_no_show_all();
447 range_mark_label.set_name ("EditorTimeButton");
448 range_mark_label.set_size_request (-1, (int)timebar_height);
449 range_mark_label.set_alignment (1.0, 0.5);
450 range_mark_label.set_padding (5,0);
451 range_mark_label.hide();
452 range_mark_label.set_no_show_all();
454 transport_mark_label.set_name ("EditorTimeButton");
455 transport_mark_label.set_size_request (-1, (int)timebar_height);
456 transport_mark_label.set_alignment (1.0, 0.5);
457 transport_mark_label.set_padding (5,0);
458 transport_mark_label.hide();
459 transport_mark_label.set_no_show_all();
461 initialize_rulers ();
462 initialize_canvas ();
464 _summary = new EditorSummary (this);
466 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
467 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
469 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
471 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
472 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
474 edit_controls_vbox.set_spacing (0);
475 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
476 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
478 HBox* h = manage (new HBox);
479 _group_tabs = new EditorGroupTabs (this);
480 h->pack_start (*_group_tabs, PACK_SHRINK);
481 h->pack_start (edit_controls_vbox);
482 controls_layout.add (*h);
484 controls_layout.set_name ("EditControlsBase");
485 controls_layout.add_events (Gdk::SCROLL_MASK);
486 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
488 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
489 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
491 _cursors = new MouseCursors;
493 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
494 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
495 0.0, 1.0, 100.0, 1.0));
497 pad_line_1->property_color_rgba() = 0xFF0000FF;
502 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
503 time_canvas_vbox.set_size_request (-1, -1);
505 ruler_label_event_box.add (ruler_label_vbox);
506 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
507 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
509 time_button_event_box.add (time_button_vbox);
510 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
511 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
513 /* these enable us to have a dedicated window (for cursor setting, etc.)
514 for the canvas areas.
517 track_canvas_event_box.add (*track_canvas);
519 time_canvas_event_box.add (time_canvas_vbox);
520 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
522 edit_packer.set_col_spacings (0);
523 edit_packer.set_row_spacings (0);
524 edit_packer.set_homogeneous (false);
525 edit_packer.set_border_width (0);
526 edit_packer.set_name ("EditorWindow");
528 /* labels for the rulers */
529 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
530 /* labels for the marker "tracks" */
531 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
533 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
535 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
537 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
539 bottom_hbox.set_border_width (2);
540 bottom_hbox.set_spacing (3);
542 _route_groups = new EditorRouteGroups (this);
543 _routes = new EditorRoutes (this);
544 _regions = new EditorRegions (this);
545 _snapshots = new EditorSnapshots (this);
546 _locations = new EditorLocations (this);
548 add_notebook_page (_("Regions"), _regions->widget ());
549 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
550 add_notebook_page (_("Snapshots"), _snapshots->widget ());
551 add_notebook_page (_("Route Groups"), _route_groups->widget ());
552 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
554 _the_notebook.set_show_tabs (true);
555 _the_notebook.set_scrollable (true);
556 _the_notebook.popup_disable ();
557 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
558 _the_notebook.show_all ();
560 _notebook_shrunk = false;
562 editor_summary_pane.pack1(edit_packer);
564 Button* summary_arrows_left_left = manage (new Button);
565 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
566 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
567 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
569 Button* summary_arrows_left_right = manage (new Button);
570 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
571 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
572 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
574 VBox* summary_arrows_left = manage (new VBox);
575 summary_arrows_left->pack_start (*summary_arrows_left_left);
576 summary_arrows_left->pack_start (*summary_arrows_left_right);
578 Button* summary_arrows_right_up = manage (new Button);
579 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
580 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
581 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 Button* summary_arrows_right_down = manage (new Button);
584 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
585 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
586 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
588 VBox* summary_arrows_right = manage (new VBox);
589 summary_arrows_right->pack_start (*summary_arrows_right_up);
590 summary_arrows_right->pack_start (*summary_arrows_right_down);
592 Frame* summary_frame = manage (new Frame);
593 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
595 summary_frame->add (*_summary);
596 summary_frame->show ();
598 _summary_hbox.pack_start (*summary_arrows_left, false, false);
599 _summary_hbox.pack_start (*summary_frame, true, true);
600 _summary_hbox.pack_start (*summary_arrows_right, false, false);
602 editor_summary_pane.pack2 (_summary_hbox);
604 edit_pane.pack1 (editor_summary_pane, true, true);
605 edit_pane.pack2 (_the_notebook, false, true);
607 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
609 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
611 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
613 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
614 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
616 top_hbox.pack_start (toolbar_frame);
618 HBox *hbox = manage (new HBox);
619 hbox->pack_start (edit_pane, true, true);
621 global_vpacker.pack_start (top_hbox, false, false);
622 global_vpacker.pack_start (*hbox, true, true);
624 global_hpacker.pack_start (global_vpacker, true, true);
626 set_name ("EditorWindow");
627 add_accel_group (ActionManager::ui_manager->get_accel_group());
629 status_bar_hpacker.show ();
631 vpacker.pack_end (status_bar_hpacker, false, false);
632 vpacker.pack_end (global_hpacker, true, true);
634 /* register actions now so that set_state() can find them and set toggles/checks etc */
637 /* when we start using our own keybinding system for the editor, this
638 * will be uncommented
644 _snap_type = SnapToBeat;
645 set_snap_to (_snap_type);
646 _snap_mode = SnapOff;
647 set_snap_mode (_snap_mode);
648 set_mouse_mode (MouseObject, true);
649 pre_internal_mouse_mode = MouseObject;
650 pre_internal_snap_type = _snap_type;
651 pre_internal_snap_mode = _snap_mode;
652 internal_snap_type = _snap_type;
653 internal_snap_mode = _snap_mode;
654 set_edit_point_preference (EditAtMouse, true);
656 _playlist_selector = new PlaylistSelector();
657 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
659 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
663 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
664 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
666 nudge_forward_button.set_name ("TransportButton");
667 nudge_backward_button.set_name ("TransportButton");
669 fade_context_menu.set_name ("ArdourContextMenu");
671 /* icons, titles, WM stuff */
673 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
674 Glib::RefPtr<Gdk::Pixbuf> icon;
676 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
683 window_icons.push_back (icon);
685 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
686 window_icons.push_back (icon);
688 if (!window_icons.empty()) {
689 // set_icon_list (window_icons);
690 set_default_icon_list (window_icons);
693 WindowTitle title(Glib::get_application_name());
694 title += _("Editor");
695 set_title (title.get_string());
696 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
699 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
701 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
702 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
704 /* allow external control surfaces/protocols to do various things */
706 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
707 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
708 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
709 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
710 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
711 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
712 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
713 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
714 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
715 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
716 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
717 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
718 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
719 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
721 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
722 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
723 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
724 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
725 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
727 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
729 /* problematic: has to return a value and thus cannot be x-thread */
731 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
733 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
735 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
737 _ignore_region_action = false;
738 _last_region_menu_was_main = false;
739 _popup_region_menu_item = 0;
741 _show_marker_lines = false;
742 _over_region_trim_target = false;
744 /* Button bindings */
746 button_bindings = new Bindings;
748 XMLNode* node = button_settings();
750 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
751 button_bindings->load (**i);
758 setup_fade_images ();
764 if(image_socket_listener) {
765 if(image_socket_listener->is_connected())
767 image_socket_listener->close_connection() ;
770 delete image_socket_listener ;
771 image_socket_listener = 0 ;
775 delete button_bindings;
777 delete _route_groups;
783 Editor::button_settings () const
785 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
786 XMLNode* node = find_named_node (*settings, X_("Buttons"));
789 cerr << "new empty Button node\n";
790 node = new XMLNode (X_("Buttons"));
797 Editor::add_toplevel_controls (Container& cont)
799 vpacker.pack_start (cont, false, false);
804 Editor::catch_vanishing_regionview (RegionView *rv)
806 /* note: the selection will take care of the vanishing
807 audioregionview by itself.
810 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
814 if (clicked_regionview == rv) {
815 clicked_regionview = 0;
818 if (entered_regionview == rv) {
819 set_entered_regionview (0);
822 if (!_all_region_actions_sensitized) {
823 sensitize_all_region_actions (true);
826 _over_region_trim_target = false;
830 Editor::set_entered_regionview (RegionView* rv)
832 if (rv == entered_regionview) {
836 if (entered_regionview) {
837 entered_regionview->exited ();
840 if ((entered_regionview = rv) != 0) {
841 entered_regionview->entered (internal_editing ());
844 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
845 /* This RegionView entry might have changed what region actions
846 are allowed, so sensitize them all in case a key is pressed.
848 sensitize_all_region_actions (true);
853 Editor::set_entered_track (TimeAxisView* tav)
856 entered_track->exited ();
859 if ((entered_track = tav) != 0) {
860 entered_track->entered ();
865 Editor::show_window ()
867 if (!is_visible ()) {
870 /* XXX: this is a bit unfortunate; it would probably
871 be nicer if we could just call show () above rather
872 than needing the show_all ()
875 /* re-hide stuff if necessary */
876 editor_list_button_toggled ();
877 parameter_changed ("show-summary");
878 parameter_changed ("show-group-tabs");
879 parameter_changed ("show-zoom-tools");
881 /* now reset all audio_time_axis heights, because widgets might need
887 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
888 tv = (static_cast<TimeAxisView*>(*i));
892 if (current_mixer_strip) {
893 current_mixer_strip->hide_things ();
894 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
902 Editor::instant_save ()
904 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
909 _session->add_instant_xml(get_state());
911 Config->add_instant_xml(get_state());
916 Editor::zoom_adjustment_changed ()
922 double fpu = zoom_range_clock->current_duration() / _canvas_width;
926 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
927 } else if (fpu > _session->current_end_frame() / _canvas_width) {
928 fpu = _session->current_end_frame() / _canvas_width;
929 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
936 Editor::control_vertical_zoom_in_all ()
938 tav_zoom_smooth (false, true);
942 Editor::control_vertical_zoom_out_all ()
944 tav_zoom_smooth (true, true);
948 Editor::control_vertical_zoom_in_selected ()
950 tav_zoom_smooth (false, false);
954 Editor::control_vertical_zoom_out_selected ()
956 tav_zoom_smooth (true, false);
960 Editor::control_view (uint32_t view)
962 goto_visual_state (view);
966 Editor::control_unselect ()
968 selection->clear_tracks ();
972 Editor::control_select (uint32_t rid, Selection::Operation op)
974 /* handles the (static) signal from the ControlProtocol class that
975 * requests setting the selected track to a given RID
982 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
988 TimeAxisView* tav = axis_view_from_route (r);
993 selection->add (tav);
995 case Selection::Toggle:
996 selection->toggle (tav);
998 case Selection::Extend:
1000 case Selection::Set:
1001 selection->set (tav);
1005 selection->clear_tracks ();
1010 Editor::control_step_tracks_up ()
1012 scroll_tracks_up_line ();
1016 Editor::control_step_tracks_down ()
1018 scroll_tracks_down_line ();
1022 Editor::control_scroll (float fraction)
1024 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1030 double step = fraction * current_page_frames();
1033 _control_scroll_target is an optional<T>
1035 it acts like a pointer to an framepos_t, with
1036 a operator conversion to boolean to check
1037 that it has a value could possibly use
1038 playhead_cursor->current_frame to store the
1039 value and a boolean in the class to know
1040 when it's out of date
1043 if (!_control_scroll_target) {
1044 _control_scroll_target = _session->transport_frame();
1045 _dragging_playhead = true;
1048 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1049 *_control_scroll_target = 0;
1050 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1051 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1053 *_control_scroll_target += (framepos_t) floor (step);
1056 /* move visuals, we'll catch up with it later */
1058 playhead_cursor->set_position (*_control_scroll_target);
1059 UpdateAllTransportClocks (*_control_scroll_target);
1061 if (*_control_scroll_target > (current_page_frames() / 2)) {
1062 /* try to center PH in window */
1063 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1069 Now we do a timeout to actually bring the session to the right place
1070 according to the playhead. This is to avoid reading disk buffers on every
1071 call to control_scroll, which is driven by ScrollTimeline and therefore
1072 probably by a control surface wheel which can generate lots of events.
1074 /* cancel the existing timeout */
1076 control_scroll_connection.disconnect ();
1078 /* add the next timeout */
1080 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1084 Editor::deferred_control_scroll (framepos_t /*target*/)
1086 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1087 // reset for next stream
1088 _control_scroll_target = boost::none;
1089 _dragging_playhead = false;
1094 Editor::access_action (std::string action_group, std::string action_item)
1100 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1103 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1111 Editor::on_realize ()
1113 Window::on_realize ();
1118 Editor::map_position_change (framepos_t frame)
1120 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1122 if (_session == 0) {
1126 if (_follow_playhead) {
1127 center_screen (frame);
1130 playhead_cursor->set_position (frame);
1134 Editor::center_screen (framepos_t frame)
1136 double page = _canvas_width * frames_per_unit;
1138 /* if we're off the page, then scroll.
1141 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1142 center_screen_internal (frame, page);
1147 Editor::center_screen_internal (framepos_t frame, float page)
1152 frame -= (framepos_t) page;
1157 reset_x_origin (frame);
1162 Editor::update_title ()
1164 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1167 bool dirty = _session->dirty();
1169 string session_name;
1171 if (_session->snap_name() != _session->name()) {
1172 session_name = _session->snap_name();
1174 session_name = _session->name();
1178 session_name = "*" + session_name;
1181 WindowTitle title(session_name);
1182 title += Glib::get_application_name();
1183 set_title (title.get_string());
1188 Editor::set_session (Session *t)
1190 SessionHandlePtr::set_session (t);
1196 zoom_range_clock->set_session (_session);
1197 _playlist_selector->set_session (_session);
1198 nudge_clock->set_session (_session);
1199 _summary->set_session (_session);
1200 _group_tabs->set_session (_session);
1201 _route_groups->set_session (_session);
1202 _regions->set_session (_session);
1203 _snapshots->set_session (_session);
1204 _routes->set_session (_session);
1205 _locations->set_session (_session);
1207 if (rhythm_ferret) {
1208 rhythm_ferret->set_session (_session);
1211 if (analysis_window) {
1212 analysis_window->set_session (_session);
1216 sfbrowser->set_session (_session);
1219 compute_fixed_ruler_scale ();
1221 /* Make sure we have auto loop and auto punch ranges */
1223 Location* loc = _session->locations()->auto_loop_location();
1225 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1227 if (loc->start() == loc->end()) {
1228 loc->set_end (loc->start() + 1);
1231 _session->locations()->add (loc, false);
1232 _session->set_auto_loop_location (loc);
1235 loc->set_name (_("Loop"));
1238 loc = _session->locations()->auto_punch_location();
1241 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1243 if (loc->start() == loc->end()) {
1244 loc->set_end (loc->start() + 1);
1247 _session->locations()->add (loc, false);
1248 _session->set_auto_punch_location (loc);
1251 loc->set_name (_("Punch"));
1254 refresh_location_display ();
1256 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1257 the selected Marker; this needs the LocationMarker list to be available.
1259 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1260 set_state (*node, Stateful::loading_state_version);
1262 /* catch up with the playhead */
1264 _session->request_locate (playhead_cursor->current_frame);
1265 _pending_initial_locate = true;
1269 /* These signals can all be emitted by a non-GUI thread. Therefore the
1270 handlers for them must not attempt to directly interact with the GUI,
1271 but use Gtkmm2ext::UI::instance()->call_slot();
1274 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1275 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1276 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1277 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::handle_new_route, this, _1), gui_context());
1278 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1279 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1280 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1281 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1282 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1283 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1284 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1285 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1286 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1287 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1289 playhead_cursor->canvas_item.show ();
1291 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1292 Config->map_parameters (pc);
1293 _session->config.map_parameters (pc);
1295 restore_ruler_visibility ();
1296 //tempo_map_changed (PropertyChange (0));
1297 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1299 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1300 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1303 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1304 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1307 switch (_snap_type) {
1308 case SnapToRegionStart:
1309 case SnapToRegionEnd:
1310 case SnapToRegionSync:
1311 case SnapToRegionBoundary:
1312 build_region_boundary_cache ();
1319 /* register for undo history */
1320 _session->register_with_memento_command_factory(id(), this);
1322 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1324 start_updating_meters ();
1328 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1330 if (a->get_name() == "RegionMenu") {
1331 /* When the main menu's region menu is opened, we setup the actions so that they look right
1332 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1333 so we resensitize all region actions when the entered regionview or the region selection
1334 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1335 happens after the region context menu is opened. So we set a flag here, too.
1339 sensitize_the_right_region_actions ();
1340 _last_region_menu_was_main = true;
1344 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1346 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1348 using namespace Menu_Helpers;
1349 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1352 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1356 MenuList& items (fade_context_menu.items());
1360 switch (item_type) {
1362 case FadeInHandleItem:
1363 if (arv->audio_region()->fade_in_active()) {
1364 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1366 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1369 items.push_back (SeparatorElem());
1371 if (Profile->get_sae()) {
1373 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1374 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1381 *_fade_in_images[FadeLinear],
1382 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1386 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1391 *_fade_in_images[FadeFast],
1392 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1395 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1400 *_fade_in_images[FadeLogB],
1401 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1409 *_fade_in_images[FadeLogA],
1410 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1413 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1418 *_fade_in_images[FadeSlow],
1419 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1422 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1428 case FadeOutHandleItem:
1429 if (arv->audio_region()->fade_out_active()) {
1430 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1432 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1435 items.push_back (SeparatorElem());
1437 if (Profile->get_sae()) {
1438 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1439 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1445 *_fade_out_images[FadeLinear],
1446 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1450 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1455 *_fade_out_images[FadeFast],
1456 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1459 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1464 *_fade_out_images[FadeLogB],
1465 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1468 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1473 *_fade_out_images[FadeLogA],
1474 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1477 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1482 *_fade_out_images[FadeSlow],
1483 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1492 fatal << _("programming error: ")
1493 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1498 fade_context_menu.popup (button, time);
1502 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1504 using namespace Menu_Helpers;
1505 Menu* (Editor::*build_menu_function)();
1508 switch (item_type) {
1510 case RegionViewName:
1511 case RegionViewNameHighlight:
1512 case LeftFrameHandle:
1513 case RightFrameHandle:
1514 if (with_selection) {
1515 build_menu_function = &Editor::build_track_selection_context_menu;
1517 build_menu_function = &Editor::build_track_region_context_menu;
1522 if (with_selection) {
1523 build_menu_function = &Editor::build_track_selection_context_menu;
1525 build_menu_function = &Editor::build_track_context_menu;
1530 if (clicked_routeview->track()) {
1531 build_menu_function = &Editor::build_track_context_menu;
1533 build_menu_function = &Editor::build_track_bus_context_menu;
1538 /* probably shouldn't happen but if it does, we don't care */
1542 menu = (this->*build_menu_function)();
1543 menu->set_name ("ArdourContextMenu");
1545 /* now handle specific situations */
1547 switch (item_type) {
1549 case RegionViewName:
1550 case RegionViewNameHighlight:
1551 case LeftFrameHandle:
1552 case RightFrameHandle:
1553 if (!with_selection) {
1554 if (region_edit_menu_split_item) {
1555 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1556 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1558 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1561 if (region_edit_menu_split_multichannel_item) {
1562 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1563 region_edit_menu_split_multichannel_item->set_sensitive (true);
1565 region_edit_menu_split_multichannel_item->set_sensitive (false);
1578 /* probably shouldn't happen but if it does, we don't care */
1582 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1584 /* Bounce to disk */
1586 using namespace Menu_Helpers;
1587 MenuList& edit_items = menu->items();
1589 edit_items.push_back (SeparatorElem());
1591 switch (clicked_routeview->audio_track()->freeze_state()) {
1592 case AudioTrack::NoFreeze:
1593 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1596 case AudioTrack::Frozen:
1597 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1600 case AudioTrack::UnFrozen:
1601 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1607 if (item_type == StreamItem && clicked_routeview) {
1608 clicked_routeview->build_underlay_menu(menu);
1611 /* When the region menu is opened, we setup the actions so that they look right
1614 sensitize_the_right_region_actions ();
1615 _last_region_menu_was_main = false;
1617 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1618 menu->popup (button, time);
1622 Editor::build_track_context_menu ()
1624 using namespace Menu_Helpers;
1626 MenuList& edit_items = track_context_menu.items();
1629 add_dstream_context_items (edit_items);
1630 return &track_context_menu;
1634 Editor::build_track_bus_context_menu ()
1636 using namespace Menu_Helpers;
1638 MenuList& edit_items = track_context_menu.items();
1641 add_bus_context_items (edit_items);
1642 return &track_context_menu;
1646 Editor::build_track_region_context_menu ()
1648 using namespace Menu_Helpers;
1649 MenuList& edit_items = track_region_context_menu.items();
1652 /* we've just cleared the track region context menu, so the menu that these
1653 two items were on will have disappeared; stop them dangling.
1655 region_edit_menu_split_item = 0;
1656 region_edit_menu_split_multichannel_item = 0;
1658 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1661 boost::shared_ptr<Track> tr;
1662 boost::shared_ptr<Playlist> pl;
1664 if ((tr = rtv->track())) {
1665 add_region_context_items (edit_items, tr);
1669 add_dstream_context_items (edit_items);
1671 return &track_region_context_menu;
1675 Editor::analyze_region_selection ()
1677 if (analysis_window == 0) {
1678 analysis_window = new AnalysisWindow();
1681 analysis_window->set_session(_session);
1683 analysis_window->show_all();
1686 analysis_window->set_regionmode();
1687 analysis_window->analyze();
1689 analysis_window->present();
1693 Editor::analyze_range_selection()
1695 if (analysis_window == 0) {
1696 analysis_window = new AnalysisWindow();
1699 analysis_window->set_session(_session);
1701 analysis_window->show_all();
1704 analysis_window->set_rangemode();
1705 analysis_window->analyze();
1707 analysis_window->present();
1711 Editor::build_track_selection_context_menu ()
1713 using namespace Menu_Helpers;
1714 MenuList& edit_items = track_selection_context_menu.items();
1715 edit_items.clear ();
1717 add_selection_context_items (edit_items);
1718 // edit_items.push_back (SeparatorElem());
1719 // add_dstream_context_items (edit_items);
1721 return &track_selection_context_menu;
1725 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1727 using namespace Menu_Helpers;
1729 /* OK, stick the region submenu at the top of the list, and then add
1733 RegionSelection rs = get_regions_from_selection_and_entered ();
1735 string::size_type pos = 0;
1736 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1738 /* we have to hack up the region name because "_" has a special
1739 meaning for menu titles.
1742 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1743 menu_item_name.replace (pos, 1, "__");
1747 if (_popup_region_menu_item == 0) {
1748 _popup_region_menu_item = new MenuItem (menu_item_name);
1749 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1750 _popup_region_menu_item->show ();
1752 _popup_region_menu_item->set_label (menu_item_name);
1755 const framepos_t position = get_preferred_edit_position (false, true);
1757 edit_items.push_back (*_popup_region_menu_item);
1758 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1759 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1761 edit_items.push_back (SeparatorElem());
1764 /** Add context menu items relevant to selection ranges.
1765 * @param edit_items List to add the items to.
1768 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1770 using namespace Menu_Helpers;
1772 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1773 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1775 edit_items.push_back (SeparatorElem());
1776 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1778 edit_items.push_back (SeparatorElem());
1780 edit_items.push_back (
1782 _("Move Range Start to Previous Region Boundary"),
1783 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1787 edit_items.push_back (
1789 _("Move Range Start to Next Region Boundary"),
1790 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1794 edit_items.push_back (
1796 _("Move Range End to Previous Region Boundary"),
1797 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1801 edit_items.push_back (
1803 _("Move Range End to Next Region Boundary"),
1804 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1808 edit_items.push_back (SeparatorElem());
1809 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1810 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1812 edit_items.push_back (SeparatorElem());
1813 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1815 edit_items.push_back (SeparatorElem());
1816 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1817 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1819 edit_items.push_back (SeparatorElem());
1820 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1822 edit_items.push_back (SeparatorElem());
1823 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1824 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1825 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1827 edit_items.push_back (SeparatorElem());
1828 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1829 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1830 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1831 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1832 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1837 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1839 using namespace Menu_Helpers;
1843 Menu *play_menu = manage (new Menu);
1844 MenuList& play_items = play_menu->items();
1845 play_menu->set_name ("ArdourContextMenu");
1847 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1848 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1849 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1850 play_items.push_back (SeparatorElem());
1851 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1853 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1857 Menu *select_menu = manage (new Menu);
1858 MenuList& select_items = select_menu->items();
1859 select_menu->set_name ("ArdourContextMenu");
1861 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1862 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1863 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1864 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1865 select_items.push_back (SeparatorElem());
1866 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1867 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1868 select_items.push_back (SeparatorElem());
1869 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1870 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1871 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1872 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1873 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1874 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1875 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1877 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1881 Menu *cutnpaste_menu = manage (new Menu);
1882 MenuList& cutnpaste_items = cutnpaste_menu->items();
1883 cutnpaste_menu->set_name ("ArdourContextMenu");
1885 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1886 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1887 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1889 cutnpaste_items.push_back (SeparatorElem());
1891 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1892 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1894 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1896 /* Adding new material */
1898 edit_items.push_back (SeparatorElem());
1899 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1900 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1904 Menu *nudge_menu = manage (new Menu());
1905 MenuList& nudge_items = nudge_menu->items();
1906 nudge_menu->set_name ("ArdourContextMenu");
1908 edit_items.push_back (SeparatorElem());
1909 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1910 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1911 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1912 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1914 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1918 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1920 using namespace Menu_Helpers;
1924 Menu *play_menu = manage (new Menu);
1925 MenuList& play_items = play_menu->items();
1926 play_menu->set_name ("ArdourContextMenu");
1928 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1929 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1930 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1934 Menu *select_menu = manage (new Menu);
1935 MenuList& select_items = select_menu->items();
1936 select_menu->set_name ("ArdourContextMenu");
1938 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1939 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1940 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1941 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1942 select_items.push_back (SeparatorElem());
1943 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1944 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1945 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1946 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1948 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1952 Menu *cutnpaste_menu = manage (new Menu);
1953 MenuList& cutnpaste_items = cutnpaste_menu->items();
1954 cutnpaste_menu->set_name ("ArdourContextMenu");
1956 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1957 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1958 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1960 Menu *nudge_menu = manage (new Menu());
1961 MenuList& nudge_items = nudge_menu->items();
1962 nudge_menu->set_name ("ArdourContextMenu");
1964 edit_items.push_back (SeparatorElem());
1965 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1966 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1967 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1968 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1970 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1974 Editor::snap_type() const
1980 Editor::snap_mode() const
1986 Editor::set_snap_to (SnapType st)
1988 unsigned int snap_ind = (unsigned int)st;
1992 if (snap_ind > snap_type_strings.size() - 1) {
1994 _snap_type = (SnapType)snap_ind;
1997 string str = snap_type_strings[snap_ind];
1999 if (str != snap_type_selector.get_active_text()) {
2000 snap_type_selector.set_active_text (str);
2005 switch (_snap_type) {
2006 case SnapToBeatDiv128:
2007 case SnapToBeatDiv64:
2008 case SnapToBeatDiv32:
2009 case SnapToBeatDiv28:
2010 case SnapToBeatDiv24:
2011 case SnapToBeatDiv20:
2012 case SnapToBeatDiv16:
2013 case SnapToBeatDiv14:
2014 case SnapToBeatDiv12:
2015 case SnapToBeatDiv10:
2016 case SnapToBeatDiv8:
2017 case SnapToBeatDiv7:
2018 case SnapToBeatDiv6:
2019 case SnapToBeatDiv5:
2020 case SnapToBeatDiv4:
2021 case SnapToBeatDiv3:
2022 case SnapToBeatDiv2:
2023 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2024 update_tempo_based_rulers ();
2027 case SnapToRegionStart:
2028 case SnapToRegionEnd:
2029 case SnapToRegionSync:
2030 case SnapToRegionBoundary:
2031 build_region_boundary_cache ();
2039 SnapChanged (); /* EMIT SIGNAL */
2043 Editor::set_snap_mode (SnapMode mode)
2046 string str = snap_mode_strings[(int)mode];
2048 if (str != snap_mode_selector.get_active_text ()) {
2049 snap_mode_selector.set_active_text (str);
2055 Editor::set_edit_point_preference (EditPoint ep, bool force)
2057 bool changed = (_edit_point != ep);
2060 string str = edit_point_strings[(int)ep];
2062 if (str != edit_point_selector.get_active_text ()) {
2063 edit_point_selector.set_active_text (str);
2066 set_canvas_cursor ();
2068 if (!force && !changed) {
2072 const char* action=NULL;
2074 switch (_edit_point) {
2075 case EditAtPlayhead:
2076 action = "edit-at-playhead";
2078 case EditAtSelectedMarker:
2079 action = "edit-at-marker";
2082 action = "edit-at-mouse";
2086 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2088 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2092 bool in_track_canvas;
2094 if (!mouse_frame (foo, in_track_canvas)) {
2095 in_track_canvas = false;
2098 reset_canvas_action_sensitivity (in_track_canvas);
2104 Editor::set_state (const XMLNode& node, int /*version*/)
2106 const XMLProperty* prop;
2113 g.base_width = default_width;
2114 g.base_height = default_height;
2118 if ((geometry = find_named_node (node, "geometry")) != 0) {
2122 if ((prop = geometry->property("x_size")) == 0) {
2123 prop = geometry->property ("x-size");
2126 g.base_width = atoi(prop->value());
2128 if ((prop = geometry->property("y_size")) == 0) {
2129 prop = geometry->property ("y-size");
2132 g.base_height = atoi(prop->value());
2135 if ((prop = geometry->property ("x_pos")) == 0) {
2136 prop = geometry->property ("x-pos");
2139 x = atoi (prop->value());
2142 if ((prop = geometry->property ("y_pos")) == 0) {
2143 prop = geometry->property ("y-pos");
2146 y = atoi (prop->value());
2150 set_default_size (g.base_width, g.base_height);
2153 if (_session && (prop = node.property ("playhead"))) {
2155 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2156 playhead_cursor->set_position (pos);
2158 playhead_cursor->set_position (0);
2161 if ((prop = node.property ("mixer-width"))) {
2162 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2165 if ((prop = node.property ("zoom-focus"))) {
2166 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2169 if ((prop = node.property ("zoom"))) {
2170 reset_zoom (PBD::atof (prop->value()));
2172 reset_zoom (frames_per_unit);
2175 if ((prop = node.property ("snap-to"))) {
2176 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2179 if ((prop = node.property ("snap-mode"))) {
2180 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2183 if ((prop = node.property ("internal-snap-to"))) {
2184 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2187 if ((prop = node.property ("internal-snap-mode"))) {
2188 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2191 if ((prop = node.property ("pre-internal-snap-to"))) {
2192 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2195 if ((prop = node.property ("pre-internal-snap-mode"))) {
2196 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2199 if ((prop = node.property ("mouse-mode"))) {
2200 MouseMode m = str2mousemode(prop->value());
2201 set_mouse_mode (m, true);
2203 set_mouse_mode (MouseObject, true);
2206 if ((prop = node.property ("left-frame")) != 0) {
2208 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2212 reset_x_origin (pos);
2216 if ((prop = node.property ("y-origin")) != 0) {
2217 reset_y_origin (atof (prop->value ()));
2220 if ((prop = node.property ("internal-edit"))) {
2221 bool yn = string_is_affirmative (prop->value());
2222 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2224 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2225 tact->set_active (!yn);
2226 tact->set_active (yn);
2230 if ((prop = node.property ("join-object-range"))) {
2231 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2234 if ((prop = node.property ("edit-point"))) {
2235 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2238 if ((prop = node.property ("show-measures"))) {
2239 bool yn = string_is_affirmative (prop->value());
2240 _show_measures = yn;
2241 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2243 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2244 /* do it twice to force the change */
2245 tact->set_active (!yn);
2246 tact->set_active (yn);
2250 if ((prop = node.property ("follow-playhead"))) {
2251 bool yn = string_is_affirmative (prop->value());
2252 set_follow_playhead (yn);
2253 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2255 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2256 if (tact->get_active() != yn) {
2257 tact->set_active (yn);
2262 if ((prop = node.property ("stationary-playhead"))) {
2263 bool yn = string_is_affirmative (prop->value());
2264 set_stationary_playhead (yn);
2265 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2267 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2268 if (tact->get_active() != yn) {
2269 tact->set_active (yn);
2274 if ((prop = node.property ("region-list-sort-type"))) {
2275 RegionListSortType st;
2276 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2279 if ((prop = node.property ("show-editor-mixer"))) {
2281 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2284 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2285 bool yn = string_is_affirmative (prop->value());
2287 /* do it twice to force the change */
2289 tact->set_active (!yn);
2290 tact->set_active (yn);
2293 if ((prop = node.property ("show-editor-list"))) {
2295 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2298 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2299 bool yn = string_is_affirmative (prop->value());
2301 /* do it twice to force the change */
2303 tact->set_active (!yn);
2304 tact->set_active (yn);
2307 if ((prop = node.property (X_("editor-list-page")))) {
2308 _the_notebook.set_current_page (atoi (prop->value ()));
2311 if ((prop = node.property (X_("show-marker-lines")))) {
2312 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2314 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2315 bool yn = string_is_affirmative (prop->value ());
2317 tact->set_active (!yn);
2318 tact->set_active (yn);
2321 XMLNodeList children = node.children ();
2322 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2323 selection->set_state (**i, Stateful::current_state_version);
2324 _regions->set_state (**i);
2327 if ((prop = node.property ("maximised"))) {
2328 bool yn = string_is_affirmative (prop->value());
2330 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2334 if ((prop = node.property ("nudge-clock-value"))) {
2336 sscanf (prop->value().c_str(), "%" PRId64, &f);
2337 nudge_clock->set (f);
2339 nudge_clock->set_mode (AudioClock::Timecode);
2340 nudge_clock->set (_session->frame_rate() * 5, true);
2347 Editor::get_state ()
2349 XMLNode* node = new XMLNode ("Editor");
2352 id().print (buf, sizeof (buf));
2353 node->add_property ("id", buf);
2355 if (is_realized()) {
2356 Glib::RefPtr<Gdk::Window> win = get_window();
2358 int x, y, width, height;
2359 win->get_root_origin(x, y);
2360 win->get_size(width, height);
2362 XMLNode* geometry = new XMLNode ("geometry");
2364 snprintf(buf, sizeof(buf), "%d", width);
2365 geometry->add_property("x-size", string(buf));
2366 snprintf(buf, sizeof(buf), "%d", height);
2367 geometry->add_property("y-size", string(buf));
2368 snprintf(buf, sizeof(buf), "%d", x);
2369 geometry->add_property("x-pos", string(buf));
2370 snprintf(buf, sizeof(buf), "%d", y);
2371 geometry->add_property("y-pos", string(buf));
2372 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2373 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2374 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2375 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2376 geometry->add_property("edit-vertical-pane-pos", string(buf));
2378 node->add_child_nocopy (*geometry);
2381 maybe_add_mixer_strip_width (*node);
2383 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2384 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2385 node->add_property ("zoom", buf);
2386 node->add_property ("snap-to", enum_2_string (_snap_type));
2387 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2388 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2389 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2390 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2391 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2392 node->add_property ("edit-point", enum_2_string (_edit_point));
2394 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2395 node->add_property ("playhead", buf);
2396 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2397 node->add_property ("left-frame", buf);
2398 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2399 node->add_property ("y-origin", buf);
2401 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2402 node->add_property ("maximised", _maximised ? "yes" : "no");
2403 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2404 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2405 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2406 node->add_property ("mouse-mode", enum2str(mouse_mode));
2407 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2408 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2410 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2412 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2413 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2416 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2418 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2419 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2422 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2423 node->add_property (X_("editor-list-page"), buf);
2425 if (button_bindings) {
2426 XMLNode* bb = new XMLNode (X_("Buttons"));
2427 button_bindings->save (*bb);
2428 node->add_child_nocopy (*bb);
2431 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2433 node->add_child_nocopy (selection->get_state ());
2434 node->add_child_nocopy (_regions->get_state ());
2436 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2437 node->add_property ("nudge-clock-value", buf);
2444 /** @param y y offset from the top of all trackviews.
2445 * @return pair: TimeAxisView that y is over, layer index.
2446 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2447 * in stacked or expanded region display mode, otherwise 0.
2449 std::pair<TimeAxisView *, double>
2450 Editor::trackview_by_y_position (double y)
2452 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2454 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2460 return std::make_pair ( (TimeAxisView *) 0, 0);
2463 /** Snap a position to the grid, if appropriate, taking into account current
2464 * grid settings and also the state of any snap modifier keys that may be pressed.
2465 * @param start Position to snap.
2466 * @param event Event to get current key modifier information from, or 0.
2469 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2471 if (!_session || !event) {
2475 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2476 if (_snap_mode == SnapOff) {
2477 snap_to_internal (start, direction, for_mark);
2480 if (_snap_mode != SnapOff) {
2481 snap_to_internal (start, direction, for_mark);
2487 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2489 if (!_session || _snap_mode == SnapOff) {
2493 snap_to_internal (start, direction, for_mark);
2497 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2499 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2500 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2502 switch (_snap_type) {
2503 case SnapToTimecodeFrame:
2504 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2505 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2507 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2511 case SnapToTimecodeSeconds:
2512 if (_session->config.get_timecode_offset_negative()) {
2513 start += _session->config.get_timecode_offset ();
2515 start -= _session->config.get_timecode_offset ();
2517 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2518 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2520 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2523 if (_session->config.get_timecode_offset_negative()) {
2524 start -= _session->config.get_timecode_offset ();
2526 start += _session->config.get_timecode_offset ();
2530 case SnapToTimecodeMinutes:
2531 if (_session->config.get_timecode_offset_negative()) {
2532 start += _session->config.get_timecode_offset ();
2534 start -= _session->config.get_timecode_offset ();
2536 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2537 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2539 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2541 if (_session->config.get_timecode_offset_negative()) {
2542 start -= _session->config.get_timecode_offset ();
2544 start += _session->config.get_timecode_offset ();
2548 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2554 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2556 const framepos_t one_second = _session->frame_rate();
2557 const framepos_t one_minute = _session->frame_rate() * 60;
2558 framepos_t presnap = start;
2562 switch (_snap_type) {
2563 case SnapToTimecodeFrame:
2564 case SnapToTimecodeSeconds:
2565 case SnapToTimecodeMinutes:
2566 return timecode_snap_to_internal (start, direction, for_mark);
2569 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2570 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2572 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2577 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2578 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2580 start = (framepos_t) floor ((double) start / one_second) * one_second;
2585 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2586 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2588 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2593 start = _session->tempo_map().round_to_bar (start, direction);
2597 start = _session->tempo_map().round_to_beat (start, direction);
2600 case SnapToBeatDiv128:
2601 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2603 case SnapToBeatDiv64:
2604 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2606 case SnapToBeatDiv32:
2607 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2609 case SnapToBeatDiv28:
2610 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2612 case SnapToBeatDiv24:
2613 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2615 case SnapToBeatDiv20:
2616 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2618 case SnapToBeatDiv16:
2619 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2621 case SnapToBeatDiv14:
2622 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2624 case SnapToBeatDiv12:
2625 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2627 case SnapToBeatDiv10:
2628 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2630 case SnapToBeatDiv8:
2631 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2633 case SnapToBeatDiv7:
2634 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2636 case SnapToBeatDiv6:
2637 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2639 case SnapToBeatDiv5:
2640 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2642 case SnapToBeatDiv4:
2643 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2645 case SnapToBeatDiv3:
2646 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2648 case SnapToBeatDiv2:
2649 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2657 _session->locations()->marks_either_side (start, before, after);
2659 if (before == max_framepos) {
2661 } else if (after == max_framepos) {
2663 } else if (before != max_framepos && after != max_framepos) {
2664 /* have before and after */
2665 if ((start - before) < (after - start)) {
2674 case SnapToRegionStart:
2675 case SnapToRegionEnd:
2676 case SnapToRegionSync:
2677 case SnapToRegionBoundary:
2678 if (!region_boundary_cache.empty()) {
2680 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2681 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2683 if (direction > 0) {
2684 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2686 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2689 if (next != region_boundary_cache.begin ()) {
2694 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2695 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2697 if (start > (p + n) / 2) {
2706 switch (_snap_mode) {
2712 if (presnap > start) {
2713 if (presnap > (start + unit_to_frame(snap_threshold))) {
2717 } else if (presnap < start) {
2718 if (presnap < (start - unit_to_frame(snap_threshold))) {
2724 /* handled at entry */
2732 Editor::setup_toolbar ()
2734 HBox* mode_box = manage(new HBox);
2735 mode_box->set_border_width (2);
2736 mode_box->set_spacing(4);
2738 HBox* mouse_mode_box = manage (new HBox);
2739 HBox* mouse_mode_hbox1 = manage (new HBox);
2740 HBox* mouse_mode_hbox2 = manage (new HBox);
2741 VBox* mouse_mode_vbox1 = manage (new VBox);
2742 VBox* mouse_mode_vbox2 = manage (new VBox);
2743 Alignment* mouse_mode_align1 = manage (new Alignment);
2744 Alignment* mouse_mode_align2 = manage (new Alignment);
2746 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2747 mouse_mode_size_group->add_widget (mouse_move_button);
2748 mouse_mode_size_group->add_widget (mouse_select_button);
2749 mouse_mode_size_group->add_widget (mouse_zoom_button);
2750 mouse_mode_size_group->add_widget (mouse_gain_button);
2751 mouse_mode_size_group->add_widget (mouse_timefx_button);
2752 mouse_mode_size_group->add_widget (mouse_audition_button);
2753 mouse_mode_size_group->add_widget (mouse_draw_button);
2754 mouse_mode_size_group->add_widget (internal_edit_button);
2756 /* make them just a bit bigger */
2757 mouse_move_button.set_size_request (-1, 25);
2759 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2760 smart_mode_joiner->set_related_action (smart_mode_action);
2762 mouse_mode_hbox2->set_spacing (2);
2763 mouse_mode_box->set_spacing (2);
2765 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2766 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2767 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2768 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2769 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2770 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2771 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2773 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2774 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2776 mouse_mode_align1->add (*mouse_mode_vbox1);
2777 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2778 mouse_mode_align2->add (*mouse_mode_vbox2);
2779 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2781 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2782 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2784 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2785 if (!Profile->get_sae()) {
2786 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2788 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2790 edit_mode_selector.set_name ("EditModeSelector");
2791 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2792 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2794 mode_box->pack_start (edit_mode_selector, false, false);
2795 mode_box->pack_start (*mouse_mode_box, false, false);
2797 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2798 _mouse_mode_tearoff->set_name ("MouseModeBase");
2799 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2801 if (Profile->get_sae()) {
2802 _mouse_mode_tearoff->set_can_be_torn_off (false);
2805 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2806 &_mouse_mode_tearoff->tearoff_window()));
2807 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2808 &_mouse_mode_tearoff->tearoff_window(), 1));
2809 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2810 &_mouse_mode_tearoff->tearoff_window()));
2811 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2812 &_mouse_mode_tearoff->tearoff_window(), 1));
2816 _zoom_box.set_spacing (2);
2817 _zoom_box.set_border_width (2);
2821 zoom_in_button.set_name ("zoom button");
2822 zoom_in_button.set_image (::get_icon ("zoom_in"));
2823 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2824 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2825 zoom_in_button.set_related_action (act);
2827 zoom_out_button.set_name ("zoom button");
2828 zoom_out_button.set_image (::get_icon ("zoom_out"));
2829 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2830 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2831 zoom_out_button.set_related_action (act);
2833 zoom_out_full_button.set_name ("zoom button");
2834 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2835 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2836 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2837 zoom_out_full_button.set_related_action (act);
2839 zoom_focus_selector.set_name ("ZoomFocusSelector");
2840 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2841 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2843 _zoom_box.pack_start (zoom_out_button, false, false);
2844 _zoom_box.pack_start (zoom_in_button, false, false);
2845 _zoom_box.pack_start (zoom_out_full_button, false, false);
2847 _zoom_box.pack_start (zoom_focus_selector, false, false);
2849 /* Track zoom buttons */
2850 tav_expand_button.set_name ("TrackHeightButton");
2851 tav_expand_button.set_size_request (-1, 20);
2852 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2853 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2854 act->connect_proxy (tav_expand_button);
2856 tav_shrink_button.set_name ("TrackHeightButton");
2857 tav_shrink_button.set_size_request (-1, 20);
2858 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2859 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2860 act->connect_proxy (tav_shrink_button);
2862 _zoom_box.pack_start (tav_shrink_button);
2863 _zoom_box.pack_start (tav_expand_button);
2865 _zoom_tearoff = manage (new TearOff (_zoom_box));
2867 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2868 &_zoom_tearoff->tearoff_window()));
2869 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2870 &_zoom_tearoff->tearoff_window(), 0));
2871 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2872 &_zoom_tearoff->tearoff_window()));
2873 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2874 &_zoom_tearoff->tearoff_window(), 0));
2876 snap_box.set_spacing (1);
2877 snap_box.set_border_width (2);
2879 snap_type_selector.set_name ("SnapTypeSelector");
2880 set_popdown_strings (snap_type_selector, snap_type_strings);
2881 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2883 snap_mode_selector.set_name ("SnapModeSelector");
2884 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2885 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2887 edit_point_selector.set_name ("EditPointSelector");
2888 set_popdown_strings (edit_point_selector, edit_point_strings);
2889 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2891 snap_box.pack_start (snap_mode_selector, false, false);
2892 snap_box.pack_start (snap_type_selector, false, false);
2893 snap_box.pack_start (edit_point_selector, false, false);
2897 HBox *nudge_box = manage (new HBox);
2898 nudge_box->set_spacing (2);
2899 nudge_box->set_border_width (2);
2901 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2902 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2904 nudge_box->pack_start (nudge_backward_button, false, false);
2905 nudge_box->pack_start (nudge_forward_button, false, false);
2906 nudge_box->pack_start (*nudge_clock, false, false);
2909 /* Pack everything in... */
2911 HBox* hbox = manage (new HBox);
2912 hbox->set_spacing(10);
2914 _tools_tearoff = manage (new TearOff (*hbox));
2915 _tools_tearoff->set_name ("MouseModeBase");
2916 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2918 if (Profile->get_sae()) {
2919 _tools_tearoff->set_can_be_torn_off (false);
2922 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2923 &_tools_tearoff->tearoff_window()));
2924 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2925 &_tools_tearoff->tearoff_window(), 0));
2926 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2927 &_tools_tearoff->tearoff_window()));
2928 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2929 &_tools_tearoff->tearoff_window(), 0));
2931 toolbar_hbox.set_spacing (10);
2932 toolbar_hbox.set_border_width (1);
2934 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2935 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2936 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2938 hbox->pack_start (snap_box, false, false);
2939 if (!Profile->get_small_screen()) {
2940 hbox->pack_start (*nudge_box, false, false);
2942 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2944 hbox->pack_start (panic_box, false, false);
2948 toolbar_base.set_name ("ToolBarBase");
2949 toolbar_base.add (toolbar_hbox);
2951 _toolbar_viewport.add (toolbar_base);
2952 /* stick to the required height but allow width to vary if there's not enough room */
2953 _toolbar_viewport.set_size_request (1, -1);
2955 toolbar_frame.set_shadow_type (SHADOW_OUT);
2956 toolbar_frame.set_name ("BaseFrame");
2957 toolbar_frame.add (_toolbar_viewport);
2961 Editor::setup_tooltips ()
2963 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2964 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
2965 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
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 (smart_mode_joiner, _("Smart Mode (Select/Move Objects + 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"));
2985 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
2989 Editor::convert_drop_to_paths (
2990 vector<string>& paths,
2991 const RefPtr<Gdk::DragContext>& /*context*/,
2994 const SelectionData& data,
2998 if (_session == 0) {
3002 vector<string> uris = data.get_uris();
3006 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3007 are actually URI lists. So do it by hand.
3010 if (data.get_target() != "text/plain") {
3014 /* Parse the "uri-list" format that Nautilus provides,
3015 where each pathname is delimited by \r\n.
3017 THERE MAY BE NO NULL TERMINATING CHAR!!!
3020 string txt = data.get_text();
3024 p = (const char *) malloc (txt.length() + 1);
3025 txt.copy ((char *) p, txt.length(), 0);
3026 ((char*)p)[txt.length()] = '\0';
3032 while (g_ascii_isspace (*p))
3036 while (*q && (*q != '\n') && (*q != '\r')) {
3043 while (q > p && g_ascii_isspace (*q))
3048 uris.push_back (string (p, q - p + 1));
3052 p = strchr (p, '\n');
3064 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3066 if ((*i).substr (0,7) == "file://") {
3068 string const p = PBD::url_decode (*i);
3070 // scan forward past three slashes
3072 string::size_type slashcnt = 0;
3073 string::size_type n = 0;
3074 string::const_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);
3119 Editor::begin_reversible_command (string name)
3122 _session->begin_reversible_command (name);
3127 Editor::begin_reversible_command (GQuark q)
3130 _session->begin_reversible_command (q);
3135 Editor::commit_reversible_command ()
3138 _session->commit_reversible_command ();
3143 Editor::history_changed ()
3147 if (undo_action && _session) {
3148 if (_session->undo_depth() == 0) {
3149 label = S_("Command|Undo");
3151 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3153 undo_action->property_label() = label;
3156 if (redo_action && _session) {
3157 if (_session->redo_depth() == 0) {
3160 label = string_compose(_("Redo (%1)"), _session->next_redo());
3162 redo_action->property_label() = label;
3167 Editor::duplicate_dialog (bool with_dialog)
3171 if (mouse_mode == MouseRange) {
3172 if (selection->time.length() == 0) {
3177 RegionSelection rs = get_regions_from_selection_and_entered ();
3179 if (mouse_mode != MouseRange && rs.empty()) {
3185 ArdourDialog win (_("Duplicate"));
3186 Label label (_("Number of duplications:"));
3187 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3188 SpinButton spinner (adjustment, 0.0, 1);
3191 win.get_vbox()->set_spacing (12);
3192 win.get_vbox()->pack_start (hbox);
3193 hbox.set_border_width (6);
3194 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3196 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3197 place, visually. so do this by hand.
3200 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3201 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3202 spinner.grab_focus();
3208 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3209 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3210 win.set_default_response (RESPONSE_ACCEPT);
3212 win.set_position (WIN_POS_MOUSE);
3214 spinner.grab_focus ();
3216 switch (win.run ()) {
3217 case RESPONSE_ACCEPT:
3223 times = adjustment.get_value();
3226 if (mouse_mode == MouseRange) {
3227 duplicate_selection (times);
3229 duplicate_some_regions (rs, times);
3234 Editor::set_edit_mode (EditMode m)
3236 Config->set_edit_mode (m);
3240 Editor::cycle_edit_mode ()
3242 switch (Config->get_edit_mode()) {
3244 if (Profile->get_sae()) {
3245 Config->set_edit_mode (Lock);
3247 Config->set_edit_mode (Splice);
3251 Config->set_edit_mode (Lock);
3254 Config->set_edit_mode (Slide);
3260 Editor::edit_mode_selection_done ()
3262 string s = edit_mode_selector.get_active_text ();
3265 Config->set_edit_mode (string_to_edit_mode (s));
3270 Editor::snap_type_selection_done ()
3272 string choice = snap_type_selector.get_active_text();
3273 SnapType snaptype = SnapToBeat;
3275 if (choice == _("Beats/2")) {
3276 snaptype = SnapToBeatDiv2;
3277 } else if (choice == _("Beats/3")) {
3278 snaptype = SnapToBeatDiv3;
3279 } else if (choice == _("Beats/4")) {
3280 snaptype = SnapToBeatDiv4;
3281 } else if (choice == _("Beats/5")) {
3282 snaptype = SnapToBeatDiv5;
3283 } else if (choice == _("Beats/6")) {
3284 snaptype = SnapToBeatDiv6;
3285 } else if (choice == _("Beats/7")) {
3286 snaptype = SnapToBeatDiv7;
3287 } else if (choice == _("Beats/8")) {
3288 snaptype = SnapToBeatDiv8;
3289 } else if (choice == _("Beats/10")) {
3290 snaptype = SnapToBeatDiv10;
3291 } else if (choice == _("Beats/12")) {
3292 snaptype = SnapToBeatDiv12;
3293 } else if (choice == _("Beats/14")) {
3294 snaptype = SnapToBeatDiv14;
3295 } else if (choice == _("Beats/16")) {
3296 snaptype = SnapToBeatDiv16;
3297 } else if (choice == _("Beats/20")) {
3298 snaptype = SnapToBeatDiv20;
3299 } else if (choice == _("Beats/24")) {
3300 snaptype = SnapToBeatDiv24;
3301 } else if (choice == _("Beats/28")) {
3302 snaptype = SnapToBeatDiv28;
3303 } else if (choice == _("Beats/32")) {
3304 snaptype = SnapToBeatDiv32;
3305 } else if (choice == _("Beats/64")) {
3306 snaptype = SnapToBeatDiv64;
3307 } else if (choice == _("Beats/128")) {
3308 snaptype = SnapToBeatDiv128;
3309 } else if (choice == _("Beats")) {
3310 snaptype = SnapToBeat;
3311 } else if (choice == _("Bars")) {
3312 snaptype = SnapToBar;
3313 } else if (choice == _("Marks")) {
3314 snaptype = SnapToMark;
3315 } else if (choice == _("Region starts")) {
3316 snaptype = SnapToRegionStart;
3317 } else if (choice == _("Region ends")) {
3318 snaptype = SnapToRegionEnd;
3319 } else if (choice == _("Region bounds")) {
3320 snaptype = SnapToRegionBoundary;
3321 } else if (choice == _("Region syncs")) {
3322 snaptype = SnapToRegionSync;
3323 } else if (choice == _("CD Frames")) {
3324 snaptype = SnapToCDFrame;
3325 } else if (choice == _("Timecode Frames")) {
3326 snaptype = SnapToTimecodeFrame;
3327 } else if (choice == _("Timecode Seconds")) {
3328 snaptype = SnapToTimecodeSeconds;
3329 } else if (choice == _("Timecode Minutes")) {
3330 snaptype = SnapToTimecodeMinutes;
3331 } else if (choice == _("Seconds")) {
3332 snaptype = SnapToSeconds;
3333 } else if (choice == _("Minutes")) {
3334 snaptype = SnapToMinutes;
3337 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3339 ract->set_active ();
3344 Editor::snap_mode_selection_done ()
3346 string choice = snap_mode_selector.get_active_text();
3347 SnapMode mode = SnapNormal;
3349 if (choice == _("No Grid")) {
3351 } else if (choice == _("Grid")) {
3353 } else if (choice == _("Magnetic")) {
3354 mode = SnapMagnetic;
3357 RefPtr<RadioAction> ract = snap_mode_action (mode);
3360 ract->set_active (true);
3365 Editor::cycle_edit_point (bool with_marker)
3367 switch (_edit_point) {
3369 set_edit_point_preference (EditAtPlayhead);
3371 case EditAtPlayhead:
3373 set_edit_point_preference (EditAtSelectedMarker);
3375 set_edit_point_preference (EditAtMouse);
3378 case EditAtSelectedMarker:
3379 set_edit_point_preference (EditAtMouse);
3385 Editor::edit_point_selection_done ()
3387 string choice = edit_point_selector.get_active_text();
3388 EditPoint ep = EditAtSelectedMarker;
3390 if (choice == _("Marker")) {
3391 set_edit_point_preference (EditAtSelectedMarker);
3392 } else if (choice == _("Playhead")) {
3393 set_edit_point_preference (EditAtPlayhead);
3395 set_edit_point_preference (EditAtMouse);
3398 RefPtr<RadioAction> ract = edit_point_action (ep);
3401 ract->set_active (true);
3406 Editor::zoom_focus_selection_done ()
3408 string choice = zoom_focus_selector.get_active_text();
3409 ZoomFocus focus_type = ZoomFocusLeft;
3411 if (choice == _("Left")) {
3412 focus_type = ZoomFocusLeft;
3413 } else if (choice == _("Right")) {
3414 focus_type = ZoomFocusRight;
3415 } else if (choice == _("Center")) {
3416 focus_type = ZoomFocusCenter;
3417 } else if (choice == _("Playhead")) {
3418 focus_type = ZoomFocusPlayhead;
3419 } else if (choice == _("Mouse")) {
3420 focus_type = ZoomFocusMouse;
3421 } else if (choice == _("Edit point")) {
3422 focus_type = ZoomFocusEdit;
3425 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3428 ract->set_active ();
3433 Editor::edit_controls_button_release (GdkEventButton* ev)
3435 if (Keyboard::is_context_menu_event (ev)) {
3436 ARDOUR_UI::instance()->add_route (this);
3437 } else if (ev->button == 1) {
3438 selection->clear_tracks ();
3445 Editor::mouse_select_button_release (GdkEventButton* ev)
3447 /* this handles just right-clicks */
3449 if (ev->button != 3) {
3457 Editor::set_zoom_focus (ZoomFocus f)
3459 string str = zoom_focus_strings[(int)f];
3461 if (str != zoom_focus_selector.get_active_text()) {
3462 zoom_focus_selector.set_active_text (str);
3465 if (zoom_focus != f) {
3472 Editor::ensure_float (Window& win)
3474 win.set_transient_for (*this);
3478 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3480 /* recover or initialize pane positions. do this here rather than earlier because
3481 we don't want the positions to change the child allocations, which they seem to do.
3487 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3496 XMLNode* geometry = find_named_node (*node, "geometry");
3498 if (which == static_cast<Paned*> (&edit_pane)) {
3500 if (done & Horizontal) {
3504 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3505 _notebook_shrunk = string_is_affirmative (prop->value ());
3508 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3509 /* initial allocation is 90% to canvas, 10% to notebook */
3510 pos = (int) floor (alloc.get_width() * 0.90f);
3511 snprintf (buf, sizeof(buf), "%d", pos);
3513 pos = atoi (prop->value());
3516 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3517 edit_pane.set_position (pos);
3520 done = (Pane) (done | Horizontal);
3522 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3524 if (done & Vertical) {
3528 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3529 /* initial allocation is 90% to canvas, 10% to summary */
3530 pos = (int) floor (alloc.get_height() * 0.90f);
3531 snprintf (buf, sizeof(buf), "%d", pos);
3534 pos = atoi (prop->value());
3537 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3538 editor_summary_pane.set_position (pos);
3541 done = (Pane) (done | Vertical);
3546 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3548 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3549 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3550 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3551 top_hbox.remove (toolbar_frame);
3556 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3558 if (toolbar_frame.get_parent() == 0) {
3559 top_hbox.pack_end (toolbar_frame);
3564 Editor::set_show_measures (bool yn)
3566 if (_show_measures != yn) {
3569 if ((_show_measures = yn) == true) {
3571 tempo_lines->show();
3579 Editor::toggle_follow_playhead ()
3581 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3583 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3584 set_follow_playhead (tact->get_active());
3588 /** @param yn true to follow playhead, otherwise false.
3589 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3592 Editor::set_follow_playhead (bool yn, bool catch_up)
3594 if (_follow_playhead != yn) {
3595 if ((_follow_playhead = yn) == true && catch_up) {
3597 reset_x_origin_to_follow_playhead ();
3604 Editor::toggle_stationary_playhead ()
3606 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3608 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3609 set_stationary_playhead (tact->get_active());
3614 Editor::set_stationary_playhead (bool yn)
3616 if (_stationary_playhead != yn) {
3617 if ((_stationary_playhead = yn) == true) {
3619 // FIXME need a 3.0 equivalent of this 2.X call
3620 // update_current_screen ();
3627 Editor::playlist_selector () const
3629 return *_playlist_selector;
3633 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3637 switch (_snap_type) {
3642 case SnapToBeatDiv128:
3645 case SnapToBeatDiv64:
3648 case SnapToBeatDiv32:
3651 case SnapToBeatDiv28:
3654 case SnapToBeatDiv24:
3657 case SnapToBeatDiv20:
3660 case SnapToBeatDiv16:
3663 case SnapToBeatDiv14:
3666 case SnapToBeatDiv12:
3669 case SnapToBeatDiv10:
3672 case SnapToBeatDiv8:
3675 case SnapToBeatDiv7:
3678 case SnapToBeatDiv6:
3681 case SnapToBeatDiv5:
3684 case SnapToBeatDiv4:
3687 case SnapToBeatDiv3:
3690 case SnapToBeatDiv2:
3696 return _session->tempo_map().meter_at (position).divisions_per_bar();
3701 case SnapToTimecodeFrame:
3702 case SnapToTimecodeSeconds:
3703 case SnapToTimecodeMinutes:
3706 case SnapToRegionStart:
3707 case SnapToRegionEnd:
3708 case SnapToRegionSync:
3709 case SnapToRegionBoundary:
3719 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3723 ret = nudge_clock->current_duration (pos);
3724 next = ret + 1; /* XXXX fix me */
3730 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3732 ArdourDialog dialog (_("Playlist Deletion"));
3733 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3734 "If it is kept, its audio files will not be cleaned.\n"
3735 "If it is deleted, audio files used by it alone will be cleaned."),
3738 dialog.set_position (WIN_POS_CENTER);
3739 dialog.get_vbox()->pack_start (label);
3743 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3744 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3745 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3747 switch (dialog.run ()) {
3748 case RESPONSE_ACCEPT:
3749 /* delete the playlist */
3753 case RESPONSE_REJECT:
3754 /* keep the playlist */
3766 Editor::audio_region_selection_covers (framepos_t where)
3768 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3769 if ((*a)->region()->covers (where)) {
3778 Editor::prepare_for_cleanup ()
3780 cut_buffer->clear_regions ();
3781 cut_buffer->clear_playlists ();
3783 selection->clear_regions ();
3784 selection->clear_playlists ();
3786 _regions->suspend_redisplay ();
3790 Editor::finish_cleanup ()
3792 _regions->resume_redisplay ();
3796 Editor::transport_loop_location()
3799 return _session->locations()->auto_loop_location();
3806 Editor::transport_punch_location()
3809 return _session->locations()->auto_punch_location();
3816 Editor::control_layout_scroll (GdkEventScroll* ev)
3818 if (Keyboard::some_magic_widget_has_focus()) {
3822 switch (ev->direction) {
3824 scroll_tracks_up_line ();
3828 case GDK_SCROLL_DOWN:
3829 scroll_tracks_down_line ();
3833 /* no left/right handling yet */
3841 Editor::session_state_saved (string)
3844 _snapshots->redisplay ();
3848 Editor::maximise_editing_space ()
3856 if (!Config->get_keep_tearoffs()) {
3857 /* these calls will leave each tearoff visible *if* it is torn off,
3858 but invisible otherwise.
3860 _mouse_mode_tearoff->set_visible (false);
3861 _tools_tearoff->set_visible (false);
3862 _zoom_tearoff->set_visible (false);
3869 Editor::restore_editing_space ()
3877 if (!Config->get_keep_tearoffs()) {
3878 _mouse_mode_tearoff->set_visible (true);
3879 _tools_tearoff->set_visible (true);
3880 _zoom_tearoff->set_visible (true);
3887 * Make new playlists for a given track and also any others that belong
3888 * to the same active route group with the `edit' property.
3893 Editor::new_playlists (TimeAxisView* v)
3895 begin_reversible_command (_("new playlists"));
3896 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3897 _session->playlists->get (playlists);
3898 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3899 commit_reversible_command ();
3903 * Use a copy of the current playlist for a given track and also any others that belong
3904 * to the same active route group with the `edit' property.
3909 Editor::copy_playlists (TimeAxisView* v)
3911 begin_reversible_command (_("copy playlists"));
3912 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3913 _session->playlists->get (playlists);
3914 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3915 commit_reversible_command ();
3918 /** Clear the current playlist for a given track and also any others that belong
3919 * to the same active route group with the `edit' property.
3924 Editor::clear_playlists (TimeAxisView* v)
3926 begin_reversible_command (_("clear playlists"));
3927 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3928 _session->playlists->get (playlists);
3929 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
3930 commit_reversible_command ();
3934 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3936 atv.use_new_playlist (sz > 1 ? false : true, playlists);
3940 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3942 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
3946 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
3948 atv.clear_playlist ();
3952 Editor::on_key_press_event (GdkEventKey* ev)
3954 return key_press_focus_accelerator_handler (*this, ev);
3958 Editor::on_key_release_event (GdkEventKey* ev)
3960 return Gtk::Window::on_key_release_event (ev);
3961 // return key_press_focus_accelerator_handler (*this, ev);
3964 /** Queue up a change to the viewport x origin.
3965 * @param frame New x origin.
3968 Editor::reset_x_origin (framepos_t frame)
3970 queue_visual_change (frame);
3974 Editor::reset_y_origin (double y)
3976 queue_visual_change_y (y);
3980 Editor::reset_zoom (double fpu)
3982 queue_visual_change (fpu);
3986 Editor::reposition_and_zoom (framepos_t frame, double fpu)
3988 reset_x_origin (frame);
3991 if (!no_save_visual) {
3992 undo_visual_stack.push_back (current_visual_state(false));
3996 Editor::VisualState::VisualState (bool with_tracks)
3997 : gui_state (with_tracks ? new GUIObjectState : 0)
4001 Editor::VisualState::~VisualState ()
4006 Editor::VisualState*
4007 Editor::current_visual_state (bool with_tracks)
4009 VisualState* vs = new VisualState (with_tracks);
4010 vs->y_position = vertical_adjustment.get_value();
4011 vs->frames_per_unit = frames_per_unit;
4012 vs->leftmost_frame = leftmost_frame;
4013 vs->zoom_focus = zoom_focus;
4016 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4023 Editor::undo_visual_state ()
4025 if (undo_visual_stack.empty()) {
4029 VisualState* vs = undo_visual_stack.back();
4030 undo_visual_stack.pop_back();
4033 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4035 use_visual_state (*vs);
4039 Editor::redo_visual_state ()
4041 if (redo_visual_stack.empty()) {
4045 VisualState* vs = redo_visual_stack.back();
4046 redo_visual_stack.pop_back();
4048 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4050 use_visual_state (*vs);
4054 Editor::swap_visual_state ()
4056 if (undo_visual_stack.empty()) {
4057 redo_visual_state ();
4059 undo_visual_state ();
4064 Editor::use_visual_state (VisualState& vs)
4066 PBD::Unwinder<bool> nsv (no_save_visual, true);
4068 _routes->suspend_redisplay ();
4070 vertical_adjustment.set_value (vs.y_position);
4072 set_zoom_focus (vs.zoom_focus);
4073 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4076 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4078 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4079 (*i)->reset_visual_state ();
4083 _routes->update_visibility ();
4084 _routes->resume_redisplay ();
4088 Editor::set_frames_per_unit (double fpu)
4090 /* this is the core function that controls the zoom level of the canvas. it is called
4091 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4094 if (fpu == frames_per_unit) {
4103 /* don't allow zooms that fit more than the maximum number
4104 of frames into an 800 pixel wide space.
4107 if (max_framepos / fpu < 800.0) {
4112 tempo_lines->tempo_map_changed();
4114 frames_per_unit = fpu;
4119 Editor::post_zoom ()
4121 // convert fpu to frame count
4123 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4125 if (frames_per_unit != zoom_range_clock->current_duration()) {
4126 zoom_range_clock->set (frames);
4129 bool const showing_time_selection =
4130 mouse_mode == MouseRange ||
4131 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4133 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4134 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4135 (*i)->reshow_selection (selection->time);
4139 ZoomChanged (); /* EMIT_SIGNAL */
4141 //reset_scrolling_region ();
4143 if (playhead_cursor) {
4144 playhead_cursor->set_position (playhead_cursor->current_frame);
4147 refresh_location_display();
4148 _summary->set_overlays_dirty ();
4150 update_marker_labels ();
4156 Editor::queue_visual_change (framepos_t where)
4158 pending_visual_change.add (VisualChange::TimeOrigin);
4159 pending_visual_change.time_origin = where;
4160 ensure_visual_change_idle_handler ();
4164 Editor::queue_visual_change (double fpu)
4166 pending_visual_change.add (VisualChange::ZoomLevel);
4167 pending_visual_change.frames_per_unit = fpu;
4169 ensure_visual_change_idle_handler ();
4173 Editor::queue_visual_change_y (double y)
4175 pending_visual_change.add (VisualChange::YOrigin);
4176 pending_visual_change.y_origin = y;
4178 ensure_visual_change_idle_handler ();
4182 Editor::ensure_visual_change_idle_handler ()
4184 if (pending_visual_change.idle_handler_id < 0) {
4185 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4190 Editor::_idle_visual_changer (void* arg)
4192 return static_cast<Editor*>(arg)->idle_visual_changer ();
4196 Editor::idle_visual_changer ()
4198 VisualChange::Type p = pending_visual_change.pending;
4199 pending_visual_change.pending = (VisualChange::Type) 0;
4201 double const last_time_origin = horizontal_position ();
4203 if (p & VisualChange::ZoomLevel) {
4204 set_frames_per_unit (pending_visual_change.frames_per_unit);
4206 compute_fixed_ruler_scale ();
4207 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4208 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4209 update_tempo_based_rulers ();
4211 if (p & VisualChange::TimeOrigin) {
4212 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4214 if (p & VisualChange::YOrigin) {
4215 vertical_adjustment.set_value (pending_visual_change.y_origin);
4218 if (last_time_origin == horizontal_position ()) {
4219 /* changed signal not emitted */
4220 update_fixed_rulers ();
4221 redisplay_tempo (true);
4224 _summary->set_overlays_dirty ();
4226 pending_visual_change.idle_handler_id = -1;
4227 return 0; /* this is always a one-shot call */
4230 struct EditorOrderTimeAxisSorter {
4231 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4232 return a->order () < b->order ();
4237 Editor::sort_track_selection (TrackViewList& sel)
4239 EditorOrderTimeAxisSorter cmp;
4244 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4247 framepos_t where = 0;
4248 EditPoint ep = _edit_point;
4250 if (from_context_menu && (ep == EditAtMouse)) {
4251 return event_frame (&context_click_event, 0, 0);
4254 if (entered_marker) {
4255 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4256 return entered_marker->position();
4259 if (ignore_playhead && ep == EditAtPlayhead) {
4260 ep = EditAtSelectedMarker;
4264 case EditAtPlayhead:
4265 where = _session->audible_frame();
4266 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4269 case EditAtSelectedMarker:
4270 if (!selection->markers.empty()) {
4272 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4275 where = loc->start();
4279 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4287 if (!mouse_frame (where, ignored)) {
4288 /* XXX not right but what can we do ? */
4292 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4300 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4302 if (!_session) return;
4304 begin_reversible_command (cmd);
4308 if ((tll = transport_loop_location()) == 0) {
4309 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4310 XMLNode &before = _session->locations()->get_state();
4311 _session->locations()->add (loc, true);
4312 _session->set_auto_loop_location (loc);
4313 XMLNode &after = _session->locations()->get_state();
4314 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4316 XMLNode &before = tll->get_state();
4317 tll->set_hidden (false, this);
4318 tll->set (start, end);
4319 XMLNode &after = tll->get_state();
4320 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4323 commit_reversible_command ();
4327 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4329 if (!_session) return;
4331 begin_reversible_command (cmd);
4335 if ((tpl = transport_punch_location()) == 0) {
4336 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4337 XMLNode &before = _session->locations()->get_state();
4338 _session->locations()->add (loc, true);
4339 _session->set_auto_loop_location (loc);
4340 XMLNode &after = _session->locations()->get_state();
4341 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4344 XMLNode &before = tpl->get_state();
4345 tpl->set_hidden (false, this);
4346 tpl->set (start, end);
4347 XMLNode &after = tpl->get_state();
4348 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4351 commit_reversible_command ();
4354 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4355 * @param rs List to which found regions are added.
4356 * @param where Time to look at.
4357 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4360 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4362 const TrackViewList* tracks;
4365 tracks = &track_views;
4370 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4372 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4375 boost::shared_ptr<Track> tr;
4376 boost::shared_ptr<Playlist> pl;
4378 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4380 boost::shared_ptr<RegionList> regions = pl->regions_at (
4381 (framepos_t) floor ( (double) where * tr->speed()));
4383 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4384 RegionView* rv = rtv->view()->find_view (*i);
4395 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4397 const TrackViewList* tracks;
4400 tracks = &track_views;
4405 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4406 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4408 boost::shared_ptr<Track> tr;
4409 boost::shared_ptr<Playlist> pl;
4411 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4413 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4414 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4416 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4418 RegionView* rv = rtv->view()->find_view (*i);
4429 /** Start with regions that are selected. Then add equivalent regions
4430 * on tracks in the same active edit-enabled route group as any of
4431 * the regions that we started with.
4435 Editor::get_regions_from_selection ()
4437 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4440 /** Get regions using the following method:
4442 * Make an initial region list using the selected regions, unless
4443 * the edit point is `mouse' and the mouse is over an unselected
4444 * region. In this case, start with just that region.
4446 * Then, make an initial track list of the tracks that these
4447 * regions are on, and if the edit point is not `mouse', add the
4450 * Look at this track list and add any other tracks that are on the
4451 * same active edit-enabled route group as one of the initial tracks.
4453 * Finally take the initial region list and add any regions that are
4454 * under the edit point on one of the tracks on the track list to get
4455 * the returned region list.
4457 * The rationale here is that the mouse edit point is special in that
4458 * its position describes both a time and a track; the other edit
4459 * modes only describe a time. Hence if the edit point is `mouse' we
4460 * ignore selected tracks, as we assume the user means something by
4461 * pointing at a particular track. Also in this case we take note of
4462 * the region directly under the edit point, as there is always just one
4463 * (rather than possibly several with non-mouse edit points).
4467 Editor::get_regions_from_selection_and_edit_point ()
4469 RegionSelection regions;
4471 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4472 regions.add (entered_regionview);
4474 regions = selection->regions;
4477 TrackViewList tracks;
4479 if (_edit_point != EditAtMouse) {
4480 tracks = selection->tracks;
4483 /* Add any other tracks that have regions that are in the same
4484 edit-activated route group as one of our regions.
4486 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4488 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4490 if (g && g->is_active() && g->is_edit()) {
4491 tracks.add (axis_views_from_routes (g->route_list()));
4495 if (!tracks.empty()) {
4496 /* now find regions that are at the edit position on those tracks */
4497 framepos_t const where = get_preferred_edit_position ();
4498 get_regions_at (regions, where, tracks);
4504 /** Start with regions that are selected, or the entered regionview if none are selected.
4505 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4506 * of the regions that we started with.
4510 Editor::get_regions_from_selection_and_entered ()
4512 RegionSelection regions = selection->regions;
4514 if (regions.empty() && entered_regionview) {
4515 regions.add (entered_regionview);
4518 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4522 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4524 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4526 RouteTimeAxisView* tatv;
4528 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4530 boost::shared_ptr<Playlist> pl;
4531 vector<boost::shared_ptr<Region> > results;
4533 boost::shared_ptr<Track> tr;
4535 if ((tr = tatv->track()) == 0) {
4540 if ((pl = (tr->playlist())) != 0) {
4541 pl->get_region_list_equivalent_regions (region, results);
4544 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4545 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4546 regions.push_back (marv);
4555 Editor::show_rhythm_ferret ()
4557 if (rhythm_ferret == 0) {
4558 rhythm_ferret = new RhythmFerret(*this);
4561 rhythm_ferret->set_session (_session);
4562 rhythm_ferret->show ();
4563 rhythm_ferret->present ();
4567 Editor::first_idle ()
4569 MessageDialog* dialog = 0;
4571 if (track_views.size() > 1) {
4572 dialog = new MessageDialog (
4574 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4578 ARDOUR_UI::instance()->flush_pending ();
4581 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4585 // first idle adds route children (automation tracks), so we need to redisplay here
4586 _routes->redisplay ();
4593 Editor::_idle_resize (gpointer arg)
4595 return ((Editor*)arg)->idle_resize ();
4599 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4601 if (resize_idle_id < 0) {
4602 resize_idle_id = g_idle_add (_idle_resize, this);
4603 _pending_resize_amount = 0;
4606 /* make a note of the smallest resulting height, so that we can clamp the
4607 lower limit at TimeAxisView::hSmall */
4609 int32_t min_resulting = INT32_MAX;
4611 _pending_resize_amount += h;
4612 _pending_resize_view = view;
4614 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4616 if (selection->tracks.contains (_pending_resize_view)) {
4617 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4618 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4622 if (min_resulting < 0) {
4627 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4628 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4632 /** Handle pending resizing of tracks */
4634 Editor::idle_resize ()
4636 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4638 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4639 selection->tracks.contains (_pending_resize_view)) {
4641 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4642 if (*i != _pending_resize_view) {
4643 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4648 _pending_resize_amount = 0;
4650 _group_tabs->set_dirty ();
4651 resize_idle_id = -1;
4659 ENSURE_GUI_THREAD (*this, &Editor::located);
4661 playhead_cursor->set_position (_session->audible_frame ());
4662 if (_follow_playhead && !_pending_initial_locate) {
4663 reset_x_origin_to_follow_playhead ();
4666 _pending_locate_request = false;
4667 _pending_initial_locate = false;
4671 Editor::region_view_added (RegionView *)
4673 _summary->set_dirty ();
4677 Editor::region_view_removed ()
4679 _summary->set_dirty ();
4683 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4685 TrackViewList::const_iterator j = track_views.begin ();
4686 while (j != track_views.end()) {
4687 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4688 if (rtv && rtv->route() == r) {
4699 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4703 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4704 TimeAxisView* tv = axis_view_from_route (*i);
4715 Editor::handle_new_route (RouteList& routes)
4717 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4719 RouteTimeAxisView *rtv;
4720 list<RouteTimeAxisView*> new_views;
4722 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4723 boost::shared_ptr<Route> route = (*x);
4725 if (route->is_hidden() || route->is_monitor()) {
4729 DataType dt = route->input()->default_type();
4731 if (dt == ARDOUR::DataType::AUDIO) {
4732 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4733 rtv->set_route (route);
4734 } else if (dt == ARDOUR::DataType::MIDI) {
4735 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4736 rtv->set_route (route);
4738 throw unknown_type();
4741 new_views.push_back (rtv);
4742 track_views.push_back (rtv);
4744 rtv->effective_gain_display ();
4746 if (internal_editing()) {
4747 rtv->enter_internal_edit_mode ();
4749 rtv->leave_internal_edit_mode ();
4752 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4753 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4756 _routes->routes_added (new_views);
4757 _summary->routes_added (new_views);
4759 if (show_editor_mixer_when_tracks_arrive) {
4760 show_editor_mixer (true);
4763 editor_list_button.set_sensitive (true);
4767 Editor::timeaxisview_deleted (TimeAxisView *tv)
4769 if (_session && _session->deletion_in_progress()) {
4770 /* the situation is under control */
4774 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4776 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4778 _routes->route_removed (tv);
4780 if (tv == entered_track) {
4784 TimeAxisView::Children c = tv->get_child_list ();
4785 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4786 if (entered_track == i->get()) {
4791 /* remove it from the list of track views */
4793 TrackViewList::iterator i;
4795 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4796 i = track_views.erase (i);
4799 /* update whatever the current mixer strip is displaying, if revelant */
4801 boost::shared_ptr<Route> route;
4804 route = rtav->route ();
4807 if (current_mixer_strip && current_mixer_strip->route() == route) {
4809 TimeAxisView* next_tv;
4811 if (track_views.empty()) {
4813 } else if (i == track_views.end()) {
4814 next_tv = track_views.front();
4821 set_selected_mixer_strip (*next_tv);
4823 /* make the editor mixer strip go away setting the
4824 * button to inactive (which also unticks the menu option)
4827 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4833 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4835 if (apply_to_selection) {
4836 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4838 TrackSelection::iterator j = i;
4841 hide_track_in_display (*i, false);
4846 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4848 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4849 // this will hide the mixer strip
4850 set_selected_mixer_strip (*tv);
4853 _routes->hide_track_in_display (*tv);
4858 Editor::sync_track_view_list_and_routes ()
4860 track_views = TrackViewList (_routes->views ());
4862 _summary->set_dirty ();
4863 _group_tabs->set_dirty ();
4865 return false; // do not call again (until needed)
4869 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4871 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4876 /** Find a RouteTimeAxisView by the ID of its route */
4878 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4880 RouteTimeAxisView* v;
4882 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4883 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4884 if(v->route()->id() == id) {
4894 Editor::fit_route_group (RouteGroup *g)
4896 TrackViewList ts = axis_views_from_routes (g->route_list ());
4901 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4903 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4906 _session->cancel_audition ();
4910 if (_session->is_auditioning()) {
4911 _session->cancel_audition ();
4912 if (r == last_audition_region) {
4917 _session->audition_region (r);
4918 last_audition_region = r;
4923 Editor::hide_a_region (boost::shared_ptr<Region> r)
4925 r->set_hidden (true);
4929 Editor::show_a_region (boost::shared_ptr<Region> r)
4931 r->set_hidden (false);
4935 Editor::audition_region_from_region_list ()
4937 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
4941 Editor::hide_region_from_region_list ()
4943 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
4947 Editor::show_region_in_region_list ()
4949 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
4953 Editor::step_edit_status_change (bool yn)
4956 start_step_editing ();
4958 stop_step_editing ();
4963 Editor::start_step_editing ()
4965 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
4969 Editor::stop_step_editing ()
4971 step_edit_connection.disconnect ();
4975 Editor::check_step_edit ()
4977 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4978 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
4980 mtv->check_step_edit ();
4984 return true; // do it again, till we stop
4988 Editor::scroll_press (Direction dir)
4990 ++_scroll_callbacks;
4992 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
4993 /* delay the first auto-repeat */
4999 scroll_backward (1);
5007 scroll_tracks_up_line ();
5011 scroll_tracks_down_line ();
5015 /* do hacky auto-repeat */
5016 if (!_scroll_connection.connected ()) {
5018 _scroll_connection = Glib::signal_timeout().connect (
5019 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5022 _scroll_callbacks = 0;
5029 Editor::scroll_release ()
5031 _scroll_connection.disconnect ();
5034 /** Queue a change for the Editor viewport x origin to follow the playhead */
5036 Editor::reset_x_origin_to_follow_playhead ()
5038 framepos_t const frame = playhead_cursor->current_frame;
5040 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5042 if (_session->transport_speed() < 0) {
5044 if (frame > (current_page_frames() / 2)) {
5045 center_screen (frame-(current_page_frames()/2));
5047 center_screen (current_page_frames()/2);
5054 if (frame < leftmost_frame) {
5056 if (_session->transport_rolling()) {
5057 /* rolling; end up with the playhead at the right of the page */
5058 l = frame - current_page_frames ();
5060 /* not rolling: end up with the playhead 1/4 of the way along the page */
5061 l = frame - current_page_frames() / 4;
5065 if (_session->transport_rolling()) {
5066 /* rolling: end up with the playhead on the left of the page */
5069 /* not rolling: end up with the playhead 3/4 of the way along the page */
5070 l = frame - 3 * current_page_frames() / 4;
5078 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5084 Editor::super_rapid_screen_update ()
5086 if (!_session || !_session->engine().running()) {
5090 /* METERING / MIXER STRIPS */
5092 /* update track meters, if required */
5093 if (is_mapped() && meters_running) {
5094 RouteTimeAxisView* rtv;
5095 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5096 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5097 rtv->fast_update ();
5102 /* and any current mixer strip */
5103 if (current_mixer_strip) {
5104 current_mixer_strip->fast_update ();
5107 /* PLAYHEAD AND VIEWPORT */
5109 framepos_t const frame = _session->audible_frame();
5111 /* There are a few reasons why we might not update the playhead / viewport stuff:
5113 * 1. we don't update things when there's a pending locate request, otherwise
5114 * when the editor requests a locate there is a chance that this method
5115 * will move the playhead before the locate request is processed, causing
5117 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5118 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5121 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5123 last_update_frame = frame;
5125 if (!_dragging_playhead) {
5126 playhead_cursor->set_position (frame);
5129 if (!_stationary_playhead) {
5131 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5132 reset_x_origin_to_follow_playhead ();
5137 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5141 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5142 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5143 if (target <= 0.0) {
5146 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5147 target = (target * 0.15) + (current * 0.85);
5153 set_horizontal_position (current);
5162 Editor::session_going_away ()
5164 _have_idled = false;
5166 _session_connections.drop_connections ();
5168 super_rapid_screen_update_connection.disconnect ();
5170 selection->clear ();
5171 cut_buffer->clear ();
5173 clicked_regionview = 0;
5174 clicked_axisview = 0;
5175 clicked_routeview = 0;
5176 entered_regionview = 0;
5178 last_update_frame = 0;
5181 playhead_cursor->canvas_item.hide ();
5183 /* rip everything out of the list displays */
5187 _route_groups->clear ();
5189 /* do this first so that deleting a track doesn't reset cms to null
5190 and thus cause a leak.
5193 if (current_mixer_strip) {
5194 if (current_mixer_strip->get_parent() != 0) {
5195 global_hpacker.remove (*current_mixer_strip);
5197 delete current_mixer_strip;
5198 current_mixer_strip = 0;
5201 /* delete all trackviews */
5203 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5206 track_views.clear ();
5208 zoom_range_clock->set_session (0);
5209 nudge_clock->set_session (0);
5211 editor_list_button.set_active(false);
5212 editor_list_button.set_sensitive(false);
5214 /* clear tempo/meter rulers */
5215 remove_metric_marks ();
5217 clear_marker_display ();
5219 current_bbt_points_begin = current_bbt_points_end;
5221 /* get rid of any existing editor mixer strip */
5223 WindowTitle title(Glib::get_application_name());
5224 title += _("Editor");
5226 set_title (title.get_string());
5228 SessionHandlePtr::session_going_away ();
5233 Editor::show_editor_list (bool yn)
5236 _the_notebook.show ();
5238 _the_notebook.hide ();
5243 Editor::change_region_layering_order (bool from_context_menu)
5245 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5247 if (!clicked_routeview) {
5248 if (layering_order_editor) {
5249 layering_order_editor->hide ();
5254 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5260 boost::shared_ptr<Playlist> pl = track->playlist();
5266 if (layering_order_editor == 0) {
5267 layering_order_editor = new RegionLayeringOrderEditor (*this);
5268 layering_order_editor->set_position (WIN_POS_MOUSE);
5271 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5272 layering_order_editor->maybe_present ();
5276 Editor::update_region_layering_order_editor ()
5278 if (layering_order_editor && layering_order_editor->is_visible ()) {
5279 change_region_layering_order (true);
5284 Editor::setup_fade_images ()
5286 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5287 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5288 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5289 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5290 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5292 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5293 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5294 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5295 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5296 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5299 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5301 Editor::action_menu_item (std::string const & name)
5303 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5306 return *manage (a->create_menu_item ());
5310 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5312 EventBox* b = manage (new EventBox);
5313 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5314 Label* l = manage (new Label (name));
5318 _the_notebook.append_page (widget, *b);
5322 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5324 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5325 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5328 if (ev->type == GDK_2BUTTON_PRESS) {
5330 /* double-click on a notebook tab shrinks or expands the notebook */
5332 if (_notebook_shrunk) {
5333 if (pre_notebook_shrink_pane_width) {
5334 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5336 _notebook_shrunk = false;
5338 pre_notebook_shrink_pane_width = edit_pane.get_position();
5340 /* this expands the LHS of the edit pane to cover the notebook
5341 PAGE but leaves the tabs visible.
5343 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5344 _notebook_shrunk = true;
5352 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5354 using namespace Menu_Helpers;
5356 MenuList& items = _control_point_context_menu.items ();
5359 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5360 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5361 if (!can_remove_control_point (item)) {
5362 items.back().set_sensitive (false);
5365 _control_point_context_menu.popup (event->button.button, event->button.time);