2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "canvas/debug.h"
74 #include "canvas/text.h"
76 #include "control_protocol/control_protocol.h"
80 #include "analysis_window.h"
81 #include "audio_clock.h"
82 #include "audio_region_view.h"
83 #include "audio_streamview.h"
84 #include "audio_time_axis.h"
85 #include "automation_time_axis.h"
86 #include "bundle_manager.h"
87 #include "crossfade_edit.h"
91 #include "editor_cursors.h"
92 #include "editor_drag.h"
93 #include "editor_group_tabs.h"
94 #include "editor_locations.h"
95 #include "editor_regions.h"
96 #include "editor_route_groups.h"
97 #include "editor_routes.h"
98 #include "editor_snapshots.h"
99 #include "editor_summary.h"
100 #include "global_port_matrix.h"
101 #include "gui_object.h"
102 #include "gui_thread.h"
103 #include "keyboard.h"
105 #include "midi_time_axis.h"
106 #include "mixer_strip.h"
107 #include "mixer_ui.h"
108 #include "mouse_cursors.h"
109 #include "playlist_selector.h"
110 #include "public_editor.h"
111 #include "region_layering_order_editor.h"
112 #include "rgb_macros.h"
113 #include "rhythm_ferret.h"
114 #include "selection.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
238 /* time display buttons */
239 , minsec_label (_("Mins:Secs"))
240 , bbt_label (_("Bars:Beats"))
241 , timecode_label (_("Timecode"))
242 , samples_label (_("Samples"))
243 , tempo_label (_("Tempo"))
244 , meter_label (_("Meter"))
245 , mark_label (_("Location Markers"))
246 , range_mark_label (_("Range Markers"))
247 , transport_mark_label (_("Loop/Punch Ranges"))
248 , cd_mark_label (_("CD Markers"))
249 #ifdef WITH_VIDEOTIMELINE
250 , videotl_label (_("Video Timeline"))
252 , edit_packer (4, 4, true)
254 /* the values here don't matter: layout widgets
255 reset them as needed.
258 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260 /* tool bar related */
262 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
264 , toolbar_selection_clock_table (2,3)
266 , automation_mode_button (_("mode"))
268 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
271 , image_socket_listener(0)
276 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
277 , meters_running(false)
278 , _pending_locate_request (false)
279 , _pending_initial_locate (false)
280 , _last_cut_copy_source_track (0)
282 , _region_selection_change_updates_region_list (true)
283 , _following_mixer_selection (false)
284 , _control_point_toggled_on_press (false)
285 , _stepping_axis_view (0)
289 /* we are a singleton */
291 PublicEditor::_instance = this;
295 selection = new Selection (this);
296 cut_buffer = new Selection (this);
298 clicked_regionview = 0;
299 clicked_axisview = 0;
300 clicked_routeview = 0;
301 clicked_control_point = 0;
302 last_update_frame = 0;
303 pre_press_cursor = 0;
304 _drags = new DragManager (this);
305 current_mixer_strip = 0;
308 snap_type_strings = I18N (_snap_type_strings);
309 snap_mode_strings = I18N (_snap_mode_strings);
310 zoom_focus_strings = I18N (_zoom_focus_strings);
311 edit_point_strings = I18N (_edit_point_strings);
312 #ifdef USE_RUBBERBAND
313 rb_opt_strings = I18N (_rb_opt_strings);
317 snap_threshold = 5.0;
318 bbt_beat_subdivision = 4;
319 _visible_canvas_width = 0;
320 _visible_canvas_height = 0;
321 last_autoscroll_x = 0;
322 last_autoscroll_y = 0;
323 autoscroll_active = false;
324 autoscroll_timeout_tag = -1;
329 current_interthread_info = 0;
330 _show_measures = true;
332 show_gain_after_trim = false;
334 have_pending_keyboard_selection = false;
335 _follow_playhead = true;
336 _stationary_playhead = false;
337 editor_ruler_menu = 0;
338 no_ruler_shown_update = false;
340 range_marker_menu = 0;
341 marker_menu_item = 0;
342 tempo_or_meter_marker_menu = 0;
343 transport_marker_menu = 0;
344 new_transport_marker_menu = 0;
345 editor_mixer_strip_width = Wide;
346 show_editor_mixer_when_tracks_arrive = false;
347 region_edit_menu_split_multichannel_item = 0;
348 region_edit_menu_split_item = 0;
351 current_stepping_trackview = 0;
353 entered_regionview = 0;
355 clear_entered_track = false;
358 button_release_can_deselect = true;
359 _dragging_playhead = false;
360 _dragging_edit_point = false;
361 select_new_marker = false;
363 layering_order_editor = 0;
364 no_save_visual = false;
366 within_track_canvas = false;
368 scrubbing_direction = 0;
372 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
373 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
374 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
375 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
376 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
378 _edit_point = EditAtMouse;
379 _internal_editing = false;
380 current_canvas_cursor = 0;
382 frames_per_pixel = 2048; /* too early to use reset_zoom () */
384 _scroll_callbacks = 0;
386 zoom_focus = ZoomFocusLeft;
387 set_zoom_focus (ZoomFocusLeft);
388 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
390 bbt_label.set_name ("EditorRulerLabel");
391 bbt_label.set_size_request (-1, (int)timebar_height);
392 bbt_label.set_alignment (1.0, 0.5);
393 bbt_label.set_padding (5,0);
395 bbt_label.set_no_show_all();
396 minsec_label.set_name ("EditorRulerLabel");
397 minsec_label.set_size_request (-1, (int)timebar_height);
398 minsec_label.set_alignment (1.0, 0.5);
399 minsec_label.set_padding (5,0);
400 minsec_label.hide ();
401 minsec_label.set_no_show_all();
402 timecode_label.set_name ("EditorRulerLabel");
403 timecode_label.set_size_request (-1, (int)timebar_height);
404 timecode_label.set_alignment (1.0, 0.5);
405 timecode_label.set_padding (5,0);
406 timecode_label.hide ();
407 timecode_label.set_no_show_all();
408 samples_label.set_name ("EditorRulerLabel");
409 samples_label.set_size_request (-1, (int)timebar_height);
410 samples_label.set_alignment (1.0, 0.5);
411 samples_label.set_padding (5,0);
412 samples_label.hide ();
413 samples_label.set_no_show_all();
415 tempo_label.set_name ("EditorRulerLabel");
416 tempo_label.set_size_request (-1, (int)timebar_height);
417 tempo_label.set_alignment (1.0, 0.5);
418 tempo_label.set_padding (5,0);
420 tempo_label.set_no_show_all();
422 meter_label.set_name ("EditorRulerLabel");
423 meter_label.set_size_request (-1, (int)timebar_height);
424 meter_label.set_alignment (1.0, 0.5);
425 meter_label.set_padding (5,0);
427 meter_label.set_no_show_all();
429 mark_label.set_name ("EditorRulerLabel");
430 mark_label.set_size_request (-1, (int)timebar_height);
431 mark_label.set_alignment (1.0, 0.5);
432 mark_label.set_padding (5,0);
434 mark_label.set_no_show_all();
436 cd_mark_label.set_name ("EditorRulerLabel");
437 cd_mark_label.set_size_request (-1, (int)timebar_height);
438 cd_mark_label.set_alignment (1.0, 0.5);
439 cd_mark_label.set_padding (5,0);
440 cd_mark_label.hide();
441 cd_mark_label.set_no_show_all();
443 #ifdef WITH_VIDEOTIMELINE
444 videotl_bar_height = 4;
445 videotl_label.set_name ("EditorRulerLabel");
446 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
447 videotl_label.set_alignment (1.0, 0.5);
448 videotl_label.set_padding (5,0);
449 videotl_label.hide();
450 videotl_label.set_no_show_all();
453 range_mark_label.set_name ("EditorRulerLabel");
454 range_mark_label.set_size_request (-1, (int)timebar_height);
455 range_mark_label.set_alignment (1.0, 0.5);
456 range_mark_label.set_padding (5,0);
457 range_mark_label.hide();
458 range_mark_label.set_no_show_all();
460 transport_mark_label.set_name ("EditorRulerLabel");
461 transport_mark_label.set_size_request (-1, (int)timebar_height);
462 transport_mark_label.set_alignment (1.0, 0.5);
463 transport_mark_label.set_padding (5,0);
464 transport_mark_label.hide();
465 transport_mark_label.set_no_show_all();
467 initialize_rulers ();
468 initialize_canvas ();
470 _summary = new EditorSummary (this);
472 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
473 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
475 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
477 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
478 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
480 edit_controls_vbox.set_spacing (0);
481 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
482 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
484 HBox* h = manage (new HBox);
485 _group_tabs = new EditorGroupTabs (this);
486 h->pack_start (*_group_tabs, PACK_SHRINK);
487 h->pack_start (edit_controls_vbox);
488 controls_layout.add (*h);
490 controls_layout.set_name ("EditControlsBase");
491 controls_layout.add_events (Gdk::SCROLL_MASK);
492 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
494 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
495 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
497 _cursors = new MouseCursors;
499 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
501 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
502 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
503 pad_line_1->set_outline_color (0xFF0000FF);
509 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
510 time_canvas_vbox.set_size_request (-1, -1);
512 ruler_label_event_box.add (ruler_label_vbox);
513 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
514 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
516 time_bars_event_box.add (time_bars_vbox);
517 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
518 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
520 /* these enable us to have a dedicated window (for cursor setting, etc.)
521 for the canvas areas.
524 track_canvas_event_box.add (*_track_canvas_viewport);
526 time_canvas_event_box.add (time_canvas_vbox);
527 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
529 edit_packer.set_col_spacings (0);
530 edit_packer.set_row_spacings (0);
531 edit_packer.set_homogeneous (false);
532 edit_packer.set_border_width (0);
533 edit_packer.set_name ("EditorWindow");
535 /* labels for the rulers */
536 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
537 /* labels for the marker "tracks" (time bars) */
538 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
540 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
542 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
543 /* time bars canvas */
544 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
546 edit_packer.attach (track_canvas_event_box, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
548 bottom_hbox.set_border_width (2);
549 bottom_hbox.set_spacing (3);
551 _route_groups = new EditorRouteGroups (this);
552 _routes = new EditorRoutes (this);
553 _regions = new EditorRegions (this);
554 _snapshots = new EditorSnapshots (this);
555 _locations = new EditorLocations (this);
557 add_notebook_page (_("Regions"), _regions->widget ());
558 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
559 add_notebook_page (_("Snapshots"), _snapshots->widget ());
560 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
561 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
563 _the_notebook.set_show_tabs (true);
564 _the_notebook.set_scrollable (true);
565 _the_notebook.popup_disable ();
566 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
567 _the_notebook.show_all ();
569 _notebook_shrunk = false;
571 editor_summary_pane.pack1(edit_packer);
573 Button* summary_arrows_left_left = manage (new Button);
574 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
575 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
576 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 Button* summary_arrows_left_right = manage (new Button);
579 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
580 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
581 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 VBox* summary_arrows_left = manage (new VBox);
584 summary_arrows_left->pack_start (*summary_arrows_left_left);
585 summary_arrows_left->pack_start (*summary_arrows_left_right);
587 Button* summary_arrows_right_up = manage (new Button);
588 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
589 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
590 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
592 Button* summary_arrows_right_down = manage (new Button);
593 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
594 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
595 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
597 VBox* summary_arrows_right = manage (new VBox);
598 summary_arrows_right->pack_start (*summary_arrows_right_up);
599 summary_arrows_right->pack_start (*summary_arrows_right_down);
601 Frame* summary_frame = manage (new Frame);
602 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
604 summary_frame->add (*_summary);
605 summary_frame->show ();
607 _summary_hbox.pack_start (*summary_arrows_left, false, false);
608 _summary_hbox.pack_start (*summary_frame, true, true);
609 _summary_hbox.pack_start (*summary_arrows_right, false, false);
611 editor_summary_pane.pack2 (_summary_hbox);
613 edit_pane.pack1 (editor_summary_pane, true, true);
614 edit_pane.pack2 (_the_notebook, false, true);
616 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
618 /* XXX: editor_summary_pane might need similar to the edit_pane */
620 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
622 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
623 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
625 top_hbox.pack_start (toolbar_frame);
627 HBox *hbox = manage (new HBox);
628 hbox->pack_start (edit_pane, true, true);
630 global_vpacker.pack_start (top_hbox, false, false);
631 global_vpacker.pack_start (*hbox, true, true);
633 global_hpacker.pack_start (global_vpacker, true, true);
635 set_name ("EditorWindow");
636 add_accel_group (ActionManager::ui_manager->get_accel_group());
638 status_bar_hpacker.show ();
640 vpacker.pack_end (status_bar_hpacker, false, false);
641 vpacker.pack_end (global_hpacker, true, true);
643 /* register actions now so that set_state() can find them and set toggles/checks etc */
646 /* when we start using our own keybinding system for the editor, this
647 * will be uncommented
653 _snap_type = SnapToBeat;
654 set_snap_to (_snap_type);
655 _snap_mode = SnapOff;
656 set_snap_mode (_snap_mode);
657 set_mouse_mode (MouseObject, true);
658 pre_internal_mouse_mode = MouseObject;
659 pre_internal_snap_type = _snap_type;
660 pre_internal_snap_mode = _snap_mode;
661 internal_snap_type = _snap_type;
662 internal_snap_mode = _snap_mode;
663 set_edit_point_preference (EditAtMouse, true);
665 _playlist_selector = new PlaylistSelector();
666 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
668 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
672 nudge_forward_button.set_name ("zoom button");
673 nudge_forward_button.add_elements (ArdourButton::FlatFace);
674 nudge_forward_button.set_image(::get_icon("nudge_right"));
676 nudge_backward_button.set_name ("zoom button");
677 nudge_backward_button.add_elements (ArdourButton::FlatFace);
678 nudge_backward_button.set_image(::get_icon("nudge_left"));
680 fade_context_menu.set_name ("ArdourContextMenu");
682 /* icons, titles, WM stuff */
684 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
685 Glib::RefPtr<Gdk::Pixbuf> icon;
687 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
688 window_icons.push_back (icon);
690 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
691 window_icons.push_back (icon);
693 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
694 window_icons.push_back (icon);
696 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
697 window_icons.push_back (icon);
699 if (!window_icons.empty()) {
700 // set_icon_list (window_icons);
701 set_default_icon_list (window_icons);
704 WindowTitle title(Glib::get_application_name());
705 title += _("Editor");
706 set_title (title.get_string());
707 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
710 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
712 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
713 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
715 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
717 /* allow external control surfaces/protocols to do various things */
719 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
720 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
721 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
722 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
723 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
724 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
725 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
726 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
727 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
728 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
729 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
730 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
731 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
732 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
734 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
735 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
736 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
737 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
738 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
740 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
742 /* problematic: has to return a value and thus cannot be x-thread */
744 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
746 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
748 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
750 _ignore_region_action = false;
751 _last_region_menu_was_main = false;
752 _popup_region_menu_item = 0;
754 _show_marker_lines = false;
755 _over_region_trim_target = false;
757 /* Button bindings */
759 button_bindings = new Bindings;
761 XMLNode* node = button_settings();
763 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
764 button_bindings->load (**i);
771 setup_fade_images ();
777 if(image_socket_listener) {
778 if(image_socket_listener->is_connected())
780 image_socket_listener->close_connection() ;
783 delete image_socket_listener ;
784 image_socket_listener = 0 ;
788 delete button_bindings;
790 delete _route_groups;
791 delete _track_canvas_viewport;
796 Editor::button_settings () const
798 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
799 XMLNode* node = find_named_node (*settings, X_("Buttons"));
802 node = new XMLNode (X_("Buttons"));
809 Editor::add_toplevel_controls (Container& cont)
811 vpacker.pack_start (cont, false, false);
816 Editor::get_smart_mode () const
818 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
822 Editor::catch_vanishing_regionview (RegionView *rv)
824 /* note: the selection will take care of the vanishing
825 audioregionview by itself.
828 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
832 if (clicked_regionview == rv) {
833 clicked_regionview = 0;
836 if (entered_regionview == rv) {
837 set_entered_regionview (0);
840 if (!_all_region_actions_sensitized) {
841 sensitize_all_region_actions (true);
844 _over_region_trim_target = false;
848 Editor::set_entered_regionview (RegionView* rv)
850 if (rv == entered_regionview) {
854 if (entered_regionview) {
855 entered_regionview->exited ();
858 if ((entered_regionview = rv) != 0) {
859 entered_regionview->entered (internal_editing ());
862 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
863 /* This RegionView entry might have changed what region actions
864 are allowed, so sensitize them all in case a key is pressed.
866 sensitize_all_region_actions (true);
871 Editor::set_entered_track (TimeAxisView* tav)
874 entered_track->exited ();
877 if ((entered_track = tav) != 0) {
878 entered_track->entered ();
883 Editor::show_window ()
885 if (!is_visible ()) {
888 /* XXX: this is a bit unfortunate; it would probably
889 be nicer if we could just call show () above rather
890 than needing the show_all ()
893 /* re-hide stuff if necessary */
894 editor_list_button_toggled ();
895 parameter_changed ("show-summary");
896 parameter_changed ("show-group-tabs");
897 parameter_changed ("show-zoom-tools");
899 /* now reset all audio_time_axis heights, because widgets might need
905 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
906 tv = (static_cast<TimeAxisView*>(*i));
910 if (current_mixer_strip) {
911 current_mixer_strip->hide_things ();
912 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
920 Editor::instant_save ()
922 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
927 _session->add_instant_xml(get_state());
929 Config->add_instant_xml(get_state());
934 Editor::zoom_adjustment_changed ()
940 double fpu = zoom_range_clock->current_duration() / _visible_canvas_width;
941 bool clamped = clamp_frames_per_pixel (fpu);
944 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
951 Editor::control_vertical_zoom_in_all ()
953 tav_zoom_smooth (false, true);
957 Editor::control_vertical_zoom_out_all ()
959 tav_zoom_smooth (true, true);
963 Editor::control_vertical_zoom_in_selected ()
965 tav_zoom_smooth (false, false);
969 Editor::control_vertical_zoom_out_selected ()
971 tav_zoom_smooth (true, false);
975 Editor::control_view (uint32_t view)
977 goto_visual_state (view);
981 Editor::control_unselect ()
983 selection->clear_tracks ();
987 Editor::control_select (uint32_t rid, Selection::Operation op)
989 /* handles the (static) signal from the ControlProtocol class that
990 * requests setting the selected track to a given RID
997 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1003 TimeAxisView* tav = axis_view_from_route (r);
1007 case Selection::Add:
1008 selection->add (tav);
1010 case Selection::Toggle:
1011 selection->toggle (tav);
1013 case Selection::Extend:
1015 case Selection::Set:
1016 selection->set (tav);
1020 selection->clear_tracks ();
1025 Editor::control_step_tracks_up ()
1027 scroll_tracks_up_line ();
1031 Editor::control_step_tracks_down ()
1033 scroll_tracks_down_line ();
1037 Editor::control_scroll (float fraction)
1039 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1045 double step = fraction * current_page_frames();
1048 _control_scroll_target is an optional<T>
1050 it acts like a pointer to an framepos_t, with
1051 a operator conversion to boolean to check
1052 that it has a value could possibly use
1053 playhead_cursor->current_frame to store the
1054 value and a boolean in the class to know
1055 when it's out of date
1058 if (!_control_scroll_target) {
1059 _control_scroll_target = _session->transport_frame();
1060 _dragging_playhead = true;
1063 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1064 *_control_scroll_target = 0;
1065 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1066 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1068 *_control_scroll_target += (framepos_t) floor (step);
1071 /* move visuals, we'll catch up with it later */
1073 playhead_cursor->set_position (*_control_scroll_target);
1074 UpdateAllTransportClocks (*_control_scroll_target);
1076 if (*_control_scroll_target > (current_page_frames() / 2)) {
1077 /* try to center PH in window */
1078 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1084 Now we do a timeout to actually bring the session to the right place
1085 according to the playhead. This is to avoid reading disk buffers on every
1086 call to control_scroll, which is driven by ScrollTimeline and therefore
1087 probably by a control surface wheel which can generate lots of events.
1089 /* cancel the existing timeout */
1091 control_scroll_connection.disconnect ();
1093 /* add the next timeout */
1095 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1099 Editor::deferred_control_scroll (framepos_t /*target*/)
1101 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1102 // reset for next stream
1103 _control_scroll_target = boost::none;
1104 _dragging_playhead = false;
1109 Editor::access_action (std::string action_group, std::string action_item)
1115 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1118 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1126 Editor::on_realize ()
1128 Window::on_realize ();
1133 Editor::map_position_change (framepos_t frame)
1135 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1137 if (_session == 0) {
1141 if (_follow_playhead) {
1142 center_screen (frame);
1145 playhead_cursor->set_position (frame);
1149 Editor::center_screen (framepos_t frame)
1151 double const page = _visible_canvas_width * frames_per_pixel;
1153 /* if we're off the page, then scroll.
1156 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1157 center_screen_internal (frame, page);
1162 Editor::center_screen_internal (framepos_t frame, float page)
1167 frame -= (framepos_t) page;
1172 reset_x_origin (frame);
1177 Editor::update_title ()
1179 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1182 bool dirty = _session->dirty();
1184 string session_name;
1186 if (_session->snap_name() != _session->name()) {
1187 session_name = _session->snap_name();
1189 session_name = _session->name();
1193 session_name = "*" + session_name;
1196 WindowTitle title(session_name);
1197 title += Glib::get_application_name();
1198 set_title (title.get_string());
1200 /* ::session_going_away() will have taken care of it */
1205 Editor::set_session (Session *t)
1207 SessionHandlePtr::set_session (t);
1213 zoom_range_clock->set_session (_session);
1214 _playlist_selector->set_session (_session);
1215 nudge_clock->set_session (_session);
1216 _summary->set_session (_session);
1217 _group_tabs->set_session (_session);
1218 _route_groups->set_session (_session);
1219 _regions->set_session (_session);
1220 _snapshots->set_session (_session);
1221 _routes->set_session (_session);
1222 _locations->set_session (_session);
1224 if (rhythm_ferret) {
1225 rhythm_ferret->set_session (_session);
1228 if (analysis_window) {
1229 analysis_window->set_session (_session);
1233 sfbrowser->set_session (_session);
1236 compute_fixed_ruler_scale ();
1238 /* Make sure we have auto loop and auto punch ranges */
1240 Location* loc = _session->locations()->auto_loop_location();
1242 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1244 if (loc->start() == loc->end()) {
1245 loc->set_end (loc->start() + 1);
1248 _session->locations()->add (loc, false);
1249 _session->set_auto_loop_location (loc);
1252 loc->set_name (_("Loop"));
1255 loc = _session->locations()->auto_punch_location();
1258 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1260 if (loc->start() == loc->end()) {
1261 loc->set_end (loc->start() + 1);
1264 _session->locations()->add (loc, false);
1265 _session->set_auto_punch_location (loc);
1268 loc->set_name (_("Punch"));
1271 refresh_location_display ();
1273 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1274 the selected Marker; this needs the LocationMarker list to be available.
1276 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1277 set_state (*node, Stateful::loading_state_version);
1279 /* catch up with the playhead */
1281 _session->request_locate (playhead_cursor->current_frame ());
1282 _pending_initial_locate = true;
1286 /* These signals can all be emitted by a non-GUI thread. Therefore the
1287 handlers for them must not attempt to directly interact with the GUI,
1288 but use Gtkmm2ext::UI::instance()->call_slot();
1291 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1292 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1293 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1294 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1295 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1296 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1297 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1298 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1299 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1300 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1301 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1302 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1303 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1304 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1306 playhead_cursor->show ();
1308 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1309 Config->map_parameters (pc);
1310 _session->config.map_parameters (pc);
1312 restore_ruler_visibility ();
1313 //tempo_map_changed (PropertyChange (0));
1314 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1316 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1317 (static_cast<TimeAxisView*>(*i))->set_frames_per_pixel (frames_per_pixel);
1320 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1321 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1324 switch (_snap_type) {
1325 case SnapToRegionStart:
1326 case SnapToRegionEnd:
1327 case SnapToRegionSync:
1328 case SnapToRegionBoundary:
1329 build_region_boundary_cache ();
1336 /* register for undo history */
1337 _session->register_with_memento_command_factory(id(), this);
1339 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1341 start_updating_meters ();
1345 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1347 if (a->get_name() == "RegionMenu") {
1348 /* When the main menu's region menu is opened, we setup the actions so that they look right
1349 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1350 so we resensitize all region actions when the entered regionview or the region selection
1351 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1352 happens after the region context menu is opened. So we set a flag here, too.
1356 sensitize_the_right_region_actions ();
1357 _last_region_menu_was_main = true;
1362 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1364 using namespace Menu_Helpers;
1366 void (Editor::*emf)(FadeShape);
1367 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1370 images = &_xfade_in_images;
1371 emf = &Editor::set_fade_in_shape;
1373 images = &_xfade_out_images;
1374 emf = &Editor::set_fade_out_shape;
1379 _("Linear (for highly correlated material)"),
1380 *(*images)[FadeLinear],
1381 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1385 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1389 _("Constant power"),
1390 *(*images)[FadeConstantPower],
1391 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1394 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1399 *(*images)[FadeSymmetric],
1400 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1409 *(*images)[FadeSlow],
1410 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1413 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1418 *(*images)[FadeFast],
1419 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1422 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1425 /** Pop up a context menu for when the user clicks on a start crossfade */
1427 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1429 using namespace Menu_Helpers;
1431 MenuList& items (xfade_in_context_menu.items());
1433 if (items.empty()) {
1434 fill_xfade_menu (items, true);
1437 xfade_in_context_menu.popup (button, time);
1440 /** Pop up a context menu for when the user clicks on an end crossfade */
1442 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1444 using namespace Menu_Helpers;
1446 MenuList& items (xfade_out_context_menu.items());
1448 if (items.empty()) {
1449 fill_xfade_menu (items, false);
1452 xfade_out_context_menu.popup (button, time);
1456 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1458 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1460 using namespace Menu_Helpers;
1461 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1464 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1468 MenuList& items (fade_context_menu.items());
1471 switch (item_type) {
1473 case FadeInHandleItem:
1474 if (arv->audio_region()->fade_in_active()) {
1475 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1477 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1480 items.push_back (SeparatorElem());
1482 if (Profile->get_sae()) {
1484 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1485 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1492 *_fade_in_images[FadeLinear],
1493 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1497 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1502 *_fade_in_images[FadeSlow],
1503 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 *_fade_in_images[FadeFast],
1512 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1515 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 *_fade_in_images[FadeSymmetric],
1521 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1526 _("Constant power"),
1527 *_fade_in_images[FadeConstantPower],
1528 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1531 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1537 case FadeOutHandleItem:
1538 if (arv->audio_region()->fade_out_active()) {
1539 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1541 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1544 items.push_back (SeparatorElem());
1546 if (Profile->get_sae()) {
1547 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1548 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1554 *_fade_out_images[FadeLinear],
1555 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1559 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1564 *_fade_out_images[FadeSlow],
1565 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1568 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1573 *_fade_out_images[FadeFast],
1574 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1577 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1582 *_fade_out_images[FadeSymmetric],
1583 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1588 _("Constant power"),
1589 *_fade_out_images[FadeConstantPower],
1590 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1593 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1599 fatal << _("programming error: ")
1600 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1605 fade_context_menu.popup (button, time);
1609 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1611 using namespace Menu_Helpers;
1612 Menu* (Editor::*build_menu_function)();
1615 switch (item_type) {
1617 case RegionViewName:
1618 case RegionViewNameHighlight:
1619 case LeftFrameHandle:
1620 case RightFrameHandle:
1621 if (with_selection) {
1622 build_menu_function = &Editor::build_track_selection_context_menu;
1624 build_menu_function = &Editor::build_track_region_context_menu;
1629 if (with_selection) {
1630 build_menu_function = &Editor::build_track_selection_context_menu;
1632 build_menu_function = &Editor::build_track_context_menu;
1637 if (clicked_routeview->track()) {
1638 build_menu_function = &Editor::build_track_context_menu;
1640 build_menu_function = &Editor::build_track_bus_context_menu;
1645 /* probably shouldn't happen but if it does, we don't care */
1649 menu = (this->*build_menu_function)();
1650 menu->set_name ("ArdourContextMenu");
1652 /* now handle specific situations */
1654 switch (item_type) {
1656 case RegionViewName:
1657 case RegionViewNameHighlight:
1658 case LeftFrameHandle:
1659 case RightFrameHandle:
1660 if (!with_selection) {
1661 if (region_edit_menu_split_item) {
1662 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1663 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1665 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1668 if (region_edit_menu_split_multichannel_item) {
1669 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1670 region_edit_menu_split_multichannel_item->set_sensitive (true);
1672 region_edit_menu_split_multichannel_item->set_sensitive (false);
1685 /* probably shouldn't happen but if it does, we don't care */
1689 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1691 /* Bounce to disk */
1693 using namespace Menu_Helpers;
1694 MenuList& edit_items = menu->items();
1696 edit_items.push_back (SeparatorElem());
1698 switch (clicked_routeview->audio_track()->freeze_state()) {
1699 case AudioTrack::NoFreeze:
1700 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1703 case AudioTrack::Frozen:
1704 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1707 case AudioTrack::UnFrozen:
1708 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1714 if (item_type == StreamItem && clicked_routeview) {
1715 clicked_routeview->build_underlay_menu(menu);
1718 /* When the region menu is opened, we setup the actions so that they look right
1721 sensitize_the_right_region_actions ();
1722 _last_region_menu_was_main = false;
1724 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1725 menu->popup (button, time);
1729 Editor::build_track_context_menu ()
1731 using namespace Menu_Helpers;
1733 MenuList& edit_items = track_context_menu.items();
1736 add_dstream_context_items (edit_items);
1737 return &track_context_menu;
1741 Editor::build_track_bus_context_menu ()
1743 using namespace Menu_Helpers;
1745 MenuList& edit_items = track_context_menu.items();
1748 add_bus_context_items (edit_items);
1749 return &track_context_menu;
1753 Editor::build_track_region_context_menu ()
1755 using namespace Menu_Helpers;
1756 MenuList& edit_items = track_region_context_menu.items();
1759 /* we've just cleared the track region context menu, so the menu that these
1760 two items were on will have disappeared; stop them dangling.
1762 region_edit_menu_split_item = 0;
1763 region_edit_menu_split_multichannel_item = 0;
1765 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1768 boost::shared_ptr<Track> tr;
1769 boost::shared_ptr<Playlist> pl;
1771 if ((tr = rtv->track())) {
1772 add_region_context_items (edit_items, tr);
1776 add_dstream_context_items (edit_items);
1778 return &track_region_context_menu;
1782 Editor::analyze_region_selection ()
1784 if (analysis_window == 0) {
1785 analysis_window = new AnalysisWindow();
1788 analysis_window->set_session(_session);
1790 analysis_window->show_all();
1793 analysis_window->set_regionmode();
1794 analysis_window->analyze();
1796 analysis_window->present();
1800 Editor::analyze_range_selection()
1802 if (analysis_window == 0) {
1803 analysis_window = new AnalysisWindow();
1806 analysis_window->set_session(_session);
1808 analysis_window->show_all();
1811 analysis_window->set_rangemode();
1812 analysis_window->analyze();
1814 analysis_window->present();
1818 Editor::build_track_selection_context_menu ()
1820 using namespace Menu_Helpers;
1821 MenuList& edit_items = track_selection_context_menu.items();
1822 edit_items.clear ();
1824 add_selection_context_items (edit_items);
1825 // edit_items.push_back (SeparatorElem());
1826 // add_dstream_context_items (edit_items);
1828 return &track_selection_context_menu;
1832 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1834 using namespace Menu_Helpers;
1836 /* OK, stick the region submenu at the top of the list, and then add
1840 RegionSelection rs = get_regions_from_selection_and_entered ();
1842 string::size_type pos = 0;
1843 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1845 /* we have to hack up the region name because "_" has a special
1846 meaning for menu titles.
1849 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1850 menu_item_name.replace (pos, 1, "__");
1854 if (_popup_region_menu_item == 0) {
1855 _popup_region_menu_item = new MenuItem (menu_item_name);
1856 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1857 _popup_region_menu_item->show ();
1859 _popup_region_menu_item->set_label (menu_item_name);
1862 const framepos_t position = get_preferred_edit_position (false, true);
1864 edit_items.push_back (*_popup_region_menu_item);
1865 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1866 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1868 edit_items.push_back (SeparatorElem());
1871 /** Add context menu items relevant to selection ranges.
1872 * @param edit_items List to add the items to.
1875 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1877 using namespace Menu_Helpers;
1879 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1880 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1882 edit_items.push_back (SeparatorElem());
1883 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1885 edit_items.push_back (SeparatorElem());
1887 edit_items.push_back (
1889 _("Move Range Start to Previous Region Boundary"),
1890 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1894 edit_items.push_back (
1896 _("Move Range Start to Next Region Boundary"),
1897 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1901 edit_items.push_back (
1903 _("Move Range End to Previous Region Boundary"),
1904 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1908 edit_items.push_back (
1910 _("Move Range End to Next Region Boundary"),
1911 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1915 edit_items.push_back (SeparatorElem());
1916 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1917 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1919 edit_items.push_back (SeparatorElem());
1920 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1922 edit_items.push_back (SeparatorElem());
1923 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1924 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1926 edit_items.push_back (SeparatorElem());
1927 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1929 edit_items.push_back (SeparatorElem());
1930 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1931 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1932 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1934 edit_items.push_back (SeparatorElem());
1935 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1936 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1937 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1938 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1939 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1944 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1946 using namespace Menu_Helpers;
1950 Menu *play_menu = manage (new Menu);
1951 MenuList& play_items = play_menu->items();
1952 play_menu->set_name ("ArdourContextMenu");
1954 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1955 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1956 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1957 play_items.push_back (SeparatorElem());
1958 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1960 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1964 Menu *select_menu = manage (new Menu);
1965 MenuList& select_items = select_menu->items();
1966 select_menu->set_name ("ArdourContextMenu");
1968 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1969 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1970 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1971 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1972 select_items.push_back (SeparatorElem());
1973 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1974 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1975 select_items.push_back (SeparatorElem());
1976 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1977 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1978 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1979 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1980 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1981 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1982 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1984 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1988 Menu *cutnpaste_menu = manage (new Menu);
1989 MenuList& cutnpaste_items = cutnpaste_menu->items();
1990 cutnpaste_menu->set_name ("ArdourContextMenu");
1992 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1993 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1994 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1996 cutnpaste_items.push_back (SeparatorElem());
1998 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1999 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2001 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2003 /* Adding new material */
2005 edit_items.push_back (SeparatorElem());
2006 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2007 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2011 Menu *nudge_menu = manage (new Menu());
2012 MenuList& nudge_items = nudge_menu->items();
2013 nudge_menu->set_name ("ArdourContextMenu");
2015 edit_items.push_back (SeparatorElem());
2016 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2018 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2019 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2021 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2025 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2027 using namespace Menu_Helpers;
2031 Menu *play_menu = manage (new Menu);
2032 MenuList& play_items = play_menu->items();
2033 play_menu->set_name ("ArdourContextMenu");
2035 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2036 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2037 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2041 Menu *select_menu = manage (new Menu);
2042 MenuList& select_items = select_menu->items();
2043 select_menu->set_name ("ArdourContextMenu");
2045 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2046 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2047 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2048 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2049 select_items.push_back (SeparatorElem());
2050 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2051 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2052 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2053 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2055 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2059 Menu *cutnpaste_menu = manage (new Menu);
2060 MenuList& cutnpaste_items = cutnpaste_menu->items();
2061 cutnpaste_menu->set_name ("ArdourContextMenu");
2063 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2064 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2065 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2067 Menu *nudge_menu = manage (new Menu());
2068 MenuList& nudge_items = nudge_menu->items();
2069 nudge_menu->set_name ("ArdourContextMenu");
2071 edit_items.push_back (SeparatorElem());
2072 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2074 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2075 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2077 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2081 Editor::snap_type() const
2087 Editor::snap_mode() const
2093 Editor::set_snap_to (SnapType st)
2095 unsigned int snap_ind = (unsigned int)st;
2099 if (snap_ind > snap_type_strings.size() - 1) {
2101 _snap_type = (SnapType)snap_ind;
2104 string str = snap_type_strings[snap_ind];
2106 if (str != snap_type_selector.get_active_text()) {
2107 snap_type_selector.set_active_text (str);
2112 switch (_snap_type) {
2113 case SnapToBeatDiv128:
2114 case SnapToBeatDiv64:
2115 case SnapToBeatDiv32:
2116 case SnapToBeatDiv28:
2117 case SnapToBeatDiv24:
2118 case SnapToBeatDiv20:
2119 case SnapToBeatDiv16:
2120 case SnapToBeatDiv14:
2121 case SnapToBeatDiv12:
2122 case SnapToBeatDiv10:
2123 case SnapToBeatDiv8:
2124 case SnapToBeatDiv7:
2125 case SnapToBeatDiv6:
2126 case SnapToBeatDiv5:
2127 case SnapToBeatDiv4:
2128 case SnapToBeatDiv3:
2129 case SnapToBeatDiv2: {
2130 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2131 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2133 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2134 current_bbt_points_begin, current_bbt_points_end);
2135 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2136 current_bbt_points_begin, current_bbt_points_end);
2137 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2141 case SnapToRegionStart:
2142 case SnapToRegionEnd:
2143 case SnapToRegionSync:
2144 case SnapToRegionBoundary:
2145 build_region_boundary_cache ();
2153 SnapChanged (); /* EMIT SIGNAL */
2157 Editor::set_snap_mode (SnapMode mode)
2159 string str = snap_mode_strings[(int)mode];
2161 if (_internal_editing) {
2162 internal_snap_mode = mode;
2164 pre_internal_snap_mode = mode;
2169 if (str != snap_mode_selector.get_active_text ()) {
2170 snap_mode_selector.set_active_text (str);
2176 Editor::set_edit_point_preference (EditPoint ep, bool force)
2178 bool changed = (_edit_point != ep);
2181 string str = edit_point_strings[(int)ep];
2183 if (str != edit_point_selector.get_active_text ()) {
2184 edit_point_selector.set_active_text (str);
2187 set_canvas_cursor ();
2189 if (!force && !changed) {
2193 const char* action=NULL;
2195 switch (_edit_point) {
2196 case EditAtPlayhead:
2197 action = "edit-at-playhead";
2199 case EditAtSelectedMarker:
2200 action = "edit-at-marker";
2203 action = "edit-at-mouse";
2207 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2209 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2213 bool in_track_canvas;
2215 if (!mouse_frame (foo, in_track_canvas)) {
2216 in_track_canvas = false;
2219 reset_canvas_action_sensitivity (in_track_canvas);
2225 Editor::set_state (const XMLNode& node, int /*version*/)
2227 const XMLProperty* prop;
2234 g.base_width = default_width;
2235 g.base_height = default_height;
2239 if ((geometry = find_named_node (node, "geometry")) != 0) {
2243 if ((prop = geometry->property("x_size")) == 0) {
2244 prop = geometry->property ("x-size");
2247 g.base_width = atoi(prop->value());
2249 if ((prop = geometry->property("y_size")) == 0) {
2250 prop = geometry->property ("y-size");
2253 g.base_height = atoi(prop->value());
2256 if ((prop = geometry->property ("x_pos")) == 0) {
2257 prop = geometry->property ("x-pos");
2260 x = atoi (prop->value());
2263 if ((prop = geometry->property ("y_pos")) == 0) {
2264 prop = geometry->property ("y-pos");
2267 y = atoi (prop->value());
2271 set_default_size (g.base_width, g.base_height);
2274 if (_session && (prop = node.property ("playhead"))) {
2276 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2277 playhead_cursor->set_position (pos);
2279 playhead_cursor->set_position (0);
2282 if ((prop = node.property ("mixer-width"))) {
2283 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2286 if ((prop = node.property ("zoom-focus"))) {
2287 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2290 if ((prop = node.property ("zoom"))) {
2291 reset_zoom (PBD::atof (prop->value()));
2293 reset_zoom (frames_per_pixel);
2296 if ((prop = node.property ("snap-to"))) {
2297 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2300 if ((prop = node.property ("snap-mode"))) {
2301 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2304 if ((prop = node.property ("internal-snap-to"))) {
2305 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2308 if ((prop = node.property ("internal-snap-mode"))) {
2309 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2312 if ((prop = node.property ("pre-internal-snap-to"))) {
2313 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2317 if ((prop = node.property ("pre-internal-snap-mode"))) {
2318 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2321 if ((prop = node.property ("mouse-mode"))) {
2322 MouseMode m = str2mousemode(prop->value());
2323 set_mouse_mode (m, true);
2325 set_mouse_mode (MouseObject, true);
2328 if ((prop = node.property ("left-frame")) != 0) {
2330 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2334 reset_x_origin (pos);
2338 if ((prop = node.property ("y-origin")) != 0) {
2339 reset_y_origin (atof (prop->value ()));
2342 if ((prop = node.property ("internal-edit"))) {
2343 bool yn = string_is_affirmative (prop->value());
2344 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2346 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2347 tact->set_active (!yn);
2348 tact->set_active (yn);
2352 if ((prop = node.property ("join-object-range"))) {
2353 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2354 bool yn = string_is_affirmative (prop->value());
2356 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2357 tact->set_active (!yn);
2358 tact->set_active (yn);
2360 set_mouse_mode(mouse_mode, true);
2363 if ((prop = node.property ("edit-point"))) {
2364 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2367 if ((prop = node.property ("show-measures"))) {
2368 bool yn = string_is_affirmative (prop->value());
2369 _show_measures = yn;
2370 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2372 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2373 /* do it twice to force the change */
2374 tact->set_active (!yn);
2375 tact->set_active (yn);
2379 if ((prop = node.property ("follow-playhead"))) {
2380 bool yn = string_is_affirmative (prop->value());
2381 set_follow_playhead (yn);
2382 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2384 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2385 if (tact->get_active() != yn) {
2386 tact->set_active (yn);
2391 if ((prop = node.property ("stationary-playhead"))) {
2392 bool yn = string_is_affirmative (prop->value());
2393 set_stationary_playhead (yn);
2394 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2396 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2397 if (tact->get_active() != yn) {
2398 tact->set_active (yn);
2403 if ((prop = node.property ("region-list-sort-type"))) {
2404 RegionListSortType st;
2405 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2408 if ((prop = node.property ("show-editor-mixer"))) {
2410 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2413 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2414 bool yn = string_is_affirmative (prop->value());
2416 /* do it twice to force the change */
2418 tact->set_active (!yn);
2419 tact->set_active (yn);
2422 if ((prop = node.property ("show-editor-list"))) {
2424 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2427 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2428 bool yn = string_is_affirmative (prop->value());
2430 /* do it twice to force the change */
2432 tact->set_active (!yn);
2433 tact->set_active (yn);
2436 if ((prop = node.property (X_("editor-list-page")))) {
2437 _the_notebook.set_current_page (atoi (prop->value ()));
2440 if ((prop = node.property (X_("show-marker-lines")))) {
2441 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2443 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2444 bool yn = string_is_affirmative (prop->value ());
2446 tact->set_active (!yn);
2447 tact->set_active (yn);
2450 XMLNodeList children = node.children ();
2451 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2452 selection->set_state (**i, Stateful::current_state_version);
2453 _regions->set_state (**i);
2456 if ((prop = node.property ("maximised"))) {
2457 bool yn = string_is_affirmative (prop->value());
2459 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2463 if ((prop = node.property ("nudge-clock-value"))) {
2465 sscanf (prop->value().c_str(), "%" PRId64, &f);
2466 nudge_clock->set (f);
2468 nudge_clock->set_mode (AudioClock::Timecode);
2469 nudge_clock->set (_session->frame_rate() * 5, true);
2476 Editor::get_state ()
2478 XMLNode* node = new XMLNode ("Editor");
2481 id().print (buf, sizeof (buf));
2482 node->add_property ("id", buf);
2484 if (is_realized()) {
2485 Glib::RefPtr<Gdk::Window> win = get_window();
2487 int x, y, width, height;
2488 win->get_root_origin(x, y);
2489 win->get_size(width, height);
2491 XMLNode* geometry = new XMLNode ("geometry");
2493 snprintf(buf, sizeof(buf), "%d", width);
2494 geometry->add_property("x-size", string(buf));
2495 snprintf(buf, sizeof(buf), "%d", height);
2496 geometry->add_property("y-size", string(buf));
2497 snprintf(buf, sizeof(buf), "%d", x);
2498 geometry->add_property("x-pos", string(buf));
2499 snprintf(buf, sizeof(buf), "%d", y);
2500 geometry->add_property("y-pos", string(buf));
2501 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2502 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2503 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2504 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2505 geometry->add_property("edit-vertical-pane-pos", string(buf));
2507 node->add_child_nocopy (*geometry);
2510 maybe_add_mixer_strip_width (*node);
2512 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2513 snprintf (buf, sizeof(buf), "%f", frames_per_pixel);
2514 node->add_property ("zoom", buf);
2515 node->add_property ("snap-to", enum_2_string (_snap_type));
2516 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2517 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2518 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2519 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2520 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2521 node->add_property ("edit-point", enum_2_string (_edit_point));
2523 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2524 node->add_property ("playhead", buf);
2525 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2526 node->add_property ("left-frame", buf);
2527 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2528 node->add_property ("y-origin", buf);
2530 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2531 node->add_property ("maximised", _maximised ? "yes" : "no");
2532 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2533 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2534 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2535 node->add_property ("mouse-mode", enum2str(mouse_mode));
2536 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2537 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2539 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2541 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2542 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2545 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2547 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2548 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2551 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2552 node->add_property (X_("editor-list-page"), buf);
2554 if (button_bindings) {
2555 XMLNode* bb = new XMLNode (X_("Buttons"));
2556 button_bindings->save (*bb);
2557 node->add_child_nocopy (*bb);
2560 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2562 node->add_child_nocopy (selection->get_state ());
2563 node->add_child_nocopy (_regions->get_state ());
2565 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2566 node->add_property ("nudge-clock-value", buf);
2573 /** @param y y offset from the top of all trackviews.
2574 * @return pair: TimeAxisView that y is over, layer index.
2575 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2576 * in stacked or expanded region display mode, otherwise 0.
2578 std::pair<TimeAxisView *, double>
2579 Editor::trackview_by_y_position (double y)
2581 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2583 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2589 return std::make_pair ( (TimeAxisView *) 0, 0);
2592 /** Snap a position to the grid, if appropriate, taking into account current
2593 * grid settings and also the state of any snap modifier keys that may be pressed.
2594 * @param start Position to snap.
2595 * @param event Event to get current key modifier information from, or 0.
2598 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2600 if (!_session || !event) {
2604 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2605 if (_snap_mode == SnapOff) {
2606 snap_to_internal (start, direction, for_mark);
2609 if (_snap_mode != SnapOff) {
2610 snap_to_internal (start, direction, for_mark);
2616 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2618 if (!_session || _snap_mode == SnapOff) {
2622 snap_to_internal (start, direction, for_mark);
2626 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2628 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2629 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2631 switch (_snap_type) {
2632 case SnapToTimecodeFrame:
2633 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2634 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2636 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2640 case SnapToTimecodeSeconds:
2641 if (_session->config.get_timecode_offset_negative()) {
2642 start += _session->config.get_timecode_offset ();
2644 start -= _session->config.get_timecode_offset ();
2646 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2647 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2649 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2652 if (_session->config.get_timecode_offset_negative()) {
2653 start -= _session->config.get_timecode_offset ();
2655 start += _session->config.get_timecode_offset ();
2659 case SnapToTimecodeMinutes:
2660 if (_session->config.get_timecode_offset_negative()) {
2661 start += _session->config.get_timecode_offset ();
2663 start -= _session->config.get_timecode_offset ();
2665 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2666 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2668 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2670 if (_session->config.get_timecode_offset_negative()) {
2671 start -= _session->config.get_timecode_offset ();
2673 start += _session->config.get_timecode_offset ();
2677 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2683 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2685 const framepos_t one_second = _session->frame_rate();
2686 const framepos_t one_minute = _session->frame_rate() * 60;
2687 framepos_t presnap = start;
2691 switch (_snap_type) {
2692 case SnapToTimecodeFrame:
2693 case SnapToTimecodeSeconds:
2694 case SnapToTimecodeMinutes:
2695 return timecode_snap_to_internal (start, direction, for_mark);
2698 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2699 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2701 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2706 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2707 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2709 start = (framepos_t) floor ((double) start / one_second) * one_second;
2714 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2715 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2717 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2722 start = _session->tempo_map().round_to_bar (start, direction);
2726 start = _session->tempo_map().round_to_beat (start, direction);
2729 case SnapToBeatDiv128:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2732 case SnapToBeatDiv64:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2735 case SnapToBeatDiv32:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2738 case SnapToBeatDiv28:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2741 case SnapToBeatDiv24:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2744 case SnapToBeatDiv20:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2747 case SnapToBeatDiv16:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2750 case SnapToBeatDiv14:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2753 case SnapToBeatDiv12:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2756 case SnapToBeatDiv10:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2759 case SnapToBeatDiv8:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2762 case SnapToBeatDiv7:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2765 case SnapToBeatDiv6:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2768 case SnapToBeatDiv5:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2771 case SnapToBeatDiv4:
2772 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2774 case SnapToBeatDiv3:
2775 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2777 case SnapToBeatDiv2:
2778 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2786 _session->locations()->marks_either_side (start, before, after);
2788 if (before == max_framepos && after == max_framepos) {
2789 /* No marks to snap to, so just don't snap */
2791 } else if (before == max_framepos) {
2793 } else if (after == max_framepos) {
2795 } else if (before != max_framepos && after != max_framepos) {
2796 /* have before and after */
2797 if ((start - before) < (after - start)) {
2806 case SnapToRegionStart:
2807 case SnapToRegionEnd:
2808 case SnapToRegionSync:
2809 case SnapToRegionBoundary:
2810 if (!region_boundary_cache.empty()) {
2812 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2813 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2815 if (direction > 0) {
2816 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2818 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2821 if (next != region_boundary_cache.begin ()) {
2826 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2827 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2829 if (start > (p + n) / 2) {
2838 switch (_snap_mode) {
2844 if (presnap > start) {
2845 if (presnap > (start + unit_to_frame(snap_threshold))) {
2849 } else if (presnap < start) {
2850 if (presnap < (start - unit_to_frame(snap_threshold))) {
2856 /* handled at entry */
2864 Editor::setup_toolbar ()
2866 HBox* mode_box = manage(new HBox);
2867 mode_box->set_border_width (2);
2868 mode_box->set_spacing(4);
2870 HBox* mouse_mode_box = manage (new HBox);
2871 HBox* mouse_mode_hbox = manage (new HBox);
2872 VBox* mouse_mode_vbox = manage (new VBox);
2873 Alignment* mouse_mode_align = manage (new Alignment);
2875 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2876 // mouse_mode_size_group->add_widget (smart_mode_button);
2877 mouse_mode_size_group->add_widget (mouse_move_button);
2878 mouse_mode_size_group->add_widget (mouse_select_button);
2879 mouse_mode_size_group->add_widget (mouse_zoom_button);
2880 mouse_mode_size_group->add_widget (mouse_gain_button);
2881 mouse_mode_size_group->add_widget (mouse_timefx_button);
2882 mouse_mode_size_group->add_widget (mouse_audition_button);
2883 mouse_mode_size_group->add_widget (mouse_draw_button);
2884 mouse_mode_size_group->add_widget (internal_edit_button);
2886 /* make them just a bit bigger */
2887 mouse_move_button.set_size_request (-1, 30);
2889 mouse_mode_hbox->set_spacing (2);
2891 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2894 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2895 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2896 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2897 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2898 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2899 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2901 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2903 mouse_mode_align->add (*mouse_mode_vbox);
2904 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2906 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2908 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2909 if (!Profile->get_sae()) {
2910 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2912 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2914 edit_mode_selector.set_name ("EditModeSelector");
2915 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2916 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2918 mode_box->pack_start (edit_mode_selector, false, false);
2919 mode_box->pack_start (*mouse_mode_box, false, false);
2921 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2922 _mouse_mode_tearoff->set_name ("MouseModeBase");
2923 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2925 if (Profile->get_sae()) {
2926 _mouse_mode_tearoff->set_can_be_torn_off (false);
2929 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2930 &_mouse_mode_tearoff->tearoff_window()));
2931 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2932 &_mouse_mode_tearoff->tearoff_window(), 1));
2933 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2934 &_mouse_mode_tearoff->tearoff_window()));
2935 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2936 &_mouse_mode_tearoff->tearoff_window(), 1));
2940 _zoom_box.set_spacing (2);
2941 _zoom_box.set_border_width (2);
2945 zoom_in_button.set_name ("zoom button");
2946 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2947 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2948 zoom_in_button.set_image(::get_icon ("zoom_in"));
2949 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2950 zoom_in_button.set_related_action (act);
2952 zoom_out_button.set_name ("zoom button");
2953 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2954 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2955 zoom_out_button.set_image(::get_icon ("zoom_out"));
2956 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2957 zoom_out_button.set_related_action (act);
2959 zoom_out_full_button.set_name ("zoom button");
2960 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2961 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2962 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2963 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2964 zoom_out_full_button.set_related_action (act);
2966 zoom_focus_selector.set_name ("ZoomFocusSelector");
2967 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2968 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2970 _zoom_box.pack_start (zoom_out_button, false, false);
2971 _zoom_box.pack_start (zoom_in_button, false, false);
2972 _zoom_box.pack_start (zoom_out_full_button, false, false);
2974 _zoom_box.pack_start (zoom_focus_selector, false, false);
2976 /* Track zoom buttons */
2977 tav_expand_button.set_name ("zoom button");
2978 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2979 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2980 tav_expand_button.set_size_request (-1, 20);
2981 tav_expand_button.set_image(::get_icon ("tav_exp"));
2982 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2983 tav_expand_button.set_related_action (act);
2985 tav_shrink_button.set_name ("zoom button");
2986 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2987 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2988 tav_shrink_button.set_size_request (-1, 20);
2989 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2990 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2991 tav_shrink_button.set_related_action (act);
2993 _zoom_box.pack_start (tav_shrink_button);
2994 _zoom_box.pack_start (tav_expand_button);
2996 _zoom_tearoff = manage (new TearOff (_zoom_box));
2998 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2999 &_zoom_tearoff->tearoff_window()));
3000 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3001 &_zoom_tearoff->tearoff_window(), 0));
3002 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3003 &_zoom_tearoff->tearoff_window()));
3004 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3005 &_zoom_tearoff->tearoff_window(), 0));
3007 snap_box.set_spacing (2);
3008 snap_box.set_border_width (2);
3010 snap_type_selector.set_name ("SnapTypeSelector");
3011 set_popdown_strings (snap_type_selector, snap_type_strings);
3012 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3014 snap_mode_selector.set_name ("SnapModeSelector");
3015 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3016 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3018 edit_point_selector.set_name ("EditPointSelector");
3019 set_popdown_strings (edit_point_selector, edit_point_strings);
3020 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3022 snap_box.pack_start (snap_mode_selector, false, false);
3023 snap_box.pack_start (snap_type_selector, false, false);
3024 snap_box.pack_start (edit_point_selector, false, false);
3028 HBox *nudge_box = manage (new HBox);
3029 nudge_box->set_spacing (2);
3030 nudge_box->set_border_width (2);
3032 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3033 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3035 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3036 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3038 nudge_box->pack_start (nudge_backward_button, false, false);
3039 nudge_box->pack_start (nudge_forward_button, false, false);
3040 nudge_box->pack_start (*nudge_clock, false, false);
3043 /* Pack everything in... */
3045 HBox* hbox = manage (new HBox);
3046 hbox->set_spacing(10);
3048 _tools_tearoff = manage (new TearOff (*hbox));
3049 _tools_tearoff->set_name ("MouseModeBase");
3050 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3052 if (Profile->get_sae()) {
3053 _tools_tearoff->set_can_be_torn_off (false);
3056 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3057 &_tools_tearoff->tearoff_window()));
3058 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3059 &_tools_tearoff->tearoff_window(), 0));
3060 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3061 &_tools_tearoff->tearoff_window()));
3062 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3063 &_tools_tearoff->tearoff_window(), 0));
3065 toolbar_hbox.set_spacing (10);
3066 toolbar_hbox.set_border_width (1);
3068 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3069 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3070 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3072 hbox->pack_start (snap_box, false, false);
3073 if (!Profile->get_small_screen()) {
3074 hbox->pack_start (*nudge_box, false, false);
3076 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3078 hbox->pack_start (panic_box, false, false);
3082 toolbar_base.set_name ("ToolBarBase");
3083 toolbar_base.add (toolbar_hbox);
3085 _toolbar_viewport.add (toolbar_base);
3086 /* stick to the required height but allow width to vary if there's not enough room */
3087 _toolbar_viewport.set_size_request (1, -1);
3089 toolbar_frame.set_shadow_type (SHADOW_OUT);
3090 toolbar_frame.set_name ("BaseFrame");
3091 toolbar_frame.add (_toolbar_viewport);
3095 Editor::setup_tooltips ()
3097 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3098 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3099 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3100 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3101 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3102 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3103 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3104 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3105 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3106 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3107 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3108 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3109 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3110 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3111 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3112 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3113 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3114 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3115 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3116 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3117 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3118 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3119 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3123 Editor::convert_drop_to_paths (
3124 vector<string>& paths,
3125 const RefPtr<Gdk::DragContext>& /*context*/,
3128 const SelectionData& data,
3132 if (_session == 0) {
3136 vector<string> uris = data.get_uris();
3140 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3141 are actually URI lists. So do it by hand.
3144 if (data.get_target() != "text/plain") {
3148 /* Parse the "uri-list" format that Nautilus provides,
3149 where each pathname is delimited by \r\n.
3151 THERE MAY BE NO NULL TERMINATING CHAR!!!
3154 string txt = data.get_text();
3158 p = (const char *) malloc (txt.length() + 1);
3159 txt.copy (const_cast<char *> (p), txt.length(), 0);
3160 const_cast<char*>(p)[txt.length()] = '\0';
3166 while (g_ascii_isspace (*p))
3170 while (*q && (*q != '\n') && (*q != '\r')) {
3177 while (q > p && g_ascii_isspace (*q))
3182 uris.push_back (string (p, q - p + 1));
3186 p = strchr (p, '\n');
3198 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3200 if ((*i).substr (0,7) == "file://") {
3202 string const p = PBD::url_decode (*i);
3204 // scan forward past three slashes
3206 string::size_type slashcnt = 0;
3207 string::size_type n = 0;
3208 string::const_iterator x = p.begin();
3210 while (slashcnt < 3 && x != p.end()) {
3213 } else if (slashcnt == 3) {
3220 if (slashcnt != 3 || x == p.end()) {
3221 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3225 paths.push_back (p.substr (n - 1));
3233 Editor::new_tempo_section ()
3239 Editor::map_transport_state ()
3241 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3243 if (_session && _session->transport_stopped()) {
3244 have_pending_keyboard_selection = false;
3247 update_loop_range_view (true);
3253 Editor::begin_reversible_command (string name)
3256 _session->begin_reversible_command (name);
3261 Editor::begin_reversible_command (GQuark q)
3264 _session->begin_reversible_command (q);
3269 Editor::commit_reversible_command ()
3272 _session->commit_reversible_command ();
3277 Editor::history_changed ()
3281 if (undo_action && _session) {
3282 if (_session->undo_depth() == 0) {
3283 label = S_("Command|Undo");
3285 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3287 undo_action->property_label() = label;
3290 if (redo_action && _session) {
3291 if (_session->redo_depth() == 0) {
3294 label = string_compose(_("Redo (%1)"), _session->next_redo());
3296 redo_action->property_label() = label;
3301 Editor::duplicate_range (bool with_dialog)
3305 RegionSelection rs = get_regions_from_selection_and_entered ();
3307 if ( selection->time.length() == 0 && rs.empty()) {
3313 ArdourDialog win (_("Duplicate"));
3314 Label label (_("Number of duplications:"));
3315 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3316 SpinButton spinner (adjustment, 0.0, 1);
3319 win.get_vbox()->set_spacing (12);
3320 win.get_vbox()->pack_start (hbox);
3321 hbox.set_border_width (6);
3322 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3324 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3325 place, visually. so do this by hand.
3328 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3329 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3330 spinner.grab_focus();
3336 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3337 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3338 win.set_default_response (RESPONSE_ACCEPT);
3340 win.set_position (WIN_POS_MOUSE);
3342 spinner.grab_focus ();
3344 switch (win.run ()) {
3345 case RESPONSE_ACCEPT:
3351 times = adjustment.get_value();
3354 if ((current_mouse_mode() == Editing::MouseRange)) {
3355 if (selection->time.length()) {
3356 duplicate_selection (times);
3358 } else if (get_smart_mode()) {
3359 if (selection->time.length()) {
3360 duplicate_selection (times);
3362 duplicate_some_regions (rs, times);
3364 duplicate_some_regions (rs, times);
3369 Editor::set_edit_mode (EditMode m)
3371 Config->set_edit_mode (m);
3375 Editor::cycle_edit_mode ()
3377 switch (Config->get_edit_mode()) {
3379 if (Profile->get_sae()) {
3380 Config->set_edit_mode (Lock);
3382 Config->set_edit_mode (Splice);
3386 Config->set_edit_mode (Lock);
3389 Config->set_edit_mode (Slide);
3395 Editor::edit_mode_selection_done ()
3397 string s = edit_mode_selector.get_active_text ();
3400 Config->set_edit_mode (string_to_edit_mode (s));
3405 Editor::snap_type_selection_done ()
3407 string choice = snap_type_selector.get_active_text();
3408 SnapType snaptype = SnapToBeat;
3410 if (choice == _("Beats/2")) {
3411 snaptype = SnapToBeatDiv2;
3412 } else if (choice == _("Beats/3")) {
3413 snaptype = SnapToBeatDiv3;
3414 } else if (choice == _("Beats/4")) {
3415 snaptype = SnapToBeatDiv4;
3416 } else if (choice == _("Beats/5")) {
3417 snaptype = SnapToBeatDiv5;
3418 } else if (choice == _("Beats/6")) {
3419 snaptype = SnapToBeatDiv6;
3420 } else if (choice == _("Beats/7")) {
3421 snaptype = SnapToBeatDiv7;
3422 } else if (choice == _("Beats/8")) {
3423 snaptype = SnapToBeatDiv8;
3424 } else if (choice == _("Beats/10")) {
3425 snaptype = SnapToBeatDiv10;
3426 } else if (choice == _("Beats/12")) {
3427 snaptype = SnapToBeatDiv12;
3428 } else if (choice == _("Beats/14")) {
3429 snaptype = SnapToBeatDiv14;
3430 } else if (choice == _("Beats/16")) {
3431 snaptype = SnapToBeatDiv16;
3432 } else if (choice == _("Beats/20")) {
3433 snaptype = SnapToBeatDiv20;
3434 } else if (choice == _("Beats/24")) {
3435 snaptype = SnapToBeatDiv24;
3436 } else if (choice == _("Beats/28")) {
3437 snaptype = SnapToBeatDiv28;
3438 } else if (choice == _("Beats/32")) {
3439 snaptype = SnapToBeatDiv32;
3440 } else if (choice == _("Beats/64")) {
3441 snaptype = SnapToBeatDiv64;
3442 } else if (choice == _("Beats/128")) {
3443 snaptype = SnapToBeatDiv128;
3444 } else if (choice == _("Beats")) {
3445 snaptype = SnapToBeat;
3446 } else if (choice == _("Bars")) {
3447 snaptype = SnapToBar;
3448 } else if (choice == _("Marks")) {
3449 snaptype = SnapToMark;
3450 } else if (choice == _("Region starts")) {
3451 snaptype = SnapToRegionStart;
3452 } else if (choice == _("Region ends")) {
3453 snaptype = SnapToRegionEnd;
3454 } else if (choice == _("Region bounds")) {
3455 snaptype = SnapToRegionBoundary;
3456 } else if (choice == _("Region syncs")) {
3457 snaptype = SnapToRegionSync;
3458 } else if (choice == _("CD Frames")) {
3459 snaptype = SnapToCDFrame;
3460 } else if (choice == _("Timecode Frames")) {
3461 snaptype = SnapToTimecodeFrame;
3462 } else if (choice == _("Timecode Seconds")) {
3463 snaptype = SnapToTimecodeSeconds;
3464 } else if (choice == _("Timecode Minutes")) {
3465 snaptype = SnapToTimecodeMinutes;
3466 } else if (choice == _("Seconds")) {
3467 snaptype = SnapToSeconds;
3468 } else if (choice == _("Minutes")) {
3469 snaptype = SnapToMinutes;
3472 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3474 ract->set_active ();
3479 Editor::snap_mode_selection_done ()
3481 string choice = snap_mode_selector.get_active_text();
3482 SnapMode mode = SnapNormal;
3484 if (choice == _("No Grid")) {
3486 } else if (choice == _("Grid")) {
3488 } else if (choice == _("Magnetic")) {
3489 mode = SnapMagnetic;
3492 RefPtr<RadioAction> ract = snap_mode_action (mode);
3495 ract->set_active (true);
3500 Editor::cycle_edit_point (bool with_marker)
3502 switch (_edit_point) {
3504 set_edit_point_preference (EditAtPlayhead);
3506 case EditAtPlayhead:
3508 set_edit_point_preference (EditAtSelectedMarker);
3510 set_edit_point_preference (EditAtMouse);
3513 case EditAtSelectedMarker:
3514 set_edit_point_preference (EditAtMouse);
3520 Editor::edit_point_selection_done ()
3522 string choice = edit_point_selector.get_active_text();
3523 EditPoint ep = EditAtSelectedMarker;
3525 if (choice == _("Marker")) {
3526 set_edit_point_preference (EditAtSelectedMarker);
3527 } else if (choice == _("Playhead")) {
3528 set_edit_point_preference (EditAtPlayhead);
3530 set_edit_point_preference (EditAtMouse);
3533 RefPtr<RadioAction> ract = edit_point_action (ep);
3536 ract->set_active (true);
3541 Editor::zoom_focus_selection_done ()
3543 string choice = zoom_focus_selector.get_active_text();
3544 ZoomFocus focus_type = ZoomFocusLeft;
3546 if (choice == _("Left")) {
3547 focus_type = ZoomFocusLeft;
3548 } else if (choice == _("Right")) {
3549 focus_type = ZoomFocusRight;
3550 } else if (choice == _("Center")) {
3551 focus_type = ZoomFocusCenter;
3552 } else if (choice == _("Playhead")) {
3553 focus_type = ZoomFocusPlayhead;
3554 } else if (choice == _("Mouse")) {
3555 focus_type = ZoomFocusMouse;
3556 } else if (choice == _("Edit point")) {
3557 focus_type = ZoomFocusEdit;
3560 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3563 ract->set_active ();
3568 Editor::edit_controls_button_release (GdkEventButton* ev)
3570 if (Keyboard::is_context_menu_event (ev)) {
3571 ARDOUR_UI::instance()->add_route (this);
3572 } else if (ev->button == 1) {
3573 selection->clear_tracks ();
3580 Editor::mouse_select_button_release (GdkEventButton* ev)
3582 /* this handles just right-clicks */
3584 if (ev->button != 3) {
3592 Editor::set_zoom_focus (ZoomFocus f)
3594 string str = zoom_focus_strings[(int)f];
3596 if (str != zoom_focus_selector.get_active_text()) {
3597 zoom_focus_selector.set_active_text (str);
3600 if (zoom_focus != f) {
3607 Editor::cycle_zoom_focus ()
3609 switch (zoom_focus) {
3611 set_zoom_focus (ZoomFocusRight);
3613 case ZoomFocusRight:
3614 set_zoom_focus (ZoomFocusCenter);
3616 case ZoomFocusCenter:
3617 set_zoom_focus (ZoomFocusPlayhead);
3619 case ZoomFocusPlayhead:
3620 set_zoom_focus (ZoomFocusMouse);
3622 case ZoomFocusMouse:
3623 set_zoom_focus (ZoomFocusEdit);
3626 set_zoom_focus (ZoomFocusLeft);
3632 Editor::ensure_float (Window& win)
3634 win.set_transient_for (*this);
3638 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3640 /* recover or initialize pane positions. do this here rather than earlier because
3641 we don't want the positions to change the child allocations, which they seem to do.
3647 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3656 XMLNode* geometry = find_named_node (*node, "geometry");
3658 if (which == static_cast<Paned*> (&edit_pane)) {
3660 if (done & Horizontal) {
3664 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3665 _notebook_shrunk = string_is_affirmative (prop->value ());
3668 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3669 /* initial allocation is 90% to canvas, 10% to notebook */
3670 pos = (int) floor (alloc.get_width() * 0.90f);
3671 snprintf (buf, sizeof(buf), "%d", pos);
3673 pos = atoi (prop->value());
3676 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3677 edit_pane.set_position (pos);
3680 done = (Pane) (done | Horizontal);
3682 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3684 if (done & Vertical) {
3688 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3689 /* initial allocation is 90% to canvas, 10% to summary */
3690 pos = (int) floor (alloc.get_height() * 0.90f);
3691 snprintf (buf, sizeof(buf), "%d", pos);
3694 pos = atoi (prop->value());
3697 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3698 editor_summary_pane.set_position (pos);
3701 done = (Pane) (done | Vertical);
3706 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3708 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3709 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3710 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3711 top_hbox.remove (toolbar_frame);
3716 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3718 if (toolbar_frame.get_parent() == 0) {
3719 top_hbox.pack_end (toolbar_frame);
3724 Editor::set_show_measures (bool yn)
3726 if (_show_measures != yn) {
3729 if ((_show_measures = yn) == true) {
3731 tempo_lines->show();
3733 (void) redraw_measures ();
3740 Editor::toggle_follow_playhead ()
3742 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3744 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3745 set_follow_playhead (tact->get_active());
3749 /** @param yn true to follow playhead, otherwise false.
3750 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3753 Editor::set_follow_playhead (bool yn, bool catch_up)
3755 if (_follow_playhead != yn) {
3756 if ((_follow_playhead = yn) == true && catch_up) {
3758 reset_x_origin_to_follow_playhead ();
3765 Editor::toggle_stationary_playhead ()
3767 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3769 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3770 set_stationary_playhead (tact->get_active());
3775 Editor::set_stationary_playhead (bool yn)
3777 if (_stationary_playhead != yn) {
3778 if ((_stationary_playhead = yn) == true) {
3780 // FIXME need a 3.0 equivalent of this 2.X call
3781 // update_current_screen ();
3788 Editor::playlist_selector () const
3790 return *_playlist_selector;
3794 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3798 switch (_snap_type) {
3803 case SnapToBeatDiv128:
3806 case SnapToBeatDiv64:
3809 case SnapToBeatDiv32:
3812 case SnapToBeatDiv28:
3815 case SnapToBeatDiv24:
3818 case SnapToBeatDiv20:
3821 case SnapToBeatDiv16:
3824 case SnapToBeatDiv14:
3827 case SnapToBeatDiv12:
3830 case SnapToBeatDiv10:
3833 case SnapToBeatDiv8:
3836 case SnapToBeatDiv7:
3839 case SnapToBeatDiv6:
3842 case SnapToBeatDiv5:
3845 case SnapToBeatDiv4:
3848 case SnapToBeatDiv3:
3851 case SnapToBeatDiv2:
3857 return _session->tempo_map().meter_at (position).divisions_per_bar();
3862 case SnapToTimecodeFrame:
3863 case SnapToTimecodeSeconds:
3864 case SnapToTimecodeMinutes:
3867 case SnapToRegionStart:
3868 case SnapToRegionEnd:
3869 case SnapToRegionSync:
3870 case SnapToRegionBoundary:
3880 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3884 ret = nudge_clock->current_duration (pos);
3885 next = ret + 1; /* XXXX fix me */
3891 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3893 ArdourDialog dialog (_("Playlist Deletion"));
3894 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3895 "If it is kept, its audio files will not be cleaned.\n"
3896 "If it is deleted, audio files used by it alone will be cleaned."),
3899 dialog.set_position (WIN_POS_CENTER);
3900 dialog.get_vbox()->pack_start (label);
3904 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3905 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3906 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3908 switch (dialog.run ()) {
3909 case RESPONSE_ACCEPT:
3910 /* delete the playlist */
3914 case RESPONSE_REJECT:
3915 /* keep the playlist */
3927 Editor::audio_region_selection_covers (framepos_t where)
3929 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3930 if ((*a)->region()->covers (where)) {
3939 Editor::prepare_for_cleanup ()
3941 cut_buffer->clear_regions ();
3942 cut_buffer->clear_playlists ();
3944 selection->clear_regions ();
3945 selection->clear_playlists ();
3947 _regions->suspend_redisplay ();
3951 Editor::finish_cleanup ()
3953 _regions->resume_redisplay ();
3957 Editor::transport_loop_location()
3960 return _session->locations()->auto_loop_location();
3967 Editor::transport_punch_location()
3970 return _session->locations()->auto_punch_location();
3977 Editor::control_layout_scroll (GdkEventScroll* ev)
3979 if (Keyboard::some_magic_widget_has_focus()) {
3983 switch (ev->direction) {
3985 scroll_tracks_up_line ();
3989 case GDK_SCROLL_DOWN:
3990 scroll_tracks_down_line ();
3994 /* no left/right handling yet */
4002 Editor::session_state_saved (string)
4005 _snapshots->redisplay ();
4009 Editor::update_tearoff_visibility()
4011 bool visible = Config->get_keep_tearoffs();
4012 _mouse_mode_tearoff->set_visible (visible);
4013 _tools_tearoff->set_visible (visible);
4014 _zoom_tearoff->set_visible (visible);
4018 Editor::maximise_editing_space ()
4030 Editor::restore_editing_space ()
4042 * Make new playlists for a given track and also any others that belong
4043 * to the same active route group with the `select' property.
4048 Editor::new_playlists (TimeAxisView* v)
4050 begin_reversible_command (_("new playlists"));
4051 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4052 _session->playlists->get (playlists);
4053 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4054 commit_reversible_command ();
4058 * Use a copy of the current playlist for a given track and also any others that belong
4059 * to the same active route group with the `select' property.
4064 Editor::copy_playlists (TimeAxisView* v)
4066 begin_reversible_command (_("copy playlists"));
4067 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4068 _session->playlists->get (playlists);
4069 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4070 commit_reversible_command ();
4073 /** Clear the current playlist for a given track and also any others that belong
4074 * to the same active route group with the `select' property.
4079 Editor::clear_playlists (TimeAxisView* v)
4081 begin_reversible_command (_("clear playlists"));
4082 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4083 _session->playlists->get (playlists);
4084 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4085 commit_reversible_command ();
4089 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4091 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4095 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4097 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4101 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4103 atv.clear_playlist ();
4107 Editor::on_key_press_event (GdkEventKey* ev)
4109 return key_press_focus_accelerator_handler (*this, ev);
4113 Editor::on_key_release_event (GdkEventKey* ev)
4115 return Gtk::Window::on_key_release_event (ev);
4116 // return key_press_focus_accelerator_handler (*this, ev);
4119 /** Queue up a change to the viewport x origin.
4120 * @param frame New x origin.
4123 Editor::reset_x_origin (framepos_t frame)
4125 pending_visual_change.add (VisualChange::TimeOrigin);
4126 pending_visual_change.time_origin = frame;
4127 ensure_visual_change_idle_handler ();
4131 Editor::reset_y_origin (double y)
4133 pending_visual_change.add (VisualChange::YOrigin);
4134 pending_visual_change.y_origin = y;
4135 ensure_visual_change_idle_handler ();
4139 Editor::reset_zoom (double fpp)
4141 clamp_frames_per_pixel (fpp);
4143 if (fpp == frames_per_pixel) {
4147 pending_visual_change.add (VisualChange::ZoomLevel);
4148 pending_visual_change.frames_per_pixel = fpp;
4149 ensure_visual_change_idle_handler ();
4153 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4155 reset_x_origin (frame);
4158 if (!no_save_visual) {
4159 undo_visual_stack.push_back (current_visual_state(false));
4163 Editor::VisualState::VisualState (bool with_tracks)
4164 : gui_state (with_tracks ? new GUIObjectState : 0)
4168 Editor::VisualState::~VisualState ()
4173 Editor::VisualState*
4174 Editor::current_visual_state (bool with_tracks)
4176 VisualState* vs = new VisualState (with_tracks);
4177 vs->y_position = vertical_adjustment.get_value();
4178 vs->frames_per_pixel = frames_per_pixel;
4179 vs->leftmost_frame = leftmost_frame;
4180 vs->zoom_focus = zoom_focus;
4183 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4190 Editor::undo_visual_state ()
4192 if (undo_visual_stack.empty()) {
4196 VisualState* vs = undo_visual_stack.back();
4197 undo_visual_stack.pop_back();
4200 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4202 use_visual_state (*vs);
4206 Editor::redo_visual_state ()
4208 if (redo_visual_stack.empty()) {
4212 VisualState* vs = redo_visual_stack.back();
4213 redo_visual_stack.pop_back();
4215 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4217 use_visual_state (*vs);
4221 Editor::swap_visual_state ()
4223 if (undo_visual_stack.empty()) {
4224 redo_visual_state ();
4226 undo_visual_state ();
4231 Editor::use_visual_state (VisualState& vs)
4233 PBD::Unwinder<bool> nsv (no_save_visual, true);
4235 _routes->suspend_redisplay ();
4237 vertical_adjustment.set_value (vs.y_position);
4239 set_zoom_focus (vs.zoom_focus);
4240 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_pixel);
4243 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4245 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4246 (*i)->reset_visual_state ();
4250 _routes->update_visibility ();
4251 _routes->resume_redisplay ();
4254 /** This is the core function that controls the zoom level of the canvas. It is called
4255 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4256 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4259 Editor::set_frames_per_pixel (double fpp)
4262 tempo_lines->tempo_map_changed();
4265 frames_per_pixel = fpp;
4267 /* convert fpu to frame count */
4269 framepos_t frames = (framepos_t) floor (frames_per_pixel * _visible_canvas_width);
4271 if (frames_per_pixel != zoom_range_clock->current_duration()) {
4272 zoom_range_clock->set (frames);
4275 bool const showing_time_selection = selection->time.length() > 0;
4277 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4278 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4279 (*i)->reshow_selection (selection->time);
4283 ZoomChanged (); /* EMIT_SIGNAL */
4285 //reset_scrolling_region ();
4287 if (playhead_cursor) {
4288 playhead_cursor->set_position (playhead_cursor->current_frame ());
4291 refresh_location_display();
4292 _summary->set_overlays_dirty ();
4294 update_marker_labels ();
4299 #ifdef WITH_VIDEOTIMELINE
4301 Editor::queue_visual_videotimeline_update ()
4304 * pending_visual_change.add (VisualChange::VideoTimeline);
4305 * or maybe even more specific: which videotimeline-image
4306 * currently it calls update_video_timeline() to update
4307 * _all outdated_ images on the video-timeline.
4308 * see 'exposeimg()' in video_image_frame.cc
4310 ensure_visual_change_idle_handler ();
4315 Editor::ensure_visual_change_idle_handler ()
4317 if (pending_visual_change.idle_handler_id < 0) {
4318 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4319 pending_visual_change.being_handled = false;
4324 Editor::_idle_visual_changer (void* arg)
4326 return static_cast<Editor*>(arg)->idle_visual_changer ();
4330 Editor::idle_visual_changer ()
4332 /* set_horizontal_position() below (and maybe other calls) call
4333 gtk_main_iteration(), so it's possible that a signal will be handled
4334 half-way through this method. If this signal wants an
4335 idle_visual_changer we must schedule another one after this one, so
4336 mark the idle_handler_id as -1 here to allow that. Also make a note
4337 that we are doing the visual change, so that changes in response to
4338 super-rapid-screen-update can be dropped if we are still processing
4342 pending_visual_change.idle_handler_id = -1;
4343 pending_visual_change.being_handled = true;
4345 VisualChange::Type p = pending_visual_change.pending;
4346 pending_visual_change.pending = (VisualChange::Type) 0;
4348 double const last_time_origin = horizontal_position ();
4350 if (p & VisualChange::ZoomLevel) {
4351 set_frames_per_pixel (pending_visual_change.frames_per_pixel);
4353 compute_fixed_ruler_scale ();
4355 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4356 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4358 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4359 current_bbt_points_begin, current_bbt_points_end);
4360 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4361 current_bbt_points_begin, current_bbt_points_end);
4362 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4365 #ifdef WITH_VIDEOTIMELINE
4366 if (p & VisualChange::ZoomLevel) {
4367 update_video_timeline();
4371 if (p & VisualChange::TimeOrigin) {
4372 set_horizontal_position (pending_visual_change.time_origin / frames_per_pixel);
4375 if (p & VisualChange::YOrigin) {
4376 vertical_adjustment.set_value (pending_visual_change.y_origin);
4379 if (last_time_origin == horizontal_position ()) {
4380 /* changed signal not emitted */
4381 update_fixed_rulers ();
4382 redisplay_tempo (true);
4384 #ifdef WITH_VIDEOTIMELINE
4385 if (!(p & VisualChange::ZoomLevel)) {
4386 update_video_timeline();
4390 _summary->set_overlays_dirty ();
4392 pending_visual_change.being_handled = false;
4393 return 0; /* this is always a one-shot call */
4396 struct EditorOrderTimeAxisSorter {
4397 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4398 return a->order () < b->order ();
4403 Editor::sort_track_selection (TrackViewList& sel)
4405 EditorOrderTimeAxisSorter cmp;
4410 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4413 framepos_t where = 0;
4414 EditPoint ep = _edit_point;
4416 if (from_context_menu && (ep == EditAtMouse)) {
4417 return event_frame (&context_click_event, 0, 0);
4420 if (entered_marker) {
4421 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4422 return entered_marker->position();
4425 if (ignore_playhead && ep == EditAtPlayhead) {
4426 ep = EditAtSelectedMarker;
4430 case EditAtPlayhead:
4431 where = _session->audible_frame();
4432 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4435 case EditAtSelectedMarker:
4436 if (!selection->markers.empty()) {
4438 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4441 where = loc->start();
4445 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4453 if (!mouse_frame (where, ignored)) {
4454 /* XXX not right but what can we do ? */
4458 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4466 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4468 if (!_session) return;
4470 begin_reversible_command (cmd);
4474 if ((tll = transport_loop_location()) == 0) {
4475 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4476 XMLNode &before = _session->locations()->get_state();
4477 _session->locations()->add (loc, true);
4478 _session->set_auto_loop_location (loc);
4479 XMLNode &after = _session->locations()->get_state();
4480 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4482 XMLNode &before = tll->get_state();
4483 tll->set_hidden (false, this);
4484 tll->set (start, end);
4485 XMLNode &after = tll->get_state();
4486 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4489 commit_reversible_command ();
4493 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4495 if (!_session) return;
4497 begin_reversible_command (cmd);
4501 if ((tpl = transport_punch_location()) == 0) {
4502 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4503 XMLNode &before = _session->locations()->get_state();
4504 _session->locations()->add (loc, true);
4505 _session->set_auto_loop_location (loc);
4506 XMLNode &after = _session->locations()->get_state();
4507 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4510 XMLNode &before = tpl->get_state();
4511 tpl->set_hidden (false, this);
4512 tpl->set (start, end);
4513 XMLNode &after = tpl->get_state();
4514 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4517 commit_reversible_command ();
4520 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4521 * @param rs List to which found regions are added.
4522 * @param where Time to look at.
4523 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4526 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4528 const TrackViewList* tracks;
4531 tracks = &track_views;
4536 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4538 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4541 boost::shared_ptr<Track> tr;
4542 boost::shared_ptr<Playlist> pl;
4544 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4546 boost::shared_ptr<RegionList> regions = pl->regions_at (
4547 (framepos_t) floor ( (double) where * tr->speed()));
4549 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4550 RegionView* rv = rtv->view()->find_view (*i);
4561 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4563 const TrackViewList* tracks;
4566 tracks = &track_views;
4571 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4572 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4574 boost::shared_ptr<Track> tr;
4575 boost::shared_ptr<Playlist> pl;
4577 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4579 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4580 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4582 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4584 RegionView* rv = rtv->view()->find_view (*i);
4595 /** Get regions using the following method:
4597 * Make a region list using the selected regions, unless
4598 * the edit point is `mouse' and the mouse is over an unselected
4599 * region. In this case, use just that region.
4601 * If the edit point is not 'mouse', and there are no regions selected,
4602 * search the list of selected tracks and return regions that are under
4603 * the edit point on these tracks. If there are no selected tracks and
4604 * 'No Selection = All Tracks' is active, search all tracks,
4606 * The rationale here is that the mouse edit point is special in that
4607 * its position describes both a time and a track; the other edit
4608 * modes only describe a time. Hence if the edit point is `mouse' we
4609 * ignore selected tracks, as we assume the user means something by
4610 * pointing at a particular track. Also in this case we take note of
4611 * the region directly under the edit point, as there is always just one
4612 * (rather than possibly several with non-mouse edit points).
4616 Editor::get_regions_from_selection_and_edit_point ()
4618 RegionSelection regions;
4620 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4621 regions.add (entered_regionview);
4623 regions = selection->regions;
4627 if (regions.empty() && _edit_point != EditAtMouse) {
4628 TrackViewList tracks = selection->tracks;
4630 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4631 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4632 * is enabled, so consider all tracks
4634 tracks = track_views;
4637 if (!tracks.empty()) {
4638 /* no region selected or entered, but some selected tracks:
4639 * act on all regions on the selected tracks at the edit point
4641 framepos_t const where = get_preferred_edit_position ();
4642 get_regions_at(regions, where, tracks);
4648 /** Start with regions that are selected, or the entered regionview if none are selected.
4649 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4650 * of the regions that we started with.
4654 Editor::get_regions_from_selection_and_entered ()
4656 RegionSelection regions = selection->regions;
4658 if (regions.empty() && entered_regionview) {
4659 regions.add (entered_regionview);
4666 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4668 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4670 RouteTimeAxisView* tatv;
4672 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4674 boost::shared_ptr<Playlist> pl;
4675 vector<boost::shared_ptr<Region> > results;
4677 boost::shared_ptr<Track> tr;
4679 if ((tr = tatv->track()) == 0) {
4684 if ((pl = (tr->playlist())) != 0) {
4685 if (src_comparison) {
4686 pl->get_source_equivalent_regions (region, results);
4688 pl->get_region_list_equivalent_regions (region, results);
4692 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4693 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4694 regions.push_back (marv);
4703 Editor::show_rhythm_ferret ()
4705 if (rhythm_ferret == 0) {
4706 rhythm_ferret = new RhythmFerret(*this);
4709 rhythm_ferret->set_session (_session);
4710 rhythm_ferret->show ();
4711 rhythm_ferret->present ();
4715 Editor::first_idle ()
4717 MessageDialog* dialog = 0;
4719 if (track_views.size() > 1) {
4720 dialog = new MessageDialog (
4722 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4726 ARDOUR_UI::instance()->flush_pending ();
4729 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4733 // first idle adds route children (automation tracks), so we need to redisplay here
4734 _routes->redisplay ();
4741 Editor::_idle_resize (gpointer arg)
4743 return ((Editor*)arg)->idle_resize ();
4747 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4749 if (resize_idle_id < 0) {
4750 resize_idle_id = g_idle_add (_idle_resize, this);
4751 _pending_resize_amount = 0;
4754 /* make a note of the smallest resulting height, so that we can clamp the
4755 lower limit at TimeAxisView::hSmall */
4757 int32_t min_resulting = INT32_MAX;
4759 _pending_resize_amount += h;
4760 _pending_resize_view = view;
4762 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4764 if (selection->tracks.contains (_pending_resize_view)) {
4765 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4766 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4770 if (min_resulting < 0) {
4775 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4776 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4780 /** Handle pending resizing of tracks */
4782 Editor::idle_resize ()
4784 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4786 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4787 selection->tracks.contains (_pending_resize_view)) {
4789 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4790 if (*i != _pending_resize_view) {
4791 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4796 _pending_resize_amount = 0;
4798 _group_tabs->set_dirty ();
4799 resize_idle_id = -1;
4807 ENSURE_GUI_THREAD (*this, &Editor::located);
4810 playhead_cursor->set_position (_session->audible_frame ());
4811 if (_follow_playhead && !_pending_initial_locate) {
4812 reset_x_origin_to_follow_playhead ();
4816 _pending_locate_request = false;
4817 _pending_initial_locate = false;
4821 Editor::region_view_added (RegionView *)
4823 _summary->set_dirty ();
4827 Editor::region_view_removed ()
4829 _summary->set_dirty ();
4833 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4835 TrackViewList::const_iterator j = track_views.begin ();
4836 while (j != track_views.end()) {
4837 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4838 if (rtv && rtv->route() == r) {
4849 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4853 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4854 TimeAxisView* tv = axis_view_from_route (*i);
4864 Editor::add_routes (RouteList& routes)
4866 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4868 RouteTimeAxisView *rtv;
4869 list<RouteTimeAxisView*> new_views;
4871 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4872 boost::shared_ptr<Route> route = (*x);
4874 if (route->is_auditioner() || route->is_monitor()) {
4878 DataType dt = route->input()->default_type();
4880 if (dt == ARDOUR::DataType::AUDIO) {
4881 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4882 rtv->set_route (route);
4883 } else if (dt == ARDOUR::DataType::MIDI) {
4884 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4885 rtv->set_route (route);
4887 throw unknown_type();
4890 new_views.push_back (rtv);
4891 track_views.push_back (rtv);
4893 rtv->effective_gain_display ();
4895 if (internal_editing()) {
4896 rtv->enter_internal_edit_mode ();
4898 rtv->leave_internal_edit_mode ();
4901 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4902 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4905 _routes->routes_added (new_views);
4906 _summary->routes_added (new_views);
4908 if (show_editor_mixer_when_tracks_arrive) {
4909 show_editor_mixer (true);
4912 editor_list_button.set_sensitive (true);
4916 Editor::timeaxisview_deleted (TimeAxisView *tv)
4918 if (_session && _session->deletion_in_progress()) {
4919 /* the situation is under control */
4923 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4925 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4927 _routes->route_removed (tv);
4929 if (tv == entered_track) {
4933 TimeAxisView::Children c = tv->get_child_list ();
4934 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4935 if (entered_track == i->get()) {
4940 /* remove it from the list of track views */
4942 TrackViewList::iterator i;
4944 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4945 i = track_views.erase (i);
4948 /* update whatever the current mixer strip is displaying, if revelant */
4950 boost::shared_ptr<Route> route;
4953 route = rtav->route ();
4956 if (current_mixer_strip && current_mixer_strip->route() == route) {
4958 TimeAxisView* next_tv;
4960 if (track_views.empty()) {
4962 } else if (i == track_views.end()) {
4963 next_tv = track_views.front();
4970 set_selected_mixer_strip (*next_tv);
4972 /* make the editor mixer strip go away setting the
4973 * button to inactive (which also unticks the menu option)
4976 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4982 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4984 if (apply_to_selection) {
4985 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4987 TrackSelection::iterator j = i;
4990 hide_track_in_display (*i, false);
4995 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4997 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4998 // this will hide the mixer strip
4999 set_selected_mixer_strip (*tv);
5002 _routes->hide_track_in_display (*tv);
5007 Editor::sync_track_view_list_and_routes ()
5009 track_views = TrackViewList (_routes->views ());
5011 _summary->set_dirty ();
5012 _group_tabs->set_dirty ();
5014 return false; // do not call again (until needed)
5018 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5020 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5025 /** Find a RouteTimeAxisView by the ID of its route */
5027 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5029 RouteTimeAxisView* v;
5031 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5032 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5033 if(v->route()->id() == id) {
5043 Editor::fit_route_group (RouteGroup *g)
5045 TrackViewList ts = axis_views_from_routes (g->route_list ());
5050 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5052 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5055 _session->cancel_audition ();
5059 if (_session->is_auditioning()) {
5060 _session->cancel_audition ();
5061 if (r == last_audition_region) {
5066 _session->audition_region (r);
5067 last_audition_region = r;
5072 Editor::hide_a_region (boost::shared_ptr<Region> r)
5074 r->set_hidden (true);
5078 Editor::show_a_region (boost::shared_ptr<Region> r)
5080 r->set_hidden (false);
5084 Editor::audition_region_from_region_list ()
5086 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5090 Editor::hide_region_from_region_list ()
5092 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5096 Editor::show_region_in_region_list ()
5098 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5102 Editor::step_edit_status_change (bool yn)
5105 start_step_editing ();
5107 stop_step_editing ();
5112 Editor::start_step_editing ()
5114 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5118 Editor::stop_step_editing ()
5120 step_edit_connection.disconnect ();
5124 Editor::check_step_edit ()
5126 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5127 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5129 mtv->check_step_edit ();
5133 return true; // do it again, till we stop
5137 Editor::scroll_press (Direction dir)
5139 ++_scroll_callbacks;
5141 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5142 /* delay the first auto-repeat */
5148 scroll_backward (1);
5156 scroll_tracks_up_line ();
5160 scroll_tracks_down_line ();
5164 /* do hacky auto-repeat */
5165 if (!_scroll_connection.connected ()) {
5167 _scroll_connection = Glib::signal_timeout().connect (
5168 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5171 _scroll_callbacks = 0;
5178 Editor::scroll_release ()
5180 _scroll_connection.disconnect ();
5183 /** Queue a change for the Editor viewport x origin to follow the playhead */
5185 Editor::reset_x_origin_to_follow_playhead ()
5187 framepos_t const frame = playhead_cursor->current_frame ();
5189 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5191 if (_session->transport_speed() < 0) {
5193 if (frame > (current_page_frames() / 2)) {
5194 center_screen (frame-(current_page_frames()/2));
5196 center_screen (current_page_frames()/2);
5203 if (frame < leftmost_frame) {
5205 if (_session->transport_rolling()) {
5206 /* rolling; end up with the playhead at the right of the page */
5207 l = frame - current_page_frames ();
5209 /* not rolling: end up with the playhead 1/4 of the way along the page */
5210 l = frame - current_page_frames() / 4;
5214 if (_session->transport_rolling()) {
5215 /* rolling: end up with the playhead on the left of the page */
5218 /* not rolling: end up with the playhead 3/4 of the way along the page */
5219 l = frame - 3 * current_page_frames() / 4;
5227 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5233 Editor::super_rapid_screen_update ()
5235 if (!_session || !_session->engine().running()) {
5239 /* METERING / MIXER STRIPS */
5241 /* update track meters, if required */
5242 if (is_mapped() && meters_running) {
5243 RouteTimeAxisView* rtv;
5244 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5245 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5246 rtv->fast_update ();
5251 /* and any current mixer strip */
5252 if (current_mixer_strip) {
5253 current_mixer_strip->fast_update ();
5256 /* PLAYHEAD AND VIEWPORT */
5258 framepos_t const frame = _session->audible_frame();
5260 /* There are a few reasons why we might not update the playhead / viewport stuff:
5262 * 1. we don't update things when there's a pending locate request, otherwise
5263 * when the editor requests a locate there is a chance that this method
5264 * will move the playhead before the locate request is processed, causing
5266 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5267 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5270 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5272 last_update_frame = frame;
5274 if (!_dragging_playhead) {
5275 playhead_cursor->set_position (frame);
5278 if (!_stationary_playhead) {
5280 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5281 /* We only do this if we aren't already
5282 handling a visual change (ie if
5283 pending_visual_change.being_handled is
5284 false) so that these requests don't stack
5285 up there are too many of them to handle in
5288 reset_x_origin_to_follow_playhead ();
5293 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5297 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5298 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_pixel;
5299 if (target <= 0.0) {
5302 if (fabs(target - current) < current_page_frames() / frames_per_pixel) {
5303 target = (target * 0.15) + (current * 0.85);
5309 set_horizontal_position (current);
5318 Editor::session_going_away ()
5320 _have_idled = false;
5322 _session_connections.drop_connections ();
5324 super_rapid_screen_update_connection.disconnect ();
5326 selection->clear ();
5327 cut_buffer->clear ();
5329 clicked_regionview = 0;
5330 clicked_axisview = 0;
5331 clicked_routeview = 0;
5332 entered_regionview = 0;
5334 last_update_frame = 0;
5337 playhead_cursor->hide ();
5339 /* rip everything out of the list displays */
5343 _route_groups->clear ();
5345 /* do this first so that deleting a track doesn't reset cms to null
5346 and thus cause a leak.
5349 if (current_mixer_strip) {
5350 if (current_mixer_strip->get_parent() != 0) {
5351 global_hpacker.remove (*current_mixer_strip);
5353 delete current_mixer_strip;
5354 current_mixer_strip = 0;
5357 /* delete all trackviews */
5359 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5362 track_views.clear ();
5364 zoom_range_clock->set_session (0);
5365 nudge_clock->set_session (0);
5367 editor_list_button.set_active(false);
5368 editor_list_button.set_sensitive(false);
5370 /* clear tempo/meter rulers */
5371 remove_metric_marks ();
5373 clear_marker_display ();
5375 stop_step_editing ();
5377 /* get rid of any existing editor mixer strip */
5379 WindowTitle title(Glib::get_application_name());
5380 title += _("Editor");
5382 set_title (title.get_string());
5384 SessionHandlePtr::session_going_away ();
5389 Editor::show_editor_list (bool yn)
5392 _the_notebook.show ();
5394 _the_notebook.hide ();
5399 Editor::change_region_layering_order (bool from_context_menu)
5401 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5403 if (!clicked_routeview) {
5404 if (layering_order_editor) {
5405 layering_order_editor->hide ();
5410 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5416 boost::shared_ptr<Playlist> pl = track->playlist();
5422 if (layering_order_editor == 0) {
5423 layering_order_editor = new RegionLayeringOrderEditor (*this);
5424 layering_order_editor->set_position (WIN_POS_MOUSE);
5427 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5428 layering_order_editor->maybe_present ();
5432 Editor::update_region_layering_order_editor ()
5434 if (layering_order_editor && layering_order_editor->is_visible ()) {
5435 change_region_layering_order (true);
5440 Editor::setup_fade_images ()
5442 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5443 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5444 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5445 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5446 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5448 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5449 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5450 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5451 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5452 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5454 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5455 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5456 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5457 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5458 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5460 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5461 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5462 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5463 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5464 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5468 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5470 Editor::action_menu_item (std::string const & name)
5472 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5475 return *manage (a->create_menu_item ());
5479 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5481 EventBox* b = manage (new EventBox);
5482 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5483 Label* l = manage (new Label (name));
5487 _the_notebook.append_page (widget, *b);
5491 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5493 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5494 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5497 if (ev->type == GDK_2BUTTON_PRESS) {
5499 /* double-click on a notebook tab shrinks or expands the notebook */
5501 if (_notebook_shrunk) {
5502 if (pre_notebook_shrink_pane_width) {
5503 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5505 _notebook_shrunk = false;
5507 pre_notebook_shrink_pane_width = edit_pane.get_position();
5509 /* this expands the LHS of the edit pane to cover the notebook
5510 PAGE but leaves the tabs visible.
5512 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5513 _notebook_shrunk = true;
5521 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5523 using namespace Menu_Helpers;
5525 MenuList& items = _control_point_context_menu.items ();
5528 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5529 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5530 if (!can_remove_control_point (item)) {
5531 items.back().set_sensitive (false);
5534 _control_point_context_menu.popup (event->button.button, event->button.time);
5538 Editor::shift_key_released ()
5540 _stepping_axis_view = 0;
5545 Editor::save_canvas_state ()
5547 XMLTree* tree = static_cast<ArdourCanvas::Canvas*>(_track_canvas)->get_state ();
5548 string path = string_compose ("%1/canvas-state.xml", _session->path());