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/stacktrace.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"
93 #include "crossfade_view.h"
97 #include "editor_cursors.h"
98 #include "editor_drag.h"
99 #include "editor_group_tabs.h"
100 #include "editor_locations.h"
101 #include "editor_regions.h"
102 #include "editor_route_groups.h"
103 #include "editor_routes.h"
104 #include "editor_snapshots.h"
105 #include "editor_summary.h"
106 #include "global_port_matrix.h"
107 #include "gui_object.h"
108 #include "gui_thread.h"
109 #include "keyboard.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "playlist_selector.h"
116 #include "public_editor.h"
117 #include "region_layering_order_editor.h"
118 #include "rgb_macros.h"
119 #include "rhythm_ferret.h"
120 #include "selection.h"
122 #include "simpleline.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
130 #include "imageframe_socket_handler.h"
134 using namespace ARDOUR;
137 using namespace Glib;
138 using namespace Gtkmm2ext;
139 using namespace Editing;
141 using PBD::internationalize;
143 using Gtkmm2ext::Keyboard;
145 const double Editor::timebar_height = 15.0;
147 static const gchar *_snap_type_strings[] = {
149 N_("Timecode Frames"),
150 N_("Timecode Seconds"),
151 N_("Timecode Minutes"),
181 static const gchar *_snap_mode_strings[] = {
188 static const gchar *_edit_point_strings[] = {
195 static const gchar *_zoom_focus_strings[] = {
205 #ifdef USE_RUBBERBAND
206 static const gchar *_rb_opt_strings[] = {
209 N_("Balanced multitimbral mixture"),
210 N_("Unpitched percussion with stable notes"),
211 N_("Crisp monophonic instrumental"),
212 N_("Unpitched solo percussion"),
213 N_("Resample without preserving pitch"),
219 show_me_the_size (Requisition* r, const char* what)
221 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
226 pane_size_watcher (Paned* pane)
228 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
229 it is no longer accessible. so stop that. this doesn't happen on X11,
230 just the quartz backend.
235 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
237 gint pos = pane->get_position ();
239 if (pos > max_width_of_lhs) {
240 pane->set_position (max_width_of_lhs);
246 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
248 /* time display buttons */
249 , minsec_label (_("Mins:Secs"))
250 , bbt_label (_("Bars:Beats"))
251 , timecode_label (_("Timecode"))
252 , samples_label (_("Samples"))
253 , tempo_label (_("Tempo"))
254 , meter_label (_("Meter"))
255 , mark_label (_("Location Markers"))
256 , range_mark_label (_("Range Markers"))
257 , transport_mark_label (_("Loop/Punch Ranges"))
258 , cd_mark_label (_("CD Markers"))
259 , edit_packer (4, 4, true)
261 /* the values here don't matter: layout widgets
262 reset them as needed.
265 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
267 /* tool bar related */
269 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
271 , toolbar_selection_clock_table (2,3)
273 , automation_mode_button (_("mode"))
275 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
278 , image_socket_listener(0)
283 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
284 , meters_running(false)
285 , _pending_locate_request (false)
286 , _pending_initial_locate (false)
287 , _last_cut_copy_source_track (0)
289 , _region_selection_change_updates_region_list (true)
290 , _following_mixer_selection (false)
294 /* we are a singleton */
296 PublicEditor::_instance = this;
300 selection = new Selection (this);
301 cut_buffer = new Selection (this);
303 clicked_regionview = 0;
304 clicked_axisview = 0;
305 clicked_routeview = 0;
306 clicked_crossfadeview = 0;
307 clicked_control_point = 0;
308 last_update_frame = 0;
309 pre_press_cursor = 0;
310 _drags = new DragManager (this);
311 current_mixer_strip = 0;
314 snap_type_strings = I18N (_snap_type_strings);
315 snap_mode_strings = I18N (_snap_mode_strings);
316 zoom_focus_strings = I18N (_zoom_focus_strings);
317 edit_point_strings = I18N (_edit_point_strings);
318 #ifdef USE_RUBBERBAND
319 rb_opt_strings = I18N (_rb_opt_strings);
323 snap_threshold = 5.0;
324 bbt_beat_subdivision = 4;
327 last_autoscroll_x = 0;
328 last_autoscroll_y = 0;
329 autoscroll_active = false;
330 autoscroll_timeout_tag = -1;
335 current_interthread_info = 0;
336 _show_measures = true;
338 show_gain_after_trim = false;
340 have_pending_keyboard_selection = false;
341 _follow_playhead = true;
342 _stationary_playhead = false;
343 _xfade_visibility = true;
344 editor_ruler_menu = 0;
345 no_ruler_shown_update = false;
347 range_marker_menu = 0;
348 marker_menu_item = 0;
349 tempo_or_meter_marker_menu = 0;
350 transport_marker_menu = 0;
351 new_transport_marker_menu = 0;
352 editor_mixer_strip_width = Wide;
353 show_editor_mixer_when_tracks_arrive = false;
354 region_edit_menu_split_multichannel_item = 0;
355 region_edit_menu_split_item = 0;
358 current_stepping_trackview = 0;
360 entered_regionview = 0;
362 clear_entered_track = false;
365 button_release_can_deselect = true;
366 _dragging_playhead = false;
367 _dragging_edit_point = false;
368 select_new_marker = false;
370 layering_order_editor = 0;
371 no_save_visual = false;
374 scrubbing_direction = 0;
378 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
379 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
380 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
381 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
382 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
384 _edit_point = EditAtMouse;
385 _internal_editing = false;
386 current_canvas_cursor = 0;
388 frames_per_unit = 2048; /* too early to use reset_zoom () */
390 _scroll_callbacks = 0;
392 zoom_focus = ZoomFocusLeft;
393 set_zoom_focus (ZoomFocusLeft);
394 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
396 bbt_label.set_name ("EditorTimeButton");
397 bbt_label.set_size_request (-1, (int)timebar_height);
398 bbt_label.set_alignment (1.0, 0.5);
399 bbt_label.set_padding (5,0);
401 bbt_label.set_no_show_all();
402 minsec_label.set_name ("EditorTimeButton");
403 minsec_label.set_size_request (-1, (int)timebar_height);
404 minsec_label.set_alignment (1.0, 0.5);
405 minsec_label.set_padding (5,0);
406 minsec_label.hide ();
407 minsec_label.set_no_show_all();
408 timecode_label.set_name ("EditorTimeButton");
409 timecode_label.set_size_request (-1, (int)timebar_height);
410 timecode_label.set_alignment (1.0, 0.5);
411 timecode_label.set_padding (5,0);
412 timecode_label.hide ();
413 timecode_label.set_no_show_all();
414 samples_label.set_name ("EditorTimeButton");
415 samples_label.set_size_request (-1, (int)timebar_height);
416 samples_label.set_alignment (1.0, 0.5);
417 samples_label.set_padding (5,0);
418 samples_label.hide ();
419 samples_label.set_no_show_all();
421 tempo_label.set_name ("EditorTimeButton");
422 tempo_label.set_size_request (-1, (int)timebar_height);
423 tempo_label.set_alignment (1.0, 0.5);
424 tempo_label.set_padding (5,0);
426 tempo_label.set_no_show_all();
428 meter_label.set_name ("EditorTimeButton");
429 meter_label.set_size_request (-1, (int)timebar_height);
430 meter_label.set_alignment (1.0, 0.5);
431 meter_label.set_padding (5,0);
433 meter_label.set_no_show_all();
435 mark_label.set_name ("EditorTimeButton");
436 mark_label.set_size_request (-1, (int)timebar_height);
437 mark_label.set_alignment (1.0, 0.5);
438 mark_label.set_padding (5,0);
440 mark_label.set_no_show_all();
442 cd_mark_label.set_name ("EditorTimeButton");
443 cd_mark_label.set_size_request (-1, (int)timebar_height);
444 cd_mark_label.set_alignment (1.0, 0.5);
445 cd_mark_label.set_padding (5,0);
446 cd_mark_label.hide();
447 cd_mark_label.set_no_show_all();
449 range_mark_label.set_name ("EditorTimeButton");
450 range_mark_label.set_size_request (-1, (int)timebar_height);
451 range_mark_label.set_alignment (1.0, 0.5);
452 range_mark_label.set_padding (5,0);
453 range_mark_label.hide();
454 range_mark_label.set_no_show_all();
456 transport_mark_label.set_name ("EditorTimeButton");
457 transport_mark_label.set_size_request (-1, (int)timebar_height);
458 transport_mark_label.set_alignment (1.0, 0.5);
459 transport_mark_label.set_padding (5,0);
460 transport_mark_label.hide();
461 transport_mark_label.set_no_show_all();
463 initialize_rulers ();
464 initialize_canvas ();
466 _summary = new EditorSummary (this);
468 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
469 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
471 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
473 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
474 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
476 edit_controls_vbox.set_spacing (0);
477 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
478 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
480 HBox* h = manage (new HBox);
481 _group_tabs = new EditorGroupTabs (this);
482 h->pack_start (*_group_tabs, PACK_SHRINK);
483 h->pack_start (edit_controls_vbox);
484 controls_layout.add (*h);
486 controls_layout.set_name ("EditControlsBase");
487 controls_layout.add_events (Gdk::SCROLL_MASK);
488 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
490 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
491 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
493 _cursors = new MouseCursors;
495 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
496 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
497 0.0, 1.0, 100.0, 1.0));
499 pad_line_1->property_color_rgba() = 0xFF0000FF;
504 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
505 time_canvas_vbox.set_size_request (-1, -1);
507 ruler_label_event_box.add (ruler_label_vbox);
508 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
509 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
511 time_button_event_box.add (time_button_vbox);
512 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
513 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
515 /* these enable us to have a dedicated window (for cursor setting, etc.)
516 for the canvas areas.
519 track_canvas_event_box.add (*track_canvas);
521 time_canvas_event_box.add (time_canvas_vbox);
522 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
524 edit_packer.set_col_spacings (0);
525 edit_packer.set_row_spacings (0);
526 edit_packer.set_homogeneous (false);
527 edit_packer.set_border_width (0);
528 edit_packer.set_name ("EditorWindow");
530 /* labels for the rulers */
531 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
532 /* labels for the marker "tracks" */
533 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
535 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
537 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
539 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
541 bottom_hbox.set_border_width (2);
542 bottom_hbox.set_spacing (3);
544 _route_groups = new EditorRouteGroups (this);
545 _routes = new EditorRoutes (this);
546 _regions = new EditorRegions (this);
547 _snapshots = new EditorSnapshots (this);
548 _locations = new EditorLocations (this);
550 add_notebook_page (_("Regions"), _regions->widget ());
551 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
552 add_notebook_page (_("Snapshots"), _snapshots->widget ());
553 add_notebook_page (_("Route Groups"), _route_groups->widget ());
554 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
556 _the_notebook.set_show_tabs (true);
557 _the_notebook.set_scrollable (true);
558 _the_notebook.popup_disable ();
559 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
560 _the_notebook.show_all ();
562 _notebook_shrunk = false;
564 editor_summary_pane.pack1(edit_packer);
566 Button* summary_arrows_left_left = manage (new Button);
567 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
568 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
569 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
571 Button* summary_arrows_left_right = manage (new Button);
572 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
573 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
574 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
576 VBox* summary_arrows_left = manage (new VBox);
577 summary_arrows_left->pack_start (*summary_arrows_left_left);
578 summary_arrows_left->pack_start (*summary_arrows_left_right);
580 Button* summary_arrows_right_up = manage (new Button);
581 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
582 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
583 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
585 Button* summary_arrows_right_down = manage (new Button);
586 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
587 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
588 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
590 VBox* summary_arrows_right = manage (new VBox);
591 summary_arrows_right->pack_start (*summary_arrows_right_up);
592 summary_arrows_right->pack_start (*summary_arrows_right_down);
594 Frame* summary_frame = manage (new Frame);
595 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
597 summary_frame->add (*_summary);
598 summary_frame->show ();
600 _summary_hbox.pack_start (*summary_arrows_left, false, false);
601 _summary_hbox.pack_start (*summary_frame, true, true);
602 _summary_hbox.pack_start (*summary_arrows_right, false, false);
604 editor_summary_pane.pack2 (_summary_hbox);
606 edit_pane.pack1 (editor_summary_pane, true, true);
607 edit_pane.pack2 (_the_notebook, false, true);
609 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
611 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
613 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
615 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
616 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
618 top_hbox.pack_start (toolbar_frame);
620 HBox *hbox = manage (new HBox);
621 hbox->pack_start (edit_pane, true, true);
623 global_vpacker.pack_start (top_hbox, false, false);
624 global_vpacker.pack_start (*hbox, true, true);
626 global_hpacker.pack_start (global_vpacker, true, true);
628 set_name ("EditorWindow");
629 add_accel_group (ActionManager::ui_manager->get_accel_group());
631 status_bar_hpacker.show ();
633 vpacker.pack_end (status_bar_hpacker, false, false);
634 vpacker.pack_end (global_hpacker, true, true);
636 /* register actions now so that set_state() can find them and set toggles/checks etc */
639 /* when we start using our own keybinding system for the editor, this
640 * will be uncommented
646 _snap_type = SnapToBeat;
647 set_snap_to (_snap_type);
648 _snap_mode = SnapOff;
649 set_snap_mode (_snap_mode);
650 set_mouse_mode (MouseObject, true);
651 pre_internal_mouse_mode = MouseObject;
652 pre_internal_snap_type = _snap_type;
653 pre_internal_snap_mode = _snap_mode;
654 internal_snap_type = _snap_type;
655 internal_snap_mode = _snap_mode;
656 set_edit_point_preference (EditAtMouse, true);
658 _playlist_selector = new PlaylistSelector();
659 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
661 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
665 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
666 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
668 nudge_forward_button.set_name ("TransportButton");
669 nudge_backward_button.set_name ("TransportButton");
671 fade_context_menu.set_name ("ArdourContextMenu");
673 /* icons, titles, WM stuff */
675 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
676 Glib::RefPtr<Gdk::Pixbuf> icon;
678 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
679 window_icons.push_back (icon);
681 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
682 window_icons.push_back (icon);
684 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
685 window_icons.push_back (icon);
687 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
688 window_icons.push_back (icon);
690 if (!window_icons.empty()) {
691 // set_icon_list (window_icons);
692 set_default_icon_list (window_icons);
695 WindowTitle title(Glib::get_application_name());
696 title += _("Editor");
697 set_title (title.get_string());
698 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
701 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
703 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
704 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
706 /* allow external control surfaces/protocols to do various things */
708 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
709 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
710 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
711 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
712 ControlProtocol::SelectByRID.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1), gui_context());
713 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
715 /* problematic: has to return a value and thus cannot be x-thread */
717 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
719 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
721 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
723 _ignore_region_action = false;
724 _last_region_menu_was_main = false;
725 _popup_region_menu_item = 0;
727 _show_marker_lines = false;
728 _over_region_trim_target = false;
730 /* Button bindings */
732 button_bindings = new Bindings;
734 XMLNode* node = button_settings();
736 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
737 button_bindings->load (**i);
744 setup_fade_images ();
750 if(image_socket_listener) {
751 if(image_socket_listener->is_connected())
753 image_socket_listener->close_connection() ;
756 delete image_socket_listener ;
757 image_socket_listener = 0 ;
761 delete button_bindings;
763 delete _route_groups;
769 Editor::button_settings () const
771 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
772 XMLNode* node = find_named_node (*settings, X_("Buttons"));
775 cerr << "new empty Button node\n";
776 node = new XMLNode (X_("Buttons"));
783 Editor::add_toplevel_controls (Container& cont)
785 vpacker.pack_start (cont, false, false);
790 Editor::catch_vanishing_regionview (RegionView *rv)
792 /* note: the selection will take care of the vanishing
793 audioregionview by itself.
796 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
800 if (clicked_regionview == rv) {
801 clicked_regionview = 0;
804 if (entered_regionview == rv) {
805 set_entered_regionview (0);
808 if (!_all_region_actions_sensitized) {
809 sensitize_all_region_actions (true);
812 _over_region_trim_target = false;
816 Editor::set_entered_regionview (RegionView* rv)
818 if (rv == entered_regionview) {
822 if (entered_regionview) {
823 entered_regionview->exited ();
826 if ((entered_regionview = rv) != 0) {
827 entered_regionview->entered (internal_editing ());
830 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
831 /* This RegionView entry might have changed what region actions
832 are allowed, so sensitize them all in case a key is pressed.
834 sensitize_all_region_actions (true);
839 Editor::set_entered_track (TimeAxisView* tav)
842 entered_track->exited ();
845 if ((entered_track = tav) != 0) {
846 entered_track->entered ();
851 Editor::show_window ()
853 if (!is_visible ()) {
856 /* XXX: this is a bit unfortunate; it would probably
857 be nicer if we could just call show () above rather
858 than needing the show_all ()
861 /* re-hide stuff if necessary */
862 editor_list_button_toggled ();
863 parameter_changed ("show-summary");
864 parameter_changed ("show-group-tabs");
865 parameter_changed ("show-zoom-tools");
867 /* now reset all audio_time_axis heights, because widgets might need
873 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
874 tv = (static_cast<TimeAxisView*>(*i));
878 if (current_mixer_strip) {
879 current_mixer_strip->hide_things ();
880 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
888 Editor::instant_save ()
890 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
895 _session->add_instant_xml(get_state());
897 Config->add_instant_xml(get_state());
902 Editor::zoom_adjustment_changed ()
908 double fpu = zoom_range_clock->current_duration() / _canvas_width;
912 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
913 } else if (fpu > _session->current_end_frame() / _canvas_width) {
914 fpu = _session->current_end_frame() / _canvas_width;
915 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
922 Editor::control_select (uint32_t rid)
924 /* handles the (static) signal from the ControlProtocol class that
925 * requests setting the selected track to a given RID
932 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
938 TimeAxisView* tav = axis_view_from_route (r);
941 selection->set (tav);
943 selection->clear_tracks ();
948 Editor::control_scroll (float fraction)
950 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
956 double step = fraction * current_page_frames();
959 _control_scroll_target is an optional<T>
961 it acts like a pointer to an framepos_t, with
962 a operator conversion to boolean to check
963 that it has a value could possibly use
964 playhead_cursor->current_frame to store the
965 value and a boolean in the class to know
966 when it's out of date
969 if (!_control_scroll_target) {
970 _control_scroll_target = _session->transport_frame();
971 _dragging_playhead = true;
974 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
975 *_control_scroll_target = 0;
976 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
977 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
979 *_control_scroll_target += (framepos_t) floor (step);
982 /* move visuals, we'll catch up with it later */
984 playhead_cursor->set_position (*_control_scroll_target);
985 UpdateAllTransportClocks (*_control_scroll_target);
987 if (*_control_scroll_target > (current_page_frames() / 2)) {
988 /* try to center PH in window */
989 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
995 Now we do a timeout to actually bring the session to the right place
996 according to the playhead. This is to avoid reading disk buffers on every
997 call to control_scroll, which is driven by ScrollTimeline and therefore
998 probably by a control surface wheel which can generate lots of events.
1000 /* cancel the existing timeout */
1002 control_scroll_connection.disconnect ();
1004 /* add the next timeout */
1006 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1010 Editor::deferred_control_scroll (framepos_t /*target*/)
1012 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1013 // reset for next stream
1014 _control_scroll_target = boost::none;
1015 _dragging_playhead = false;
1020 Editor::access_action (std::string action_group, std::string action_item)
1026 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1029 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1037 Editor::on_realize ()
1039 Window::on_realize ();
1044 Editor::map_position_change (framepos_t frame)
1046 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1048 if (_session == 0) {
1052 if (_follow_playhead) {
1053 center_screen (frame);
1056 playhead_cursor->set_position (frame);
1060 Editor::center_screen (framepos_t frame)
1062 double page = _canvas_width * frames_per_unit;
1064 /* if we're off the page, then scroll.
1067 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1068 center_screen_internal (frame, page);
1073 Editor::center_screen_internal (framepos_t frame, float page)
1078 frame -= (framepos_t) page;
1083 reset_x_origin (frame);
1088 Editor::update_title ()
1090 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1093 bool dirty = _session->dirty();
1095 string session_name;
1097 if (_session->snap_name() != _session->name()) {
1098 session_name = _session->snap_name();
1100 session_name = _session->name();
1104 session_name = "*" + session_name;
1107 WindowTitle title(session_name);
1108 title += Glib::get_application_name();
1109 set_title (title.get_string());
1114 Editor::set_session (Session *t)
1116 SessionHandlePtr::set_session (t);
1122 zoom_range_clock->set_session (_session);
1123 _playlist_selector->set_session (_session);
1124 nudge_clock->set_session (_session);
1125 _summary->set_session (_session);
1126 _group_tabs->set_session (_session);
1127 _route_groups->set_session (_session);
1128 _regions->set_session (_session);
1129 _snapshots->set_session (_session);
1130 _routes->set_session (_session);
1131 _locations->set_session (_session);
1133 if (rhythm_ferret) {
1134 rhythm_ferret->set_session (_session);
1137 if (analysis_window) {
1138 analysis_window->set_session (_session);
1142 sfbrowser->set_session (_session);
1145 compute_fixed_ruler_scale ();
1147 /* Make sure we have auto loop and auto punch ranges */
1149 Location* loc = _session->locations()->auto_loop_location();
1151 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1153 if (loc->start() == loc->end()) {
1154 loc->set_end (loc->start() + 1);
1157 _session->locations()->add (loc, false);
1158 _session->set_auto_loop_location (loc);
1161 loc->set_name (_("Loop"));
1164 loc = _session->locations()->auto_punch_location();
1167 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1169 if (loc->start() == loc->end()) {
1170 loc->set_end (loc->start() + 1);
1173 _session->locations()->add (loc, false);
1174 _session->set_auto_punch_location (loc);
1177 loc->set_name (_("Punch"));
1180 refresh_location_display ();
1182 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1183 the selected Marker; this needs the LocationMarker list to be available.
1185 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1186 set_state (*node, Stateful::loading_state_version);
1188 /* catch up with the playhead */
1190 _session->request_locate (playhead_cursor->current_frame);
1191 _pending_initial_locate = true;
1195 /* These signals can all be emitted by a non-GUI thread. Therefore the
1196 handlers for them must not attempt to directly interact with the GUI,
1197 but use Gtkmm2ext::UI::instance()->call_slot();
1200 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1201 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1202 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1203 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1204 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1205 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1206 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1207 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1208 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1209 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1210 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1211 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1212 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display, this), gui_context());
1213 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1215 if (Profile->get_sae()) {
1216 Timecode::BBT_Time bbt;
1220 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1221 nudge_clock->set_mode(AudioClock::BBT);
1222 nudge_clock->set (pos, true);
1225 nudge_clock->set_mode (AudioClock::Timecode);
1226 nudge_clock->set (_session->frame_rate() * 5, true);
1229 playhead_cursor->canvas_item.show ();
1231 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1232 Config->map_parameters (pc);
1233 _session->config.map_parameters (pc);
1235 restore_ruler_visibility ();
1236 //tempo_map_changed (PropertyChange (0));
1237 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1239 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1240 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1243 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1244 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1247 switch (_snap_type) {
1248 case SnapToRegionStart:
1249 case SnapToRegionEnd:
1250 case SnapToRegionSync:
1251 case SnapToRegionBoundary:
1252 build_region_boundary_cache ();
1259 /* register for undo history */
1260 _session->register_with_memento_command_factory(id(), this);
1262 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1264 start_updating_meters ();
1268 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1270 if (a->get_name() == "RegionMenu") {
1271 /* When the main menu's region menu is opened, we setup the actions so that they look right
1272 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1273 so we resensitize all region actions when the entered regionview or the region selection
1274 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1275 happens after the region context menu is opened. So we set a flag here, too.
1279 sensitize_the_right_region_actions ();
1280 _last_region_menu_was_main = true;
1284 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1286 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1288 using namespace Menu_Helpers;
1289 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1292 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1296 MenuList& items (fade_context_menu.items());
1300 switch (item_type) {
1302 case FadeInHandleItem:
1303 if (arv->audio_region()->fade_in_active()) {
1304 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1306 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1309 items.push_back (SeparatorElem());
1311 if (Profile->get_sae()) {
1313 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1314 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1321 *_fade_in_images[FadeLinear],
1322 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1326 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1331 *_fade_in_images[FadeFast],
1332 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1335 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1340 *_fade_in_images[FadeLogB],
1341 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1344 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1349 *_fade_in_images[FadeLogA],
1350 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1353 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1358 *_fade_in_images[FadeSlow],
1359 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1362 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1368 case FadeOutHandleItem:
1369 if (arv->audio_region()->fade_out_active()) {
1370 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1372 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1375 items.push_back (SeparatorElem());
1377 if (Profile->get_sae()) {
1378 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1379 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1385 *_fade_out_images[FadeLinear],
1386 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1390 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1395 *_fade_out_images[FadeFast],
1396 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1399 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1404 *_fade_out_images[FadeLogB],
1405 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1408 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1413 *_fade_out_images[FadeLogA],
1414 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1417 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1422 *_fade_out_images[FadeSlow],
1423 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1426 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1432 fatal << _("programming error: ")
1433 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1438 fade_context_menu.popup (button, time);
1442 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1444 using namespace Menu_Helpers;
1445 Menu* (Editor::*build_menu_function)();
1448 switch (item_type) {
1450 case RegionViewName:
1451 case RegionViewNameHighlight:
1452 case LeftFrameHandle:
1453 case RightFrameHandle:
1454 if (with_selection) {
1455 build_menu_function = &Editor::build_track_selection_context_menu;
1457 build_menu_function = &Editor::build_track_region_context_menu;
1462 if (with_selection) {
1463 build_menu_function = &Editor::build_track_selection_context_menu;
1465 build_menu_function = &Editor::build_track_context_menu;
1469 case CrossfadeViewItem:
1470 build_menu_function = &Editor::build_track_crossfade_context_menu;
1474 if (clicked_routeview->track()) {
1475 build_menu_function = &Editor::build_track_context_menu;
1477 build_menu_function = &Editor::build_track_bus_context_menu;
1482 /* probably shouldn't happen but if it does, we don't care */
1486 menu = (this->*build_menu_function)();
1487 menu->set_name ("ArdourContextMenu");
1489 /* now handle specific situations */
1491 switch (item_type) {
1493 case RegionViewName:
1494 case RegionViewNameHighlight:
1495 case LeftFrameHandle:
1496 case RightFrameHandle:
1497 if (!with_selection) {
1498 if (region_edit_menu_split_item) {
1499 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1500 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1502 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1505 if (region_edit_menu_split_multichannel_item) {
1506 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1507 region_edit_menu_split_multichannel_item->set_sensitive (true);
1509 region_edit_menu_split_multichannel_item->set_sensitive (false);
1518 case CrossfadeViewItem:
1525 /* probably shouldn't happen but if it does, we don't care */
1529 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1531 /* Bounce to disk */
1533 using namespace Menu_Helpers;
1534 MenuList& edit_items = menu->items();
1536 edit_items.push_back (SeparatorElem());
1538 switch (clicked_routeview->audio_track()->freeze_state()) {
1539 case AudioTrack::NoFreeze:
1540 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1543 case AudioTrack::Frozen:
1544 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1547 case AudioTrack::UnFrozen:
1548 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1554 if (item_type == StreamItem && clicked_routeview) {
1555 clicked_routeview->build_underlay_menu(menu);
1558 /* When the region menu is opened, we setup the actions so that they look right
1561 sensitize_the_right_region_actions ();
1562 _last_region_menu_was_main = false;
1564 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1565 menu->popup (button, time);
1569 Editor::build_track_context_menu ()
1571 using namespace Menu_Helpers;
1573 MenuList& edit_items = track_context_menu.items();
1576 add_dstream_context_items (edit_items);
1577 return &track_context_menu;
1581 Editor::build_track_bus_context_menu ()
1583 using namespace Menu_Helpers;
1585 MenuList& edit_items = track_context_menu.items();
1588 add_bus_context_items (edit_items);
1589 return &track_context_menu;
1593 Editor::build_track_region_context_menu ()
1595 using namespace Menu_Helpers;
1596 MenuList& edit_items = track_region_context_menu.items();
1599 /* we've just cleared the track region context menu, so the menu that these
1600 two items were on will have disappeared; stop them dangling.
1602 region_edit_menu_split_item = 0;
1603 region_edit_menu_split_multichannel_item = 0;
1605 /* we might try to use items that are currently attached to a crossfade menu,
1608 track_crossfade_context_menu.items().clear ();
1610 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1613 boost::shared_ptr<Track> tr;
1614 boost::shared_ptr<Playlist> pl;
1616 if ((tr = rtv->track())) {
1617 add_region_context_items (edit_items, tr);
1621 add_dstream_context_items (edit_items);
1623 return &track_region_context_menu;
1627 Editor::build_track_crossfade_context_menu ()
1629 using namespace Menu_Helpers;
1630 MenuList& edit_items = track_crossfade_context_menu.items();
1631 edit_items.clear ();
1633 /* we might try to use items that are currently attached to a crossfade menu,
1636 track_region_context_menu.items().clear ();
1638 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1641 boost::shared_ptr<Track> tr;
1642 boost::shared_ptr<Playlist> pl;
1643 boost::shared_ptr<AudioPlaylist> apl;
1645 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1647 AudioPlaylist::Crossfades xfades;
1651 /* The xfade menu is a bit of a special case, as we always use the mouse position
1652 to decide whether or not to display it (rather than the edit point). No particularly
1653 strong reasons for this, other than it is a bit surprising to right-click on a xfade
1656 mouse_frame (where, ignored);
1657 apl->crossfades_at (where, xfades);
1659 bool const many = xfades.size() > 1;
1661 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1662 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1665 add_region_context_items (edit_items, tr);
1669 add_dstream_context_items (edit_items);
1671 return &track_crossfade_context_menu;
1675 Editor::analyze_region_selection ()
1677 if (analysis_window == 0) {
1678 analysis_window = new AnalysisWindow();
1681 analysis_window->set_session(_session);
1683 analysis_window->show_all();
1686 analysis_window->set_regionmode();
1687 analysis_window->analyze();
1689 analysis_window->present();
1693 Editor::analyze_range_selection()
1695 if (analysis_window == 0) {
1696 analysis_window = new AnalysisWindow();
1699 analysis_window->set_session(_session);
1701 analysis_window->show_all();
1704 analysis_window->set_rangemode();
1705 analysis_window->analyze();
1707 analysis_window->present();
1711 Editor::build_track_selection_context_menu ()
1713 using namespace Menu_Helpers;
1714 MenuList& edit_items = track_selection_context_menu.items();
1715 edit_items.clear ();
1717 add_selection_context_items (edit_items);
1718 // edit_items.push_back (SeparatorElem());
1719 // add_dstream_context_items (edit_items);
1721 return &track_selection_context_menu;
1724 /** Add context menu items relevant to crossfades.
1725 * @param edit_items List to add the items to.
1728 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1730 using namespace Menu_Helpers;
1731 Menu *xfade_menu = manage (new Menu);
1732 MenuList& items = xfade_menu->items();
1733 xfade_menu->set_name ("ArdourContextMenu");
1736 if (xfade->active()) {
1743 MenuElem (str, sigc::bind (sigc::mem_fun (*this, &Editor::toggle_xfade_active), &view->trackview(), boost::weak_ptr<Crossfade> (xfade)))
1747 MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade)))
1750 if (xfade->can_follow_overlap()) {
1752 if (xfade->following_overlap()) {
1753 str = _("Convert to Short");
1755 str = _("Convert to Full");
1759 MenuElem (str, sigc::bind (sigc::mem_fun (*this, &Editor::toggle_xfade_length), &view->trackview(), xfade))
1764 str = xfade->out()->name();
1766 str += xfade->in()->name();
1768 str = _("Crossfade");
1771 edit_items.push_back (MenuElem (str, *xfade_menu));
1772 edit_items.push_back (SeparatorElem());
1776 Editor::xfade_edit_left_region ()
1778 if (clicked_crossfadeview) {
1779 clicked_crossfadeview->left_view.show_region_editor ();
1784 Editor::xfade_edit_right_region ()
1786 if (clicked_crossfadeview) {
1787 clicked_crossfadeview->right_view.show_region_editor ();
1792 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1794 using namespace Menu_Helpers;
1796 /* OK, stick the region submenu at the top of the list, and then add
1800 RegionSelection rs = get_regions_from_selection_and_entered ();
1802 string::size_type pos = 0;
1803 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1805 /* we have to hack up the region name because "_" has a special
1806 meaning for menu titles.
1809 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1810 menu_item_name.replace (pos, 1, "__");
1814 if (_popup_region_menu_item == 0) {
1815 _popup_region_menu_item = new MenuItem (menu_item_name);
1816 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1817 _popup_region_menu_item->show ();
1819 _popup_region_menu_item->set_label (menu_item_name);
1822 const framepos_t position = get_preferred_edit_position (false, true);
1824 edit_items.push_back (*_popup_region_menu_item);
1825 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1826 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1828 edit_items.push_back (SeparatorElem());
1831 /** Add context menu items relevant to selection ranges.
1832 * @param edit_items List to add the items to.
1835 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1837 using namespace Menu_Helpers;
1839 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1840 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1842 edit_items.push_back (SeparatorElem());
1843 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1845 edit_items.push_back (SeparatorElem());
1847 edit_items.push_back (
1849 _("Move Range Start to Previous Region Boundary"),
1850 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1854 edit_items.push_back (
1856 _("Move Range Start to Next Region Boundary"),
1857 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1861 edit_items.push_back (
1863 _("Move Range End to Previous Region Boundary"),
1864 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1868 edit_items.push_back (
1870 _("Move Range End to Next Region Boundary"),
1871 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1877 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1879 edit_items.push_back (SeparatorElem());
1880 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1882 edit_items.push_back (SeparatorElem());
1883 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1884 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1886 edit_items.push_back (SeparatorElem());
1887 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1889 edit_items.push_back (SeparatorElem());
1890 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1891 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1892 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1894 edit_items.push_back (SeparatorElem());
1895 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1896 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1897 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1898 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1899 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1904 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1906 using namespace Menu_Helpers;
1910 Menu *play_menu = manage (new Menu);
1911 MenuList& play_items = play_menu->items();
1912 play_menu->set_name ("ArdourContextMenu");
1914 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1915 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1916 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1917 play_items.push_back (SeparatorElem());
1918 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1920 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1924 Menu *select_menu = manage (new Menu);
1925 MenuList& select_items = select_menu->items();
1926 select_menu->set_name ("ArdourContextMenu");
1928 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1929 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1930 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1931 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1932 select_items.push_back (SeparatorElem());
1933 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1934 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1935 select_items.push_back (SeparatorElem());
1936 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1937 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1938 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1939 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1940 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1941 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1942 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1944 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1948 Menu *cutnpaste_menu = manage (new Menu);
1949 MenuList& cutnpaste_items = cutnpaste_menu->items();
1950 cutnpaste_menu->set_name ("ArdourContextMenu");
1952 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1953 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1954 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1956 cutnpaste_items.push_back (SeparatorElem());
1958 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1959 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1961 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1963 /* Adding new material */
1965 edit_items.push_back (SeparatorElem());
1966 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1967 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1971 Menu *nudge_menu = manage (new Menu());
1972 MenuList& nudge_items = nudge_menu->items();
1973 nudge_menu->set_name ("ArdourContextMenu");
1975 edit_items.push_back (SeparatorElem());
1976 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1977 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1978 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1979 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1981 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1985 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1987 using namespace Menu_Helpers;
1991 Menu *play_menu = manage (new Menu);
1992 MenuList& play_items = play_menu->items();
1993 play_menu->set_name ("ArdourContextMenu");
1995 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1996 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1997 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2001 Menu *select_menu = manage (new Menu);
2002 MenuList& select_items = select_menu->items();
2003 select_menu->set_name ("ArdourContextMenu");
2005 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2006 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2007 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2008 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2009 select_items.push_back (SeparatorElem());
2010 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2011 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2012 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2013 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2015 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2019 Menu *cutnpaste_menu = manage (new Menu);
2020 MenuList& cutnpaste_items = cutnpaste_menu->items();
2021 cutnpaste_menu->set_name ("ArdourContextMenu");
2023 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2024 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2025 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2027 Menu *nudge_menu = manage (new Menu());
2028 MenuList& nudge_items = nudge_menu->items();
2029 nudge_menu->set_name ("ArdourContextMenu");
2031 edit_items.push_back (SeparatorElem());
2032 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2033 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2034 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2035 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2037 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2041 Editor::snap_type() const
2047 Editor::snap_mode() const
2053 Editor::set_snap_to (SnapType st)
2055 unsigned int snap_ind = (unsigned int)st;
2059 if (snap_ind > snap_type_strings.size() - 1) {
2061 _snap_type = (SnapType)snap_ind;
2064 string str = snap_type_strings[snap_ind];
2066 if (str != snap_type_selector.get_active_text()) {
2067 snap_type_selector.set_active_text (str);
2072 switch (_snap_type) {
2073 case SnapToBeatDiv128:
2074 case SnapToBeatDiv64:
2075 case SnapToBeatDiv32:
2076 case SnapToBeatDiv28:
2077 case SnapToBeatDiv24:
2078 case SnapToBeatDiv20:
2079 case SnapToBeatDiv16:
2080 case SnapToBeatDiv14:
2081 case SnapToBeatDiv12:
2082 case SnapToBeatDiv10:
2083 case SnapToBeatDiv8:
2084 case SnapToBeatDiv7:
2085 case SnapToBeatDiv6:
2086 case SnapToBeatDiv5:
2087 case SnapToBeatDiv4:
2088 case SnapToBeatDiv3:
2089 case SnapToBeatDiv2:
2090 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2091 update_tempo_based_rulers ();
2094 case SnapToRegionStart:
2095 case SnapToRegionEnd:
2096 case SnapToRegionSync:
2097 case SnapToRegionBoundary:
2098 build_region_boundary_cache ();
2106 SnapChanged (); /* EMIT SIGNAL */
2110 Editor::set_snap_mode (SnapMode mode)
2113 string str = snap_mode_strings[(int)mode];
2115 if (str != snap_mode_selector.get_active_text ()) {
2116 snap_mode_selector.set_active_text (str);
2122 Editor::set_edit_point_preference (EditPoint ep, bool force)
2124 bool changed = (_edit_point != ep);
2127 string str = edit_point_strings[(int)ep];
2129 if (str != edit_point_selector.get_active_text ()) {
2130 edit_point_selector.set_active_text (str);
2133 set_canvas_cursor ();
2135 if (!force && !changed) {
2139 const char* action=NULL;
2141 switch (_edit_point) {
2142 case EditAtPlayhead:
2143 action = "edit-at-playhead";
2145 case EditAtSelectedMarker:
2146 action = "edit-at-marker";
2149 action = "edit-at-mouse";
2153 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2155 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2159 bool in_track_canvas;
2161 if (!mouse_frame (foo, in_track_canvas)) {
2162 in_track_canvas = false;
2165 reset_canvas_action_sensitivity (in_track_canvas);
2171 Editor::set_state (const XMLNode& node, int /*version*/)
2173 const XMLProperty* prop;
2180 g.base_width = default_width;
2181 g.base_height = default_height;
2185 if ((geometry = find_named_node (node, "geometry")) != 0) {
2189 if ((prop = geometry->property("x_size")) == 0) {
2190 prop = geometry->property ("x-size");
2193 g.base_width = atoi(prop->value());
2195 if ((prop = geometry->property("y_size")) == 0) {
2196 prop = geometry->property ("y-size");
2199 g.base_height = atoi(prop->value());
2202 if ((prop = geometry->property ("x_pos")) == 0) {
2203 prop = geometry->property ("x-pos");
2206 x = atoi (prop->value());
2209 if ((prop = geometry->property ("y_pos")) == 0) {
2210 prop = geometry->property ("y-pos");
2213 y = atoi (prop->value());
2217 set_default_size (g.base_width, g.base_height);
2220 if (_session && (prop = node.property ("playhead"))) {
2222 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2223 playhead_cursor->set_position (pos);
2225 playhead_cursor->set_position (0);
2228 if ((prop = node.property ("mixer-width"))) {
2229 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2232 if ((prop = node.property ("zoom-focus"))) {
2233 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2236 if ((prop = node.property ("zoom"))) {
2237 reset_zoom (PBD::atof (prop->value()));
2239 reset_zoom (frames_per_unit);
2242 if ((prop = node.property ("snap-to"))) {
2243 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2246 if ((prop = node.property ("snap-mode"))) {
2247 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2250 if ((prop = node.property ("internal-snap-to"))) {
2251 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2254 if ((prop = node.property ("internal-snap-mode"))) {
2255 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2258 if ((prop = node.property ("pre-internal-snap-to"))) {
2259 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2262 if ((prop = node.property ("pre-internal-snap-mode"))) {
2263 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2266 if ((prop = node.property ("mouse-mode"))) {
2267 MouseMode m = str2mousemode(prop->value());
2268 set_mouse_mode (m, true);
2270 set_mouse_mode (MouseObject, true);
2273 if ((prop = node.property ("left-frame")) != 0) {
2275 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2279 reset_x_origin (pos);
2283 if ((prop = node.property ("y-origin")) != 0) {
2284 reset_y_origin (atof (prop->value ()));
2287 if ((prop = node.property ("internal-edit"))) {
2288 bool yn = string_is_affirmative (prop->value());
2289 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2291 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2292 tact->set_active (!yn);
2293 tact->set_active (yn);
2297 if ((prop = node.property ("join-object-range"))) {
2298 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2301 if ((prop = node.property ("edit-point"))) {
2302 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2305 if ((prop = node.property ("show-measures"))) {
2306 bool yn = string_is_affirmative (prop->value());
2307 _show_measures = yn;
2308 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2310 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2311 /* do it twice to force the change */
2312 tact->set_active (!yn);
2313 tact->set_active (yn);
2317 if ((prop = node.property ("follow-playhead"))) {
2318 bool yn = string_is_affirmative (prop->value());
2319 set_follow_playhead (yn);
2320 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2322 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2323 if (tact->get_active() != yn) {
2324 tact->set_active (yn);
2329 if ((prop = node.property ("stationary-playhead"))) {
2330 bool yn = string_is_affirmative (prop->value());
2331 set_stationary_playhead (yn);
2332 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2334 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2335 if (tact->get_active() != yn) {
2336 tact->set_active (yn);
2341 if ((prop = node.property ("region-list-sort-type"))) {
2342 RegionListSortType st;
2343 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2346 if ((prop = node.property ("xfades-visible"))) {
2347 bool yn = string_is_affirmative (prop->value());
2348 _xfade_visibility = !yn;
2349 // set_xfade_visibility (yn);
2352 if ((prop = node.property ("show-editor-mixer"))) {
2354 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2357 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2358 bool yn = string_is_affirmative (prop->value());
2360 /* do it twice to force the change */
2362 tact->set_active (!yn);
2363 tact->set_active (yn);
2366 if ((prop = node.property ("show-editor-list"))) {
2368 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2371 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2372 bool yn = string_is_affirmative (prop->value());
2374 /* do it twice to force the change */
2376 tact->set_active (!yn);
2377 tact->set_active (yn);
2380 if ((prop = node.property (X_("editor-list-page")))) {
2381 _the_notebook.set_current_page (atoi (prop->value ()));
2384 if ((prop = node.property (X_("show-marker-lines")))) {
2385 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2387 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2388 bool yn = string_is_affirmative (prop->value ());
2390 tact->set_active (!yn);
2391 tact->set_active (yn);
2394 XMLNodeList children = node.children ();
2395 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2396 selection->set_state (**i, Stateful::current_state_version);
2397 _regions->set_state (**i);
2400 if ((prop = node.property ("maximised"))) {
2401 bool yn = string_is_affirmative (prop->value());
2403 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2411 Editor::get_state ()
2413 XMLNode* node = new XMLNode ("Editor");
2416 id().print (buf, sizeof (buf));
2417 node->add_property ("id", buf);
2419 if (is_realized()) {
2420 Glib::RefPtr<Gdk::Window> win = get_window();
2422 int x, y, width, height;
2423 win->get_root_origin(x, y);
2424 win->get_size(width, height);
2426 XMLNode* geometry = new XMLNode ("geometry");
2428 snprintf(buf, sizeof(buf), "%d", width);
2429 geometry->add_property("x-size", string(buf));
2430 snprintf(buf, sizeof(buf), "%d", height);
2431 geometry->add_property("y-size", string(buf));
2432 snprintf(buf, sizeof(buf), "%d", x);
2433 geometry->add_property("x-pos", string(buf));
2434 snprintf(buf, sizeof(buf), "%d", y);
2435 geometry->add_property("y-pos", string(buf));
2436 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2437 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2438 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2439 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2440 geometry->add_property("edit-vertical-pane-pos", string(buf));
2442 node->add_child_nocopy (*geometry);
2445 maybe_add_mixer_strip_width (*node);
2447 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2448 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2449 node->add_property ("zoom", buf);
2450 node->add_property ("snap-to", enum_2_string (_snap_type));
2451 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2452 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2453 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2454 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2455 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2456 node->add_property ("edit-point", enum_2_string (_edit_point));
2458 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2459 node->add_property ("playhead", buf);
2460 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2461 node->add_property ("left-frame", buf);
2462 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2463 node->add_property ("y-origin", buf);
2465 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2466 node->add_property ("maximised", _maximised ? "yes" : "no");
2467 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2468 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2469 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2470 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2471 node->add_property ("mouse-mode", enum2str(mouse_mode));
2472 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2473 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2475 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2477 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2478 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2481 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2483 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2484 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2487 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2488 node->add_property (X_("editor-list-page"), buf);
2490 if (button_bindings) {
2491 XMLNode* bb = new XMLNode (X_("Buttons"));
2492 button_bindings->save (*bb);
2493 node->add_child_nocopy (*bb);
2496 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2498 node->add_child_nocopy (selection->get_state ());
2499 node->add_child_nocopy (_regions->get_state ());
2506 /** @param y y offset from the top of all trackviews.
2507 * @return pair: TimeAxisView that y is over, layer index.
2508 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2509 * in stacked or expanded region display mode, otherwise 0.
2511 std::pair<TimeAxisView *, double>
2512 Editor::trackview_by_y_position (double y)
2514 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2516 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2522 return std::make_pair ( (TimeAxisView *) 0, 0);
2525 /** Snap a position to the grid, if appropriate, taking into account current
2526 * grid settings and also the state of any snap modifier keys that may be pressed.
2527 * @param start Position to snap.
2528 * @param event Event to get current key modifier information from, or 0.
2531 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2533 if (!_session || !event) {
2537 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2538 if (_snap_mode == SnapOff) {
2539 snap_to_internal (start, direction, for_mark);
2542 if (_snap_mode != SnapOff) {
2543 snap_to_internal (start, direction, for_mark);
2549 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2551 if (!_session || _snap_mode == SnapOff) {
2555 snap_to_internal (start, direction, for_mark);
2559 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2561 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2562 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2564 switch (_snap_type) {
2565 case SnapToTimecodeFrame:
2566 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2567 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2569 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2573 case SnapToTimecodeSeconds:
2574 if (_session->config.get_timecode_offset_negative()) {
2575 start += _session->config.get_timecode_offset ();
2577 start -= _session->config.get_timecode_offset ();
2579 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2580 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2582 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2585 if (_session->config.get_timecode_offset_negative()) {
2586 start -= _session->config.get_timecode_offset ();
2588 start += _session->config.get_timecode_offset ();
2592 case SnapToTimecodeMinutes:
2593 if (_session->config.get_timecode_offset_negative()) {
2594 start += _session->config.get_timecode_offset ();
2596 start -= _session->config.get_timecode_offset ();
2598 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2599 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2601 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2603 if (_session->config.get_timecode_offset_negative()) {
2604 start -= _session->config.get_timecode_offset ();
2606 start += _session->config.get_timecode_offset ();
2610 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2616 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2618 const framepos_t one_second = _session->frame_rate();
2619 const framepos_t one_minute = _session->frame_rate() * 60;
2620 framepos_t presnap = start;
2624 switch (_snap_type) {
2625 case SnapToTimecodeFrame:
2626 case SnapToTimecodeSeconds:
2627 case SnapToTimecodeMinutes:
2628 return timecode_snap_to_internal (start, direction, for_mark);
2631 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2632 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2634 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2639 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2640 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2642 start = (framepos_t) floor ((double) start / one_second) * one_second;
2647 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2648 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2650 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2655 start = _session->tempo_map().round_to_bar (start, direction);
2659 start = _session->tempo_map().round_to_beat (start, direction);
2662 case SnapToBeatDiv128:
2663 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2665 case SnapToBeatDiv64:
2666 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2668 case SnapToBeatDiv32:
2669 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2671 case SnapToBeatDiv28:
2672 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2674 case SnapToBeatDiv24:
2675 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2677 case SnapToBeatDiv20:
2678 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2680 case SnapToBeatDiv16:
2681 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2683 case SnapToBeatDiv14:
2684 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2686 case SnapToBeatDiv12:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2689 case SnapToBeatDiv10:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2692 case SnapToBeatDiv8:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2695 case SnapToBeatDiv7:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2698 case SnapToBeatDiv6:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2701 case SnapToBeatDiv5:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2704 case SnapToBeatDiv4:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2707 case SnapToBeatDiv3:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2710 case SnapToBeatDiv2:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2719 _session->locations()->marks_either_side (start, before, after);
2721 if (before == max_framepos) {
2723 } else if (after == max_framepos) {
2725 } else if (before != max_framepos && after != max_framepos) {
2726 /* have before and after */
2727 if ((start - before) < (after - start)) {
2736 case SnapToRegionStart:
2737 case SnapToRegionEnd:
2738 case SnapToRegionSync:
2739 case SnapToRegionBoundary:
2740 if (!region_boundary_cache.empty()) {
2742 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2743 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2745 if (direction > 0) {
2746 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2748 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2751 if (next != region_boundary_cache.begin ()) {
2756 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2757 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2759 if (start > (p + n) / 2) {
2768 switch (_snap_mode) {
2774 if (presnap > start) {
2775 if (presnap > (start + unit_to_frame(snap_threshold))) {
2779 } else if (presnap < start) {
2780 if (presnap < (start - unit_to_frame(snap_threshold))) {
2786 /* handled at entry */
2794 Editor::setup_toolbar ()
2796 HBox* mode_box = manage(new HBox);
2797 mode_box->set_border_width (2);
2798 mode_box->set_spacing(4);
2800 HBox* mouse_mode_box = manage (new HBox);
2801 HBox* mouse_mode_hbox1 = manage (new HBox);
2802 HBox* mouse_mode_hbox2 = manage (new HBox);
2803 VBox* mouse_mode_vbox1 = manage (new VBox);
2804 VBox* mouse_mode_vbox2 = manage (new VBox);
2805 Alignment* mouse_mode_align1 = manage (new Alignment);
2806 Alignment* mouse_mode_align2 = manage (new Alignment);
2808 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2809 mouse_mode_size_group->add_widget (mouse_move_button);
2810 mouse_mode_size_group->add_widget (mouse_select_button);
2811 mouse_mode_size_group->add_widget (mouse_zoom_button);
2812 mouse_mode_size_group->add_widget (mouse_gain_button);
2813 mouse_mode_size_group->add_widget (mouse_timefx_button);
2814 mouse_mode_size_group->add_widget (mouse_audition_button);
2815 mouse_mode_size_group->add_widget (mouse_draw_button);
2816 mouse_mode_size_group->add_widget (internal_edit_button);
2818 /* make them just a bit bigger */
2819 mouse_move_button.set_size_request (-1, 25);
2821 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button));
2822 smart_mode_joiner->set_related_action (smart_mode_action);
2824 mouse_move_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
2825 mouse_select_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
2827 mouse_move_button.set_rounded_corner_mask (0x1); // upper left only
2828 mouse_select_button.set_rounded_corner_mask (0x2); // upper right only
2830 mouse_mode_hbox2->set_spacing (2);
2831 mouse_mode_box->set_spacing (2);
2833 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2834 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2835 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2836 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2837 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2838 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2839 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2841 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2842 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2844 mouse_mode_align1->add (*mouse_mode_vbox1);
2845 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2846 mouse_mode_align2->add (*mouse_mode_vbox2);
2847 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2849 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2850 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2852 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2853 if (!Profile->get_sae()) {
2854 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2856 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2858 edit_mode_selector.set_name ("EditModeSelector");
2859 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2860 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2862 mode_box->pack_start (edit_mode_selector, false, false);
2863 mode_box->pack_start (*mouse_mode_box, false, false);
2865 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2866 _mouse_mode_tearoff->set_name ("MouseModeBase");
2867 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2869 if (Profile->get_sae()) {
2870 _mouse_mode_tearoff->set_can_be_torn_off (false);
2873 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2874 &_mouse_mode_tearoff->tearoff_window()));
2875 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2876 &_mouse_mode_tearoff->tearoff_window(), 1));
2877 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2878 &_mouse_mode_tearoff->tearoff_window()));
2879 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2880 &_mouse_mode_tearoff->tearoff_window(), 1));
2884 _zoom_box.set_spacing (2);
2885 _zoom_box.set_border_width (2);
2889 zoom_in_button.set_name ("zoom button");
2890 zoom_in_button.set_image (::get_icon ("zoom_in"));
2891 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2892 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2893 zoom_in_button.set_related_action (act);
2895 zoom_out_button.set_name ("zoom button");
2896 zoom_out_button.set_image (::get_icon ("zoom_out"));
2897 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2898 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2899 zoom_out_button.set_related_action (act);
2901 zoom_out_full_button.set_name ("zoom button");
2902 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2903 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2904 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2905 zoom_out_full_button.set_related_action (act);
2907 zoom_focus_selector.set_name ("ZoomFocusSelector");
2908 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2909 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2911 _zoom_box.pack_start (zoom_out_button, false, false);
2912 _zoom_box.pack_start (zoom_in_button, false, false);
2913 _zoom_box.pack_start (zoom_out_full_button, false, false);
2915 _zoom_box.pack_start (zoom_focus_selector, false, false);
2917 /* Track zoom buttons */
2918 tav_expand_button.set_name ("TrackHeightButton");
2919 tav_expand_button.set_size_request (-1, 20);
2920 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2921 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2922 act->connect_proxy (tav_expand_button);
2924 tav_shrink_button.set_name ("TrackHeightButton");
2925 tav_shrink_button.set_size_request (-1, 20);
2926 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2927 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2928 act->connect_proxy (tav_shrink_button);
2930 _zoom_box.pack_start (tav_shrink_button);
2931 _zoom_box.pack_start (tav_expand_button);
2933 _zoom_tearoff = manage (new TearOff (_zoom_box));
2935 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2936 &_zoom_tearoff->tearoff_window()));
2937 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2938 &_zoom_tearoff->tearoff_window(), 0));
2939 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2940 &_zoom_tearoff->tearoff_window()));
2941 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2942 &_zoom_tearoff->tearoff_window(), 0));
2944 snap_box.set_spacing (1);
2945 snap_box.set_border_width (2);
2947 snap_type_selector.set_name ("SnapTypeSelector");
2948 set_popdown_strings (snap_type_selector, snap_type_strings);
2949 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2951 snap_mode_selector.set_name ("SnapModeSelector");
2952 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2953 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2955 edit_point_selector.set_name ("EditPointSelector");
2956 set_popdown_strings (edit_point_selector, edit_point_strings);
2957 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2959 snap_box.pack_start (snap_mode_selector, false, false);
2960 snap_box.pack_start (snap_type_selector, false, false);
2961 snap_box.pack_start (edit_point_selector, false, false);
2965 HBox *nudge_box = manage (new HBox);
2966 nudge_box->set_spacing (2);
2967 nudge_box->set_border_width (2);
2969 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2970 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2972 nudge_box->pack_start (nudge_backward_button, false, false);
2973 nudge_box->pack_start (nudge_forward_button, false, false);
2974 nudge_box->pack_start (*nudge_clock, false, false);
2977 /* Pack everything in... */
2979 HBox* hbox = manage (new HBox);
2980 hbox->set_spacing(10);
2982 _tools_tearoff = manage (new TearOff (*hbox));
2983 _tools_tearoff->set_name ("MouseModeBase");
2984 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2986 if (Profile->get_sae()) {
2987 _tools_tearoff->set_can_be_torn_off (false);
2990 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2991 &_tools_tearoff->tearoff_window()));
2992 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2993 &_tools_tearoff->tearoff_window(), 0));
2994 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2995 &_tools_tearoff->tearoff_window()));
2996 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2997 &_tools_tearoff->tearoff_window(), 0));
2999 toolbar_hbox.set_spacing (10);
3000 toolbar_hbox.set_border_width (1);
3002 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3003 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3004 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3006 hbox->pack_start (snap_box, false, false);
3007 if (!Profile->get_small_screen()) {
3008 hbox->pack_start (*nudge_box, false, false);
3010 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3012 hbox->pack_start (panic_box, false, false);
3016 toolbar_base.set_name ("ToolBarBase");
3017 toolbar_base.add (toolbar_hbox);
3019 _toolbar_viewport.add (toolbar_base);
3020 /* stick to the required height but allow width to vary if there's not enough room */
3021 _toolbar_viewport.set_size_request (1, -1);
3023 toolbar_frame.set_shadow_type (SHADOW_OUT);
3024 toolbar_frame.set_name ("BaseFrame");
3025 toolbar_frame.add (_toolbar_viewport);
3029 Editor::setup_tooltips ()
3031 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3032 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3033 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3034 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3035 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3036 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3037 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3038 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3039 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3040 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3041 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
3042 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
3043 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3044 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3045 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3046 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3047 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3048 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3049 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3050 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3051 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3052 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3053 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3057 Editor::convert_drop_to_paths (
3058 vector<string>& paths,
3059 const RefPtr<Gdk::DragContext>& /*context*/,
3062 const SelectionData& data,
3066 if (_session == 0) {
3070 vector<string> uris = data.get_uris();
3074 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3075 are actually URI lists. So do it by hand.
3078 if (data.get_target() != "text/plain") {
3082 /* Parse the "uri-list" format that Nautilus provides,
3083 where each pathname is delimited by \r\n.
3085 THERE MAY BE NO NULL TERMINATING CHAR!!!
3088 string txt = data.get_text();
3092 p = (const char *) malloc (txt.length() + 1);
3093 txt.copy ((char *) p, txt.length(), 0);
3094 ((char*)p)[txt.length()] = '\0';
3100 while (g_ascii_isspace (*p))
3104 while (*q && (*q != '\n') && (*q != '\r')) {
3111 while (q > p && g_ascii_isspace (*q))
3116 uris.push_back (string (p, q - p + 1));
3120 p = strchr (p, '\n');
3132 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3134 if ((*i).substr (0,7) == "file://") {
3137 PBD::url_decode (p);
3139 // scan forward past three slashes
3141 string::size_type slashcnt = 0;
3142 string::size_type n = 0;
3143 string::iterator x = p.begin();
3145 while (slashcnt < 3 && x != p.end()) {
3148 } else if (slashcnt == 3) {
3155 if (slashcnt != 3 || x == p.end()) {
3156 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3160 paths.push_back (p.substr (n - 1));
3168 Editor::new_tempo_section ()
3174 Editor::map_transport_state ()
3176 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3178 if (_session && _session->transport_stopped()) {
3179 have_pending_keyboard_selection = false;
3182 update_loop_range_view (true);
3187 Editor::State::State (PublicEditor const * e)
3189 selection = new Selection (e);
3192 Editor::State::~State ()
3198 Editor::begin_reversible_command (string name)
3201 _session->begin_reversible_command (name);
3206 Editor::begin_reversible_command (GQuark q)
3209 _session->begin_reversible_command (q);
3214 Editor::commit_reversible_command ()
3217 _session->commit_reversible_command ();
3222 Editor::history_changed ()
3226 if (undo_action && _session) {
3227 if (_session->undo_depth() == 0) {
3228 label = S_("Command|Undo");
3230 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3232 undo_action->property_label() = label;
3235 if (redo_action && _session) {
3236 if (_session->redo_depth() == 0) {
3239 label = string_compose(_("Redo (%1)"), _session->next_redo());
3241 redo_action->property_label() = label;
3246 Editor::duplicate_dialog (bool with_dialog)
3250 if (mouse_mode == MouseRange) {
3251 if (selection->time.length() == 0) {
3256 RegionSelection rs = get_regions_from_selection_and_entered ();
3258 if (mouse_mode != MouseRange && rs.empty()) {
3264 ArdourDialog win (_("Duplicate"));
3265 Label label (_("Number of duplications:"));
3266 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3267 SpinButton spinner (adjustment, 0.0, 1);
3270 win.get_vbox()->set_spacing (12);
3271 win.get_vbox()->pack_start (hbox);
3272 hbox.set_border_width (6);
3273 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3275 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3276 place, visually. so do this by hand.
3279 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3280 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3281 spinner.grab_focus();
3287 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3288 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3289 win.set_default_response (RESPONSE_ACCEPT);
3291 win.set_position (WIN_POS_MOUSE);
3293 spinner.grab_focus ();
3295 switch (win.run ()) {
3296 case RESPONSE_ACCEPT:
3302 times = adjustment.get_value();
3305 if (mouse_mode == MouseRange) {
3306 duplicate_selection (times);
3308 duplicate_some_regions (rs, times);
3313 Editor::set_edit_mode (EditMode m)
3315 Config->set_edit_mode (m);
3319 Editor::cycle_edit_mode ()
3321 switch (Config->get_edit_mode()) {
3323 if (Profile->get_sae()) {
3324 Config->set_edit_mode (Lock);
3326 Config->set_edit_mode (Splice);
3330 Config->set_edit_mode (Lock);
3333 Config->set_edit_mode (Slide);
3339 Editor::edit_mode_selection_done ()
3341 string s = edit_mode_selector.get_active_text ();
3344 Config->set_edit_mode (string_to_edit_mode (s));
3349 Editor::snap_type_selection_done ()
3351 string choice = snap_type_selector.get_active_text();
3352 SnapType snaptype = SnapToBeat;
3354 if (choice == _("Beats/2")) {
3355 snaptype = SnapToBeatDiv2;
3356 } else if (choice == _("Beats/3")) {
3357 snaptype = SnapToBeatDiv3;
3358 } else if (choice == _("Beats/4")) {
3359 snaptype = SnapToBeatDiv4;
3360 } else if (choice == _("Beats/5")) {
3361 snaptype = SnapToBeatDiv5;
3362 } else if (choice == _("Beats/6")) {
3363 snaptype = SnapToBeatDiv6;
3364 } else if (choice == _("Beats/7")) {
3365 snaptype = SnapToBeatDiv7;
3366 } else if (choice == _("Beats/8")) {
3367 snaptype = SnapToBeatDiv8;
3368 } else if (choice == _("Beats/10")) {
3369 snaptype = SnapToBeatDiv10;
3370 } else if (choice == _("Beats/12")) {
3371 snaptype = SnapToBeatDiv12;
3372 } else if (choice == _("Beats/14")) {
3373 snaptype = SnapToBeatDiv14;
3374 } else if (choice == _("Beats/16")) {
3375 snaptype = SnapToBeatDiv16;
3376 } else if (choice == _("Beats/20")) {
3377 snaptype = SnapToBeatDiv20;
3378 } else if (choice == _("Beats/24")) {
3379 snaptype = SnapToBeatDiv24;
3380 } else if (choice == _("Beats/28")) {
3381 snaptype = SnapToBeatDiv28;
3382 } else if (choice == _("Beats/32")) {
3383 snaptype = SnapToBeatDiv32;
3384 } else if (choice == _("Beats/64")) {
3385 snaptype = SnapToBeatDiv64;
3386 } else if (choice == _("Beats/128")) {
3387 snaptype = SnapToBeatDiv128;
3388 } else if (choice == _("Beats")) {
3389 snaptype = SnapToBeat;
3390 } else if (choice == _("Bars")) {
3391 snaptype = SnapToBar;
3392 } else if (choice == _("Marks")) {
3393 snaptype = SnapToMark;
3394 } else if (choice == _("Region starts")) {
3395 snaptype = SnapToRegionStart;
3396 } else if (choice == _("Region ends")) {
3397 snaptype = SnapToRegionEnd;
3398 } else if (choice == _("Region bounds")) {
3399 snaptype = SnapToRegionBoundary;
3400 } else if (choice == _("Region syncs")) {
3401 snaptype = SnapToRegionSync;
3402 } else if (choice == _("CD Frames")) {
3403 snaptype = SnapToCDFrame;
3404 } else if (choice == _("Timecode Frames")) {
3405 snaptype = SnapToTimecodeFrame;
3406 } else if (choice == _("Timecode Seconds")) {
3407 snaptype = SnapToTimecodeSeconds;
3408 } else if (choice == _("Timecode Minutes")) {
3409 snaptype = SnapToTimecodeMinutes;
3410 } else if (choice == _("Seconds")) {
3411 snaptype = SnapToSeconds;
3412 } else if (choice == _("Minutes")) {
3413 snaptype = SnapToMinutes;
3416 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3418 ract->set_active ();
3423 Editor::snap_mode_selection_done ()
3425 string choice = snap_mode_selector.get_active_text();
3426 SnapMode mode = SnapNormal;
3428 if (choice == _("No Grid")) {
3430 } else if (choice == _("Grid")) {
3432 } else if (choice == _("Magnetic")) {
3433 mode = SnapMagnetic;
3436 RefPtr<RadioAction> ract = snap_mode_action (mode);
3439 ract->set_active (true);
3444 Editor::cycle_edit_point (bool with_marker)
3446 switch (_edit_point) {
3448 set_edit_point_preference (EditAtPlayhead);
3450 case EditAtPlayhead:
3452 set_edit_point_preference (EditAtSelectedMarker);
3454 set_edit_point_preference (EditAtMouse);
3457 case EditAtSelectedMarker:
3458 set_edit_point_preference (EditAtMouse);
3464 Editor::edit_point_selection_done ()
3466 string choice = edit_point_selector.get_active_text();
3467 EditPoint ep = EditAtSelectedMarker;
3469 if (choice == _("Marker")) {
3470 set_edit_point_preference (EditAtSelectedMarker);
3471 } else if (choice == _("Playhead")) {
3472 set_edit_point_preference (EditAtPlayhead);
3474 set_edit_point_preference (EditAtMouse);
3477 RefPtr<RadioAction> ract = edit_point_action (ep);
3480 ract->set_active (true);
3485 Editor::zoom_focus_selection_done ()
3487 string choice = zoom_focus_selector.get_active_text();
3488 ZoomFocus focus_type = ZoomFocusLeft;
3490 if (choice == _("Left")) {
3491 focus_type = ZoomFocusLeft;
3492 } else if (choice == _("Right")) {
3493 focus_type = ZoomFocusRight;
3494 } else if (choice == _("Center")) {
3495 focus_type = ZoomFocusCenter;
3496 } else if (choice == _("Playhead")) {
3497 focus_type = ZoomFocusPlayhead;
3498 } else if (choice == _("Mouse")) {
3499 focus_type = ZoomFocusMouse;
3500 } else if (choice == _("Edit point")) {
3501 focus_type = ZoomFocusEdit;
3504 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3507 ract->set_active ();
3512 Editor::edit_controls_button_release (GdkEventButton* ev)
3514 if (Keyboard::is_context_menu_event (ev)) {
3515 ARDOUR_UI::instance()->add_route (this);
3516 } else if (ev->button == 1) {
3517 selection->clear_tracks ();
3524 Editor::mouse_select_button_release (GdkEventButton* ev)
3526 /* this handles just right-clicks */
3528 if (ev->button != 3) {
3536 Editor::set_zoom_focus (ZoomFocus f)
3538 string str = zoom_focus_strings[(int)f];
3540 if (str != zoom_focus_selector.get_active_text()) {
3541 zoom_focus_selector.set_active_text (str);
3544 if (zoom_focus != f) {
3551 Editor::ensure_float (Window& win)
3553 win.set_transient_for (*this);
3557 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3559 /* recover or initialize pane positions. do this here rather than earlier because
3560 we don't want the positions to change the child allocations, which they seem to do.
3566 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3575 XMLNode* geometry = find_named_node (*node, "geometry");
3577 if (which == static_cast<Paned*> (&edit_pane)) {
3579 if (done & Horizontal) {
3583 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3584 _notebook_shrunk = string_is_affirmative (prop->value ());
3587 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3588 /* initial allocation is 90% to canvas, 10% to notebook */
3589 pos = (int) floor (alloc.get_width() * 0.90f);
3590 snprintf (buf, sizeof(buf), "%d", pos);
3592 pos = atoi (prop->value());
3595 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3596 edit_pane.set_position (pos);
3599 done = (Pane) (done | Horizontal);
3601 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3603 if (done & Vertical) {
3607 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3608 /* initial allocation is 90% to canvas, 10% to summary */
3609 pos = (int) floor (alloc.get_height() * 0.90f);
3610 snprintf (buf, sizeof(buf), "%d", pos);
3613 pos = atoi (prop->value());
3616 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3617 editor_summary_pane.set_position (pos);
3620 done = (Pane) (done | Vertical);
3625 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3627 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3628 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3629 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3630 top_hbox.remove (toolbar_frame);
3635 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3637 if (toolbar_frame.get_parent() == 0) {
3638 top_hbox.pack_end (toolbar_frame);
3643 Editor::set_show_measures (bool yn)
3645 if (_show_measures != yn) {
3648 if ((_show_measures = yn) == true) {
3650 tempo_lines->show();
3658 Editor::toggle_follow_playhead ()
3660 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3662 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3663 set_follow_playhead (tact->get_active());
3667 /** @param yn true to follow playhead, otherwise false.
3668 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3671 Editor::set_follow_playhead (bool yn, bool catch_up)
3673 if (_follow_playhead != yn) {
3674 if ((_follow_playhead = yn) == true && catch_up) {
3676 reset_x_origin_to_follow_playhead ();
3683 Editor::toggle_stationary_playhead ()
3685 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3687 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3688 set_stationary_playhead (tact->get_active());
3693 Editor::set_stationary_playhead (bool yn)
3695 if (_stationary_playhead != yn) {
3696 if ((_stationary_playhead = yn) == true) {
3698 // FIXME need a 3.0 equivalent of this 2.X call
3699 // update_current_screen ();
3706 Editor::toggle_xfade_active (RouteTimeAxisView* tv, boost::weak_ptr<Crossfade> wxfade)
3708 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3713 vector<boost::shared_ptr<Crossfade> > all = get_equivalent_crossfades (*tv, xfade, ARDOUR::Properties::edit.property_id);
3715 _session->begin_reversible_command (_("Change crossfade active state"));
3717 for (vector<boost::shared_ptr<Crossfade> >::iterator i = all.begin(); i != all.end(); ++i) {
3718 (*i)->clear_changes ();
3719 (*i)->set_active (!(*i)->active());
3720 _session->add_command (new StatefulDiffCommand (*i));
3723 _session->commit_reversible_command ();
3727 Editor::toggle_xfade_length (RouteTimeAxisView* tv, boost::weak_ptr<Crossfade> wxfade)
3729 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3734 vector<boost::shared_ptr<Crossfade> > all = get_equivalent_crossfades (*tv, xfade, ARDOUR::Properties::edit.property_id);
3736 /* This can't be a StatefulDiffCommand as the fade shapes are not
3737 managed by the Stateful properties system.
3739 _session->begin_reversible_command (_("Change crossfade length"));
3741 for (vector<boost::shared_ptr<Crossfade> >::iterator i = all.begin(); i != all.end(); ++i) {
3742 XMLNode& before = (*i)->get_state ();
3743 (*i)->set_follow_overlap (!(*i)->following_overlap());
3744 XMLNode& after = (*i)->get_state ();
3746 _session->add_command (new MementoCommand<Crossfade> (*i->get(), &before, &after));
3749 _session->commit_reversible_command ();
3753 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3755 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3761 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3765 switch (cew.run ()) {
3766 case RESPONSE_ACCEPT:
3773 PropertyChange all_crossfade_properties;
3774 all_crossfade_properties.add (ARDOUR::Properties::active);
3775 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3776 xfade->PropertyChanged (all_crossfade_properties);
3780 Editor::playlist_selector () const
3782 return *_playlist_selector;
3786 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3790 switch (_snap_type) {
3795 case SnapToBeatDiv128:
3798 case SnapToBeatDiv64:
3801 case SnapToBeatDiv32:
3804 case SnapToBeatDiv28:
3807 case SnapToBeatDiv24:
3810 case SnapToBeatDiv20:
3813 case SnapToBeatDiv16:
3816 case SnapToBeatDiv14:
3819 case SnapToBeatDiv12:
3822 case SnapToBeatDiv10:
3825 case SnapToBeatDiv8:
3828 case SnapToBeatDiv7:
3831 case SnapToBeatDiv6:
3834 case SnapToBeatDiv5:
3837 case SnapToBeatDiv4:
3840 case SnapToBeatDiv3:
3843 case SnapToBeatDiv2:
3849 return _session->tempo_map().meter_at (position).divisions_per_bar();
3854 case SnapToTimecodeFrame:
3855 case SnapToTimecodeSeconds:
3856 case SnapToTimecodeMinutes:
3859 case SnapToRegionStart:
3860 case SnapToRegionEnd:
3861 case SnapToRegionSync:
3862 case SnapToRegionBoundary:
3872 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3876 ret = nudge_clock->current_duration (pos);
3877 next = ret + 1; /* XXXX fix me */
3883 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3885 ArdourDialog dialog (_("Playlist Deletion"));
3886 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3887 "If it is kept, its audio files will not be cleaned.\n"
3888 "If it is deleted, audio files used by it alone will be cleaned."),
3891 dialog.set_position (WIN_POS_CENTER);
3892 dialog.get_vbox()->pack_start (label);
3896 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3897 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3898 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3900 switch (dialog.run ()) {
3901 case RESPONSE_ACCEPT:
3902 /* delete the playlist */
3906 case RESPONSE_REJECT:
3907 /* keep the playlist */
3919 Editor::audio_region_selection_covers (framepos_t where)
3921 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3922 if ((*a)->region()->covers (where)) {
3931 Editor::prepare_for_cleanup ()
3933 cut_buffer->clear_regions ();
3934 cut_buffer->clear_playlists ();
3936 selection->clear_regions ();
3937 selection->clear_playlists ();
3939 _regions->suspend_redisplay ();
3943 Editor::finish_cleanup ()
3945 _regions->resume_redisplay ();
3949 Editor::transport_loop_location()
3952 return _session->locations()->auto_loop_location();
3959 Editor::transport_punch_location()
3962 return _session->locations()->auto_punch_location();
3969 Editor::control_layout_scroll (GdkEventScroll* ev)
3971 if (Keyboard::some_magic_widget_has_focus()) {
3975 switch (ev->direction) {
3977 scroll_tracks_up_line ();
3981 case GDK_SCROLL_DOWN:
3982 scroll_tracks_down_line ();
3986 /* no left/right handling yet */
3994 Editor::session_state_saved (string)
3997 _snapshots->redisplay ();
4001 Editor::maximise_editing_space ()
4009 if (!Config->get_keep_tearoffs()) {
4010 /* these calls will leave each tearoff visible *if* it is torn off,
4011 but invisible otherwise.
4013 _mouse_mode_tearoff->set_visible (false);
4014 _tools_tearoff->set_visible (false);
4015 _zoom_tearoff->set_visible (false);
4022 Editor::restore_editing_space ()
4030 if (!Config->get_keep_tearoffs()) {
4031 _mouse_mode_tearoff->set_visible (true);
4032 _tools_tearoff->set_visible (true);
4033 _zoom_tearoff->set_visible (true);
4040 * Make new playlists for a given track and also any others that belong
4041 * to the same active route group with the `edit' property.
4046 Editor::new_playlists (TimeAxisView* v)
4048 begin_reversible_command (_("new playlists"));
4049 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4050 _session->playlists->get (playlists);
4051 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4052 commit_reversible_command ();
4056 * Use a copy of the current playlist for a given track and also any others that belong
4057 * to the same active route group with the `edit' property.
4062 Editor::copy_playlists (TimeAxisView* v)
4064 begin_reversible_command (_("copy playlists"));
4065 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4066 _session->playlists->get (playlists);
4067 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4068 commit_reversible_command ();
4071 /** Clear the current playlist for a given track and also any others that belong
4072 * to the same active route group with the `edit' property.
4077 Editor::clear_playlists (TimeAxisView* v)
4079 begin_reversible_command (_("clear playlists"));
4080 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4081 _session->playlists->get (playlists);
4082 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4083 commit_reversible_command ();
4087 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4089 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4093 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4095 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4099 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4101 atv.clear_playlist ();
4105 Editor::on_key_press_event (GdkEventKey* ev)
4107 return key_press_focus_accelerator_handler (*this, ev);
4111 Editor::on_key_release_event (GdkEventKey* ev)
4113 return Gtk::Window::on_key_release_event (ev);
4114 // return key_press_focus_accelerator_handler (*this, ev);
4117 /** Queue up a change to the viewport x origin.
4118 * @param frame New x origin.
4121 Editor::reset_x_origin (framepos_t frame)
4123 queue_visual_change (frame);
4127 Editor::reset_y_origin (double y)
4129 queue_visual_change_y (y);
4133 Editor::reset_zoom (double fpu)
4135 queue_visual_change (fpu);
4139 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4141 reset_x_origin (frame);
4144 if (!no_save_visual) {
4145 undo_visual_stack.push_back (current_visual_state(false));
4149 Editor::VisualState::VisualState ()
4150 : gui_state (new GUIObjectState)
4154 Editor::VisualState::~VisualState ()
4159 Editor::VisualState*
4160 Editor::current_visual_state (bool with_tracks)
4162 VisualState* vs = new VisualState;
4163 vs->y_position = vertical_adjustment.get_value();
4164 vs->frames_per_unit = frames_per_unit;
4165 vs->leftmost_frame = leftmost_frame;
4166 vs->zoom_focus = zoom_focus;
4169 *(vs->gui_state) = *ARDOUR_UI::instance()->gui_object_state;
4176 Editor::undo_visual_state ()
4178 if (undo_visual_stack.empty()) {
4182 redo_visual_stack.push_back (current_visual_state());
4184 VisualState* vs = undo_visual_stack.back();
4185 undo_visual_stack.pop_back();
4186 use_visual_state (*vs);
4190 Editor::redo_visual_state ()
4192 if (redo_visual_stack.empty()) {
4196 undo_visual_stack.push_back (current_visual_state());
4198 VisualState* vs = redo_visual_stack.back();
4199 redo_visual_stack.pop_back();
4200 use_visual_state (*vs);
4204 Editor::swap_visual_state ()
4206 if (undo_visual_stack.empty()) {
4207 redo_visual_state ();
4209 undo_visual_state ();
4214 Editor::use_visual_state (VisualState& vs)
4216 no_save_visual = true;
4218 _routes->suspend_redisplay ();
4220 vertical_adjustment.set_value (vs.y_position);
4222 set_zoom_focus (vs.zoom_focus);
4223 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4225 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4227 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4228 (*i)->reset_visual_state ();
4231 _routes->update_visibility ();
4232 _routes->resume_redisplay ();
4234 no_save_visual = false;
4238 Editor::set_frames_per_unit (double fpu)
4240 /* this is the core function that controls the zoom level of the canvas. it is called
4241 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4244 if (fpu == frames_per_unit) {
4253 /* don't allow zooms that fit more than the maximum number
4254 of frames into an 800 pixel wide space.
4257 if (max_framepos / fpu < 800.0) {
4262 tempo_lines->tempo_map_changed();
4264 frames_per_unit = fpu;
4269 Editor::post_zoom ()
4271 // convert fpu to frame count
4273 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4275 if (frames_per_unit != zoom_range_clock->current_duration()) {
4276 zoom_range_clock->set (frames);
4279 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4280 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4281 (*i)->reshow_selection (selection->time);
4285 ZoomChanged (); /* EMIT_SIGNAL */
4287 //reset_scrolling_region ();
4289 if (playhead_cursor) {
4290 playhead_cursor->set_position (playhead_cursor->current_frame);
4293 refresh_location_display();
4294 _summary->set_overlays_dirty ();
4296 update_marker_labels ();
4302 Editor::queue_visual_change (framepos_t where)
4304 pending_visual_change.add (VisualChange::TimeOrigin);
4305 pending_visual_change.time_origin = where;
4306 ensure_visual_change_idle_handler ();
4310 Editor::queue_visual_change (double fpu)
4312 pending_visual_change.add (VisualChange::ZoomLevel);
4313 pending_visual_change.frames_per_unit = fpu;
4315 ensure_visual_change_idle_handler ();
4319 Editor::queue_visual_change_y (double y)
4321 pending_visual_change.add (VisualChange::YOrigin);
4322 pending_visual_change.y_origin = y;
4324 ensure_visual_change_idle_handler ();
4328 Editor::ensure_visual_change_idle_handler ()
4330 if (pending_visual_change.idle_handler_id < 0) {
4331 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4336 Editor::_idle_visual_changer (void* arg)
4338 return static_cast<Editor*>(arg)->idle_visual_changer ();
4342 Editor::idle_visual_changer ()
4344 VisualChange::Type p = pending_visual_change.pending;
4345 pending_visual_change.pending = (VisualChange::Type) 0;
4347 double const last_time_origin = horizontal_position ();
4349 if (p & VisualChange::TimeOrigin) {
4350 /* This is a bit of a hack, but set_frames_per_unit
4351 below will (if called) end up with the
4352 CrossfadeViews looking at Editor::leftmost_frame,
4353 and if we're changing origin and zoom in the same
4354 operation it will be the wrong value unless we
4358 leftmost_frame = pending_visual_change.time_origin;
4359 assert (leftmost_frame >= 0);
4362 if (p & VisualChange::ZoomLevel) {
4363 set_frames_per_unit (pending_visual_change.frames_per_unit);
4365 compute_fixed_ruler_scale ();
4366 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4367 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4368 update_tempo_based_rulers ();
4370 if (p & VisualChange::TimeOrigin) {
4371 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4373 if (p & VisualChange::YOrigin) {
4374 vertical_adjustment.set_value (pending_visual_change.y_origin);
4377 if (last_time_origin == horizontal_position ()) {
4378 /* changed signal not emitted */
4379 update_fixed_rulers ();
4380 redisplay_tempo (true);
4383 _summary->set_overlays_dirty ();
4385 pending_visual_change.idle_handler_id = -1;
4386 return 0; /* this is always a one-shot call */
4389 struct EditorOrderTimeAxisSorter {
4390 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4391 return a->order () < b->order ();
4396 Editor::sort_track_selection (TrackViewList& sel)
4398 EditorOrderTimeAxisSorter cmp;
4403 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4406 framepos_t where = 0;
4407 EditPoint ep = _edit_point;
4409 if (from_context_menu && (ep == EditAtMouse)) {
4410 return event_frame (&context_click_event, 0, 0);
4413 if (entered_marker) {
4414 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4415 return entered_marker->position();
4418 if (ignore_playhead && ep == EditAtPlayhead) {
4419 ep = EditAtSelectedMarker;
4423 case EditAtPlayhead:
4424 where = _session->audible_frame();
4425 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4428 case EditAtSelectedMarker:
4429 if (!selection->markers.empty()) {
4431 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4434 where = loc->start();
4438 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4446 if (!mouse_frame (where, ignored)) {
4447 /* XXX not right but what can we do ? */
4451 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4459 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4461 if (!_session) return;
4463 begin_reversible_command (cmd);
4467 if ((tll = transport_loop_location()) == 0) {
4468 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4469 XMLNode &before = _session->locations()->get_state();
4470 _session->locations()->add (loc, true);
4471 _session->set_auto_loop_location (loc);
4472 XMLNode &after = _session->locations()->get_state();
4473 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4475 XMLNode &before = tll->get_state();
4476 tll->set_hidden (false, this);
4477 tll->set (start, end);
4478 XMLNode &after = tll->get_state();
4479 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4482 commit_reversible_command ();
4486 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4488 if (!_session) return;
4490 begin_reversible_command (cmd);
4494 if ((tpl = transport_punch_location()) == 0) {
4495 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4496 XMLNode &before = _session->locations()->get_state();
4497 _session->locations()->add (loc, true);
4498 _session->set_auto_loop_location (loc);
4499 XMLNode &after = _session->locations()->get_state();
4500 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4503 XMLNode &before = tpl->get_state();
4504 tpl->set_hidden (false, this);
4505 tpl->set (start, end);
4506 XMLNode &after = tpl->get_state();
4507 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4510 commit_reversible_command ();
4513 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4514 * @param rs List to which found regions are added.
4515 * @param where Time to look at.
4516 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4519 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4521 const TrackViewList* tracks;
4524 tracks = &track_views;
4529 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4531 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4534 boost::shared_ptr<Track> tr;
4535 boost::shared_ptr<Playlist> pl;
4537 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4539 boost::shared_ptr<RegionList> regions = pl->regions_at (
4540 (framepos_t) floor ( (double) where * tr->speed()));
4542 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4543 RegionView* rv = rtv->view()->find_view (*i);
4554 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4556 const TrackViewList* tracks;
4559 tracks = &track_views;
4564 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4565 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4567 boost::shared_ptr<Track> tr;
4568 boost::shared_ptr<Playlist> pl;
4570 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4572 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4573 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4575 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4577 RegionView* rv = rtv->view()->find_view (*i);
4588 /** Start with regions that are selected. Then add equivalent regions
4589 * on tracks in the same active edit-enabled route group as any of
4590 * the regions that we started with.
4594 Editor::get_regions_from_selection ()
4596 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4599 /** Get regions using the following method:
4601 * Make an initial region list using the selected regions, unless
4602 * the edit point is `mouse' and the mouse is over an unselected
4603 * region. In this case, start with just that region.
4605 * Then, make an initial track list of the tracks that these
4606 * regions are on, and if the edit point is not `mouse', add the
4609 * Look at this track list and add any other tracks that are on the
4610 * same active edit-enabled route group as one of the initial tracks.
4612 * Finally take the initial region list and add any regions that are
4613 * under the edit point on one of the tracks on the track list to get
4614 * the returned region list.
4616 * The rationale here is that the mouse edit point is special in that
4617 * its position describes both a time and a track; the other edit
4618 * modes only describe a time. Hence if the edit point is `mouse' we
4619 * ignore selected tracks, as we assume the user means something by
4620 * pointing at a particular track. Also in this case we take note of
4621 * the region directly under the edit point, as there is always just one
4622 * (rather than possibly several with non-mouse edit points).
4626 Editor::get_regions_from_selection_and_edit_point ()
4628 RegionSelection regions;
4630 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4631 regions.add (entered_regionview);
4633 regions = selection->regions;
4636 TrackViewList tracks;
4638 if (_edit_point != EditAtMouse) {
4639 tracks = selection->tracks;
4642 /* Add any other tracks that have regions that are in the same
4643 edit-activated route group as one of our regions.
4645 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4647 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4649 if (g && g->is_active() && g->is_edit()) {
4650 tracks.add (axis_views_from_routes (g->route_list()));
4654 if (!tracks.empty()) {
4655 /* now find regions that are at the edit position on those tracks */
4656 framepos_t const where = get_preferred_edit_position ();
4657 get_regions_at (regions, where, tracks);
4663 /** Start with regions that are selected, or the entered regionview if none are selected.
4664 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4665 * of the regions that we started with.
4669 Editor::get_regions_from_selection_and_entered ()
4671 RegionSelection regions = selection->regions;
4673 if (regions.empty() && entered_regionview) {
4674 regions.add (entered_regionview);
4677 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4681 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4683 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4685 RouteTimeAxisView* tatv;
4687 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4689 boost::shared_ptr<Playlist> pl;
4690 vector<boost::shared_ptr<Region> > results;
4692 boost::shared_ptr<Track> tr;
4694 if ((tr = tatv->track()) == 0) {
4699 if ((pl = (tr->playlist())) != 0) {
4700 pl->get_region_list_equivalent_regions (region, results);
4703 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4704 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4705 regions.push_back (marv);
4714 Editor::show_rhythm_ferret ()
4716 if (rhythm_ferret == 0) {
4717 rhythm_ferret = new RhythmFerret(*this);
4720 rhythm_ferret->set_session (_session);
4721 rhythm_ferret->show ();
4722 rhythm_ferret->present ();
4726 Editor::first_idle ()
4728 MessageDialog* dialog = 0;
4730 if (track_views.size() > 1) {
4731 dialog = new MessageDialog (
4733 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4737 ARDOUR_UI::instance()->flush_pending ();
4740 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4744 // first idle adds route children (automation tracks), so we need to redisplay here
4745 _routes->redisplay ();
4752 Editor::_idle_resize (gpointer arg)
4754 return ((Editor*)arg)->idle_resize ();
4758 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4760 if (resize_idle_id < 0) {
4761 resize_idle_id = g_idle_add (_idle_resize, this);
4762 _pending_resize_amount = 0;
4765 /* make a note of the smallest resulting height, so that we can clamp the
4766 lower limit at TimeAxisView::hSmall */
4768 int32_t min_resulting = INT32_MAX;
4770 _pending_resize_amount += h;
4771 _pending_resize_view = view;
4773 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4775 if (selection->tracks.contains (_pending_resize_view)) {
4776 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4777 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4781 if (min_resulting < 0) {
4786 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4787 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4791 /** Handle pending resizing of tracks */
4793 Editor::idle_resize ()
4795 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4797 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4798 selection->tracks.contains (_pending_resize_view)) {
4800 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4801 if (*i != _pending_resize_view) {
4802 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4807 _pending_resize_amount = 0;
4809 _group_tabs->set_dirty ();
4810 resize_idle_id = -1;
4818 ENSURE_GUI_THREAD (*this, &Editor::located);
4820 playhead_cursor->set_position (_session->audible_frame ());
4821 if (_follow_playhead && !_pending_initial_locate) {
4822 reset_x_origin_to_follow_playhead ();
4825 _pending_locate_request = false;
4826 _pending_initial_locate = false;
4830 Editor::region_view_added (RegionView *)
4832 _summary->set_dirty ();
4836 Editor::region_view_removed ()
4838 _summary->set_dirty ();
4842 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4844 TrackViewList::const_iterator j = track_views.begin ();
4845 while (j != track_views.end()) {
4846 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4847 if (rtv && rtv->route() == r) {
4858 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4862 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4863 TimeAxisView* tv = axis_view_from_route (*i);
4874 Editor::handle_new_route (RouteList& routes)
4876 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4878 RouteTimeAxisView *rtv;
4879 list<RouteTimeAxisView*> new_views;
4881 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4882 boost::shared_ptr<Route> route = (*x);
4884 if (route->is_hidden() || route->is_monitor()) {
4888 DataType dt = route->input()->default_type();
4890 if (dt == ARDOUR::DataType::AUDIO) {
4891 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4892 rtv->set_route (route);
4893 } else if (dt == ARDOUR::DataType::MIDI) {
4894 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4895 rtv->set_route (route);
4897 throw unknown_type();
4900 new_views.push_back (rtv);
4901 track_views.push_back (rtv);
4903 rtv->effective_gain_display ();
4905 if (internal_editing()) {
4906 rtv->enter_internal_edit_mode ();
4908 rtv->leave_internal_edit_mode ();
4911 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4912 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4915 _routes->routes_added (new_views);
4916 _summary->routes_added (new_views);
4918 if (show_editor_mixer_when_tracks_arrive) {
4919 show_editor_mixer (true);
4922 editor_list_button.set_sensitive (true);
4926 Editor::timeaxisview_deleted (TimeAxisView *tv)
4928 if (_session && _session->deletion_in_progress()) {
4929 /* the situation is under control */
4933 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4935 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4937 _routes->route_removed (tv);
4939 if (tv == entered_track) {
4943 TimeAxisView::Children c = tv->get_child_list ();
4944 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4945 if (entered_track == i->get()) {
4950 /* remove it from the list of track views */
4952 TrackViewList::iterator i;
4954 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4955 i = track_views.erase (i);
4958 /* update whatever the current mixer strip is displaying, if revelant */
4960 boost::shared_ptr<Route> route;
4963 route = rtav->route ();
4966 if (current_mixer_strip && current_mixer_strip->route() == route) {
4968 TimeAxisView* next_tv;
4970 if (track_views.empty()) {
4972 } else if (i == track_views.end()) {
4973 next_tv = track_views.front();
4980 set_selected_mixer_strip (*next_tv);
4982 /* make the editor mixer strip go away setting the
4983 * button to inactive (which also unticks the menu option)
4986 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4992 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4994 if (apply_to_selection) {
4995 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4997 TrackSelection::iterator j = i;
5000 hide_track_in_display (*i, false);
5005 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5007 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5008 // this will hide the mixer strip
5009 set_selected_mixer_strip (*tv);
5012 _routes->hide_track_in_display (*tv);
5017 Editor::sync_track_view_list_and_routes ()
5019 track_views = TrackViewList (_routes->views ());
5021 _summary->set_dirty ();
5022 _group_tabs->set_dirty ();
5024 return false; // do not call again (until needed)
5028 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5030 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5035 /** Find a RouteTimeAxisView by the ID of its route */
5037 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5039 RouteTimeAxisView* v;
5041 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5042 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5043 if(v->route()->id() == id) {
5053 Editor::fit_route_group (RouteGroup *g)
5055 TrackViewList ts = axis_views_from_routes (g->route_list ());
5060 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5062 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5065 _session->cancel_audition ();
5069 if (_session->is_auditioning()) {
5070 _session->cancel_audition ();
5071 if (r == last_audition_region) {
5076 _session->audition_region (r);
5077 last_audition_region = r;
5082 Editor::hide_a_region (boost::shared_ptr<Region> r)
5084 r->set_hidden (true);
5088 Editor::show_a_region (boost::shared_ptr<Region> r)
5090 r->set_hidden (false);
5094 Editor::audition_region_from_region_list ()
5096 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5100 Editor::hide_region_from_region_list ()
5102 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5106 Editor::show_region_in_region_list ()
5108 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5112 Editor::step_edit_status_change (bool yn)
5115 start_step_editing ();
5117 stop_step_editing ();
5122 Editor::start_step_editing ()
5124 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5128 Editor::stop_step_editing ()
5130 step_edit_connection.disconnect ();
5134 Editor::check_step_edit ()
5136 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5137 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5139 mtv->check_step_edit ();
5143 return true; // do it again, till we stop
5147 Editor::scroll_press (Direction dir)
5149 ++_scroll_callbacks;
5151 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5152 /* delay the first auto-repeat */
5158 scroll_backward (1);
5166 scroll_tracks_up_line ();
5170 scroll_tracks_down_line ();
5174 /* do hacky auto-repeat */
5175 if (!_scroll_connection.connected ()) {
5177 _scroll_connection = Glib::signal_timeout().connect (
5178 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5181 _scroll_callbacks = 0;
5188 Editor::scroll_release ()
5190 _scroll_connection.disconnect ();
5193 /** Queue a change for the Editor viewport x origin to follow the playhead */
5195 Editor::reset_x_origin_to_follow_playhead ()
5197 framepos_t const frame = playhead_cursor->current_frame;
5199 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5201 if (_session->transport_speed() < 0) {
5203 if (frame > (current_page_frames() / 2)) {
5204 center_screen (frame-(current_page_frames()/2));
5206 center_screen (current_page_frames()/2);
5213 if (frame < leftmost_frame) {
5215 if (_session->transport_rolling()) {
5216 /* rolling; end up with the playhead at the right of the page */
5217 l = frame - current_page_frames ();
5219 /* not rolling: end up with the playhead 1/4 of the way along the page */
5220 l = frame - current_page_frames() / 4;
5224 if (_session->transport_rolling()) {
5225 /* rolling: end up with the playhead on the left of the page */
5228 /* not rolling: end up with the playhead 3/4 of the way along the page */
5229 l = frame - 3 * current_page_frames() / 4;
5237 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5243 Editor::super_rapid_screen_update ()
5245 if (!_session || !_session->engine().running()) {
5249 /* METERING / MIXER STRIPS */
5251 /* update track meters, if required */
5252 if (is_mapped() && meters_running) {
5253 RouteTimeAxisView* rtv;
5254 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5255 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5256 rtv->fast_update ();
5261 /* and any current mixer strip */
5262 if (current_mixer_strip) {
5263 current_mixer_strip->fast_update ();
5266 /* PLAYHEAD AND VIEWPORT */
5268 framepos_t const frame = _session->audible_frame();
5270 /* There are a few reasons why we might not update the playhead / viewport stuff:
5272 * 1. we don't update things when there's a pending locate request, otherwise
5273 * when the editor requests a locate there is a chance that this method
5274 * will move the playhead before the locate request is processed, causing
5276 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5277 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5280 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5282 last_update_frame = frame;
5284 if (!_dragging_playhead) {
5285 playhead_cursor->set_position (frame);
5288 if (!_stationary_playhead) {
5290 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5291 reset_x_origin_to_follow_playhead ();
5296 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5300 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5301 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5302 if (target <= 0.0) {
5305 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5306 target = (target * 0.15) + (current * 0.85);
5312 set_horizontal_position (current);
5321 Editor::session_going_away ()
5323 _have_idled = false;
5325 _session_connections.drop_connections ();
5327 super_rapid_screen_update_connection.disconnect ();
5329 selection->clear ();
5330 cut_buffer->clear ();
5332 clicked_regionview = 0;
5333 clicked_axisview = 0;
5334 clicked_routeview = 0;
5335 clicked_crossfadeview = 0;
5336 entered_regionview = 0;
5338 last_update_frame = 0;
5341 playhead_cursor->canvas_item.hide ();
5343 /* rip everything out of the list displays */
5347 _route_groups->clear ();
5349 /* do this first so that deleting a track doesn't reset cms to null
5350 and thus cause a leak.
5353 if (current_mixer_strip) {
5354 if (current_mixer_strip->get_parent() != 0) {
5355 global_hpacker.remove (*current_mixer_strip);
5357 delete current_mixer_strip;
5358 current_mixer_strip = 0;
5361 /* delete all trackviews */
5363 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5366 track_views.clear ();
5368 zoom_range_clock->set_session (0);
5369 nudge_clock->set_session (0);
5371 editor_list_button.set_active(false);
5372 editor_list_button.set_sensitive(false);
5374 /* clear tempo/meter rulers */
5375 remove_metric_marks ();
5377 clear_marker_display ();
5379 current_bbt_points_begin = current_bbt_points_end;
5381 /* get rid of any existing editor mixer strip */
5383 WindowTitle title(Glib::get_application_name());
5384 title += _("Editor");
5386 set_title (title.get_string());
5388 SessionHandlePtr::session_going_away ();
5393 Editor::show_editor_list (bool yn)
5396 _the_notebook.show ();
5398 _the_notebook.hide ();
5403 Editor::change_region_layering_order (bool from_context_menu)
5405 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5407 if (!clicked_routeview) {
5408 if (layering_order_editor) {
5409 layering_order_editor->hide ();
5414 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5420 boost::shared_ptr<Playlist> pl = track->playlist();
5426 if (layering_order_editor == 0) {
5427 layering_order_editor = new RegionLayeringOrderEditor (*this);
5428 layering_order_editor->set_position (WIN_POS_MOUSE);
5431 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5432 layering_order_editor->maybe_present ();
5436 Editor::update_region_layering_order_editor ()
5438 if (layering_order_editor && layering_order_editor->is_visible ()) {
5439 change_region_layering_order (true);
5444 Editor::setup_fade_images ()
5446 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5447 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5448 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5449 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5450 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5452 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5453 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5454 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5455 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5456 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5460 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5462 Editor::action_menu_item (std::string const & name)
5464 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5467 return *manage (a->create_menu_item ());
5471 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5473 EventBox* b = manage (new EventBox);
5474 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5475 Label* l = manage (new Label (name));
5479 _the_notebook.append_page (widget, *b);
5483 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5485 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5486 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5489 if (ev->type == GDK_2BUTTON_PRESS) {
5491 /* double-click on a notebook tab shrinks or expands the notebook */
5493 if (_notebook_shrunk) {
5494 if (pre_notebook_shrink_pane_width) {
5495 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5497 _notebook_shrunk = false;
5499 pre_notebook_shrink_pane_width = edit_pane.get_position();
5501 /* this expands the LHS of the edit pane to cover the notebook
5502 PAGE but leaves the tabs visible.
5504 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5505 _notebook_shrunk = true;
5513 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5515 using namespace Menu_Helpers;
5517 MenuList& items = _control_point_context_menu.items ();
5520 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5521 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5522 if (!can_remove_control_point (item)) {
5523 items.back().set_sensitive (false);
5526 _control_point_context_menu.popup (event->button.button, event->button.time);