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 <glibmm/uriutils.h>
51 #include <gtkmm/image.h>
52 #include <gdkmm/color.h>
53 #include <gdkmm/bitmap.h>
55 #include "gtkmm2ext/bindings.h"
56 #include "gtkmm2ext/grouped_buttons.h"
57 #include "gtkmm2ext/gtk_ui.h"
58 #include "gtkmm2ext/tearoff.h"
59 #include "gtkmm2ext/utils.h"
60 #include "gtkmm2ext/window_title.h"
61 #include "gtkmm2ext/choice.h"
62 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
64 #include "ardour/audio_track.h"
65 #include "ardour/audioengine.h"
66 #include "ardour/audioregion.h"
67 #include "ardour/location.h"
68 #include "ardour/profile.h"
69 #include "ardour/route_group.h"
70 #include "ardour/session_playlists.h"
71 #include "ardour/tempo.h"
72 #include "ardour/utils.h"
74 #include "canvas/debug.h"
75 #include "canvas/text.h"
77 #include "control_protocol/control_protocol.h"
81 #include "analysis_window.h"
82 #include "audio_clock.h"
83 #include "audio_region_view.h"
84 #include "audio_streamview.h"
85 #include "audio_time_axis.h"
86 #include "automation_time_axis.h"
87 #include "bundle_manager.h"
88 #include "crossfade_edit.h"
92 #include "editor_cursors.h"
93 #include "editor_drag.h"
94 #include "editor_group_tabs.h"
95 #include "editor_locations.h"
96 #include "editor_regions.h"
97 #include "editor_route_groups.h"
98 #include "editor_routes.h"
99 #include "editor_snapshots.h"
100 #include "editor_summary.h"
101 #include "global_port_matrix.h"
102 #include "gui_object.h"
103 #include "gui_thread.h"
104 #include "keyboard.h"
106 #include "midi_time_axis.h"
107 #include "mixer_strip.h"
108 #include "mixer_ui.h"
109 #include "mouse_cursors.h"
110 #include "playlist_selector.h"
111 #include "public_editor.h"
112 #include "region_layering_order_editor.h"
113 #include "rgb_macros.h"
114 #include "rhythm_ferret.h"
115 #include "selection.h"
117 #include "tempo_lines.h"
118 #include "time_axis_view.h"
124 using namespace ARDOUR;
127 using namespace Glib;
128 using namespace Gtkmm2ext;
129 using namespace Editing;
131 using PBD::internationalize;
133 using Gtkmm2ext::Keyboard;
135 const double Editor::timebar_height = 15.0;
137 static const gchar *_snap_type_strings[] = {
139 N_("Timecode Frames"),
140 N_("Timecode Seconds"),
141 N_("Timecode Minutes"),
171 static const gchar *_snap_mode_strings[] = {
178 static const gchar *_edit_point_strings[] = {
185 static const gchar *_zoom_focus_strings[] = {
195 #ifdef USE_RUBBERBAND
196 static const gchar *_rb_opt_strings[] = {
199 N_("Balanced multitimbral mixture"),
200 N_("Unpitched percussion with stable notes"),
201 N_("Crisp monophonic instrumental"),
202 N_("Unpitched solo percussion"),
203 N_("Resample without preserving pitch"),
209 pane_size_watcher (Paned* pane)
211 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
215 Quartz: impossible to access
217 so stop that by preventing it from ever getting too narrow. 35
218 pixels is basically a rough guess at the tab width.
223 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
225 gint pos = pane->get_position ();
227 if (pos > max_width_of_lhs) {
228 pane->set_position (max_width_of_lhs);
233 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
235 /* time display buttons */
236 , minsec_label (_("Mins:Secs"))
237 , bbt_label (_("Bars:Beats"))
238 , timecode_label (_("Timecode"))
239 , samples_label (_("Samples"))
240 , tempo_label (_("Tempo"))
241 , meter_label (_("Meter"))
242 , mark_label (_("Location Markers"))
243 , range_mark_label (_("Range Markers"))
244 , transport_mark_label (_("Loop/Punch Ranges"))
245 , cd_mark_label (_("CD Markers"))
246 , videotl_label (_("Video Timeline"))
247 , edit_packer (4, 4, true)
249 /* the values here don't matter: layout widgets
250 reset them as needed.
253 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
254 , horizontal_adjustment (0.0, 0.0, 1e16)
255 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
257 , controls_layout (unused_adjustment, vertical_adjustment)
259 /* tool bar related */
261 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
263 , toolbar_selection_clock_table (2,3)
265 , automation_mode_button (_("mode"))
267 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
271 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
272 , meters_running(false)
273 , _pending_locate_request (false)
274 , _pending_initial_locate (false)
275 , _last_cut_copy_source_track (0)
277 , _region_selection_change_updates_region_list (true)
278 , _following_mixer_selection (false)
279 , _control_point_toggled_on_press (false)
280 , _stepping_axis_view (0)
284 /* we are a singleton */
286 PublicEditor::_instance = this;
290 selection = new Selection (this);
291 cut_buffer = new Selection (this);
293 clicked_regionview = 0;
294 clicked_axisview = 0;
295 clicked_routeview = 0;
296 clicked_control_point = 0;
297 last_update_frame = 0;
298 pre_press_cursor = 0;
299 _drags = new DragManager (this);
300 current_mixer_strip = 0;
303 snap_type_strings = I18N (_snap_type_strings);
304 snap_mode_strings = I18N (_snap_mode_strings);
305 zoom_focus_strings = I18N (_zoom_focus_strings);
306 edit_point_strings = I18N (_edit_point_strings);
307 #ifdef USE_RUBBERBAND
308 rb_opt_strings = I18N (_rb_opt_strings);
312 snap_threshold = 5.0;
313 bbt_beat_subdivision = 4;
314 _visible_canvas_width = 0;
315 _visible_canvas_height = 0;
316 last_autoscroll_x = 0;
317 last_autoscroll_y = 0;
318 autoscroll_active = false;
319 autoscroll_timeout_tag = -1;
324 current_interthread_info = 0;
325 _show_measures = true;
327 show_gain_after_trim = false;
329 have_pending_keyboard_selection = false;
330 _follow_playhead = true;
331 _stationary_playhead = false;
332 editor_ruler_menu = 0;
333 no_ruler_shown_update = false;
335 range_marker_menu = 0;
336 marker_menu_item = 0;
337 tempo_or_meter_marker_menu = 0;
338 transport_marker_menu = 0;
339 new_transport_marker_menu = 0;
340 editor_mixer_strip_width = Wide;
341 show_editor_mixer_when_tracks_arrive = false;
342 region_edit_menu_split_multichannel_item = 0;
343 region_edit_menu_split_item = 0;
346 current_stepping_trackview = 0;
348 entered_regionview = 0;
350 clear_entered_track = false;
353 button_release_can_deselect = true;
354 _dragging_playhead = false;
355 _dragging_edit_point = false;
356 select_new_marker = false;
358 layering_order_editor = 0;
359 no_save_visual = false;
361 within_track_canvas = false;
363 scrubbing_direction = 0;
367 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
368 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
369 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
370 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
371 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
373 zoom_focus = ZoomFocusLeft;
374 _edit_point = EditAtMouse;
375 _internal_editing = false;
376 current_canvas_cursor = 0;
378 samples_per_pixel = 2048; /* too early to use reset_zoom () */
380 _scroll_callbacks = 0;
382 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
384 bbt_label.set_name ("EditorRulerLabel");
385 bbt_label.set_size_request (-1, (int)timebar_height);
386 bbt_label.set_alignment (1.0, 0.5);
387 bbt_label.set_padding (5,0);
389 bbt_label.set_no_show_all();
390 minsec_label.set_name ("EditorRulerLabel");
391 minsec_label.set_size_request (-1, (int)timebar_height);
392 minsec_label.set_alignment (1.0, 0.5);
393 minsec_label.set_padding (5,0);
394 minsec_label.hide ();
395 minsec_label.set_no_show_all();
396 timecode_label.set_name ("EditorRulerLabel");
397 timecode_label.set_size_request (-1, (int)timebar_height);
398 timecode_label.set_alignment (1.0, 0.5);
399 timecode_label.set_padding (5,0);
400 timecode_label.hide ();
401 timecode_label.set_no_show_all();
402 samples_label.set_name ("EditorRulerLabel");
403 samples_label.set_size_request (-1, (int)timebar_height);
404 samples_label.set_alignment (1.0, 0.5);
405 samples_label.set_padding (5,0);
406 samples_label.hide ();
407 samples_label.set_no_show_all();
409 tempo_label.set_name ("EditorRulerLabel");
410 tempo_label.set_size_request (-1, (int)timebar_height);
411 tempo_label.set_alignment (1.0, 0.5);
412 tempo_label.set_padding (5,0);
414 tempo_label.set_no_show_all();
416 meter_label.set_name ("EditorRulerLabel");
417 meter_label.set_size_request (-1, (int)timebar_height);
418 meter_label.set_alignment (1.0, 0.5);
419 meter_label.set_padding (5,0);
421 meter_label.set_no_show_all();
423 mark_label.set_name ("EditorRulerLabel");
424 mark_label.set_size_request (-1, (int)timebar_height);
425 mark_label.set_alignment (1.0, 0.5);
426 mark_label.set_padding (5,0);
428 mark_label.set_no_show_all();
430 cd_mark_label.set_name ("EditorRulerLabel");
431 cd_mark_label.set_size_request (-1, (int)timebar_height);
432 cd_mark_label.set_alignment (1.0, 0.5);
433 cd_mark_label.set_padding (5,0);
434 cd_mark_label.hide();
435 cd_mark_label.set_no_show_all();
437 videotl_bar_height = 4;
438 videotl_label.set_name ("EditorRulerLabel");
439 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
440 videotl_label.set_alignment (1.0, 0.5);
441 videotl_label.set_padding (5,0);
442 videotl_label.hide();
443 videotl_label.set_no_show_all();
445 range_mark_label.set_name ("EditorRulerLabel");
446 range_mark_label.set_size_request (-1, (int)timebar_height);
447 range_mark_label.set_alignment (1.0, 0.5);
448 range_mark_label.set_padding (5,0);
449 range_mark_label.hide();
450 range_mark_label.set_no_show_all();
452 transport_mark_label.set_name ("EditorRulerLabel");
453 transport_mark_label.set_size_request (-1, (int)timebar_height);
454 transport_mark_label.set_alignment (1.0, 0.5);
455 transport_mark_label.set_padding (5,0);
456 transport_mark_label.hide();
457 transport_mark_label.set_no_show_all();
459 initialize_rulers ();
460 initialize_canvas ();
462 _summary = new EditorSummary (this);
464 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
465 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
467 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
469 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
470 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
472 edit_controls_vbox.set_spacing (0);
473 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
474 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
476 HBox* h = manage (new HBox);
477 _group_tabs = new EditorGroupTabs (this);
478 h->pack_start (*_group_tabs, PACK_SHRINK);
479 h->pack_start (edit_controls_vbox);
480 controls_layout.add (*h);
482 controls_layout.set_name ("EditControlsBase");
483 controls_layout.add_events (Gdk::SCROLL_MASK);
484 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
486 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
487 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
489 _cursors = new MouseCursors;
491 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
493 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
494 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
495 pad_line_1->set_outline_color (0xFF0000FF);
501 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
502 time_canvas_vbox.set_size_request (-1, -1);
504 ruler_label_event_box.add (ruler_label_vbox);
505 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
506 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
508 time_bars_event_box.add (time_bars_vbox);
509 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
510 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512 time_canvas_event_box.add (time_canvas_vbox);
513 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
515 edit_packer.set_col_spacings (0);
516 edit_packer.set_row_spacings (0);
517 edit_packer.set_homogeneous (false);
518 edit_packer.set_border_width (0);
519 edit_packer.set_name ("EditorWindow");
521 /* labels for the rulers */
522 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
523 /* labels for the marker "tracks" (time bars) */
524 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
526 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
528 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
529 /* time bars canvas */
530 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
532 edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
534 bottom_hbox.set_border_width (2);
535 bottom_hbox.set_spacing (3);
537 _route_groups = new EditorRouteGroups (this);
538 _routes = new EditorRoutes (this);
539 _regions = new EditorRegions (this);
540 _snapshots = new EditorSnapshots (this);
541 _locations = new EditorLocations (this);
543 add_notebook_page (_("Regions"), _regions->widget ());
544 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
545 add_notebook_page (_("Snapshots"), _snapshots->widget ());
546 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
547 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
549 _the_notebook.set_show_tabs (true);
550 _the_notebook.set_scrollable (true);
551 _the_notebook.popup_disable ();
552 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
553 _the_notebook.show_all ();
555 _notebook_shrunk = false;
557 editor_summary_pane.pack1(edit_packer);
559 Button* summary_arrows_left_left = manage (new Button);
560 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
561 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
562 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
564 Button* summary_arrows_left_right = manage (new Button);
565 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
566 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
567 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
569 VBox* summary_arrows_left = manage (new VBox);
570 summary_arrows_left->pack_start (*summary_arrows_left_left);
571 summary_arrows_left->pack_start (*summary_arrows_left_right);
573 Button* summary_arrows_right_up = manage (new Button);
574 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
575 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
576 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 Button* summary_arrows_right_down = manage (new Button);
579 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
580 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
581 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 VBox* summary_arrows_right = manage (new VBox);
584 summary_arrows_right->pack_start (*summary_arrows_right_up);
585 summary_arrows_right->pack_start (*summary_arrows_right_down);
587 Frame* summary_frame = manage (new Frame);
588 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
590 summary_frame->add (*_summary);
591 summary_frame->show ();
593 _summary_hbox.pack_start (*summary_arrows_left, false, false);
594 _summary_hbox.pack_start (*summary_frame, true, true);
595 _summary_hbox.pack_start (*summary_arrows_right, false, false);
597 editor_summary_pane.pack2 (_summary_hbox);
599 edit_pane.pack1 (editor_summary_pane, true, true);
600 edit_pane.pack2 (_the_notebook, false, true);
602 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
604 /* XXX: editor_summary_pane might need similar to the edit_pane */
606 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
608 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
609 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
611 top_hbox.pack_start (toolbar_frame);
613 HBox *hbox = manage (new HBox);
614 hbox->pack_start (edit_pane, true, true);
616 global_vpacker.pack_start (top_hbox, false, false);
617 global_vpacker.pack_start (*hbox, true, true);
619 global_hpacker.pack_start (global_vpacker, true, true);
621 set_name ("EditorWindow");
622 add_accel_group (ActionManager::ui_manager->get_accel_group());
624 status_bar_hpacker.show ();
626 vpacker.pack_end (status_bar_hpacker, false, false);
627 vpacker.pack_end (global_hpacker, true, true);
629 /* register actions now so that set_state() can find them and set toggles/checks etc */
632 /* when we start using our own keybinding system for the editor, this
633 * will be uncommented
639 set_zoom_focus (zoom_focus);
640 _snap_type = SnapToBeat;
641 set_snap_to (_snap_type);
642 _snap_mode = SnapOff;
643 set_snap_mode (_snap_mode);
644 set_mouse_mode (MouseObject, true);
645 pre_internal_mouse_mode = MouseObject;
646 pre_internal_snap_type = _snap_type;
647 pre_internal_snap_mode = _snap_mode;
648 internal_snap_type = _snap_type;
649 internal_snap_mode = _snap_mode;
650 set_edit_point_preference (EditAtMouse, true);
652 _playlist_selector = new PlaylistSelector();
653 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
655 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
659 nudge_forward_button.set_name ("zoom button");
660 nudge_forward_button.add_elements (ArdourButton::FlatFace);
661 nudge_forward_button.set_image(::get_icon("nudge_right"));
663 nudge_backward_button.set_name ("zoom button");
664 nudge_backward_button.add_elements (ArdourButton::FlatFace);
665 nudge_backward_button.set_image(::get_icon("nudge_left"));
667 fade_context_menu.set_name ("ArdourContextMenu");
669 /* icons, titles, WM stuff */
671 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
672 Glib::RefPtr<Gdk::Pixbuf> icon;
674 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
675 window_icons.push_back (icon);
677 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
678 window_icons.push_back (icon);
680 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
681 window_icons.push_back (icon);
683 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
684 window_icons.push_back (icon);
686 if (!window_icons.empty()) {
687 // set_icon_list (window_icons);
688 set_default_icon_list (window_icons);
691 WindowTitle title(Glib::get_application_name());
692 title += _("Editor");
693 set_title (title.get_string());
694 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
697 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
699 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
700 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
702 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
704 /* allow external control surfaces/protocols to do various things */
706 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
707 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
708 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
709 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
710 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
711 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
712 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
713 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
714 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
715 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
716 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
717 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
718 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
719 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
721 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
722 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
723 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
724 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
725 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
727 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
729 /* problematic: has to return a value and thus cannot be x-thread */
731 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
733 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
735 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
737 _ignore_region_action = false;
738 _last_region_menu_was_main = false;
739 _popup_region_menu_item = 0;
741 _show_marker_lines = false;
742 _over_region_trim_target = false;
744 /* Button bindings */
746 button_bindings = new Bindings;
748 XMLNode* node = button_settings();
750 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
751 button_bindings->load (**i);
758 setup_fade_images ();
763 delete button_bindings;
765 delete _route_groups;
766 delete _time_bars_canvas_viewport;
767 delete _track_canvas_viewport;
772 Editor::button_settings () const
774 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
775 XMLNode* node = find_named_node (*settings, X_("Buttons"));
778 node = new XMLNode (X_("Buttons"));
785 Editor::add_toplevel_controls (Container& cont)
787 vpacker.pack_start (cont, false, false);
792 Editor::get_smart_mode () const
794 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
798 Editor::catch_vanishing_regionview (RegionView *rv)
800 /* note: the selection will take care of the vanishing
801 audioregionview by itself.
804 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
808 if (clicked_regionview == rv) {
809 clicked_regionview = 0;
812 if (entered_regionview == rv) {
813 set_entered_regionview (0);
816 if (!_all_region_actions_sensitized) {
817 sensitize_all_region_actions (true);
820 _over_region_trim_target = false;
824 Editor::set_entered_regionview (RegionView* rv)
826 if (rv == entered_regionview) {
830 if (entered_regionview) {
831 entered_regionview->exited ();
834 if ((entered_regionview = rv) != 0) {
835 entered_regionview->entered (internal_editing ());
838 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
839 /* This RegionView entry might have changed what region actions
840 are allowed, so sensitize them all in case a key is pressed.
842 sensitize_all_region_actions (true);
847 Editor::set_entered_track (TimeAxisView* tav)
850 entered_track->exited ();
853 if ((entered_track = tav) != 0) {
854 entered_track->entered ();
859 Editor::show_window ()
861 if (!is_visible ()) {
864 /* XXX: this is a bit unfortunate; it would probably
865 be nicer if we could just call show () above rather
866 than needing the show_all ()
869 /* re-hide stuff if necessary */
870 editor_list_button_toggled ();
871 parameter_changed ("show-summary");
872 parameter_changed ("show-group-tabs");
873 parameter_changed ("show-zoom-tools");
875 /* now reset all audio_time_axis heights, because widgets might need
881 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
882 tv = (static_cast<TimeAxisView*>(*i));
886 if (current_mixer_strip) {
887 current_mixer_strip->hide_things ();
888 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
896 Editor::instant_save ()
898 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
903 _session->add_instant_xml(get_state());
905 Config->add_instant_xml(get_state());
910 Editor::zoom_adjustment_changed ()
916 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
917 bool clamped = clamp_samples_per_pixel (fpu);
920 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
927 Editor::control_vertical_zoom_in_all ()
929 tav_zoom_smooth (false, true);
933 Editor::control_vertical_zoom_out_all ()
935 tav_zoom_smooth (true, true);
939 Editor::control_vertical_zoom_in_selected ()
941 tav_zoom_smooth (false, false);
945 Editor::control_vertical_zoom_out_selected ()
947 tav_zoom_smooth (true, false);
951 Editor::control_view (uint32_t view)
953 goto_visual_state (view);
957 Editor::control_unselect ()
959 selection->clear_tracks ();
963 Editor::control_select (uint32_t rid, Selection::Operation op)
965 /* handles the (static) signal from the ControlProtocol class that
966 * requests setting the selected track to a given RID
973 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
979 TimeAxisView* tav = axis_view_from_route (r);
984 selection->add (tav);
986 case Selection::Toggle:
987 selection->toggle (tav);
989 case Selection::Extend:
992 selection->set (tav);
996 selection->clear_tracks ();
1001 Editor::control_step_tracks_up ()
1003 scroll_tracks_up_line ();
1007 Editor::control_step_tracks_down ()
1009 scroll_tracks_down_line ();
1013 Editor::control_scroll (float fraction)
1015 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1021 double step = fraction * current_page_samples();
1024 _control_scroll_target is an optional<T>
1026 it acts like a pointer to an framepos_t, with
1027 a operator conversion to boolean to check
1028 that it has a value could possibly use
1029 playhead_cursor->current_frame to store the
1030 value and a boolean in the class to know
1031 when it's out of date
1034 if (!_control_scroll_target) {
1035 _control_scroll_target = _session->transport_frame();
1036 _dragging_playhead = true;
1039 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1040 *_control_scroll_target = 0;
1041 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1042 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1044 *_control_scroll_target += (framepos_t) floor (step);
1047 /* move visuals, we'll catch up with it later */
1049 playhead_cursor->set_position (*_control_scroll_target);
1050 UpdateAllTransportClocks (*_control_scroll_target);
1052 if (*_control_scroll_target > (current_page_samples() / 2)) {
1053 /* try to center PH in window */
1054 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1060 Now we do a timeout to actually bring the session to the right place
1061 according to the playhead. This is to avoid reading disk buffers on every
1062 call to control_scroll, which is driven by ScrollTimeline and therefore
1063 probably by a control surface wheel which can generate lots of events.
1065 /* cancel the existing timeout */
1067 control_scroll_connection.disconnect ();
1069 /* add the next timeout */
1071 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1075 Editor::deferred_control_scroll (framepos_t /*target*/)
1077 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1078 // reset for next stream
1079 _control_scroll_target = boost::none;
1080 _dragging_playhead = false;
1085 Editor::access_action (std::string action_group, std::string action_item)
1091 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1094 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1102 Editor::on_realize ()
1104 Window::on_realize ();
1109 Editor::map_position_change (framepos_t frame)
1111 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1113 if (_session == 0) {
1117 if (_follow_playhead) {
1118 center_screen (frame);
1121 playhead_cursor->set_position (frame);
1125 Editor::center_screen (framepos_t frame)
1127 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1129 /* if we're off the page, then scroll.
1132 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1133 center_screen_internal (frame, page);
1138 Editor::center_screen_internal (framepos_t frame, float page)
1143 frame -= (framepos_t) page;
1148 reset_x_origin (frame);
1153 Editor::update_title ()
1155 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1158 bool dirty = _session->dirty();
1160 string session_name;
1162 if (_session->snap_name() != _session->name()) {
1163 session_name = _session->snap_name();
1165 session_name = _session->name();
1169 session_name = "*" + session_name;
1172 WindowTitle title(session_name);
1173 title += Glib::get_application_name();
1174 set_title (title.get_string());
1176 /* ::session_going_away() will have taken care of it */
1181 Editor::set_session (Session *t)
1183 SessionHandlePtr::set_session (t);
1189 zoom_range_clock->set_session (_session);
1190 _playlist_selector->set_session (_session);
1191 nudge_clock->set_session (_session);
1192 _summary->set_session (_session);
1193 _group_tabs->set_session (_session);
1194 _route_groups->set_session (_session);
1195 _regions->set_session (_session);
1196 _snapshots->set_session (_session);
1197 _routes->set_session (_session);
1198 _locations->set_session (_session);
1200 if (rhythm_ferret) {
1201 rhythm_ferret->set_session (_session);
1204 if (analysis_window) {
1205 analysis_window->set_session (_session);
1209 sfbrowser->set_session (_session);
1212 compute_fixed_ruler_scale ();
1214 /* Make sure we have auto loop and auto punch ranges */
1216 Location* loc = _session->locations()->auto_loop_location();
1218 loc->set_name (_("Loop"));
1221 loc = _session->locations()->auto_punch_location();
1224 loc->set_name (_("Punch"));
1227 refresh_location_display ();
1229 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1230 the selected Marker; this needs the LocationMarker list to be available.
1232 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1233 set_state (*node, Stateful::loading_state_version);
1235 /* catch up with the playhead */
1237 _session->request_locate (playhead_cursor->current_frame ());
1238 _pending_initial_locate = true;
1242 /* These signals can all be emitted by a non-GUI thread. Therefore the
1243 handlers for them must not attempt to directly interact with the GUI,
1244 but use PBD::Signal<T>::connect() which accepts an event loop
1245 ("context") where the handler will be asked to run.
1248 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1249 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1250 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1251 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1252 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1253 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1254 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1255 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1256 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1257 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1258 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1259 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1260 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1261 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1263 playhead_cursor->show ();
1265 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1266 Config->map_parameters (pc);
1267 _session->config.map_parameters (pc);
1269 restore_ruler_visibility ();
1270 //tempo_map_changed (PropertyChange (0));
1271 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1273 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1274 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1277 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1278 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1281 switch (_snap_type) {
1282 case SnapToRegionStart:
1283 case SnapToRegionEnd:
1284 case SnapToRegionSync:
1285 case SnapToRegionBoundary:
1286 build_region_boundary_cache ();
1293 /* register for undo history */
1294 _session->register_with_memento_command_factory(id(), this);
1296 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1298 start_updating_meters ();
1302 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1304 if (a->get_name() == "RegionMenu") {
1305 /* When the main menu's region menu is opened, we setup the actions so that they look right
1306 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1307 so we resensitize all region actions when the entered regionview or the region selection
1308 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1309 happens after the region context menu is opened. So we set a flag here, too.
1313 sensitize_the_right_region_actions ();
1314 _last_region_menu_was_main = true;
1319 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1321 using namespace Menu_Helpers;
1323 void (Editor::*emf)(FadeShape);
1324 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1327 images = &_xfade_in_images;
1328 emf = &Editor::set_fade_in_shape;
1330 images = &_xfade_out_images;
1331 emf = &Editor::set_fade_out_shape;
1336 _("Linear (for highly correlated material)"),
1337 *(*images)[FadeLinear],
1338 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1342 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1346 _("Constant power"),
1347 *(*images)[FadeConstantPower],
1348 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1351 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1356 *(*images)[FadeSymmetric],
1357 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1361 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1366 *(*images)[FadeSlow],
1367 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1370 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1375 *(*images)[FadeFast],
1376 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1379 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1382 /** Pop up a context menu for when the user clicks on a start crossfade */
1384 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1386 using namespace Menu_Helpers;
1388 MenuList& items (xfade_in_context_menu.items());
1390 if (items.empty()) {
1391 fill_xfade_menu (items, true);
1394 xfade_in_context_menu.popup (button, time);
1397 /** Pop up a context menu for when the user clicks on an end crossfade */
1399 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1401 using namespace Menu_Helpers;
1403 MenuList& items (xfade_out_context_menu.items());
1405 if (items.empty()) {
1406 fill_xfade_menu (items, false);
1409 xfade_out_context_menu.popup (button, time);
1413 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1415 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1417 using namespace Menu_Helpers;
1418 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1421 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1425 MenuList& items (fade_context_menu.items());
1428 switch (item_type) {
1430 case FadeInHandleItem:
1431 if (arv->audio_region()->fade_in_active()) {
1432 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1434 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1437 items.push_back (SeparatorElem());
1439 if (Profile->get_sae()) {
1441 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1442 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1449 *_fade_in_images[FadeLinear],
1450 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1454 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 *_fade_in_images[FadeSlow],
1460 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1463 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1468 *_fade_in_images[FadeFast],
1469 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1472 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 *_fade_in_images[FadeSymmetric],
1478 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1483 _("Constant power"),
1484 *_fade_in_images[FadeConstantPower],
1485 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1488 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 case FadeOutHandleItem:
1495 if (arv->audio_region()->fade_out_active()) {
1496 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1498 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1501 items.push_back (SeparatorElem());
1503 if (Profile->get_sae()) {
1504 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1505 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1511 *_fade_out_images[FadeLinear],
1512 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1516 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1521 *_fade_out_images[FadeSlow],
1522 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1525 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1530 *_fade_out_images[FadeFast],
1531 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1534 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1539 *_fade_out_images[FadeSymmetric],
1540 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1545 _("Constant power"),
1546 *_fade_out_images[FadeConstantPower],
1547 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1550 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1556 fatal << _("programming error: ")
1557 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1562 fade_context_menu.popup (button, time);
1566 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1568 using namespace Menu_Helpers;
1569 Menu* (Editor::*build_menu_function)();
1572 switch (item_type) {
1574 case RegionViewName:
1575 case RegionViewNameHighlight:
1576 case LeftFrameHandle:
1577 case RightFrameHandle:
1578 if (with_selection) {
1579 build_menu_function = &Editor::build_track_selection_context_menu;
1581 build_menu_function = &Editor::build_track_region_context_menu;
1586 if (with_selection) {
1587 build_menu_function = &Editor::build_track_selection_context_menu;
1589 build_menu_function = &Editor::build_track_context_menu;
1594 if (clicked_routeview->track()) {
1595 build_menu_function = &Editor::build_track_context_menu;
1597 build_menu_function = &Editor::build_track_bus_context_menu;
1602 /* probably shouldn't happen but if it does, we don't care */
1606 menu = (this->*build_menu_function)();
1607 menu->set_name ("ArdourContextMenu");
1609 /* now handle specific situations */
1611 switch (item_type) {
1613 case RegionViewName:
1614 case RegionViewNameHighlight:
1615 case LeftFrameHandle:
1616 case RightFrameHandle:
1617 if (!with_selection) {
1618 if (region_edit_menu_split_item) {
1619 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1620 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1622 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1625 if (region_edit_menu_split_multichannel_item) {
1626 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1627 region_edit_menu_split_multichannel_item->set_sensitive (true);
1629 region_edit_menu_split_multichannel_item->set_sensitive (false);
1642 /* probably shouldn't happen but if it does, we don't care */
1646 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1648 /* Bounce to disk */
1650 using namespace Menu_Helpers;
1651 MenuList& edit_items = menu->items();
1653 edit_items.push_back (SeparatorElem());
1655 switch (clicked_routeview->audio_track()->freeze_state()) {
1656 case AudioTrack::NoFreeze:
1657 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1660 case AudioTrack::Frozen:
1661 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1664 case AudioTrack::UnFrozen:
1665 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1671 if (item_type == StreamItem && clicked_routeview) {
1672 clicked_routeview->build_underlay_menu(menu);
1675 /* When the region menu is opened, we setup the actions so that they look right
1678 sensitize_the_right_region_actions ();
1679 _last_region_menu_was_main = false;
1681 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1682 menu->popup (button, time);
1686 Editor::build_track_context_menu ()
1688 using namespace Menu_Helpers;
1690 MenuList& edit_items = track_context_menu.items();
1693 add_dstream_context_items (edit_items);
1694 return &track_context_menu;
1698 Editor::build_track_bus_context_menu ()
1700 using namespace Menu_Helpers;
1702 MenuList& edit_items = track_context_menu.items();
1705 add_bus_context_items (edit_items);
1706 return &track_context_menu;
1710 Editor::build_track_region_context_menu ()
1712 using namespace Menu_Helpers;
1713 MenuList& edit_items = track_region_context_menu.items();
1716 /* we've just cleared the track region context menu, so the menu that these
1717 two items were on will have disappeared; stop them dangling.
1719 region_edit_menu_split_item = 0;
1720 region_edit_menu_split_multichannel_item = 0;
1722 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1725 boost::shared_ptr<Track> tr;
1726 boost::shared_ptr<Playlist> pl;
1728 if ((tr = rtv->track())) {
1729 add_region_context_items (edit_items, tr);
1733 add_dstream_context_items (edit_items);
1735 return &track_region_context_menu;
1739 Editor::analyze_region_selection ()
1741 if (analysis_window == 0) {
1742 analysis_window = new AnalysisWindow();
1745 analysis_window->set_session(_session);
1747 analysis_window->show_all();
1750 analysis_window->set_regionmode();
1751 analysis_window->analyze();
1753 analysis_window->present();
1757 Editor::analyze_range_selection()
1759 if (analysis_window == 0) {
1760 analysis_window = new AnalysisWindow();
1763 analysis_window->set_session(_session);
1765 analysis_window->show_all();
1768 analysis_window->set_rangemode();
1769 analysis_window->analyze();
1771 analysis_window->present();
1775 Editor::build_track_selection_context_menu ()
1777 using namespace Menu_Helpers;
1778 MenuList& edit_items = track_selection_context_menu.items();
1779 edit_items.clear ();
1781 add_selection_context_items (edit_items);
1782 // edit_items.push_back (SeparatorElem());
1783 // add_dstream_context_items (edit_items);
1785 return &track_selection_context_menu;
1789 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1791 using namespace Menu_Helpers;
1793 /* OK, stick the region submenu at the top of the list, and then add
1797 RegionSelection rs = get_regions_from_selection_and_entered ();
1799 string::size_type pos = 0;
1800 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1802 /* we have to hack up the region name because "_" has a special
1803 meaning for menu titles.
1806 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1807 menu_item_name.replace (pos, 1, "__");
1811 if (_popup_region_menu_item == 0) {
1812 _popup_region_menu_item = new MenuItem (menu_item_name);
1813 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1814 _popup_region_menu_item->show ();
1816 _popup_region_menu_item->set_label (menu_item_name);
1819 const framepos_t position = get_preferred_edit_position (false, true);
1821 edit_items.push_back (*_popup_region_menu_item);
1822 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1823 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1825 edit_items.push_back (SeparatorElem());
1828 /** Add context menu items relevant to selection ranges.
1829 * @param edit_items List to add the items to.
1832 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1834 using namespace Menu_Helpers;
1836 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1837 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1839 edit_items.push_back (SeparatorElem());
1840 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1842 edit_items.push_back (SeparatorElem());
1844 edit_items.push_back (
1846 _("Move Range Start to Previous Region Boundary"),
1847 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1851 edit_items.push_back (
1853 _("Move Range Start to Next Region Boundary"),
1854 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1858 edit_items.push_back (
1860 _("Move Range End to Previous Region Boundary"),
1861 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1865 edit_items.push_back (
1867 _("Move Range End to Next Region Boundary"),
1868 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1872 edit_items.push_back (SeparatorElem());
1873 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1874 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1876 edit_items.push_back (SeparatorElem());
1877 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1879 edit_items.push_back (SeparatorElem());
1880 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1881 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1883 edit_items.push_back (SeparatorElem());
1884 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1886 edit_items.push_back (SeparatorElem());
1887 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1888 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1889 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1891 edit_items.push_back (SeparatorElem());
1892 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1893 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1894 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1895 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1896 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1897 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1898 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1904 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1906 using namespace Menu_Helpers;
1910 Menu *play_menu = manage (new Menu);
1911 MenuList& play_items = play_menu->items();
1912 play_menu->set_name ("ArdourContextMenu");
1914 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1915 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1916 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1917 play_items.push_back (SeparatorElem());
1918 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1920 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1924 Menu *select_menu = manage (new Menu);
1925 MenuList& select_items = select_menu->items();
1926 select_menu->set_name ("ArdourContextMenu");
1928 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1929 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1930 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1931 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1932 select_items.push_back (SeparatorElem());
1933 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1934 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1935 select_items.push_back (SeparatorElem());
1936 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1937 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1938 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1939 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1940 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1941 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1942 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1944 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1948 Menu *cutnpaste_menu = manage (new Menu);
1949 MenuList& cutnpaste_items = cutnpaste_menu->items();
1950 cutnpaste_menu->set_name ("ArdourContextMenu");
1952 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1953 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1954 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1956 cutnpaste_items.push_back (SeparatorElem());
1958 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1959 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1961 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1963 /* Adding new material */
1965 edit_items.push_back (SeparatorElem());
1966 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1967 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1971 Menu *nudge_menu = manage (new Menu());
1972 MenuList& nudge_items = nudge_menu->items();
1973 nudge_menu->set_name ("ArdourContextMenu");
1975 edit_items.push_back (SeparatorElem());
1976 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1977 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1978 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1979 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1981 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1985 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1987 using namespace Menu_Helpers;
1991 Menu *play_menu = manage (new Menu);
1992 MenuList& play_items = play_menu->items();
1993 play_menu->set_name ("ArdourContextMenu");
1995 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1996 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1997 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2001 Menu *select_menu = manage (new Menu);
2002 MenuList& select_items = select_menu->items();
2003 select_menu->set_name ("ArdourContextMenu");
2005 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2006 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2007 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2008 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2009 select_items.push_back (SeparatorElem());
2010 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2011 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2012 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2013 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2015 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2019 Menu *cutnpaste_menu = manage (new Menu);
2020 MenuList& cutnpaste_items = cutnpaste_menu->items();
2021 cutnpaste_menu->set_name ("ArdourContextMenu");
2023 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2024 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2025 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2027 Menu *nudge_menu = manage (new Menu());
2028 MenuList& nudge_items = nudge_menu->items();
2029 nudge_menu->set_name ("ArdourContextMenu");
2031 edit_items.push_back (SeparatorElem());
2032 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2033 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2034 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2035 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2037 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2041 Editor::snap_type() const
2047 Editor::snap_mode() const
2053 Editor::set_snap_to (SnapType st)
2055 unsigned int snap_ind = (unsigned int)st;
2059 if (snap_ind > snap_type_strings.size() - 1) {
2061 _snap_type = (SnapType)snap_ind;
2064 string str = snap_type_strings[snap_ind];
2066 if (str != snap_type_selector.get_active_text()) {
2067 snap_type_selector.set_active_text (str);
2072 switch (_snap_type) {
2073 case SnapToBeatDiv128:
2074 case SnapToBeatDiv64:
2075 case SnapToBeatDiv32:
2076 case SnapToBeatDiv28:
2077 case SnapToBeatDiv24:
2078 case SnapToBeatDiv20:
2079 case SnapToBeatDiv16:
2080 case SnapToBeatDiv14:
2081 case SnapToBeatDiv12:
2082 case SnapToBeatDiv10:
2083 case SnapToBeatDiv8:
2084 case SnapToBeatDiv7:
2085 case SnapToBeatDiv6:
2086 case SnapToBeatDiv5:
2087 case SnapToBeatDiv4:
2088 case SnapToBeatDiv3:
2089 case SnapToBeatDiv2: {
2090 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2091 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2093 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2094 current_bbt_points_begin, current_bbt_points_end);
2095 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2096 current_bbt_points_begin, current_bbt_points_end);
2097 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2101 case SnapToRegionStart:
2102 case SnapToRegionEnd:
2103 case SnapToRegionSync:
2104 case SnapToRegionBoundary:
2105 build_region_boundary_cache ();
2113 SnapChanged (); /* EMIT SIGNAL */
2117 Editor::set_snap_mode (SnapMode mode)
2119 string str = snap_mode_strings[(int)mode];
2121 if (_internal_editing) {
2122 internal_snap_mode = mode;
2124 pre_internal_snap_mode = mode;
2129 if (str != snap_mode_selector.get_active_text ()) {
2130 snap_mode_selector.set_active_text (str);
2136 Editor::set_edit_point_preference (EditPoint ep, bool force)
2138 bool changed = (_edit_point != ep);
2141 string str = edit_point_strings[(int)ep];
2143 if (str != edit_point_selector.get_active_text ()) {
2144 edit_point_selector.set_active_text (str);
2147 set_canvas_cursor ();
2149 if (!force && !changed) {
2153 const char* action=NULL;
2155 switch (_edit_point) {
2156 case EditAtPlayhead:
2157 action = "edit-at-playhead";
2159 case EditAtSelectedMarker:
2160 action = "edit-at-marker";
2163 action = "edit-at-mouse";
2167 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2169 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2173 bool in_track_canvas;
2175 if (!mouse_frame (foo, in_track_canvas)) {
2176 in_track_canvas = false;
2179 reset_canvas_action_sensitivity (in_track_canvas);
2185 Editor::set_state (const XMLNode& node, int /*version*/)
2187 const XMLProperty* prop;
2194 g.base_width = default_width;
2195 g.base_height = default_height;
2199 if ((geometry = find_named_node (node, "geometry")) != 0) {
2203 if ((prop = geometry->property("x_size")) == 0) {
2204 prop = geometry->property ("x-size");
2207 g.base_width = atoi(prop->value());
2209 if ((prop = geometry->property("y_size")) == 0) {
2210 prop = geometry->property ("y-size");
2213 g.base_height = atoi(prop->value());
2216 if ((prop = geometry->property ("x_pos")) == 0) {
2217 prop = geometry->property ("x-pos");
2220 x = atoi (prop->value());
2223 if ((prop = geometry->property ("y_pos")) == 0) {
2224 prop = geometry->property ("y-pos");
2227 y = atoi (prop->value());
2231 set_default_size (g.base_width, g.base_height);
2234 if (_session && (prop = node.property ("playhead"))) {
2236 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2237 playhead_cursor->set_position (pos);
2239 playhead_cursor->set_position (0);
2242 if ((prop = node.property ("mixer-width"))) {
2243 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2246 if ((prop = node.property ("zoom-focus"))) {
2247 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2250 if ((prop = node.property ("zoom"))) {
2251 /* older versions of ardour used floating point samples_per_pixel */
2252 double f = PBD::atof (prop->value());
2253 reset_zoom (llrintf (f));
2255 reset_zoom (samples_per_pixel);
2258 if ((prop = node.property ("snap-to"))) {
2259 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2262 if ((prop = node.property ("snap-mode"))) {
2263 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2266 if ((prop = node.property ("internal-snap-to"))) {
2267 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2270 if ((prop = node.property ("internal-snap-mode"))) {
2271 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2274 if ((prop = node.property ("pre-internal-snap-to"))) {
2275 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2279 if ((prop = node.property ("pre-internal-snap-mode"))) {
2280 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2283 if ((prop = node.property ("mouse-mode"))) {
2284 MouseMode m = str2mousemode(prop->value());
2285 set_mouse_mode (m, true);
2287 set_mouse_mode (MouseObject, true);
2290 if ((prop = node.property ("left-frame")) != 0) {
2292 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2296 reset_x_origin (pos);
2300 if ((prop = node.property ("y-origin")) != 0) {
2301 reset_y_origin (atof (prop->value ()));
2304 if ((prop = node.property ("internal-edit"))) {
2305 bool yn = string_is_affirmative (prop->value());
2306 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2308 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2309 tact->set_active (!yn);
2310 tact->set_active (yn);
2314 if ((prop = node.property ("join-object-range"))) {
2315 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2316 bool yn = string_is_affirmative (prop->value());
2318 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2319 tact->set_active (!yn);
2320 tact->set_active (yn);
2322 set_mouse_mode(mouse_mode, true);
2325 if ((prop = node.property ("edit-point"))) {
2326 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2329 if ((prop = node.property ("show-measures"))) {
2330 bool yn = string_is_affirmative (prop->value());
2331 _show_measures = yn;
2332 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2334 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2335 /* do it twice to force the change */
2336 tact->set_active (!yn);
2337 tact->set_active (yn);
2341 if ((prop = node.property ("follow-playhead"))) {
2342 bool yn = string_is_affirmative (prop->value());
2343 set_follow_playhead (yn);
2344 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2346 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2347 if (tact->get_active() != yn) {
2348 tact->set_active (yn);
2353 if ((prop = node.property ("stationary-playhead"))) {
2354 bool yn = string_is_affirmative (prop->value());
2355 set_stationary_playhead (yn);
2356 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2358 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2359 if (tact->get_active() != yn) {
2360 tact->set_active (yn);
2365 if ((prop = node.property ("region-list-sort-type"))) {
2366 RegionListSortType st;
2367 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2370 if ((prop = node.property ("show-editor-mixer"))) {
2372 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2375 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2376 bool yn = string_is_affirmative (prop->value());
2378 /* do it twice to force the change */
2380 tact->set_active (!yn);
2381 tact->set_active (yn);
2384 if ((prop = node.property ("show-editor-list"))) {
2386 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2389 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2390 bool yn = string_is_affirmative (prop->value());
2392 /* do it twice to force the change */
2394 tact->set_active (!yn);
2395 tact->set_active (yn);
2398 if ((prop = node.property (X_("editor-list-page")))) {
2399 _the_notebook.set_current_page (atoi (prop->value ()));
2402 if ((prop = node.property (X_("show-marker-lines")))) {
2403 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2405 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2406 bool yn = string_is_affirmative (prop->value ());
2408 tact->set_active (!yn);
2409 tact->set_active (yn);
2412 XMLNodeList children = node.children ();
2413 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2414 selection->set_state (**i, Stateful::current_state_version);
2415 _regions->set_state (**i);
2418 if ((prop = node.property ("maximised"))) {
2419 bool yn = string_is_affirmative (prop->value());
2421 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2425 if ((prop = node.property ("nudge-clock-value"))) {
2427 sscanf (prop->value().c_str(), "%" PRId64, &f);
2428 nudge_clock->set (f);
2430 nudge_clock->set_mode (AudioClock::Timecode);
2431 nudge_clock->set (_session->frame_rate() * 5, true);
2438 Editor::get_state ()
2440 XMLNode* node = new XMLNode ("Editor");
2443 id().print (buf, sizeof (buf));
2444 node->add_property ("id", buf);
2446 if (is_realized()) {
2447 Glib::RefPtr<Gdk::Window> win = get_window();
2449 int x, y, width, height;
2450 win->get_root_origin(x, y);
2451 win->get_size(width, height);
2453 XMLNode* geometry = new XMLNode ("geometry");
2455 snprintf(buf, sizeof(buf), "%d", width);
2456 geometry->add_property("x-size", string(buf));
2457 snprintf(buf, sizeof(buf), "%d", height);
2458 geometry->add_property("y-size", string(buf));
2459 snprintf(buf, sizeof(buf), "%d", x);
2460 geometry->add_property("x-pos", string(buf));
2461 snprintf(buf, sizeof(buf), "%d", y);
2462 geometry->add_property("y-pos", string(buf));
2463 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2464 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2465 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2466 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2467 geometry->add_property("edit-vertical-pane-pos", string(buf));
2469 node->add_child_nocopy (*geometry);
2472 maybe_add_mixer_strip_width (*node);
2474 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2476 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2477 node->add_property ("zoom", buf);
2478 node->add_property ("snap-to", enum_2_string (_snap_type));
2479 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2480 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2481 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2482 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2483 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2484 node->add_property ("edit-point", enum_2_string (_edit_point));
2486 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2487 node->add_property ("playhead", buf);
2488 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2489 node->add_property ("left-frame", buf);
2490 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2491 node->add_property ("y-origin", buf);
2493 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2494 node->add_property ("maximised", _maximised ? "yes" : "no");
2495 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2496 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2497 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2498 node->add_property ("mouse-mode", enum2str(mouse_mode));
2499 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2500 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2502 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2504 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2505 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2508 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2510 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2511 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2514 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2515 node->add_property (X_("editor-list-page"), buf);
2517 if (button_bindings) {
2518 XMLNode* bb = new XMLNode (X_("Buttons"));
2519 button_bindings->save (*bb);
2520 node->add_child_nocopy (*bb);
2523 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2525 node->add_child_nocopy (selection->get_state ());
2526 node->add_child_nocopy (_regions->get_state ());
2528 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2529 node->add_property ("nudge-clock-value", buf);
2536 /** @param y y offset from the top of all trackviews.
2537 * @return pair: TimeAxisView that y is over, layer index.
2538 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2539 * in stacked or expanded region display mode, otherwise 0.
2541 std::pair<TimeAxisView *, double>
2542 Editor::trackview_by_y_position (double y)
2544 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2546 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2552 return std::make_pair ( (TimeAxisView *) 0, 0);
2555 /** Snap a position to the grid, if appropriate, taking into account current
2556 * grid settings and also the state of any snap modifier keys that may be pressed.
2557 * @param start Position to snap.
2558 * @param event Event to get current key modifier information from, or 0.
2561 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2563 if (!_session || !event) {
2567 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2568 if (_snap_mode == SnapOff) {
2569 snap_to_internal (start, direction, for_mark);
2572 if (_snap_mode != SnapOff) {
2573 snap_to_internal (start, direction, for_mark);
2579 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2581 if (!_session || _snap_mode == SnapOff) {
2585 snap_to_internal (start, direction, for_mark);
2589 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2591 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2592 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2594 switch (_snap_type) {
2595 case SnapToTimecodeFrame:
2596 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2597 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2599 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2603 case SnapToTimecodeSeconds:
2604 if (_session->config.get_timecode_offset_negative()) {
2605 start += _session->config.get_timecode_offset ();
2607 start -= _session->config.get_timecode_offset ();
2609 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2610 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2612 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2615 if (_session->config.get_timecode_offset_negative()) {
2616 start -= _session->config.get_timecode_offset ();
2618 start += _session->config.get_timecode_offset ();
2622 case SnapToTimecodeMinutes:
2623 if (_session->config.get_timecode_offset_negative()) {
2624 start += _session->config.get_timecode_offset ();
2626 start -= _session->config.get_timecode_offset ();
2628 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2629 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2631 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2633 if (_session->config.get_timecode_offset_negative()) {
2634 start -= _session->config.get_timecode_offset ();
2636 start += _session->config.get_timecode_offset ();
2640 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2646 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2648 const framepos_t one_second = _session->frame_rate();
2649 const framepos_t one_minute = _session->frame_rate() * 60;
2650 framepos_t presnap = start;
2654 switch (_snap_type) {
2655 case SnapToTimecodeFrame:
2656 case SnapToTimecodeSeconds:
2657 case SnapToTimecodeMinutes:
2658 return timecode_snap_to_internal (start, direction, for_mark);
2661 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2662 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2664 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2669 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2670 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2672 start = (framepos_t) floor ((double) start / one_second) * one_second;
2677 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2678 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2680 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2685 start = _session->tempo_map().round_to_bar (start, direction);
2689 start = _session->tempo_map().round_to_beat (start, direction);
2692 case SnapToBeatDiv128:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2695 case SnapToBeatDiv64:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2698 case SnapToBeatDiv32:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2701 case SnapToBeatDiv28:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2704 case SnapToBeatDiv24:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2707 case SnapToBeatDiv20:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2710 case SnapToBeatDiv16:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2713 case SnapToBeatDiv14:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2716 case SnapToBeatDiv12:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2719 case SnapToBeatDiv10:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2722 case SnapToBeatDiv8:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2725 case SnapToBeatDiv7:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2728 case SnapToBeatDiv6:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2731 case SnapToBeatDiv5:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2734 case SnapToBeatDiv4:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2737 case SnapToBeatDiv3:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2740 case SnapToBeatDiv2:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2749 _session->locations()->marks_either_side (start, before, after);
2751 if (before == max_framepos && after == max_framepos) {
2752 /* No marks to snap to, so just don't snap */
2754 } else if (before == max_framepos) {
2756 } else if (after == max_framepos) {
2758 } else if (before != max_framepos && after != max_framepos) {
2759 /* have before and after */
2760 if ((start - before) < (after - start)) {
2769 case SnapToRegionStart:
2770 case SnapToRegionEnd:
2771 case SnapToRegionSync:
2772 case SnapToRegionBoundary:
2773 if (!region_boundary_cache.empty()) {
2775 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2776 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2778 if (direction > 0) {
2779 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2781 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2784 if (next != region_boundary_cache.begin ()) {
2789 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2790 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2792 if (start > (p + n) / 2) {
2801 switch (_snap_mode) {
2807 if (presnap > start) {
2808 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2812 } else if (presnap < start) {
2813 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2819 /* handled at entry */
2827 Editor::setup_toolbar ()
2829 HBox* mode_box = manage(new HBox);
2830 mode_box->set_border_width (2);
2831 mode_box->set_spacing(4);
2833 HBox* mouse_mode_box = manage (new HBox);
2834 HBox* mouse_mode_hbox = manage (new HBox);
2835 VBox* mouse_mode_vbox = manage (new VBox);
2836 Alignment* mouse_mode_align = manage (new Alignment);
2838 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2839 // mouse_mode_size_group->add_widget (smart_mode_button);
2840 mouse_mode_size_group->add_widget (mouse_move_button);
2841 mouse_mode_size_group->add_widget (mouse_select_button);
2842 mouse_mode_size_group->add_widget (mouse_zoom_button);
2843 mouse_mode_size_group->add_widget (mouse_gain_button);
2844 mouse_mode_size_group->add_widget (mouse_timefx_button);
2845 mouse_mode_size_group->add_widget (mouse_audition_button);
2846 mouse_mode_size_group->add_widget (mouse_draw_button);
2847 mouse_mode_size_group->add_widget (internal_edit_button);
2849 /* make them just a bit bigger */
2850 mouse_move_button.set_size_request (-1, 30);
2852 mouse_mode_hbox->set_spacing (2);
2854 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2855 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2856 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2857 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2858 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2859 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2860 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2861 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2862 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2864 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2866 mouse_mode_align->add (*mouse_mode_vbox);
2867 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2869 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2871 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2872 if (!Profile->get_sae()) {
2873 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2875 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2877 edit_mode_selector.set_name ("EditModeSelector");
2878 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2879 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2881 mode_box->pack_start (edit_mode_selector, false, false);
2882 mode_box->pack_start (*mouse_mode_box, false, false);
2884 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2885 _mouse_mode_tearoff->set_name ("MouseModeBase");
2886 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2888 if (Profile->get_sae()) {
2889 _mouse_mode_tearoff->set_can_be_torn_off (false);
2892 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2893 &_mouse_mode_tearoff->tearoff_window()));
2894 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2895 &_mouse_mode_tearoff->tearoff_window(), 1));
2896 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2897 &_mouse_mode_tearoff->tearoff_window()));
2898 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2899 &_mouse_mode_tearoff->tearoff_window(), 1));
2903 _zoom_box.set_spacing (2);
2904 _zoom_box.set_border_width (2);
2908 zoom_in_button.set_name ("zoom button");
2909 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2910 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2911 zoom_in_button.set_image(::get_icon ("zoom_in"));
2912 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2913 zoom_in_button.set_related_action (act);
2915 zoom_out_button.set_name ("zoom button");
2916 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2917 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2918 zoom_out_button.set_image(::get_icon ("zoom_out"));
2919 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2920 zoom_out_button.set_related_action (act);
2922 zoom_out_full_button.set_name ("zoom button");
2923 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2924 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2925 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2926 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2927 zoom_out_full_button.set_related_action (act);
2929 zoom_focus_selector.set_name ("ZoomFocusSelector");
2930 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2931 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2933 _zoom_box.pack_start (zoom_out_button, false, false);
2934 _zoom_box.pack_start (zoom_in_button, false, false);
2935 _zoom_box.pack_start (zoom_out_full_button, false, false);
2937 _zoom_box.pack_start (zoom_focus_selector, false, false);
2939 /* Track zoom buttons */
2940 tav_expand_button.set_name ("zoom button");
2941 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2942 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2943 tav_expand_button.set_size_request (-1, 20);
2944 tav_expand_button.set_image(::get_icon ("tav_exp"));
2945 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2946 tav_expand_button.set_related_action (act);
2948 tav_shrink_button.set_name ("zoom button");
2949 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2950 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2951 tav_shrink_button.set_size_request (-1, 20);
2952 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2953 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2954 tav_shrink_button.set_related_action (act);
2956 _zoom_box.pack_start (tav_shrink_button);
2957 _zoom_box.pack_start (tav_expand_button);
2959 _zoom_tearoff = manage (new TearOff (_zoom_box));
2961 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2962 &_zoom_tearoff->tearoff_window()));
2963 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2964 &_zoom_tearoff->tearoff_window(), 0));
2965 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2966 &_zoom_tearoff->tearoff_window()));
2967 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2968 &_zoom_tearoff->tearoff_window(), 0));
2970 snap_box.set_spacing (2);
2971 snap_box.set_border_width (2);
2973 snap_type_selector.set_name ("SnapTypeSelector");
2974 set_popdown_strings (snap_type_selector, snap_type_strings);
2975 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2977 snap_mode_selector.set_name ("SnapModeSelector");
2978 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2979 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2981 edit_point_selector.set_name ("EditPointSelector");
2982 set_popdown_strings (edit_point_selector, edit_point_strings);
2983 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2985 snap_box.pack_start (snap_mode_selector, false, false);
2986 snap_box.pack_start (snap_type_selector, false, false);
2987 snap_box.pack_start (edit_point_selector, false, false);
2991 HBox *nudge_box = manage (new HBox);
2992 nudge_box->set_spacing (2);
2993 nudge_box->set_border_width (2);
2995 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2996 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2998 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2999 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3001 nudge_box->pack_start (nudge_backward_button, false, false);
3002 nudge_box->pack_start (nudge_forward_button, false, false);
3003 nudge_box->pack_start (*nudge_clock, false, false);
3006 /* Pack everything in... */
3008 HBox* hbox = manage (new HBox);
3009 hbox->set_spacing(10);
3011 _tools_tearoff = manage (new TearOff (*hbox));
3012 _tools_tearoff->set_name ("MouseModeBase");
3013 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3015 if (Profile->get_sae()) {
3016 _tools_tearoff->set_can_be_torn_off (false);
3019 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3020 &_tools_tearoff->tearoff_window()));
3021 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3022 &_tools_tearoff->tearoff_window(), 0));
3023 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3024 &_tools_tearoff->tearoff_window()));
3025 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3026 &_tools_tearoff->tearoff_window(), 0));
3028 toolbar_hbox.set_spacing (10);
3029 toolbar_hbox.set_border_width (1);
3031 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3032 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3033 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3035 hbox->pack_start (snap_box, false, false);
3036 if (!Profile->get_small_screen()) {
3037 hbox->pack_start (*nudge_box, false, false);
3039 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3041 hbox->pack_start (panic_box, false, false);
3045 toolbar_base.set_name ("ToolBarBase");
3046 toolbar_base.add (toolbar_hbox);
3048 _toolbar_viewport.add (toolbar_base);
3049 /* stick to the required height but allow width to vary if there's not enough room */
3050 _toolbar_viewport.set_size_request (1, -1);
3052 toolbar_frame.set_shadow_type (SHADOW_OUT);
3053 toolbar_frame.set_name ("BaseFrame");
3054 toolbar_frame.add (_toolbar_viewport);
3058 Editor::setup_tooltips ()
3060 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3061 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3062 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3063 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3064 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3065 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3066 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3067 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3068 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3069 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3070 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3071 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3072 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3073 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3074 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3075 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3076 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3077 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3078 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3079 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3080 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3081 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3082 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3086 Editor::convert_drop_to_paths (
3087 vector<string>& paths,
3088 const RefPtr<Gdk::DragContext>& /*context*/,
3091 const SelectionData& data,
3095 if (_session == 0) {
3099 vector<string> uris = data.get_uris();
3103 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3104 are actually URI lists. So do it by hand.
3107 if (data.get_target() != "text/plain") {
3111 /* Parse the "uri-list" format that Nautilus provides,
3112 where each pathname is delimited by \r\n.
3114 THERE MAY BE NO NULL TERMINATING CHAR!!!
3117 string txt = data.get_text();
3121 p = (char *) malloc (txt.length() + 1);
3122 txt.copy (p, txt.length(), 0);
3123 p[txt.length()] = '\0';
3129 while (g_ascii_isspace (*p))
3133 while (*q && (*q != '\n') && (*q != '\r')) {
3140 while (q > p && g_ascii_isspace (*q))
3145 uris.push_back (string (p, q - p + 1));
3149 p = strchr (p, '\n');
3161 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3162 if ((*i).substr (0,7) == "file://") {
3163 paths.push_back (Glib::filename_from_uri (*i));
3171 Editor::new_tempo_section ()
3176 Editor::map_transport_state ()
3178 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3180 if (_session && _session->transport_stopped()) {
3181 have_pending_keyboard_selection = false;
3184 update_loop_range_view ();
3190 Editor::begin_reversible_command (string name)
3193 _session->begin_reversible_command (name);
3198 Editor::begin_reversible_command (GQuark q)
3201 _session->begin_reversible_command (q);
3206 Editor::commit_reversible_command ()
3209 _session->commit_reversible_command ();
3214 Editor::history_changed ()
3218 if (undo_action && _session) {
3219 if (_session->undo_depth() == 0) {
3220 label = S_("Command|Undo");
3222 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3224 undo_action->property_label() = label;
3227 if (redo_action && _session) {
3228 if (_session->redo_depth() == 0) {
3231 label = string_compose(_("Redo (%1)"), _session->next_redo());
3233 redo_action->property_label() = label;
3238 Editor::duplicate_range (bool with_dialog)
3242 RegionSelection rs = get_regions_from_selection_and_entered ();
3244 if ( selection->time.length() == 0 && rs.empty()) {
3250 ArdourDialog win (_("Duplicate"));
3251 Label label (_("Number of duplications:"));
3252 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3253 SpinButton spinner (adjustment, 0.0, 1);
3256 win.get_vbox()->set_spacing (12);
3257 win.get_vbox()->pack_start (hbox);
3258 hbox.set_border_width (6);
3259 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3261 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3262 place, visually. so do this by hand.
3265 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3266 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3267 spinner.grab_focus();
3273 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3274 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3275 win.set_default_response (RESPONSE_ACCEPT);
3277 spinner.grab_focus ();
3279 switch (win.run ()) {
3280 case RESPONSE_ACCEPT:
3286 times = adjustment.get_value();
3289 if ((current_mouse_mode() == Editing::MouseRange)) {
3290 if (selection->time.length()) {
3291 duplicate_selection (times);
3293 } else if (get_smart_mode()) {
3294 if (selection->time.length()) {
3295 duplicate_selection (times);
3297 duplicate_some_regions (rs, times);
3299 duplicate_some_regions (rs, times);
3304 Editor::set_edit_mode (EditMode m)
3306 Config->set_edit_mode (m);
3310 Editor::cycle_edit_mode ()
3312 switch (Config->get_edit_mode()) {
3314 if (Profile->get_sae()) {
3315 Config->set_edit_mode (Lock);
3317 Config->set_edit_mode (Splice);
3321 Config->set_edit_mode (Lock);
3324 Config->set_edit_mode (Slide);
3330 Editor::edit_mode_selection_done ()
3332 string s = edit_mode_selector.get_active_text ();
3335 Config->set_edit_mode (string_to_edit_mode (s));
3340 Editor::snap_type_selection_done ()
3342 string choice = snap_type_selector.get_active_text();
3343 SnapType snaptype = SnapToBeat;
3345 if (choice == _("Beats/2")) {
3346 snaptype = SnapToBeatDiv2;
3347 } else if (choice == _("Beats/3")) {
3348 snaptype = SnapToBeatDiv3;
3349 } else if (choice == _("Beats/4")) {
3350 snaptype = SnapToBeatDiv4;
3351 } else if (choice == _("Beats/5")) {
3352 snaptype = SnapToBeatDiv5;
3353 } else if (choice == _("Beats/6")) {
3354 snaptype = SnapToBeatDiv6;
3355 } else if (choice == _("Beats/7")) {
3356 snaptype = SnapToBeatDiv7;
3357 } else if (choice == _("Beats/8")) {
3358 snaptype = SnapToBeatDiv8;
3359 } else if (choice == _("Beats/10")) {
3360 snaptype = SnapToBeatDiv10;
3361 } else if (choice == _("Beats/12")) {
3362 snaptype = SnapToBeatDiv12;
3363 } else if (choice == _("Beats/14")) {
3364 snaptype = SnapToBeatDiv14;
3365 } else if (choice == _("Beats/16")) {
3366 snaptype = SnapToBeatDiv16;
3367 } else if (choice == _("Beats/20")) {
3368 snaptype = SnapToBeatDiv20;
3369 } else if (choice == _("Beats/24")) {
3370 snaptype = SnapToBeatDiv24;
3371 } else if (choice == _("Beats/28")) {
3372 snaptype = SnapToBeatDiv28;
3373 } else if (choice == _("Beats/32")) {
3374 snaptype = SnapToBeatDiv32;
3375 } else if (choice == _("Beats/64")) {
3376 snaptype = SnapToBeatDiv64;
3377 } else if (choice == _("Beats/128")) {
3378 snaptype = SnapToBeatDiv128;
3379 } else if (choice == _("Beats")) {
3380 snaptype = SnapToBeat;
3381 } else if (choice == _("Bars")) {
3382 snaptype = SnapToBar;
3383 } else if (choice == _("Marks")) {
3384 snaptype = SnapToMark;
3385 } else if (choice == _("Region starts")) {
3386 snaptype = SnapToRegionStart;
3387 } else if (choice == _("Region ends")) {
3388 snaptype = SnapToRegionEnd;
3389 } else if (choice == _("Region bounds")) {
3390 snaptype = SnapToRegionBoundary;
3391 } else if (choice == _("Region syncs")) {
3392 snaptype = SnapToRegionSync;
3393 } else if (choice == _("CD Frames")) {
3394 snaptype = SnapToCDFrame;
3395 } else if (choice == _("Timecode Frames")) {
3396 snaptype = SnapToTimecodeFrame;
3397 } else if (choice == _("Timecode Seconds")) {
3398 snaptype = SnapToTimecodeSeconds;
3399 } else if (choice == _("Timecode Minutes")) {
3400 snaptype = SnapToTimecodeMinutes;
3401 } else if (choice == _("Seconds")) {
3402 snaptype = SnapToSeconds;
3403 } else if (choice == _("Minutes")) {
3404 snaptype = SnapToMinutes;
3407 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3409 ract->set_active ();
3414 Editor::snap_mode_selection_done ()
3416 string choice = snap_mode_selector.get_active_text();
3417 SnapMode mode = SnapNormal;
3419 if (choice == _("No Grid")) {
3421 } else if (choice == _("Grid")) {
3423 } else if (choice == _("Magnetic")) {
3424 mode = SnapMagnetic;
3427 RefPtr<RadioAction> ract = snap_mode_action (mode);
3430 ract->set_active (true);
3435 Editor::cycle_edit_point (bool with_marker)
3437 switch (_edit_point) {
3439 set_edit_point_preference (EditAtPlayhead);
3441 case EditAtPlayhead:
3443 set_edit_point_preference (EditAtSelectedMarker);
3445 set_edit_point_preference (EditAtMouse);
3448 case EditAtSelectedMarker:
3449 set_edit_point_preference (EditAtMouse);
3455 Editor::edit_point_selection_done ()
3457 string choice = edit_point_selector.get_active_text();
3458 EditPoint ep = EditAtSelectedMarker;
3460 if (choice == _("Marker")) {
3461 set_edit_point_preference (EditAtSelectedMarker);
3462 } else if (choice == _("Playhead")) {
3463 set_edit_point_preference (EditAtPlayhead);
3465 set_edit_point_preference (EditAtMouse);
3468 RefPtr<RadioAction> ract = edit_point_action (ep);
3471 ract->set_active (true);
3476 Editor::zoom_focus_selection_done ()
3478 string choice = zoom_focus_selector.get_active_text();
3479 ZoomFocus focus_type = ZoomFocusLeft;
3481 if (choice == _("Left")) {
3482 focus_type = ZoomFocusLeft;
3483 } else if (choice == _("Right")) {
3484 focus_type = ZoomFocusRight;
3485 } else if (choice == _("Center")) {
3486 focus_type = ZoomFocusCenter;
3487 } else if (choice == _("Playhead")) {
3488 focus_type = ZoomFocusPlayhead;
3489 } else if (choice == _("Mouse")) {
3490 focus_type = ZoomFocusMouse;
3491 } else if (choice == _("Edit point")) {
3492 focus_type = ZoomFocusEdit;
3495 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3498 ract->set_active ();
3503 Editor::edit_controls_button_release (GdkEventButton* ev)
3505 if (Keyboard::is_context_menu_event (ev)) {
3506 ARDOUR_UI::instance()->add_route (this);
3507 } else if (ev->button == 1) {
3508 selection->clear_tracks ();
3515 Editor::mouse_select_button_release (GdkEventButton* ev)
3517 /* this handles just right-clicks */
3519 if (ev->button != 3) {
3527 Editor::set_zoom_focus (ZoomFocus f)
3529 string str = zoom_focus_strings[(int)f];
3531 if (str != zoom_focus_selector.get_active_text()) {
3532 zoom_focus_selector.set_active_text (str);
3535 if (zoom_focus != f) {
3542 Editor::cycle_zoom_focus ()
3544 switch (zoom_focus) {
3546 set_zoom_focus (ZoomFocusRight);
3548 case ZoomFocusRight:
3549 set_zoom_focus (ZoomFocusCenter);
3551 case ZoomFocusCenter:
3552 set_zoom_focus (ZoomFocusPlayhead);
3554 case ZoomFocusPlayhead:
3555 set_zoom_focus (ZoomFocusMouse);
3557 case ZoomFocusMouse:
3558 set_zoom_focus (ZoomFocusEdit);
3561 set_zoom_focus (ZoomFocusLeft);
3567 Editor::ensure_float (Window& win)
3569 win.set_transient_for (*this);
3573 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3575 /* recover or initialize pane positions. do this here rather than earlier because
3576 we don't want the positions to change the child allocations, which they seem to do.
3582 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3591 XMLNode* geometry = find_named_node (*node, "geometry");
3593 if (which == static_cast<Paned*> (&edit_pane)) {
3595 if (done & Horizontal) {
3599 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3600 _notebook_shrunk = string_is_affirmative (prop->value ());
3603 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3604 /* initial allocation is 90% to canvas, 10% to notebook */
3605 pos = (int) floor (alloc.get_width() * 0.90f);
3606 snprintf (buf, sizeof(buf), "%d", pos);
3608 pos = atoi (prop->value());
3611 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3612 edit_pane.set_position (pos);
3615 done = (Pane) (done | Horizontal);
3617 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3619 if (done & Vertical) {
3623 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3624 /* initial allocation is 90% to canvas, 10% to summary */
3625 pos = (int) floor (alloc.get_height() * 0.90f);
3626 snprintf (buf, sizeof(buf), "%d", pos);
3629 pos = atoi (prop->value());
3632 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3633 editor_summary_pane.set_position (pos);
3636 done = (Pane) (done | Vertical);
3641 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3643 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3644 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3645 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3646 top_hbox.remove (toolbar_frame);
3651 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3653 if (toolbar_frame.get_parent() == 0) {
3654 top_hbox.pack_end (toolbar_frame);
3659 Editor::set_show_measures (bool yn)
3661 if (_show_measures != yn) {
3664 if ((_show_measures = yn) == true) {
3666 tempo_lines->show();
3669 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3670 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3672 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3673 draw_measures (begin, end);
3681 Editor::toggle_follow_playhead ()
3683 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3685 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3686 set_follow_playhead (tact->get_active());
3690 /** @param yn true to follow playhead, otherwise false.
3691 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3694 Editor::set_follow_playhead (bool yn, bool catch_up)
3696 if (_follow_playhead != yn) {
3697 if ((_follow_playhead = yn) == true && catch_up) {
3699 reset_x_origin_to_follow_playhead ();
3706 Editor::toggle_stationary_playhead ()
3708 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3710 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3711 set_stationary_playhead (tact->get_active());
3716 Editor::set_stationary_playhead (bool yn)
3718 if (_stationary_playhead != yn) {
3719 if ((_stationary_playhead = yn) == true) {
3721 // FIXME need a 3.0 equivalent of this 2.X call
3722 // update_current_screen ();
3729 Editor::playlist_selector () const
3731 return *_playlist_selector;
3735 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3739 switch (_snap_type) {
3744 case SnapToBeatDiv128:
3747 case SnapToBeatDiv64:
3750 case SnapToBeatDiv32:
3753 case SnapToBeatDiv28:
3756 case SnapToBeatDiv24:
3759 case SnapToBeatDiv20:
3762 case SnapToBeatDiv16:
3765 case SnapToBeatDiv14:
3768 case SnapToBeatDiv12:
3771 case SnapToBeatDiv10:
3774 case SnapToBeatDiv8:
3777 case SnapToBeatDiv7:
3780 case SnapToBeatDiv6:
3783 case SnapToBeatDiv5:
3786 case SnapToBeatDiv4:
3789 case SnapToBeatDiv3:
3792 case SnapToBeatDiv2:
3798 return _session->tempo_map().meter_at (position).divisions_per_bar();
3803 case SnapToTimecodeFrame:
3804 case SnapToTimecodeSeconds:
3805 case SnapToTimecodeMinutes:
3808 case SnapToRegionStart:
3809 case SnapToRegionEnd:
3810 case SnapToRegionSync:
3811 case SnapToRegionBoundary:
3821 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3825 ret = nudge_clock->current_duration (pos);
3826 next = ret + 1; /* XXXX fix me */
3832 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3834 ArdourDialog dialog (_("Playlist Deletion"));
3835 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3836 "If it is kept, its audio files will not be cleaned.\n"
3837 "If it is deleted, audio files used by it alone will be cleaned."),
3840 dialog.set_position (WIN_POS_CENTER);
3841 dialog.get_vbox()->pack_start (label);
3845 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3846 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3847 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3849 switch (dialog.run ()) {
3850 case RESPONSE_ACCEPT:
3851 /* delete the playlist */
3855 case RESPONSE_REJECT:
3856 /* keep the playlist */
3868 Editor::audio_region_selection_covers (framepos_t where)
3870 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3871 if ((*a)->region()->covers (where)) {
3880 Editor::prepare_for_cleanup ()
3882 cut_buffer->clear_regions ();
3883 cut_buffer->clear_playlists ();
3885 selection->clear_regions ();
3886 selection->clear_playlists ();
3888 _regions->suspend_redisplay ();
3892 Editor::finish_cleanup ()
3894 _regions->resume_redisplay ();
3898 Editor::transport_loop_location()
3901 return _session->locations()->auto_loop_location();
3908 Editor::transport_punch_location()
3911 return _session->locations()->auto_punch_location();
3918 Editor::control_layout_scroll (GdkEventScroll* ev)
3920 if (Keyboard::some_magic_widget_has_focus()) {
3924 switch (ev->direction) {
3926 scroll_tracks_up_line ();
3930 case GDK_SCROLL_DOWN:
3931 scroll_tracks_down_line ();
3935 /* no left/right handling yet */
3943 Editor::session_state_saved (string)
3946 _snapshots->redisplay ();
3950 Editor::update_tearoff_visibility()
3952 bool visible = Config->get_keep_tearoffs();
3953 _mouse_mode_tearoff->set_visible (visible);
3954 _tools_tearoff->set_visible (visible);
3955 _zoom_tearoff->set_visible (visible);
3959 Editor::maximise_editing_space ()
3971 Editor::restore_editing_space ()
3983 * Make new playlists for a given track and also any others that belong
3984 * to the same active route group with the `select' property.
3989 Editor::new_playlists (TimeAxisView* v)
3991 begin_reversible_command (_("new playlists"));
3992 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3993 _session->playlists->get (playlists);
3994 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3995 commit_reversible_command ();
3999 * Use a copy of the current playlist for a given track and also any others that belong
4000 * to the same active route group with the `select' property.
4005 Editor::copy_playlists (TimeAxisView* v)
4007 begin_reversible_command (_("copy playlists"));
4008 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4009 _session->playlists->get (playlists);
4010 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4011 commit_reversible_command ();
4014 /** Clear the current playlist for a given track and also any others that belong
4015 * to the same active route group with the `select' property.
4020 Editor::clear_playlists (TimeAxisView* v)
4022 begin_reversible_command (_("clear playlists"));
4023 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4024 _session->playlists->get (playlists);
4025 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4026 commit_reversible_command ();
4030 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4032 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4036 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4038 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4042 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4044 atv.clear_playlist ();
4048 Editor::on_key_press_event (GdkEventKey* ev)
4050 return key_press_focus_accelerator_handler (*this, ev);
4054 Editor::on_key_release_event (GdkEventKey* ev)
4056 return Gtk::Window::on_key_release_event (ev);
4057 // return key_press_focus_accelerator_handler (*this, ev);
4060 /** Queue up a change to the viewport x origin.
4061 * @param frame New x origin.
4064 Editor::reset_x_origin (framepos_t frame)
4066 pending_visual_change.add (VisualChange::TimeOrigin);
4067 pending_visual_change.time_origin = frame;
4068 ensure_visual_change_idle_handler ();
4072 Editor::reset_y_origin (double y)
4074 pending_visual_change.add (VisualChange::YOrigin);
4075 pending_visual_change.y_origin = y;
4076 ensure_visual_change_idle_handler ();
4080 Editor::reset_zoom (framecnt_t spp)
4082 clamp_samples_per_pixel (spp);
4084 if (spp == samples_per_pixel) {
4088 pending_visual_change.add (VisualChange::ZoomLevel);
4089 pending_visual_change.samples_per_pixel = spp;
4090 ensure_visual_change_idle_handler ();
4094 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4096 reset_x_origin (frame);
4099 if (!no_save_visual) {
4100 undo_visual_stack.push_back (current_visual_state(false));
4104 Editor::VisualState::VisualState (bool with_tracks)
4105 : gui_state (with_tracks ? new GUIObjectState : 0)
4109 Editor::VisualState::~VisualState ()
4114 Editor::VisualState*
4115 Editor::current_visual_state (bool with_tracks)
4117 VisualState* vs = new VisualState (with_tracks);
4118 vs->y_position = vertical_adjustment.get_value();
4119 vs->samples_per_pixel = samples_per_pixel;
4120 vs->leftmost_frame = leftmost_frame;
4121 vs->zoom_focus = zoom_focus;
4124 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4131 Editor::undo_visual_state ()
4133 if (undo_visual_stack.empty()) {
4137 VisualState* vs = undo_visual_stack.back();
4138 undo_visual_stack.pop_back();
4141 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4143 use_visual_state (*vs);
4147 Editor::redo_visual_state ()
4149 if (redo_visual_stack.empty()) {
4153 VisualState* vs = redo_visual_stack.back();
4154 redo_visual_stack.pop_back();
4156 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4158 use_visual_state (*vs);
4162 Editor::swap_visual_state ()
4164 if (undo_visual_stack.empty()) {
4165 redo_visual_state ();
4167 undo_visual_state ();
4172 Editor::use_visual_state (VisualState& vs)
4174 PBD::Unwinder<bool> nsv (no_save_visual, true);
4176 _routes->suspend_redisplay ();
4178 vertical_adjustment.set_value (vs.y_position);
4180 set_zoom_focus (vs.zoom_focus);
4181 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4184 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4186 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4187 (*i)->reset_visual_state ();
4191 _routes->update_visibility ();
4192 _routes->resume_redisplay ();
4195 /** This is the core function that controls the zoom level of the canvas. It is called
4196 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4197 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4200 Editor::set_samples_per_pixel (framecnt_t spp)
4202 clamp_samples_per_pixel (spp);
4203 samples_per_pixel = spp;
4206 tempo_lines->tempo_map_changed();
4209 /* convert fpu to frame count */
4211 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4213 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4214 zoom_range_clock->set (frames);
4217 bool const showing_time_selection = selection->time.length() > 0;
4219 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4220 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4221 (*i)->reshow_selection (selection->time);
4225 ZoomChanged (); /* EMIT_SIGNAL */
4227 ArdourCanvas::GtkCanvasViewport* c;
4229 c = get_time_bars_canvas();
4231 c->canvas()->zoomed ();
4233 c = get_track_canvas();
4235 c->canvas()->zoomed ();
4238 if (playhead_cursor) {
4239 playhead_cursor->set_position (playhead_cursor->current_frame ());
4242 refresh_location_display();
4243 _summary->set_overlays_dirty ();
4245 update_marker_labels ();
4251 Editor::queue_visual_videotimeline_update ()
4254 * pending_visual_change.add (VisualChange::VideoTimeline);
4255 * or maybe even more specific: which videotimeline-image
4256 * currently it calls update_video_timeline() to update
4257 * _all outdated_ images on the video-timeline.
4258 * see 'exposeimg()' in video_image_frame.cc
4260 ensure_visual_change_idle_handler ();
4264 Editor::ensure_visual_change_idle_handler ()
4266 if (pending_visual_change.idle_handler_id < 0) {
4267 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4268 pending_visual_change.being_handled = false;
4273 Editor::_idle_visual_changer (void* arg)
4275 return static_cast<Editor*>(arg)->idle_visual_changer ();
4279 Editor::idle_visual_changer ()
4281 /* set_horizontal_position() below (and maybe other calls) call
4282 gtk_main_iteration(), so it's possible that a signal will be handled
4283 half-way through this method. If this signal wants an
4284 idle_visual_changer we must schedule another one after this one, so
4285 mark the idle_handler_id as -1 here to allow that. Also make a note
4286 that we are doing the visual change, so that changes in response to
4287 super-rapid-screen-update can be dropped if we are still processing
4291 pending_visual_change.idle_handler_id = -1;
4292 pending_visual_change.being_handled = true;
4294 VisualChange::Type p = pending_visual_change.pending;
4295 pending_visual_change.pending = (VisualChange::Type) 0;
4297 double const last_time_origin = horizontal_position ();
4300 if (p & VisualChange::ZoomLevel) {
4301 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4303 compute_fixed_ruler_scale ();
4305 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4306 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4308 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4309 current_bbt_points_begin, current_bbt_points_end);
4310 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4311 current_bbt_points_begin, current_bbt_points_end);
4312 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4314 update_video_timeline();
4317 if (p & VisualChange::TimeOrigin) {
4318 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4321 if (p & VisualChange::YOrigin) {
4322 vertical_adjustment.set_value (pending_visual_change.y_origin);
4325 if (last_time_origin == horizontal_position ()) {
4326 /* changed signal not emitted */
4327 update_fixed_rulers ();
4328 redisplay_tempo (true);
4331 if (!(p & VisualChange::ZoomLevel)) {
4332 update_video_timeline();
4335 _summary->set_overlays_dirty ();
4337 pending_visual_change.being_handled = false;
4338 return 0; /* this is always a one-shot call */
4341 struct EditorOrderTimeAxisSorter {
4342 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4343 return a->order () < b->order ();
4348 Editor::sort_track_selection (TrackViewList& sel)
4350 EditorOrderTimeAxisSorter cmp;
4355 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4358 framepos_t where = 0;
4359 EditPoint ep = _edit_point;
4361 if (from_context_menu && (ep == EditAtMouse)) {
4362 return canvas_event_frame (&context_click_event, 0, 0);
4365 if (entered_marker) {
4366 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4367 return entered_marker->position();
4370 if (ignore_playhead && ep == EditAtPlayhead) {
4371 ep = EditAtSelectedMarker;
4375 case EditAtPlayhead:
4376 where = _session->audible_frame();
4377 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4380 case EditAtSelectedMarker:
4381 if (!selection->markers.empty()) {
4383 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4386 where = loc->start();
4390 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4398 if (!mouse_frame (where, ignored)) {
4399 /* XXX not right but what can we do ? */
4403 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4411 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4413 if (!_session) return;
4415 begin_reversible_command (cmd);
4419 if ((tll = transport_loop_location()) == 0) {
4420 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4421 XMLNode &before = _session->locations()->get_state();
4422 _session->locations()->add (loc, true);
4423 _session->set_auto_loop_location (loc);
4424 XMLNode &after = _session->locations()->get_state();
4425 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4427 XMLNode &before = tll->get_state();
4428 tll->set_hidden (false, this);
4429 tll->set (start, end);
4430 XMLNode &after = tll->get_state();
4431 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4434 commit_reversible_command ();
4438 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4440 if (!_session) return;
4442 begin_reversible_command (cmd);
4446 if ((tpl = transport_punch_location()) == 0) {
4447 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4448 XMLNode &before = _session->locations()->get_state();
4449 _session->locations()->add (loc, true);
4450 _session->set_auto_punch_location (loc);
4451 XMLNode &after = _session->locations()->get_state();
4452 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4455 XMLNode &before = tpl->get_state();
4456 tpl->set_hidden (false, this);
4457 tpl->set (start, end);
4458 XMLNode &after = tpl->get_state();
4459 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4462 commit_reversible_command ();
4465 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4466 * @param rs List to which found regions are added.
4467 * @param where Time to look at.
4468 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4471 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4473 const TrackViewList* tracks;
4476 tracks = &track_views;
4481 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4483 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4486 boost::shared_ptr<Track> tr;
4487 boost::shared_ptr<Playlist> pl;
4489 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4491 boost::shared_ptr<RegionList> regions = pl->regions_at (
4492 (framepos_t) floor ( (double) where * tr->speed()));
4494 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4495 RegionView* rv = rtv->view()->find_view (*i);
4506 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4508 const TrackViewList* tracks;
4511 tracks = &track_views;
4516 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4517 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4519 boost::shared_ptr<Track> tr;
4520 boost::shared_ptr<Playlist> pl;
4522 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4524 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4525 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4527 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4529 RegionView* rv = rtv->view()->find_view (*i);
4540 /** Get regions using the following method:
4542 * Make a region list using the selected regions, unless
4543 * the edit point is `mouse' and the mouse is over an unselected
4544 * region. In this case, use just that region.
4546 * If the edit point is not 'mouse', and there are no regions selected,
4547 * search the list of selected tracks and return regions that are under
4548 * the edit point on these tracks. If there are no selected tracks and
4549 * 'No Selection = All Tracks' is active, search all tracks,
4551 * The rationale here is that the mouse edit point is special in that
4552 * its position describes both a time and a track; the other edit
4553 * modes only describe a time. Hence if the edit point is `mouse' we
4554 * ignore selected tracks, as we assume the user means something by
4555 * pointing at a particular track. Also in this case we take note of
4556 * the region directly under the edit point, as there is always just one
4557 * (rather than possibly several with non-mouse edit points).
4561 Editor::get_regions_from_selection_and_edit_point ()
4563 RegionSelection regions;
4565 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4566 regions.add (entered_regionview);
4568 regions = selection->regions;
4572 if (regions.empty() && _edit_point != EditAtMouse) {
4573 TrackViewList tracks = selection->tracks;
4575 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4576 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4577 * is enabled, so consider all tracks
4579 tracks = track_views;
4582 if (!tracks.empty()) {
4583 /* no region selected or entered, but some selected tracks:
4584 * act on all regions on the selected tracks at the edit point
4586 framepos_t const where = get_preferred_edit_position ();
4587 get_regions_at(regions, where, tracks);
4593 /** Start with regions that are selected, or the entered regionview if none are selected.
4594 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4595 * of the regions that we started with.
4599 Editor::get_regions_from_selection_and_entered ()
4601 RegionSelection regions = selection->regions;
4603 if (regions.empty() && entered_regionview) {
4604 regions.add (entered_regionview);
4611 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4613 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4615 RouteTimeAxisView* tatv;
4617 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4619 boost::shared_ptr<Playlist> pl;
4620 vector<boost::shared_ptr<Region> > results;
4622 boost::shared_ptr<Track> tr;
4624 if ((tr = tatv->track()) == 0) {
4629 if ((pl = (tr->playlist())) != 0) {
4630 if (src_comparison) {
4631 pl->get_source_equivalent_regions (region, results);
4633 pl->get_region_list_equivalent_regions (region, results);
4637 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4638 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4639 regions.push_back (marv);
4648 Editor::show_rhythm_ferret ()
4650 if (rhythm_ferret == 0) {
4651 rhythm_ferret = new RhythmFerret(*this);
4654 rhythm_ferret->set_session (_session);
4655 rhythm_ferret->show ();
4656 rhythm_ferret->present ();
4660 Editor::first_idle ()
4662 MessageDialog* dialog = 0;
4664 if (track_views.size() > 1) {
4665 dialog = new MessageDialog (
4667 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4671 ARDOUR_UI::instance()->flush_pending ();
4674 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4678 // first idle adds route children (automation tracks), so we need to redisplay here
4679 _routes->redisplay ();
4686 Editor::_idle_resize (gpointer arg)
4688 return ((Editor*)arg)->idle_resize ();
4692 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4694 if (resize_idle_id < 0) {
4695 resize_idle_id = g_idle_add (_idle_resize, this);
4696 _pending_resize_amount = 0;
4699 /* make a note of the smallest resulting height, so that we can clamp the
4700 lower limit at TimeAxisView::hSmall */
4702 int32_t min_resulting = INT32_MAX;
4704 _pending_resize_amount += h;
4705 _pending_resize_view = view;
4707 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4709 if (selection->tracks.contains (_pending_resize_view)) {
4710 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4711 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4715 if (min_resulting < 0) {
4720 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4721 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4725 /** Handle pending resizing of tracks */
4727 Editor::idle_resize ()
4729 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4731 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4732 selection->tracks.contains (_pending_resize_view)) {
4734 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4735 if (*i != _pending_resize_view) {
4736 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4741 _pending_resize_amount = 0;
4742 _group_tabs->set_dirty ();
4743 resize_idle_id = -1;
4751 ENSURE_GUI_THREAD (*this, &Editor::located);
4754 playhead_cursor->set_position (_session->audible_frame ());
4755 if (_follow_playhead && !_pending_initial_locate) {
4756 reset_x_origin_to_follow_playhead ();
4760 _pending_locate_request = false;
4761 _pending_initial_locate = false;
4765 Editor::region_view_added (RegionView *)
4767 _summary->set_dirty ();
4771 Editor::region_view_removed ()
4773 _summary->set_dirty ();
4777 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4779 TrackViewList::const_iterator j = track_views.begin ();
4780 while (j != track_views.end()) {
4781 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4782 if (rtv && rtv->route() == r) {
4793 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4797 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4798 TimeAxisView* tv = axis_view_from_route (*i);
4808 Editor::add_routes (RouteList& routes)
4810 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4812 RouteTimeAxisView *rtv;
4813 list<RouteTimeAxisView*> new_views;
4815 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4816 boost::shared_ptr<Route> route = (*x);
4818 if (route->is_auditioner() || route->is_monitor()) {
4822 DataType dt = route->input()->default_type();
4824 if (dt == ARDOUR::DataType::AUDIO) {
4825 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4826 rtv->set_route (route);
4827 } else if (dt == ARDOUR::DataType::MIDI) {
4828 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4829 rtv->set_route (route);
4831 throw unknown_type();
4834 new_views.push_back (rtv);
4835 track_views.push_back (rtv);
4837 rtv->effective_gain_display ();
4839 if (internal_editing()) {
4840 rtv->enter_internal_edit_mode ();
4842 rtv->leave_internal_edit_mode ();
4845 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4846 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4849 if (new_views.size() > 0) {
4850 _routes->routes_added (new_views);
4851 _summary->routes_added (new_views);
4854 if (show_editor_mixer_when_tracks_arrive) {
4855 show_editor_mixer (true);
4858 editor_list_button.set_sensitive (true);
4862 Editor::timeaxisview_deleted (TimeAxisView *tv)
4864 if (_session && _session->deletion_in_progress()) {
4865 /* the situation is under control */
4869 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4871 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4873 _routes->route_removed (tv);
4875 if (tv == entered_track) {
4879 TimeAxisView::Children c = tv->get_child_list ();
4880 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4881 if (entered_track == i->get()) {
4886 /* remove it from the list of track views */
4888 TrackViewList::iterator i;
4890 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4891 i = track_views.erase (i);
4894 /* update whatever the current mixer strip is displaying, if revelant */
4896 boost::shared_ptr<Route> route;
4899 route = rtav->route ();
4902 if (current_mixer_strip && current_mixer_strip->route() == route) {
4904 TimeAxisView* next_tv;
4906 if (track_views.empty()) {
4908 } else if (i == track_views.end()) {
4909 next_tv = track_views.front();
4916 set_selected_mixer_strip (*next_tv);
4918 /* make the editor mixer strip go away setting the
4919 * button to inactive (which also unticks the menu option)
4922 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4928 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4930 if (apply_to_selection) {
4931 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4933 TrackSelection::iterator j = i;
4936 hide_track_in_display (*i, false);
4941 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4943 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4944 // this will hide the mixer strip
4945 set_selected_mixer_strip (*tv);
4948 _routes->hide_track_in_display (*tv);
4953 Editor::sync_track_view_list_and_routes ()
4955 track_views = TrackViewList (_routes->views ());
4957 _summary->set_dirty ();
4958 _group_tabs->set_dirty ();
4960 return false; // do not call again (until needed)
4964 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4966 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4971 /** Find a RouteTimeAxisView by the ID of its route */
4973 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4975 RouteTimeAxisView* v;
4977 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4978 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4979 if(v->route()->id() == id) {
4989 Editor::fit_route_group (RouteGroup *g)
4991 TrackViewList ts = axis_views_from_routes (g->route_list ());
4996 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4998 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5001 _session->cancel_audition ();
5005 if (_session->is_auditioning()) {
5006 _session->cancel_audition ();
5007 if (r == last_audition_region) {
5012 _session->audition_region (r);
5013 last_audition_region = r;
5018 Editor::hide_a_region (boost::shared_ptr<Region> r)
5020 r->set_hidden (true);
5024 Editor::show_a_region (boost::shared_ptr<Region> r)
5026 r->set_hidden (false);
5030 Editor::audition_region_from_region_list ()
5032 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5036 Editor::hide_region_from_region_list ()
5038 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5042 Editor::show_region_in_region_list ()
5044 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5048 Editor::step_edit_status_change (bool yn)
5051 start_step_editing ();
5053 stop_step_editing ();
5058 Editor::start_step_editing ()
5060 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5064 Editor::stop_step_editing ()
5066 step_edit_connection.disconnect ();
5070 Editor::check_step_edit ()
5072 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5073 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5075 mtv->check_step_edit ();
5079 return true; // do it again, till we stop
5083 Editor::scroll_press (Direction dir)
5085 ++_scroll_callbacks;
5087 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5088 /* delay the first auto-repeat */
5094 scroll_backward (1);
5102 scroll_tracks_up_line ();
5106 scroll_tracks_down_line ();
5110 /* do hacky auto-repeat */
5111 if (!_scroll_connection.connected ()) {
5113 _scroll_connection = Glib::signal_timeout().connect (
5114 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5117 _scroll_callbacks = 0;
5124 Editor::scroll_release ()
5126 _scroll_connection.disconnect ();
5129 /** Queue a change for the Editor viewport x origin to follow the playhead */
5131 Editor::reset_x_origin_to_follow_playhead ()
5133 framepos_t const frame = playhead_cursor->current_frame ();
5135 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5137 if (_session->transport_speed() < 0) {
5139 if (frame > (current_page_samples() / 2)) {
5140 center_screen (frame-(current_page_samples()/2));
5142 center_screen (current_page_samples()/2);
5149 if (frame < leftmost_frame) {
5151 if (_session->transport_rolling()) {
5152 /* rolling; end up with the playhead at the right of the page */
5153 l = frame - current_page_samples ();
5155 /* not rolling: end up with the playhead 1/4 of the way along the page */
5156 l = frame - current_page_samples() / 4;
5160 if (_session->transport_rolling()) {
5161 /* rolling: end up with the playhead on the left of the page */
5164 /* not rolling: end up with the playhead 3/4 of the way along the page */
5165 l = frame - 3 * current_page_samples() / 4;
5173 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5179 Editor::super_rapid_screen_update ()
5181 if (!_session || !_session->engine().running()) {
5185 /* METERING / MIXER STRIPS */
5187 /* update track meters, if required */
5188 if (is_mapped() && meters_running) {
5189 RouteTimeAxisView* rtv;
5190 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5191 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5192 rtv->fast_update ();
5197 /* and any current mixer strip */
5198 if (current_mixer_strip) {
5199 current_mixer_strip->fast_update ();
5202 /* PLAYHEAD AND VIEWPORT */
5204 framepos_t const frame = _session->audible_frame();
5206 /* There are a few reasons why we might not update the playhead / viewport stuff:
5208 * 1. we don't update things when there's a pending locate request, otherwise
5209 * when the editor requests a locate there is a chance that this method
5210 * will move the playhead before the locate request is processed, causing
5212 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5213 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5216 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5218 last_update_frame = frame;
5220 if (!_dragging_playhead) {
5221 playhead_cursor->set_position (frame);
5224 if (!_stationary_playhead) {
5226 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5227 /* We only do this if we aren't already
5228 handling a visual change (ie if
5229 pending_visual_change.being_handled is
5230 false) so that these requests don't stack
5231 up there are too many of them to handle in
5234 reset_x_origin_to_follow_playhead ();
5239 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5243 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5244 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5245 if (target <= 0.0) {
5248 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5249 target = (target * 0.15) + (current * 0.85);
5255 set_horizontal_position (current);
5264 Editor::session_going_away ()
5266 _have_idled = false;
5268 _session_connections.drop_connections ();
5270 super_rapid_screen_update_connection.disconnect ();
5272 selection->clear ();
5273 cut_buffer->clear ();
5275 clicked_regionview = 0;
5276 clicked_axisview = 0;
5277 clicked_routeview = 0;
5278 entered_regionview = 0;
5280 last_update_frame = 0;
5283 playhead_cursor->hide ();
5285 /* rip everything out of the list displays */
5289 _route_groups->clear ();
5291 /* do this first so that deleting a track doesn't reset cms to null
5292 and thus cause a leak.
5295 if (current_mixer_strip) {
5296 if (current_mixer_strip->get_parent() != 0) {
5297 global_hpacker.remove (*current_mixer_strip);
5299 delete current_mixer_strip;
5300 current_mixer_strip = 0;
5303 /* delete all trackviews */
5305 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5308 track_views.clear ();
5310 zoom_range_clock->set_session (0);
5311 nudge_clock->set_session (0);
5313 editor_list_button.set_active(false);
5314 editor_list_button.set_sensitive(false);
5316 /* clear tempo/meter rulers */
5317 remove_metric_marks ();
5319 clear_marker_display ();
5321 stop_step_editing ();
5323 /* get rid of any existing editor mixer strip */
5325 WindowTitle title(Glib::get_application_name());
5326 title += _("Editor");
5328 set_title (title.get_string());
5330 SessionHandlePtr::session_going_away ();
5335 Editor::show_editor_list (bool yn)
5338 _the_notebook.show ();
5340 _the_notebook.hide ();
5345 Editor::change_region_layering_order (bool from_context_menu)
5347 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5349 if (!clicked_routeview) {
5350 if (layering_order_editor) {
5351 layering_order_editor->hide ();
5356 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5362 boost::shared_ptr<Playlist> pl = track->playlist();
5368 if (layering_order_editor == 0) {
5369 layering_order_editor = new RegionLayeringOrderEditor (*this);
5372 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5373 layering_order_editor->maybe_present ();
5377 Editor::update_region_layering_order_editor ()
5379 if (layering_order_editor && layering_order_editor->is_visible ()) {
5380 change_region_layering_order (true);
5385 Editor::setup_fade_images ()
5387 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5388 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5389 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5390 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5391 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5393 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5394 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5395 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5396 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5397 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5399 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5400 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5401 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5402 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5403 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5405 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5406 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5407 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5408 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5409 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5413 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5415 Editor::action_menu_item (std::string const & name)
5417 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5420 return *manage (a->create_menu_item ());
5424 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5426 EventBox* b = manage (new EventBox);
5427 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5428 Label* l = manage (new Label (name));
5432 _the_notebook.append_page (widget, *b);
5436 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5438 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5439 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5442 if (ev->type == GDK_2BUTTON_PRESS) {
5444 /* double-click on a notebook tab shrinks or expands the notebook */
5446 if (_notebook_shrunk) {
5447 if (pre_notebook_shrink_pane_width) {
5448 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5450 _notebook_shrunk = false;
5452 pre_notebook_shrink_pane_width = edit_pane.get_position();
5454 /* this expands the LHS of the edit pane to cover the notebook
5455 PAGE but leaves the tabs visible.
5457 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5458 _notebook_shrunk = true;
5466 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5468 using namespace Menu_Helpers;
5470 MenuList& items = _control_point_context_menu.items ();
5473 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5474 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5475 if (!can_remove_control_point (item)) {
5476 items.back().set_sensitive (false);
5479 _control_point_context_menu.popup (event->button.button, event->button.time);
5483 Editor::zoom_vertical_modifier_released()
5485 _stepping_axis_view = 0;