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::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
726 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
728 /* problematic: has to return a value and thus cannot be x-thread */
730 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
732 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
734 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
736 _ignore_region_action = false;
737 _last_region_menu_was_main = false;
738 _popup_region_menu_item = 0;
740 _show_marker_lines = false;
741 _over_region_trim_target = false;
743 /* Button bindings */
745 button_bindings = new Bindings;
747 XMLNode* node = button_settings();
749 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
750 button_bindings->load (**i);
757 setup_fade_images ();
763 if(image_socket_listener) {
764 if(image_socket_listener->is_connected())
766 image_socket_listener->close_connection() ;
769 delete image_socket_listener ;
770 image_socket_listener = 0 ;
774 delete button_bindings;
776 delete _route_groups;
782 Editor::button_settings () const
784 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
785 XMLNode* node = find_named_node (*settings, X_("Buttons"));
788 cerr << "new empty Button node\n";
789 node = new XMLNode (X_("Buttons"));
796 Editor::add_toplevel_controls (Container& cont)
798 vpacker.pack_start (cont, false, false);
803 Editor::catch_vanishing_regionview (RegionView *rv)
805 /* note: the selection will take care of the vanishing
806 audioregionview by itself.
809 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
813 if (clicked_regionview == rv) {
814 clicked_regionview = 0;
817 if (entered_regionview == rv) {
818 set_entered_regionview (0);
821 if (!_all_region_actions_sensitized) {
822 sensitize_all_region_actions (true);
825 _over_region_trim_target = false;
829 Editor::set_entered_regionview (RegionView* rv)
831 if (rv == entered_regionview) {
835 if (entered_regionview) {
836 entered_regionview->exited ();
839 if ((entered_regionview = rv) != 0) {
840 entered_regionview->entered (internal_editing ());
843 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
844 /* This RegionView entry might have changed what region actions
845 are allowed, so sensitize them all in case a key is pressed.
847 sensitize_all_region_actions (true);
852 Editor::set_entered_track (TimeAxisView* tav)
855 entered_track->exited ();
858 if ((entered_track = tav) != 0) {
859 entered_track->entered ();
864 Editor::show_window ()
866 if (!is_visible ()) {
869 /* XXX: this is a bit unfortunate; it would probably
870 be nicer if we could just call show () above rather
871 than needing the show_all ()
874 /* re-hide stuff if necessary */
875 editor_list_button_toggled ();
876 parameter_changed ("show-summary");
877 parameter_changed ("show-group-tabs");
878 parameter_changed ("show-zoom-tools");
880 /* now reset all audio_time_axis heights, because widgets might need
886 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
887 tv = (static_cast<TimeAxisView*>(*i));
891 if (current_mixer_strip) {
892 current_mixer_strip->hide_things ();
893 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
901 Editor::instant_save ()
903 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
908 _session->add_instant_xml(get_state());
910 Config->add_instant_xml(get_state());
915 Editor::zoom_adjustment_changed ()
921 double fpu = zoom_range_clock->current_duration() / _canvas_width;
925 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
926 } else if (fpu > _session->current_end_frame() / _canvas_width) {
927 fpu = _session->current_end_frame() / _canvas_width;
928 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
935 Editor::control_vertical_zoom_in_all ()
937 tav_zoom_smooth (false, true);
941 Editor::control_vertical_zoom_out_all ()
943 tav_zoom_smooth (true, true);
947 Editor::control_vertical_zoom_in_selected ()
949 tav_zoom_smooth (false, false);
953 Editor::control_vertical_zoom_out_selected ()
955 tav_zoom_smooth (true, false);
959 Editor::control_view (uint32_t view)
961 goto_visual_state (view);
965 Editor::control_unselect ()
967 selection->clear_tracks ();
971 Editor::control_select (uint32_t rid, Selection::Operation op)
973 /* handles the (static) signal from the ControlProtocol class that
974 * requests setting the selected track to a given RID
981 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
987 TimeAxisView* tav = axis_view_from_route (r);
992 selection->add (tav);
994 case Selection::Toggle:
995 selection->toggle (tav);
997 case Selection::Extend:
1000 selection->set (tav);
1004 selection->clear_tracks ();
1009 Editor::control_step_tracks_up ()
1011 scroll_tracks_up_line ();
1015 Editor::control_step_tracks_down ()
1017 scroll_tracks_down_line ();
1021 Editor::control_scroll (float fraction)
1023 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1029 double step = fraction * current_page_frames();
1032 _control_scroll_target is an optional<T>
1034 it acts like a pointer to an framepos_t, with
1035 a operator conversion to boolean to check
1036 that it has a value could possibly use
1037 playhead_cursor->current_frame to store the
1038 value and a boolean in the class to know
1039 when it's out of date
1042 if (!_control_scroll_target) {
1043 _control_scroll_target = _session->transport_frame();
1044 _dragging_playhead = true;
1047 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1048 *_control_scroll_target = 0;
1049 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1050 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1052 *_control_scroll_target += (framepos_t) floor (step);
1055 /* move visuals, we'll catch up with it later */
1057 playhead_cursor->set_position (*_control_scroll_target);
1058 UpdateAllTransportClocks (*_control_scroll_target);
1060 if (*_control_scroll_target > (current_page_frames() / 2)) {
1061 /* try to center PH in window */
1062 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1068 Now we do a timeout to actually bring the session to the right place
1069 according to the playhead. This is to avoid reading disk buffers on every
1070 call to control_scroll, which is driven by ScrollTimeline and therefore
1071 probably by a control surface wheel which can generate lots of events.
1073 /* cancel the existing timeout */
1075 control_scroll_connection.disconnect ();
1077 /* add the next timeout */
1079 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1083 Editor::deferred_control_scroll (framepos_t /*target*/)
1085 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1086 // reset for next stream
1087 _control_scroll_target = boost::none;
1088 _dragging_playhead = false;
1093 Editor::access_action (std::string action_group, std::string action_item)
1099 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1102 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1110 Editor::on_realize ()
1112 Window::on_realize ();
1117 Editor::map_position_change (framepos_t frame)
1119 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1121 if (_session == 0) {
1125 if (_follow_playhead) {
1126 center_screen (frame);
1129 playhead_cursor->set_position (frame);
1133 Editor::center_screen (framepos_t frame)
1135 double page = _canvas_width * frames_per_unit;
1137 /* if we're off the page, then scroll.
1140 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1141 center_screen_internal (frame, page);
1146 Editor::center_screen_internal (framepos_t frame, float page)
1151 frame -= (framepos_t) page;
1156 reset_x_origin (frame);
1161 Editor::update_title ()
1163 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1166 bool dirty = _session->dirty();
1168 string session_name;
1170 if (_session->snap_name() != _session->name()) {
1171 session_name = _session->snap_name();
1173 session_name = _session->name();
1177 session_name = "*" + session_name;
1180 WindowTitle title(session_name);
1181 title += Glib::get_application_name();
1182 set_title (title.get_string());
1187 Editor::set_session (Session *t)
1189 SessionHandlePtr::set_session (t);
1195 zoom_range_clock->set_session (_session);
1196 _playlist_selector->set_session (_session);
1197 nudge_clock->set_session (_session);
1198 _summary->set_session (_session);
1199 _group_tabs->set_session (_session);
1200 _route_groups->set_session (_session);
1201 _regions->set_session (_session);
1202 _snapshots->set_session (_session);
1203 _routes->set_session (_session);
1204 _locations->set_session (_session);
1206 if (rhythm_ferret) {
1207 rhythm_ferret->set_session (_session);
1210 if (analysis_window) {
1211 analysis_window->set_session (_session);
1215 sfbrowser->set_session (_session);
1218 compute_fixed_ruler_scale ();
1220 /* Make sure we have auto loop and auto punch ranges */
1222 Location* loc = _session->locations()->auto_loop_location();
1224 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1226 if (loc->start() == loc->end()) {
1227 loc->set_end (loc->start() + 1);
1230 _session->locations()->add (loc, false);
1231 _session->set_auto_loop_location (loc);
1234 loc->set_name (_("Loop"));
1237 loc = _session->locations()->auto_punch_location();
1240 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1242 if (loc->start() == loc->end()) {
1243 loc->set_end (loc->start() + 1);
1246 _session->locations()->add (loc, false);
1247 _session->set_auto_punch_location (loc);
1250 loc->set_name (_("Punch"));
1253 refresh_location_display ();
1255 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1256 the selected Marker; this needs the LocationMarker list to be available.
1258 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1259 set_state (*node, Stateful::loading_state_version);
1261 /* catch up with the playhead */
1263 _session->request_locate (playhead_cursor->current_frame);
1264 _pending_initial_locate = true;
1268 /* These signals can all be emitted by a non-GUI thread. Therefore the
1269 handlers for them must not attempt to directly interact with the GUI,
1270 but use Gtkmm2ext::UI::instance()->call_slot();
1273 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1274 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1275 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1276 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::handle_new_route, this, _1), gui_context());
1277 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1278 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1279 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1280 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1281 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1282 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1283 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1284 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1285 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1286 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1288 playhead_cursor->canvas_item.show ();
1290 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1291 Config->map_parameters (pc);
1292 _session->config.map_parameters (pc);
1294 restore_ruler_visibility ();
1295 //tempo_map_changed (PropertyChange (0));
1296 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1298 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1299 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1302 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1303 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1306 switch (_snap_type) {
1307 case SnapToRegionStart:
1308 case SnapToRegionEnd:
1309 case SnapToRegionSync:
1310 case SnapToRegionBoundary:
1311 build_region_boundary_cache ();
1318 /* register for undo history */
1319 _session->register_with_memento_command_factory(id(), this);
1321 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1323 start_updating_meters ();
1327 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1329 if (a->get_name() == "RegionMenu") {
1330 /* When the main menu's region menu is opened, we setup the actions so that they look right
1331 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1332 so we resensitize all region actions when the entered regionview or the region selection
1333 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1334 happens after the region context menu is opened. So we set a flag here, too.
1338 sensitize_the_right_region_actions ();
1339 _last_region_menu_was_main = true;
1343 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1345 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1347 using namespace Menu_Helpers;
1348 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1351 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1355 MenuList& items (fade_context_menu.items());
1359 switch (item_type) {
1361 case FadeInHandleItem:
1362 if (arv->audio_region()->fade_in_active()) {
1363 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1365 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1368 items.push_back (SeparatorElem());
1370 if (Profile->get_sae()) {
1372 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1373 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1380 *_fade_in_images[FadeLinear],
1381 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1385 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1390 *_fade_in_images[FadeFast],
1391 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1394 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1399 *_fade_in_images[FadeLogB],
1400 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1403 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1408 *_fade_in_images[FadeLogA],
1409 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1412 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1417 *_fade_in_images[FadeSlow],
1418 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1421 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1427 case FadeOutHandleItem:
1428 if (arv->audio_region()->fade_out_active()) {
1429 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1431 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1434 items.push_back (SeparatorElem());
1436 if (Profile->get_sae()) {
1437 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1438 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1444 *_fade_out_images[FadeLinear],
1445 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1449 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1454 *_fade_out_images[FadeFast],
1455 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1458 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1463 *_fade_out_images[FadeLogB],
1464 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1467 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1472 *_fade_out_images[FadeLogA],
1473 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1476 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1481 *_fade_out_images[FadeSlow],
1482 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1485 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 fatal << _("programming error: ")
1492 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1497 fade_context_menu.popup (button, time);
1501 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1503 using namespace Menu_Helpers;
1504 Menu* (Editor::*build_menu_function)();
1507 switch (item_type) {
1509 case RegionViewName:
1510 case RegionViewNameHighlight:
1511 case LeftFrameHandle:
1512 case RightFrameHandle:
1513 if (with_selection) {
1514 build_menu_function = &Editor::build_track_selection_context_menu;
1516 build_menu_function = &Editor::build_track_region_context_menu;
1521 if (with_selection) {
1522 build_menu_function = &Editor::build_track_selection_context_menu;
1524 build_menu_function = &Editor::build_track_context_menu;
1529 if (clicked_routeview->track()) {
1530 build_menu_function = &Editor::build_track_context_menu;
1532 build_menu_function = &Editor::build_track_bus_context_menu;
1537 /* probably shouldn't happen but if it does, we don't care */
1541 menu = (this->*build_menu_function)();
1542 menu->set_name ("ArdourContextMenu");
1544 /* now handle specific situations */
1546 switch (item_type) {
1548 case RegionViewName:
1549 case RegionViewNameHighlight:
1550 case LeftFrameHandle:
1551 case RightFrameHandle:
1552 if (!with_selection) {
1553 if (region_edit_menu_split_item) {
1554 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1555 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1557 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1560 if (region_edit_menu_split_multichannel_item) {
1561 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1562 region_edit_menu_split_multichannel_item->set_sensitive (true);
1564 region_edit_menu_split_multichannel_item->set_sensitive (false);
1577 /* probably shouldn't happen but if it does, we don't care */
1581 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1583 /* Bounce to disk */
1585 using namespace Menu_Helpers;
1586 MenuList& edit_items = menu->items();
1588 edit_items.push_back (SeparatorElem());
1590 switch (clicked_routeview->audio_track()->freeze_state()) {
1591 case AudioTrack::NoFreeze:
1592 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1595 case AudioTrack::Frozen:
1596 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1599 case AudioTrack::UnFrozen:
1600 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1606 if (item_type == StreamItem && clicked_routeview) {
1607 clicked_routeview->build_underlay_menu(menu);
1610 /* When the region menu is opened, we setup the actions so that they look right
1613 sensitize_the_right_region_actions ();
1614 _last_region_menu_was_main = false;
1616 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1617 menu->popup (button, time);
1621 Editor::build_track_context_menu ()
1623 using namespace Menu_Helpers;
1625 MenuList& edit_items = track_context_menu.items();
1628 add_dstream_context_items (edit_items);
1629 return &track_context_menu;
1633 Editor::build_track_bus_context_menu ()
1635 using namespace Menu_Helpers;
1637 MenuList& edit_items = track_context_menu.items();
1640 add_bus_context_items (edit_items);
1641 return &track_context_menu;
1645 Editor::build_track_region_context_menu ()
1647 using namespace Menu_Helpers;
1648 MenuList& edit_items = track_region_context_menu.items();
1651 /* we've just cleared the track region context menu, so the menu that these
1652 two items were on will have disappeared; stop them dangling.
1654 region_edit_menu_split_item = 0;
1655 region_edit_menu_split_multichannel_item = 0;
1657 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1660 boost::shared_ptr<Track> tr;
1661 boost::shared_ptr<Playlist> pl;
1663 if ((tr = rtv->track())) {
1664 add_region_context_items (edit_items, tr);
1668 add_dstream_context_items (edit_items);
1670 return &track_region_context_menu;
1674 Editor::analyze_region_selection ()
1676 if (analysis_window == 0) {
1677 analysis_window = new AnalysisWindow();
1680 analysis_window->set_session(_session);
1682 analysis_window->show_all();
1685 analysis_window->set_regionmode();
1686 analysis_window->analyze();
1688 analysis_window->present();
1692 Editor::analyze_range_selection()
1694 if (analysis_window == 0) {
1695 analysis_window = new AnalysisWindow();
1698 analysis_window->set_session(_session);
1700 analysis_window->show_all();
1703 analysis_window->set_rangemode();
1704 analysis_window->analyze();
1706 analysis_window->present();
1710 Editor::build_track_selection_context_menu ()
1712 using namespace Menu_Helpers;
1713 MenuList& edit_items = track_selection_context_menu.items();
1714 edit_items.clear ();
1716 add_selection_context_items (edit_items);
1717 // edit_items.push_back (SeparatorElem());
1718 // add_dstream_context_items (edit_items);
1720 return &track_selection_context_menu;
1724 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1726 using namespace Menu_Helpers;
1728 /* OK, stick the region submenu at the top of the list, and then add
1732 RegionSelection rs = get_regions_from_selection_and_entered ();
1734 string::size_type pos = 0;
1735 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1737 /* we have to hack up the region name because "_" has a special
1738 meaning for menu titles.
1741 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1742 menu_item_name.replace (pos, 1, "__");
1746 if (_popup_region_menu_item == 0) {
1747 _popup_region_menu_item = new MenuItem (menu_item_name);
1748 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1749 _popup_region_menu_item->show ();
1751 _popup_region_menu_item->set_label (menu_item_name);
1754 const framepos_t position = get_preferred_edit_position (false, true);
1756 edit_items.push_back (*_popup_region_menu_item);
1757 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1758 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1760 edit_items.push_back (SeparatorElem());
1763 /** Add context menu items relevant to selection ranges.
1764 * @param edit_items List to add the items to.
1767 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1769 using namespace Menu_Helpers;
1771 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1772 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1774 edit_items.push_back (SeparatorElem());
1775 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1777 edit_items.push_back (SeparatorElem());
1779 edit_items.push_back (
1781 _("Move Range Start to Previous Region Boundary"),
1782 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1786 edit_items.push_back (
1788 _("Move Range Start to Next Region Boundary"),
1789 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1793 edit_items.push_back (
1795 _("Move Range End to Previous Region Boundary"),
1796 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1800 edit_items.push_back (
1802 _("Move Range End to Next Region Boundary"),
1803 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1807 edit_items.push_back (SeparatorElem());
1808 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1809 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1811 edit_items.push_back (SeparatorElem());
1812 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1814 edit_items.push_back (SeparatorElem());
1815 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1816 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1818 edit_items.push_back (SeparatorElem());
1819 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1821 edit_items.push_back (SeparatorElem());
1822 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1823 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1824 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1826 edit_items.push_back (SeparatorElem());
1827 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1828 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1829 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1830 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1831 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1836 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1838 using namespace Menu_Helpers;
1842 Menu *play_menu = manage (new Menu);
1843 MenuList& play_items = play_menu->items();
1844 play_menu->set_name ("ArdourContextMenu");
1846 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1847 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1848 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1849 play_items.push_back (SeparatorElem());
1850 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1852 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1856 Menu *select_menu = manage (new Menu);
1857 MenuList& select_items = select_menu->items();
1858 select_menu->set_name ("ArdourContextMenu");
1860 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1861 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1862 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1863 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1864 select_items.push_back (SeparatorElem());
1865 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1866 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1867 select_items.push_back (SeparatorElem());
1868 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1869 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1870 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1871 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1872 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1873 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1874 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1876 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1880 Menu *cutnpaste_menu = manage (new Menu);
1881 MenuList& cutnpaste_items = cutnpaste_menu->items();
1882 cutnpaste_menu->set_name ("ArdourContextMenu");
1884 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1885 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1886 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1888 cutnpaste_items.push_back (SeparatorElem());
1890 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1891 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1893 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1895 /* Adding new material */
1897 edit_items.push_back (SeparatorElem());
1898 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1899 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1903 Menu *nudge_menu = manage (new Menu());
1904 MenuList& nudge_items = nudge_menu->items();
1905 nudge_menu->set_name ("ArdourContextMenu");
1907 edit_items.push_back (SeparatorElem());
1908 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1909 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1910 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1911 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1913 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1917 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1919 using namespace Menu_Helpers;
1923 Menu *play_menu = manage (new Menu);
1924 MenuList& play_items = play_menu->items();
1925 play_menu->set_name ("ArdourContextMenu");
1927 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1928 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1929 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1933 Menu *select_menu = manage (new Menu);
1934 MenuList& select_items = select_menu->items();
1935 select_menu->set_name ("ArdourContextMenu");
1937 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1938 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1939 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1940 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1941 select_items.push_back (SeparatorElem());
1942 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1943 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1944 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1945 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1947 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1951 Menu *cutnpaste_menu = manage (new Menu);
1952 MenuList& cutnpaste_items = cutnpaste_menu->items();
1953 cutnpaste_menu->set_name ("ArdourContextMenu");
1955 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1956 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1957 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1959 Menu *nudge_menu = manage (new Menu());
1960 MenuList& nudge_items = nudge_menu->items();
1961 nudge_menu->set_name ("ArdourContextMenu");
1963 edit_items.push_back (SeparatorElem());
1964 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1965 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1966 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1967 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1969 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1973 Editor::snap_type() const
1979 Editor::snap_mode() const
1985 Editor::set_snap_to (SnapType st)
1987 unsigned int snap_ind = (unsigned int)st;
1991 if (snap_ind > snap_type_strings.size() - 1) {
1993 _snap_type = (SnapType)snap_ind;
1996 string str = snap_type_strings[snap_ind];
1998 if (str != snap_type_selector.get_active_text()) {
1999 snap_type_selector.set_active_text (str);
2004 switch (_snap_type) {
2005 case SnapToBeatDiv128:
2006 case SnapToBeatDiv64:
2007 case SnapToBeatDiv32:
2008 case SnapToBeatDiv28:
2009 case SnapToBeatDiv24:
2010 case SnapToBeatDiv20:
2011 case SnapToBeatDiv16:
2012 case SnapToBeatDiv14:
2013 case SnapToBeatDiv12:
2014 case SnapToBeatDiv10:
2015 case SnapToBeatDiv8:
2016 case SnapToBeatDiv7:
2017 case SnapToBeatDiv6:
2018 case SnapToBeatDiv5:
2019 case SnapToBeatDiv4:
2020 case SnapToBeatDiv3:
2021 case SnapToBeatDiv2:
2022 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2023 update_tempo_based_rulers ();
2026 case SnapToRegionStart:
2027 case SnapToRegionEnd:
2028 case SnapToRegionSync:
2029 case SnapToRegionBoundary:
2030 build_region_boundary_cache ();
2038 SnapChanged (); /* EMIT SIGNAL */
2042 Editor::set_snap_mode (SnapMode mode)
2045 string str = snap_mode_strings[(int)mode];
2047 if (str != snap_mode_selector.get_active_text ()) {
2048 snap_mode_selector.set_active_text (str);
2054 Editor::set_edit_point_preference (EditPoint ep, bool force)
2056 bool changed = (_edit_point != ep);
2059 string str = edit_point_strings[(int)ep];
2061 if (str != edit_point_selector.get_active_text ()) {
2062 edit_point_selector.set_active_text (str);
2065 set_canvas_cursor ();
2067 if (!force && !changed) {
2071 const char* action=NULL;
2073 switch (_edit_point) {
2074 case EditAtPlayhead:
2075 action = "edit-at-playhead";
2077 case EditAtSelectedMarker:
2078 action = "edit-at-marker";
2081 action = "edit-at-mouse";
2085 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2087 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2091 bool in_track_canvas;
2093 if (!mouse_frame (foo, in_track_canvas)) {
2094 in_track_canvas = false;
2097 reset_canvas_action_sensitivity (in_track_canvas);
2103 Editor::set_state (const XMLNode& node, int /*version*/)
2105 const XMLProperty* prop;
2112 g.base_width = default_width;
2113 g.base_height = default_height;
2117 if ((geometry = find_named_node (node, "geometry")) != 0) {
2121 if ((prop = geometry->property("x_size")) == 0) {
2122 prop = geometry->property ("x-size");
2125 g.base_width = atoi(prop->value());
2127 if ((prop = geometry->property("y_size")) == 0) {
2128 prop = geometry->property ("y-size");
2131 g.base_height = atoi(prop->value());
2134 if ((prop = geometry->property ("x_pos")) == 0) {
2135 prop = geometry->property ("x-pos");
2138 x = atoi (prop->value());
2141 if ((prop = geometry->property ("y_pos")) == 0) {
2142 prop = geometry->property ("y-pos");
2145 y = atoi (prop->value());
2149 set_default_size (g.base_width, g.base_height);
2152 if (_session && (prop = node.property ("playhead"))) {
2154 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2155 playhead_cursor->set_position (pos);
2157 playhead_cursor->set_position (0);
2160 if ((prop = node.property ("mixer-width"))) {
2161 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2164 if ((prop = node.property ("zoom-focus"))) {
2165 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2168 if ((prop = node.property ("zoom"))) {
2169 reset_zoom (PBD::atof (prop->value()));
2171 reset_zoom (frames_per_unit);
2174 if ((prop = node.property ("snap-to"))) {
2175 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2178 if ((prop = node.property ("snap-mode"))) {
2179 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2182 if ((prop = node.property ("internal-snap-to"))) {
2183 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2186 if ((prop = node.property ("internal-snap-mode"))) {
2187 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2190 if ((prop = node.property ("pre-internal-snap-to"))) {
2191 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2194 if ((prop = node.property ("pre-internal-snap-mode"))) {
2195 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2198 if ((prop = node.property ("mouse-mode"))) {
2199 MouseMode m = str2mousemode(prop->value());
2200 set_mouse_mode (m, true);
2202 set_mouse_mode (MouseObject, true);
2205 if ((prop = node.property ("left-frame")) != 0) {
2207 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2211 reset_x_origin (pos);
2215 if ((prop = node.property ("y-origin")) != 0) {
2216 reset_y_origin (atof (prop->value ()));
2219 if ((prop = node.property ("internal-edit"))) {
2220 bool yn = string_is_affirmative (prop->value());
2221 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2223 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2224 tact->set_active (!yn);
2225 tact->set_active (yn);
2229 if ((prop = node.property ("join-object-range"))) {
2230 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2233 if ((prop = node.property ("edit-point"))) {
2234 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2237 if ((prop = node.property ("show-measures"))) {
2238 bool yn = string_is_affirmative (prop->value());
2239 _show_measures = yn;
2240 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2242 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2243 /* do it twice to force the change */
2244 tact->set_active (!yn);
2245 tact->set_active (yn);
2249 if ((prop = node.property ("follow-playhead"))) {
2250 bool yn = string_is_affirmative (prop->value());
2251 set_follow_playhead (yn);
2252 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2254 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2255 if (tact->get_active() != yn) {
2256 tact->set_active (yn);
2261 if ((prop = node.property ("stationary-playhead"))) {
2262 bool yn = string_is_affirmative (prop->value());
2263 set_stationary_playhead (yn);
2264 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2266 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2267 if (tact->get_active() != yn) {
2268 tact->set_active (yn);
2273 if ((prop = node.property ("region-list-sort-type"))) {
2274 RegionListSortType st;
2275 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2278 if ((prop = node.property ("show-editor-mixer"))) {
2280 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2283 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2284 bool yn = string_is_affirmative (prop->value());
2286 /* do it twice to force the change */
2288 tact->set_active (!yn);
2289 tact->set_active (yn);
2292 if ((prop = node.property ("show-editor-list"))) {
2294 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2297 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2298 bool yn = string_is_affirmative (prop->value());
2300 /* do it twice to force the change */
2302 tact->set_active (!yn);
2303 tact->set_active (yn);
2306 if ((prop = node.property (X_("editor-list-page")))) {
2307 _the_notebook.set_current_page (atoi (prop->value ()));
2310 if ((prop = node.property (X_("show-marker-lines")))) {
2311 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2313 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2314 bool yn = string_is_affirmative (prop->value ());
2316 tact->set_active (!yn);
2317 tact->set_active (yn);
2320 XMLNodeList children = node.children ();
2321 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2322 selection->set_state (**i, Stateful::current_state_version);
2323 _regions->set_state (**i);
2326 if ((prop = node.property ("maximised"))) {
2327 bool yn = string_is_affirmative (prop->value());
2329 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2333 if ((prop = node.property ("nudge-clock-value"))) {
2335 sscanf (prop->value().c_str(), "%" PRId64, &f);
2336 nudge_clock->set (f);
2338 nudge_clock->set_mode (AudioClock::Timecode);
2339 nudge_clock->set (_session->frame_rate() * 5, true);
2346 Editor::get_state ()
2348 XMLNode* node = new XMLNode ("Editor");
2351 id().print (buf, sizeof (buf));
2352 node->add_property ("id", buf);
2354 if (is_realized()) {
2355 Glib::RefPtr<Gdk::Window> win = get_window();
2357 int x, y, width, height;
2358 win->get_root_origin(x, y);
2359 win->get_size(width, height);
2361 XMLNode* geometry = new XMLNode ("geometry");
2363 snprintf(buf, sizeof(buf), "%d", width);
2364 geometry->add_property("x-size", string(buf));
2365 snprintf(buf, sizeof(buf), "%d", height);
2366 geometry->add_property("y-size", string(buf));
2367 snprintf(buf, sizeof(buf), "%d", x);
2368 geometry->add_property("x-pos", string(buf));
2369 snprintf(buf, sizeof(buf), "%d", y);
2370 geometry->add_property("y-pos", string(buf));
2371 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2372 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2373 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2374 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2375 geometry->add_property("edit-vertical-pane-pos", string(buf));
2377 node->add_child_nocopy (*geometry);
2380 maybe_add_mixer_strip_width (*node);
2382 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2383 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2384 node->add_property ("zoom", buf);
2385 node->add_property ("snap-to", enum_2_string (_snap_type));
2386 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2387 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2388 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2389 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2390 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2391 node->add_property ("edit-point", enum_2_string (_edit_point));
2393 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2394 node->add_property ("playhead", buf);
2395 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2396 node->add_property ("left-frame", buf);
2397 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2398 node->add_property ("y-origin", buf);
2400 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2401 node->add_property ("maximised", _maximised ? "yes" : "no");
2402 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2403 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2404 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2405 node->add_property ("mouse-mode", enum2str(mouse_mode));
2406 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2407 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2409 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2411 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2412 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2415 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2417 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2418 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2421 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2422 node->add_property (X_("editor-list-page"), buf);
2424 if (button_bindings) {
2425 XMLNode* bb = new XMLNode (X_("Buttons"));
2426 button_bindings->save (*bb);
2427 node->add_child_nocopy (*bb);
2430 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2432 node->add_child_nocopy (selection->get_state ());
2433 node->add_child_nocopy (_regions->get_state ());
2435 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2436 node->add_property ("nudge-clock-value", buf);
2443 /** @param y y offset from the top of all trackviews.
2444 * @return pair: TimeAxisView that y is over, layer index.
2445 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2446 * in stacked or expanded region display mode, otherwise 0.
2448 std::pair<TimeAxisView *, double>
2449 Editor::trackview_by_y_position (double y)
2451 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2453 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2459 return std::make_pair ( (TimeAxisView *) 0, 0);
2462 /** Snap a position to the grid, if appropriate, taking into account current
2463 * grid settings and also the state of any snap modifier keys that may be pressed.
2464 * @param start Position to snap.
2465 * @param event Event to get current key modifier information from, or 0.
2468 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2470 if (!_session || !event) {
2474 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2475 if (_snap_mode == SnapOff) {
2476 snap_to_internal (start, direction, for_mark);
2479 if (_snap_mode != SnapOff) {
2480 snap_to_internal (start, direction, for_mark);
2486 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2488 if (!_session || _snap_mode == SnapOff) {
2492 snap_to_internal (start, direction, for_mark);
2496 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2498 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2499 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2501 switch (_snap_type) {
2502 case SnapToTimecodeFrame:
2503 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2504 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2506 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2510 case SnapToTimecodeSeconds:
2511 if (_session->config.get_timecode_offset_negative()) {
2512 start += _session->config.get_timecode_offset ();
2514 start -= _session->config.get_timecode_offset ();
2516 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2517 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2519 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2522 if (_session->config.get_timecode_offset_negative()) {
2523 start -= _session->config.get_timecode_offset ();
2525 start += _session->config.get_timecode_offset ();
2529 case SnapToTimecodeMinutes:
2530 if (_session->config.get_timecode_offset_negative()) {
2531 start += _session->config.get_timecode_offset ();
2533 start -= _session->config.get_timecode_offset ();
2535 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2536 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2538 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2540 if (_session->config.get_timecode_offset_negative()) {
2541 start -= _session->config.get_timecode_offset ();
2543 start += _session->config.get_timecode_offset ();
2547 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2553 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2555 const framepos_t one_second = _session->frame_rate();
2556 const framepos_t one_minute = _session->frame_rate() * 60;
2557 framepos_t presnap = start;
2561 switch (_snap_type) {
2562 case SnapToTimecodeFrame:
2563 case SnapToTimecodeSeconds:
2564 case SnapToTimecodeMinutes:
2565 return timecode_snap_to_internal (start, direction, for_mark);
2568 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2569 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2571 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2576 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2577 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2579 start = (framepos_t) floor ((double) start / one_second) * one_second;
2584 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2585 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2587 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2592 start = _session->tempo_map().round_to_bar (start, direction);
2596 start = _session->tempo_map().round_to_beat (start, direction);
2599 case SnapToBeatDiv128:
2600 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2602 case SnapToBeatDiv64:
2603 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2605 case SnapToBeatDiv32:
2606 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2608 case SnapToBeatDiv28:
2609 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2611 case SnapToBeatDiv24:
2612 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2614 case SnapToBeatDiv20:
2615 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2617 case SnapToBeatDiv16:
2618 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2620 case SnapToBeatDiv14:
2621 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2623 case SnapToBeatDiv12:
2624 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2626 case SnapToBeatDiv10:
2627 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2629 case SnapToBeatDiv8:
2630 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2632 case SnapToBeatDiv7:
2633 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2635 case SnapToBeatDiv6:
2636 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2638 case SnapToBeatDiv5:
2639 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2641 case SnapToBeatDiv4:
2642 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2644 case SnapToBeatDiv3:
2645 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2647 case SnapToBeatDiv2:
2648 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2656 _session->locations()->marks_either_side (start, before, after);
2658 if (before == max_framepos) {
2660 } else if (after == max_framepos) {
2662 } else if (before != max_framepos && after != max_framepos) {
2663 /* have before and after */
2664 if ((start - before) < (after - start)) {
2673 case SnapToRegionStart:
2674 case SnapToRegionEnd:
2675 case SnapToRegionSync:
2676 case SnapToRegionBoundary:
2677 if (!region_boundary_cache.empty()) {
2679 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2680 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2682 if (direction > 0) {
2683 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2685 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2688 if (next != region_boundary_cache.begin ()) {
2693 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2694 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2696 if (start > (p + n) / 2) {
2705 switch (_snap_mode) {
2711 if (presnap > start) {
2712 if (presnap > (start + unit_to_frame(snap_threshold))) {
2716 } else if (presnap < start) {
2717 if (presnap < (start - unit_to_frame(snap_threshold))) {
2723 /* handled at entry */
2731 Editor::setup_toolbar ()
2733 HBox* mode_box = manage(new HBox);
2734 mode_box->set_border_width (2);
2735 mode_box->set_spacing(4);
2737 HBox* mouse_mode_box = manage (new HBox);
2738 HBox* mouse_mode_hbox1 = manage (new HBox);
2739 HBox* mouse_mode_hbox2 = manage (new HBox);
2740 VBox* mouse_mode_vbox1 = manage (new VBox);
2741 VBox* mouse_mode_vbox2 = manage (new VBox);
2742 Alignment* mouse_mode_align1 = manage (new Alignment);
2743 Alignment* mouse_mode_align2 = manage (new Alignment);
2745 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2746 mouse_mode_size_group->add_widget (mouse_move_button);
2747 mouse_mode_size_group->add_widget (mouse_select_button);
2748 mouse_mode_size_group->add_widget (mouse_zoom_button);
2749 mouse_mode_size_group->add_widget (mouse_gain_button);
2750 mouse_mode_size_group->add_widget (mouse_timefx_button);
2751 mouse_mode_size_group->add_widget (mouse_audition_button);
2752 mouse_mode_size_group->add_widget (mouse_draw_button);
2753 mouse_mode_size_group->add_widget (internal_edit_button);
2755 /* make them just a bit bigger */
2756 mouse_move_button.set_size_request (-1, 25);
2758 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2759 smart_mode_joiner->set_related_action (smart_mode_action);
2761 mouse_mode_hbox2->set_spacing (2);
2762 mouse_mode_box->set_spacing (2);
2764 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2765 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2766 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2767 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2768 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2769 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2770 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2772 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2773 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2775 mouse_mode_align1->add (*mouse_mode_vbox1);
2776 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2777 mouse_mode_align2->add (*mouse_mode_vbox2);
2778 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2780 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2781 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2783 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2784 if (!Profile->get_sae()) {
2785 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2787 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2789 edit_mode_selector.set_name ("EditModeSelector");
2790 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2791 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2793 mode_box->pack_start (edit_mode_selector, false, false);
2794 mode_box->pack_start (*mouse_mode_box, false, false);
2796 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2797 _mouse_mode_tearoff->set_name ("MouseModeBase");
2798 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2800 if (Profile->get_sae()) {
2801 _mouse_mode_tearoff->set_can_be_torn_off (false);
2804 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2805 &_mouse_mode_tearoff->tearoff_window()));
2806 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2807 &_mouse_mode_tearoff->tearoff_window(), 1));
2808 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2809 &_mouse_mode_tearoff->tearoff_window()));
2810 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2811 &_mouse_mode_tearoff->tearoff_window(), 1));
2815 _zoom_box.set_spacing (2);
2816 _zoom_box.set_border_width (2);
2820 zoom_in_button.set_name ("zoom button");
2821 zoom_in_button.set_image (::get_icon ("zoom_in"));
2822 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2823 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2824 zoom_in_button.set_related_action (act);
2826 zoom_out_button.set_name ("zoom button");
2827 zoom_out_button.set_image (::get_icon ("zoom_out"));
2828 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2829 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2830 zoom_out_button.set_related_action (act);
2832 zoom_out_full_button.set_name ("zoom button");
2833 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2834 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2835 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2836 zoom_out_full_button.set_related_action (act);
2838 zoom_focus_selector.set_name ("ZoomFocusSelector");
2839 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2840 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2842 _zoom_box.pack_start (zoom_out_button, false, false);
2843 _zoom_box.pack_start (zoom_in_button, false, false);
2844 _zoom_box.pack_start (zoom_out_full_button, false, false);
2846 _zoom_box.pack_start (zoom_focus_selector, false, false);
2848 /* Track zoom buttons */
2849 tav_expand_button.set_name ("TrackHeightButton");
2850 tav_expand_button.set_size_request (-1, 20);
2851 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2852 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2853 act->connect_proxy (tav_expand_button);
2855 tav_shrink_button.set_name ("TrackHeightButton");
2856 tav_shrink_button.set_size_request (-1, 20);
2857 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2858 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2859 act->connect_proxy (tav_shrink_button);
2861 _zoom_box.pack_start (tav_shrink_button);
2862 _zoom_box.pack_start (tav_expand_button);
2864 _zoom_tearoff = manage (new TearOff (_zoom_box));
2866 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2867 &_zoom_tearoff->tearoff_window()));
2868 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2869 &_zoom_tearoff->tearoff_window(), 0));
2870 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2871 &_zoom_tearoff->tearoff_window()));
2872 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2873 &_zoom_tearoff->tearoff_window(), 0));
2875 snap_box.set_spacing (1);
2876 snap_box.set_border_width (2);
2878 snap_type_selector.set_name ("SnapTypeSelector");
2879 set_popdown_strings (snap_type_selector, snap_type_strings);
2880 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2882 snap_mode_selector.set_name ("SnapModeSelector");
2883 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2884 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2886 edit_point_selector.set_name ("EditPointSelector");
2887 set_popdown_strings (edit_point_selector, edit_point_strings);
2888 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2890 snap_box.pack_start (snap_mode_selector, false, false);
2891 snap_box.pack_start (snap_type_selector, false, false);
2892 snap_box.pack_start (edit_point_selector, false, false);
2896 HBox *nudge_box = manage (new HBox);
2897 nudge_box->set_spacing (2);
2898 nudge_box->set_border_width (2);
2900 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2901 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2903 nudge_box->pack_start (nudge_backward_button, false, false);
2904 nudge_box->pack_start (nudge_forward_button, false, false);
2905 nudge_box->pack_start (*nudge_clock, false, false);
2908 /* Pack everything in... */
2910 HBox* hbox = manage (new HBox);
2911 hbox->set_spacing(10);
2913 _tools_tearoff = manage (new TearOff (*hbox));
2914 _tools_tearoff->set_name ("MouseModeBase");
2915 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2917 if (Profile->get_sae()) {
2918 _tools_tearoff->set_can_be_torn_off (false);
2921 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2922 &_tools_tearoff->tearoff_window()));
2923 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2924 &_tools_tearoff->tearoff_window(), 0));
2925 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2926 &_tools_tearoff->tearoff_window()));
2927 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2928 &_tools_tearoff->tearoff_window(), 0));
2930 toolbar_hbox.set_spacing (10);
2931 toolbar_hbox.set_border_width (1);
2933 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2934 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2935 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2937 hbox->pack_start (snap_box, false, false);
2938 if (!Profile->get_small_screen()) {
2939 hbox->pack_start (*nudge_box, false, false);
2941 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2943 hbox->pack_start (panic_box, false, false);
2947 toolbar_base.set_name ("ToolBarBase");
2948 toolbar_base.add (toolbar_hbox);
2950 _toolbar_viewport.add (toolbar_base);
2951 /* stick to the required height but allow width to vary if there's not enough room */
2952 _toolbar_viewport.set_size_request (1, -1);
2954 toolbar_frame.set_shadow_type (SHADOW_OUT);
2955 toolbar_frame.set_name ("BaseFrame");
2956 toolbar_frame.add (_toolbar_viewport);
2960 Editor::setup_tooltips ()
2962 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2963 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
2964 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
2965 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2966 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2967 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2968 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2969 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
2970 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2971 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2972 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2973 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2974 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2975 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2976 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2977 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2978 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2979 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2980 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2981 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2982 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2983 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2984 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
2988 Editor::convert_drop_to_paths (
2989 vector<string>& paths,
2990 const RefPtr<Gdk::DragContext>& /*context*/,
2993 const SelectionData& data,
2997 if (_session == 0) {
3001 vector<string> uris = data.get_uris();
3005 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3006 are actually URI lists. So do it by hand.
3009 if (data.get_target() != "text/plain") {
3013 /* Parse the "uri-list" format that Nautilus provides,
3014 where each pathname is delimited by \r\n.
3016 THERE MAY BE NO NULL TERMINATING CHAR!!!
3019 string txt = data.get_text();
3023 p = (const char *) malloc (txt.length() + 1);
3024 txt.copy ((char *) p, txt.length(), 0);
3025 ((char*)p)[txt.length()] = '\0';
3031 while (g_ascii_isspace (*p))
3035 while (*q && (*q != '\n') && (*q != '\r')) {
3042 while (q > p && g_ascii_isspace (*q))
3047 uris.push_back (string (p, q - p + 1));
3051 p = strchr (p, '\n');
3063 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3065 if ((*i).substr (0,7) == "file://") {
3067 string const p = PBD::url_decode (*i);
3069 // scan forward past three slashes
3071 string::size_type slashcnt = 0;
3072 string::size_type n = 0;
3073 string::const_iterator x = p.begin();
3075 while (slashcnt < 3 && x != p.end()) {
3078 } else if (slashcnt == 3) {
3085 if (slashcnt != 3 || x == p.end()) {
3086 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3090 paths.push_back (p.substr (n - 1));
3098 Editor::new_tempo_section ()
3104 Editor::map_transport_state ()
3106 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3108 if (_session && _session->transport_stopped()) {
3109 have_pending_keyboard_selection = false;
3112 update_loop_range_view (true);
3118 Editor::begin_reversible_command (string name)
3121 _session->begin_reversible_command (name);
3126 Editor::begin_reversible_command (GQuark q)
3129 _session->begin_reversible_command (q);
3134 Editor::commit_reversible_command ()
3137 _session->commit_reversible_command ();
3142 Editor::history_changed ()
3146 if (undo_action && _session) {
3147 if (_session->undo_depth() == 0) {
3148 label = S_("Command|Undo");
3150 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3152 undo_action->property_label() = label;
3155 if (redo_action && _session) {
3156 if (_session->redo_depth() == 0) {
3159 label = string_compose(_("Redo (%1)"), _session->next_redo());
3161 redo_action->property_label() = label;
3166 Editor::duplicate_dialog (bool with_dialog)
3170 if (mouse_mode == MouseRange) {
3171 if (selection->time.length() == 0) {
3176 RegionSelection rs = get_regions_from_selection_and_entered ();
3178 if (mouse_mode != MouseRange && rs.empty()) {
3184 ArdourDialog win (_("Duplicate"));
3185 Label label (_("Number of duplications:"));
3186 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3187 SpinButton spinner (adjustment, 0.0, 1);
3190 win.get_vbox()->set_spacing (12);
3191 win.get_vbox()->pack_start (hbox);
3192 hbox.set_border_width (6);
3193 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3195 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3196 place, visually. so do this by hand.
3199 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3200 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3201 spinner.grab_focus();
3207 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3208 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3209 win.set_default_response (RESPONSE_ACCEPT);
3211 win.set_position (WIN_POS_MOUSE);
3213 spinner.grab_focus ();
3215 switch (win.run ()) {
3216 case RESPONSE_ACCEPT:
3222 times = adjustment.get_value();
3225 if (mouse_mode == MouseRange) {
3226 duplicate_selection (times);
3228 duplicate_some_regions (rs, times);
3233 Editor::set_edit_mode (EditMode m)
3235 Config->set_edit_mode (m);
3239 Editor::cycle_edit_mode ()
3241 switch (Config->get_edit_mode()) {
3243 if (Profile->get_sae()) {
3244 Config->set_edit_mode (Lock);
3246 Config->set_edit_mode (Splice);
3250 Config->set_edit_mode (Lock);
3253 Config->set_edit_mode (Slide);
3259 Editor::edit_mode_selection_done ()
3261 string s = edit_mode_selector.get_active_text ();
3264 Config->set_edit_mode (string_to_edit_mode (s));
3269 Editor::snap_type_selection_done ()
3271 string choice = snap_type_selector.get_active_text();
3272 SnapType snaptype = SnapToBeat;
3274 if (choice == _("Beats/2")) {
3275 snaptype = SnapToBeatDiv2;
3276 } else if (choice == _("Beats/3")) {
3277 snaptype = SnapToBeatDiv3;
3278 } else if (choice == _("Beats/4")) {
3279 snaptype = SnapToBeatDiv4;
3280 } else if (choice == _("Beats/5")) {
3281 snaptype = SnapToBeatDiv5;
3282 } else if (choice == _("Beats/6")) {
3283 snaptype = SnapToBeatDiv6;
3284 } else if (choice == _("Beats/7")) {
3285 snaptype = SnapToBeatDiv7;
3286 } else if (choice == _("Beats/8")) {
3287 snaptype = SnapToBeatDiv8;
3288 } else if (choice == _("Beats/10")) {
3289 snaptype = SnapToBeatDiv10;
3290 } else if (choice == _("Beats/12")) {
3291 snaptype = SnapToBeatDiv12;
3292 } else if (choice == _("Beats/14")) {
3293 snaptype = SnapToBeatDiv14;
3294 } else if (choice == _("Beats/16")) {
3295 snaptype = SnapToBeatDiv16;
3296 } else if (choice == _("Beats/20")) {
3297 snaptype = SnapToBeatDiv20;
3298 } else if (choice == _("Beats/24")) {
3299 snaptype = SnapToBeatDiv24;
3300 } else if (choice == _("Beats/28")) {
3301 snaptype = SnapToBeatDiv28;
3302 } else if (choice == _("Beats/32")) {
3303 snaptype = SnapToBeatDiv32;
3304 } else if (choice == _("Beats/64")) {
3305 snaptype = SnapToBeatDiv64;
3306 } else if (choice == _("Beats/128")) {
3307 snaptype = SnapToBeatDiv128;
3308 } else if (choice == _("Beats")) {
3309 snaptype = SnapToBeat;
3310 } else if (choice == _("Bars")) {
3311 snaptype = SnapToBar;
3312 } else if (choice == _("Marks")) {
3313 snaptype = SnapToMark;
3314 } else if (choice == _("Region starts")) {
3315 snaptype = SnapToRegionStart;
3316 } else if (choice == _("Region ends")) {
3317 snaptype = SnapToRegionEnd;
3318 } else if (choice == _("Region bounds")) {
3319 snaptype = SnapToRegionBoundary;
3320 } else if (choice == _("Region syncs")) {
3321 snaptype = SnapToRegionSync;
3322 } else if (choice == _("CD Frames")) {
3323 snaptype = SnapToCDFrame;
3324 } else if (choice == _("Timecode Frames")) {
3325 snaptype = SnapToTimecodeFrame;
3326 } else if (choice == _("Timecode Seconds")) {
3327 snaptype = SnapToTimecodeSeconds;
3328 } else if (choice == _("Timecode Minutes")) {
3329 snaptype = SnapToTimecodeMinutes;
3330 } else if (choice == _("Seconds")) {
3331 snaptype = SnapToSeconds;
3332 } else if (choice == _("Minutes")) {
3333 snaptype = SnapToMinutes;
3336 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3338 ract->set_active ();
3343 Editor::snap_mode_selection_done ()
3345 string choice = snap_mode_selector.get_active_text();
3346 SnapMode mode = SnapNormal;
3348 if (choice == _("No Grid")) {
3350 } else if (choice == _("Grid")) {
3352 } else if (choice == _("Magnetic")) {
3353 mode = SnapMagnetic;
3356 RefPtr<RadioAction> ract = snap_mode_action (mode);
3359 ract->set_active (true);
3364 Editor::cycle_edit_point (bool with_marker)
3366 switch (_edit_point) {
3368 set_edit_point_preference (EditAtPlayhead);
3370 case EditAtPlayhead:
3372 set_edit_point_preference (EditAtSelectedMarker);
3374 set_edit_point_preference (EditAtMouse);
3377 case EditAtSelectedMarker:
3378 set_edit_point_preference (EditAtMouse);
3384 Editor::edit_point_selection_done ()
3386 string choice = edit_point_selector.get_active_text();
3387 EditPoint ep = EditAtSelectedMarker;
3389 if (choice == _("Marker")) {
3390 set_edit_point_preference (EditAtSelectedMarker);
3391 } else if (choice == _("Playhead")) {
3392 set_edit_point_preference (EditAtPlayhead);
3394 set_edit_point_preference (EditAtMouse);
3397 RefPtr<RadioAction> ract = edit_point_action (ep);
3400 ract->set_active (true);
3405 Editor::zoom_focus_selection_done ()
3407 string choice = zoom_focus_selector.get_active_text();
3408 ZoomFocus focus_type = ZoomFocusLeft;
3410 if (choice == _("Left")) {
3411 focus_type = ZoomFocusLeft;
3412 } else if (choice == _("Right")) {
3413 focus_type = ZoomFocusRight;
3414 } else if (choice == _("Center")) {
3415 focus_type = ZoomFocusCenter;
3416 } else if (choice == _("Playhead")) {
3417 focus_type = ZoomFocusPlayhead;
3418 } else if (choice == _("Mouse")) {
3419 focus_type = ZoomFocusMouse;
3420 } else if (choice == _("Edit point")) {
3421 focus_type = ZoomFocusEdit;
3424 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3427 ract->set_active ();
3432 Editor::edit_controls_button_release (GdkEventButton* ev)
3434 if (Keyboard::is_context_menu_event (ev)) {
3435 ARDOUR_UI::instance()->add_route (this);
3436 } else if (ev->button == 1) {
3437 selection->clear_tracks ();
3444 Editor::mouse_select_button_release (GdkEventButton* ev)
3446 /* this handles just right-clicks */
3448 if (ev->button != 3) {
3456 Editor::set_zoom_focus (ZoomFocus f)
3458 string str = zoom_focus_strings[(int)f];
3460 if (str != zoom_focus_selector.get_active_text()) {
3461 zoom_focus_selector.set_active_text (str);
3464 if (zoom_focus != f) {
3471 Editor::ensure_float (Window& win)
3473 win.set_transient_for (*this);
3477 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3479 /* recover or initialize pane positions. do this here rather than earlier because
3480 we don't want the positions to change the child allocations, which they seem to do.
3486 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3495 XMLNode* geometry = find_named_node (*node, "geometry");
3497 if (which == static_cast<Paned*> (&edit_pane)) {
3499 if (done & Horizontal) {
3503 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3504 _notebook_shrunk = string_is_affirmative (prop->value ());
3507 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3508 /* initial allocation is 90% to canvas, 10% to notebook */
3509 pos = (int) floor (alloc.get_width() * 0.90f);
3510 snprintf (buf, sizeof(buf), "%d", pos);
3512 pos = atoi (prop->value());
3515 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3516 edit_pane.set_position (pos);
3519 done = (Pane) (done | Horizontal);
3521 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3523 if (done & Vertical) {
3527 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3528 /* initial allocation is 90% to canvas, 10% to summary */
3529 pos = (int) floor (alloc.get_height() * 0.90f);
3530 snprintf (buf, sizeof(buf), "%d", pos);
3533 pos = atoi (prop->value());
3536 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3537 editor_summary_pane.set_position (pos);
3540 done = (Pane) (done | Vertical);
3545 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3547 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3548 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3549 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3550 top_hbox.remove (toolbar_frame);
3555 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3557 if (toolbar_frame.get_parent() == 0) {
3558 top_hbox.pack_end (toolbar_frame);
3563 Editor::set_show_measures (bool yn)
3565 if (_show_measures != yn) {
3568 if ((_show_measures = yn) == true) {
3570 tempo_lines->show();
3578 Editor::toggle_follow_playhead ()
3580 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3582 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3583 set_follow_playhead (tact->get_active());
3587 /** @param yn true to follow playhead, otherwise false.
3588 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3591 Editor::set_follow_playhead (bool yn, bool catch_up)
3593 if (_follow_playhead != yn) {
3594 if ((_follow_playhead = yn) == true && catch_up) {
3596 reset_x_origin_to_follow_playhead ();
3603 Editor::toggle_stationary_playhead ()
3605 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3607 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3608 set_stationary_playhead (tact->get_active());
3613 Editor::set_stationary_playhead (bool yn)
3615 if (_stationary_playhead != yn) {
3616 if ((_stationary_playhead = yn) == true) {
3618 // FIXME need a 3.0 equivalent of this 2.X call
3619 // update_current_screen ();
3626 Editor::playlist_selector () const
3628 return *_playlist_selector;
3632 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3636 switch (_snap_type) {
3641 case SnapToBeatDiv128:
3644 case SnapToBeatDiv64:
3647 case SnapToBeatDiv32:
3650 case SnapToBeatDiv28:
3653 case SnapToBeatDiv24:
3656 case SnapToBeatDiv20:
3659 case SnapToBeatDiv16:
3662 case SnapToBeatDiv14:
3665 case SnapToBeatDiv12:
3668 case SnapToBeatDiv10:
3671 case SnapToBeatDiv8:
3674 case SnapToBeatDiv7:
3677 case SnapToBeatDiv6:
3680 case SnapToBeatDiv5:
3683 case SnapToBeatDiv4:
3686 case SnapToBeatDiv3:
3689 case SnapToBeatDiv2:
3695 return _session->tempo_map().meter_at (position).divisions_per_bar();
3700 case SnapToTimecodeFrame:
3701 case SnapToTimecodeSeconds:
3702 case SnapToTimecodeMinutes:
3705 case SnapToRegionStart:
3706 case SnapToRegionEnd:
3707 case SnapToRegionSync:
3708 case SnapToRegionBoundary:
3718 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3722 ret = nudge_clock->current_duration (pos);
3723 next = ret + 1; /* XXXX fix me */
3729 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3731 ArdourDialog dialog (_("Playlist Deletion"));
3732 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3733 "If it is kept, its audio files will not be cleaned.\n"
3734 "If it is deleted, audio files used by it alone will be cleaned."),
3737 dialog.set_position (WIN_POS_CENTER);
3738 dialog.get_vbox()->pack_start (label);
3742 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3743 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3744 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3746 switch (dialog.run ()) {
3747 case RESPONSE_ACCEPT:
3748 /* delete the playlist */
3752 case RESPONSE_REJECT:
3753 /* keep the playlist */
3765 Editor::audio_region_selection_covers (framepos_t where)
3767 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3768 if ((*a)->region()->covers (where)) {
3777 Editor::prepare_for_cleanup ()
3779 cut_buffer->clear_regions ();
3780 cut_buffer->clear_playlists ();
3782 selection->clear_regions ();
3783 selection->clear_playlists ();
3785 _regions->suspend_redisplay ();
3789 Editor::finish_cleanup ()
3791 _regions->resume_redisplay ();
3795 Editor::transport_loop_location()
3798 return _session->locations()->auto_loop_location();
3805 Editor::transport_punch_location()
3808 return _session->locations()->auto_punch_location();
3815 Editor::control_layout_scroll (GdkEventScroll* ev)
3817 if (Keyboard::some_magic_widget_has_focus()) {
3821 switch (ev->direction) {
3823 scroll_tracks_up_line ();
3827 case GDK_SCROLL_DOWN:
3828 scroll_tracks_down_line ();
3832 /* no left/right handling yet */
3840 Editor::session_state_saved (string)
3843 _snapshots->redisplay ();
3847 Editor::maximise_editing_space ()
3855 if (!Config->get_keep_tearoffs()) {
3856 /* these calls will leave each tearoff visible *if* it is torn off,
3857 but invisible otherwise.
3859 _mouse_mode_tearoff->set_visible (false);
3860 _tools_tearoff->set_visible (false);
3861 _zoom_tearoff->set_visible (false);
3868 Editor::restore_editing_space ()
3876 if (!Config->get_keep_tearoffs()) {
3877 _mouse_mode_tearoff->set_visible (true);
3878 _tools_tearoff->set_visible (true);
3879 _zoom_tearoff->set_visible (true);
3886 * Make new playlists for a given track and also any others that belong
3887 * to the same active route group with the `edit' property.
3892 Editor::new_playlists (TimeAxisView* v)
3894 begin_reversible_command (_("new playlists"));
3895 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3896 _session->playlists->get (playlists);
3897 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3898 commit_reversible_command ();
3902 * Use a copy of the current playlist for a given track and also any others that belong
3903 * to the same active route group with the `edit' property.
3908 Editor::copy_playlists (TimeAxisView* v)
3910 begin_reversible_command (_("copy playlists"));
3911 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3912 _session->playlists->get (playlists);
3913 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3914 commit_reversible_command ();
3917 /** Clear the current playlist for a given track and also any others that belong
3918 * to the same active route group with the `edit' property.
3923 Editor::clear_playlists (TimeAxisView* v)
3925 begin_reversible_command (_("clear playlists"));
3926 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3927 _session->playlists->get (playlists);
3928 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
3929 commit_reversible_command ();
3933 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3935 atv.use_new_playlist (sz > 1 ? false : true, playlists);
3939 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3941 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
3945 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
3947 atv.clear_playlist ();
3951 Editor::on_key_press_event (GdkEventKey* ev)
3953 return key_press_focus_accelerator_handler (*this, ev);
3957 Editor::on_key_release_event (GdkEventKey* ev)
3959 return Gtk::Window::on_key_release_event (ev);
3960 // return key_press_focus_accelerator_handler (*this, ev);
3963 /** Queue up a change to the viewport x origin.
3964 * @param frame New x origin.
3967 Editor::reset_x_origin (framepos_t frame)
3969 queue_visual_change (frame);
3973 Editor::reset_y_origin (double y)
3975 queue_visual_change_y (y);
3979 Editor::reset_zoom (double fpu)
3981 queue_visual_change (fpu);
3985 Editor::reposition_and_zoom (framepos_t frame, double fpu)
3987 reset_x_origin (frame);
3990 if (!no_save_visual) {
3991 undo_visual_stack.push_back (current_visual_state(false));
3995 Editor::VisualState::VisualState (bool with_tracks)
3996 : gui_state (with_tracks ? new GUIObjectState : 0)
4000 Editor::VisualState::~VisualState ()
4005 Editor::VisualState*
4006 Editor::current_visual_state (bool with_tracks)
4008 VisualState* vs = new VisualState (with_tracks);
4009 vs->y_position = vertical_adjustment.get_value();
4010 vs->frames_per_unit = frames_per_unit;
4011 vs->leftmost_frame = leftmost_frame;
4012 vs->zoom_focus = zoom_focus;
4015 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4022 Editor::undo_visual_state ()
4024 if (undo_visual_stack.empty()) {
4028 VisualState* vs = undo_visual_stack.back();
4029 undo_visual_stack.pop_back();
4032 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4034 use_visual_state (*vs);
4038 Editor::redo_visual_state ()
4040 if (redo_visual_stack.empty()) {
4044 VisualState* vs = redo_visual_stack.back();
4045 redo_visual_stack.pop_back();
4047 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4049 use_visual_state (*vs);
4053 Editor::swap_visual_state ()
4055 if (undo_visual_stack.empty()) {
4056 redo_visual_state ();
4058 undo_visual_state ();
4063 Editor::use_visual_state (VisualState& vs)
4065 PBD::Unwinder<bool> nsv (no_save_visual, true);
4067 _routes->suspend_redisplay ();
4069 vertical_adjustment.set_value (vs.y_position);
4071 set_zoom_focus (vs.zoom_focus);
4072 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4075 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4077 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4078 (*i)->reset_visual_state ();
4082 _routes->update_visibility ();
4083 _routes->resume_redisplay ();
4087 Editor::set_frames_per_unit (double fpu)
4089 /* this is the core function that controls the zoom level of the canvas. it is called
4090 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4093 if (fpu == frames_per_unit) {
4102 /* don't allow zooms that fit more than the maximum number
4103 of frames into an 800 pixel wide space.
4106 if (max_framepos / fpu < 800.0) {
4111 tempo_lines->tempo_map_changed();
4113 frames_per_unit = fpu;
4118 Editor::post_zoom ()
4120 // convert fpu to frame count
4122 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4124 if (frames_per_unit != zoom_range_clock->current_duration()) {
4125 zoom_range_clock->set (frames);
4128 bool const showing_time_selection =
4129 mouse_mode == MouseRange ||
4130 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4132 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4133 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4134 (*i)->reshow_selection (selection->time);
4138 ZoomChanged (); /* EMIT_SIGNAL */
4140 //reset_scrolling_region ();
4142 if (playhead_cursor) {
4143 playhead_cursor->set_position (playhead_cursor->current_frame);
4146 refresh_location_display();
4147 _summary->set_overlays_dirty ();
4149 update_marker_labels ();
4155 Editor::queue_visual_change (framepos_t where)
4157 pending_visual_change.add (VisualChange::TimeOrigin);
4158 pending_visual_change.time_origin = where;
4159 ensure_visual_change_idle_handler ();
4163 Editor::queue_visual_change (double fpu)
4165 pending_visual_change.add (VisualChange::ZoomLevel);
4166 pending_visual_change.frames_per_unit = fpu;
4168 ensure_visual_change_idle_handler ();
4172 Editor::queue_visual_change_y (double y)
4174 pending_visual_change.add (VisualChange::YOrigin);
4175 pending_visual_change.y_origin = y;
4177 ensure_visual_change_idle_handler ();
4181 Editor::ensure_visual_change_idle_handler ()
4183 if (pending_visual_change.idle_handler_id < 0) {
4184 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4189 Editor::_idle_visual_changer (void* arg)
4191 return static_cast<Editor*>(arg)->idle_visual_changer ();
4195 Editor::idle_visual_changer ()
4197 VisualChange::Type p = pending_visual_change.pending;
4198 pending_visual_change.pending = (VisualChange::Type) 0;
4200 double const last_time_origin = horizontal_position ();
4202 if (p & VisualChange::ZoomLevel) {
4203 set_frames_per_unit (pending_visual_change.frames_per_unit);
4205 compute_fixed_ruler_scale ();
4206 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4207 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4208 update_tempo_based_rulers ();
4210 if (p & VisualChange::TimeOrigin) {
4211 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4213 if (p & VisualChange::YOrigin) {
4214 vertical_adjustment.set_value (pending_visual_change.y_origin);
4217 if (last_time_origin == horizontal_position ()) {
4218 /* changed signal not emitted */
4219 update_fixed_rulers ();
4220 redisplay_tempo (true);
4223 _summary->set_overlays_dirty ();
4225 pending_visual_change.idle_handler_id = -1;
4226 return 0; /* this is always a one-shot call */
4229 struct EditorOrderTimeAxisSorter {
4230 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4231 return a->order () < b->order ();
4236 Editor::sort_track_selection (TrackViewList& sel)
4238 EditorOrderTimeAxisSorter cmp;
4243 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4246 framepos_t where = 0;
4247 EditPoint ep = _edit_point;
4249 if (from_context_menu && (ep == EditAtMouse)) {
4250 return event_frame (&context_click_event, 0, 0);
4253 if (entered_marker) {
4254 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4255 return entered_marker->position();
4258 if (ignore_playhead && ep == EditAtPlayhead) {
4259 ep = EditAtSelectedMarker;
4263 case EditAtPlayhead:
4264 where = _session->audible_frame();
4265 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4268 case EditAtSelectedMarker:
4269 if (!selection->markers.empty()) {
4271 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4274 where = loc->start();
4278 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4286 if (!mouse_frame (where, ignored)) {
4287 /* XXX not right but what can we do ? */
4291 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4299 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4301 if (!_session) return;
4303 begin_reversible_command (cmd);
4307 if ((tll = transport_loop_location()) == 0) {
4308 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4309 XMLNode &before = _session->locations()->get_state();
4310 _session->locations()->add (loc, true);
4311 _session->set_auto_loop_location (loc);
4312 XMLNode &after = _session->locations()->get_state();
4313 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4315 XMLNode &before = tll->get_state();
4316 tll->set_hidden (false, this);
4317 tll->set (start, end);
4318 XMLNode &after = tll->get_state();
4319 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4322 commit_reversible_command ();
4326 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4328 if (!_session) return;
4330 begin_reversible_command (cmd);
4334 if ((tpl = transport_punch_location()) == 0) {
4335 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4336 XMLNode &before = _session->locations()->get_state();
4337 _session->locations()->add (loc, true);
4338 _session->set_auto_loop_location (loc);
4339 XMLNode &after = _session->locations()->get_state();
4340 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4343 XMLNode &before = tpl->get_state();
4344 tpl->set_hidden (false, this);
4345 tpl->set (start, end);
4346 XMLNode &after = tpl->get_state();
4347 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4350 commit_reversible_command ();
4353 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4354 * @param rs List to which found regions are added.
4355 * @param where Time to look at.
4356 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4359 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4361 const TrackViewList* tracks;
4364 tracks = &track_views;
4369 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4371 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4374 boost::shared_ptr<Track> tr;
4375 boost::shared_ptr<Playlist> pl;
4377 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4379 boost::shared_ptr<RegionList> regions = pl->regions_at (
4380 (framepos_t) floor ( (double) where * tr->speed()));
4382 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4383 RegionView* rv = rtv->view()->find_view (*i);
4394 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4396 const TrackViewList* tracks;
4399 tracks = &track_views;
4404 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4405 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4407 boost::shared_ptr<Track> tr;
4408 boost::shared_ptr<Playlist> pl;
4410 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4412 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4413 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4415 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4417 RegionView* rv = rtv->view()->find_view (*i);
4428 /** Start with regions that are selected. Then add equivalent regions
4429 * on tracks in the same active edit-enabled route group as any of
4430 * the regions that we started with.
4434 Editor::get_regions_from_selection ()
4436 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4439 /** Get regions using the following method:
4441 * Make an initial region list using the selected regions, unless
4442 * the edit point is `mouse' and the mouse is over an unselected
4443 * region. In this case, start with just that region.
4445 * Then, make an initial track list of the tracks that these
4446 * regions are on, and if the edit point is not `mouse', add the
4449 * Look at this track list and add any other tracks that are on the
4450 * same active edit-enabled route group as one of the initial tracks.
4452 * Finally take the initial region list and add any regions that are
4453 * under the edit point on one of the tracks on the track list to get
4454 * the returned region list.
4456 * The rationale here is that the mouse edit point is special in that
4457 * its position describes both a time and a track; the other edit
4458 * modes only describe a time. Hence if the edit point is `mouse' we
4459 * ignore selected tracks, as we assume the user means something by
4460 * pointing at a particular track. Also in this case we take note of
4461 * the region directly under the edit point, as there is always just one
4462 * (rather than possibly several with non-mouse edit points).
4466 Editor::get_regions_from_selection_and_edit_point ()
4468 RegionSelection regions;
4470 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4471 regions.add (entered_regionview);
4473 regions = selection->regions;
4476 TrackViewList tracks;
4478 if (_edit_point != EditAtMouse) {
4479 tracks = selection->tracks;
4482 /* Add any other tracks that have regions that are in the same
4483 edit-activated route group as one of our regions.
4485 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4487 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4489 if (g && g->is_active() && g->is_edit()) {
4490 tracks.add (axis_views_from_routes (g->route_list()));
4494 if (!tracks.empty()) {
4495 /* now find regions that are at the edit position on those tracks */
4496 framepos_t const where = get_preferred_edit_position ();
4497 get_regions_at (regions, where, tracks);
4503 /** Start with regions that are selected, or the entered regionview if none are selected.
4504 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4505 * of the regions that we started with.
4509 Editor::get_regions_from_selection_and_entered ()
4511 RegionSelection regions = selection->regions;
4513 if (regions.empty() && entered_regionview) {
4514 regions.add (entered_regionview);
4517 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4521 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4523 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4525 RouteTimeAxisView* tatv;
4527 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4529 boost::shared_ptr<Playlist> pl;
4530 vector<boost::shared_ptr<Region> > results;
4532 boost::shared_ptr<Track> tr;
4534 if ((tr = tatv->track()) == 0) {
4539 if ((pl = (tr->playlist())) != 0) {
4540 pl->get_region_list_equivalent_regions (region, results);
4543 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4544 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4545 regions.push_back (marv);
4554 Editor::show_rhythm_ferret ()
4556 if (rhythm_ferret == 0) {
4557 rhythm_ferret = new RhythmFerret(*this);
4560 rhythm_ferret->set_session (_session);
4561 rhythm_ferret->show ();
4562 rhythm_ferret->present ();
4566 Editor::first_idle ()
4568 MessageDialog* dialog = 0;
4570 if (track_views.size() > 1) {
4571 dialog = new MessageDialog (
4573 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4577 ARDOUR_UI::instance()->flush_pending ();
4580 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4584 // first idle adds route children (automation tracks), so we need to redisplay here
4585 _routes->redisplay ();
4592 Editor::_idle_resize (gpointer arg)
4594 return ((Editor*)arg)->idle_resize ();
4598 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4600 if (resize_idle_id < 0) {
4601 resize_idle_id = g_idle_add (_idle_resize, this);
4602 _pending_resize_amount = 0;
4605 /* make a note of the smallest resulting height, so that we can clamp the
4606 lower limit at TimeAxisView::hSmall */
4608 int32_t min_resulting = INT32_MAX;
4610 _pending_resize_amount += h;
4611 _pending_resize_view = view;
4613 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4615 if (selection->tracks.contains (_pending_resize_view)) {
4616 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4617 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4621 if (min_resulting < 0) {
4626 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4627 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4631 /** Handle pending resizing of tracks */
4633 Editor::idle_resize ()
4635 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4637 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4638 selection->tracks.contains (_pending_resize_view)) {
4640 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4641 if (*i != _pending_resize_view) {
4642 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4647 _pending_resize_amount = 0;
4649 _group_tabs->set_dirty ();
4650 resize_idle_id = -1;
4658 ENSURE_GUI_THREAD (*this, &Editor::located);
4660 playhead_cursor->set_position (_session->audible_frame ());
4661 if (_follow_playhead && !_pending_initial_locate) {
4662 reset_x_origin_to_follow_playhead ();
4665 _pending_locate_request = false;
4666 _pending_initial_locate = false;
4670 Editor::region_view_added (RegionView *)
4672 _summary->set_dirty ();
4676 Editor::region_view_removed ()
4678 _summary->set_dirty ();
4682 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4684 TrackViewList::const_iterator j = track_views.begin ();
4685 while (j != track_views.end()) {
4686 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4687 if (rtv && rtv->route() == r) {
4698 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4702 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4703 TimeAxisView* tv = axis_view_from_route (*i);
4714 Editor::handle_new_route (RouteList& routes)
4716 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4718 RouteTimeAxisView *rtv;
4719 list<RouteTimeAxisView*> new_views;
4721 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4722 boost::shared_ptr<Route> route = (*x);
4724 if (route->is_hidden() || route->is_monitor()) {
4728 DataType dt = route->input()->default_type();
4730 if (dt == ARDOUR::DataType::AUDIO) {
4731 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4732 rtv->set_route (route);
4733 } else if (dt == ARDOUR::DataType::MIDI) {
4734 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4735 rtv->set_route (route);
4737 throw unknown_type();
4740 new_views.push_back (rtv);
4741 track_views.push_back (rtv);
4743 rtv->effective_gain_display ();
4745 if (internal_editing()) {
4746 rtv->enter_internal_edit_mode ();
4748 rtv->leave_internal_edit_mode ();
4751 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4752 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4755 _routes->routes_added (new_views);
4756 _summary->routes_added (new_views);
4758 if (show_editor_mixer_when_tracks_arrive) {
4759 show_editor_mixer (true);
4762 editor_list_button.set_sensitive (true);
4766 Editor::timeaxisview_deleted (TimeAxisView *tv)
4768 if (_session && _session->deletion_in_progress()) {
4769 /* the situation is under control */
4773 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4775 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4777 _routes->route_removed (tv);
4779 if (tv == entered_track) {
4783 TimeAxisView::Children c = tv->get_child_list ();
4784 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4785 if (entered_track == i->get()) {
4790 /* remove it from the list of track views */
4792 TrackViewList::iterator i;
4794 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4795 i = track_views.erase (i);
4798 /* update whatever the current mixer strip is displaying, if revelant */
4800 boost::shared_ptr<Route> route;
4803 route = rtav->route ();
4806 if (current_mixer_strip && current_mixer_strip->route() == route) {
4808 TimeAxisView* next_tv;
4810 if (track_views.empty()) {
4812 } else if (i == track_views.end()) {
4813 next_tv = track_views.front();
4820 set_selected_mixer_strip (*next_tv);
4822 /* make the editor mixer strip go away setting the
4823 * button to inactive (which also unticks the menu option)
4826 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4832 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4834 if (apply_to_selection) {
4835 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4837 TrackSelection::iterator j = i;
4840 hide_track_in_display (*i, false);
4845 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4847 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4848 // this will hide the mixer strip
4849 set_selected_mixer_strip (*tv);
4852 _routes->hide_track_in_display (*tv);
4857 Editor::sync_track_view_list_and_routes ()
4859 track_views = TrackViewList (_routes->views ());
4861 _summary->set_dirty ();
4862 _group_tabs->set_dirty ();
4864 return false; // do not call again (until needed)
4868 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4870 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4875 /** Find a RouteTimeAxisView by the ID of its route */
4877 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4879 RouteTimeAxisView* v;
4881 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4882 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4883 if(v->route()->id() == id) {
4893 Editor::fit_route_group (RouteGroup *g)
4895 TrackViewList ts = axis_views_from_routes (g->route_list ());
4900 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4902 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4905 _session->cancel_audition ();
4909 if (_session->is_auditioning()) {
4910 _session->cancel_audition ();
4911 if (r == last_audition_region) {
4916 _session->audition_region (r);
4917 last_audition_region = r;
4922 Editor::hide_a_region (boost::shared_ptr<Region> r)
4924 r->set_hidden (true);
4928 Editor::show_a_region (boost::shared_ptr<Region> r)
4930 r->set_hidden (false);
4934 Editor::audition_region_from_region_list ()
4936 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
4940 Editor::hide_region_from_region_list ()
4942 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
4946 Editor::show_region_in_region_list ()
4948 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
4952 Editor::step_edit_status_change (bool yn)
4955 start_step_editing ();
4957 stop_step_editing ();
4962 Editor::start_step_editing ()
4964 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
4968 Editor::stop_step_editing ()
4970 step_edit_connection.disconnect ();
4974 Editor::check_step_edit ()
4976 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4977 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
4979 mtv->check_step_edit ();
4983 return true; // do it again, till we stop
4987 Editor::scroll_press (Direction dir)
4989 ++_scroll_callbacks;
4991 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
4992 /* delay the first auto-repeat */
4998 scroll_backward (1);
5006 scroll_tracks_up_line ();
5010 scroll_tracks_down_line ();
5014 /* do hacky auto-repeat */
5015 if (!_scroll_connection.connected ()) {
5017 _scroll_connection = Glib::signal_timeout().connect (
5018 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5021 _scroll_callbacks = 0;
5028 Editor::scroll_release ()
5030 _scroll_connection.disconnect ();
5033 /** Queue a change for the Editor viewport x origin to follow the playhead */
5035 Editor::reset_x_origin_to_follow_playhead ()
5037 framepos_t const frame = playhead_cursor->current_frame;
5039 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5041 if (_session->transport_speed() < 0) {
5043 if (frame > (current_page_frames() / 2)) {
5044 center_screen (frame-(current_page_frames()/2));
5046 center_screen (current_page_frames()/2);
5053 if (frame < leftmost_frame) {
5055 if (_session->transport_rolling()) {
5056 /* rolling; end up with the playhead at the right of the page */
5057 l = frame - current_page_frames ();
5059 /* not rolling: end up with the playhead 1/4 of the way along the page */
5060 l = frame - current_page_frames() / 4;
5064 if (_session->transport_rolling()) {
5065 /* rolling: end up with the playhead on the left of the page */
5068 /* not rolling: end up with the playhead 3/4 of the way along the page */
5069 l = frame - 3 * current_page_frames() / 4;
5077 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5083 Editor::super_rapid_screen_update ()
5085 if (!_session || !_session->engine().running()) {
5089 /* METERING / MIXER STRIPS */
5091 /* update track meters, if required */
5092 if (is_mapped() && meters_running) {
5093 RouteTimeAxisView* rtv;
5094 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5095 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5096 rtv->fast_update ();
5101 /* and any current mixer strip */
5102 if (current_mixer_strip) {
5103 current_mixer_strip->fast_update ();
5106 /* PLAYHEAD AND VIEWPORT */
5108 framepos_t const frame = _session->audible_frame();
5110 /* There are a few reasons why we might not update the playhead / viewport stuff:
5112 * 1. we don't update things when there's a pending locate request, otherwise
5113 * when the editor requests a locate there is a chance that this method
5114 * will move the playhead before the locate request is processed, causing
5116 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5117 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5120 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5122 last_update_frame = frame;
5124 if (!_dragging_playhead) {
5125 playhead_cursor->set_position (frame);
5128 if (!_stationary_playhead) {
5130 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5131 reset_x_origin_to_follow_playhead ();
5136 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5140 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5141 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5142 if (target <= 0.0) {
5145 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5146 target = (target * 0.15) + (current * 0.85);
5152 set_horizontal_position (current);
5161 Editor::session_going_away ()
5163 _have_idled = false;
5165 _session_connections.drop_connections ();
5167 super_rapid_screen_update_connection.disconnect ();
5169 selection->clear ();
5170 cut_buffer->clear ();
5172 clicked_regionview = 0;
5173 clicked_axisview = 0;
5174 clicked_routeview = 0;
5175 entered_regionview = 0;
5177 last_update_frame = 0;
5180 playhead_cursor->canvas_item.hide ();
5182 /* rip everything out of the list displays */
5186 _route_groups->clear ();
5188 /* do this first so that deleting a track doesn't reset cms to null
5189 and thus cause a leak.
5192 if (current_mixer_strip) {
5193 if (current_mixer_strip->get_parent() != 0) {
5194 global_hpacker.remove (*current_mixer_strip);
5196 delete current_mixer_strip;
5197 current_mixer_strip = 0;
5200 /* delete all trackviews */
5202 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5205 track_views.clear ();
5207 zoom_range_clock->set_session (0);
5208 nudge_clock->set_session (0);
5210 editor_list_button.set_active(false);
5211 editor_list_button.set_sensitive(false);
5213 /* clear tempo/meter rulers */
5214 remove_metric_marks ();
5216 clear_marker_display ();
5218 current_bbt_points_begin = current_bbt_points_end;
5220 /* get rid of any existing editor mixer strip */
5222 WindowTitle title(Glib::get_application_name());
5223 title += _("Editor");
5225 set_title (title.get_string());
5227 SessionHandlePtr::session_going_away ();
5232 Editor::show_editor_list (bool yn)
5235 _the_notebook.show ();
5237 _the_notebook.hide ();
5242 Editor::change_region_layering_order (bool from_context_menu)
5244 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5246 if (!clicked_routeview) {
5247 if (layering_order_editor) {
5248 layering_order_editor->hide ();
5253 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5259 boost::shared_ptr<Playlist> pl = track->playlist();
5265 if (layering_order_editor == 0) {
5266 layering_order_editor = new RegionLayeringOrderEditor (*this);
5267 layering_order_editor->set_position (WIN_POS_MOUSE);
5270 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5271 layering_order_editor->maybe_present ();
5275 Editor::update_region_layering_order_editor ()
5277 if (layering_order_editor && layering_order_editor->is_visible ()) {
5278 change_region_layering_order (true);
5283 Editor::setup_fade_images ()
5285 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5286 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5287 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5288 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5289 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5291 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5292 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5293 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5294 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5295 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5298 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5300 Editor::action_menu_item (std::string const & name)
5302 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5305 return *manage (a->create_menu_item ());
5309 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5311 EventBox* b = manage (new EventBox);
5312 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5313 Label* l = manage (new Label (name));
5317 _the_notebook.append_page (widget, *b);
5321 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5323 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5324 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5327 if (ev->type == GDK_2BUTTON_PRESS) {
5329 /* double-click on a notebook tab shrinks or expands the notebook */
5331 if (_notebook_shrunk) {
5332 if (pre_notebook_shrink_pane_width) {
5333 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5335 _notebook_shrunk = false;
5337 pre_notebook_shrink_pane_width = edit_pane.get_position();
5339 /* this expands the LHS of the edit pane to cover the notebook
5340 PAGE but leaves the tabs visible.
5342 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5343 _notebook_shrunk = true;
5351 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5353 using namespace Menu_Helpers;
5355 MenuList& items = _control_point_context_menu.items ();
5358 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5359 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5360 if (!can_remove_control_point (item)) {
5361 items.back().set_sensitive (false);
5364 _control_point_context_menu.popup (event->button.button, event->button.time);