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"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
86 #include "control_protocol/control_protocol.h"
89 #include "analysis_window.h"
90 #include "audio_clock.h"
91 #include "audio_region_view.h"
92 #include "audio_streamview.h"
93 #include "audio_time_axis.h"
94 #include "automation_time_axis.h"
95 #include "bundle_manager.h"
96 #include "crossfade_edit.h"
100 #include "editor_cursors.h"
101 #include "editor_drag.h"
102 #include "editor_group_tabs.h"
103 #include "editor_locations.h"
104 #include "editor_regions.h"
105 #include "editor_route_groups.h"
106 #include "editor_routes.h"
107 #include "editor_snapshots.h"
108 #include "editor_summary.h"
109 #include "export_report.h"
110 #include "global_port_matrix.h"
111 #include "gui_object.h"
112 #include "gui_thread.h"
113 #include "keyboard.h"
114 #include "keyeditor.h"
115 #include "luainstance.h"
117 #include "midi_region_view.h"
118 #include "midi_time_axis.h"
119 #include "mixer_strip.h"
120 #include "mixer_ui.h"
121 #include "mouse_cursors.h"
122 #include "note_base.h"
123 #include "playlist_selector.h"
124 #include "public_editor.h"
125 #include "quantize_dialog.h"
126 #include "region_layering_order_editor.h"
127 #include "rgb_macros.h"
128 #include "rhythm_ferret.h"
129 #include "route_sorter.h"
130 #include "selection.h"
131 #include "simple_progress_dialog.h"
133 #include "tempo_lines.h"
134 #include "time_axis_view.h"
135 #include "time_info_box.h"
137 #include "tooltips.h"
138 #include "ui_config.h"
140 #include "vca_time_axis.h"
141 #include "verbose_cursor.h"
143 #include "pbd/i18n.h"
146 using namespace ARDOUR;
147 using namespace ARDOUR_UI_UTILS;
150 using namespace Glib;
151 using namespace Gtkmm2ext;
152 using namespace Editing;
154 using PBD::internationalize;
156 using Gtkmm2ext::Keyboard;
158 double Editor::timebar_height = 15.0;
160 static const gchar *_snap_type_strings[] = {
194 static const gchar *_snap_mode_strings[] = {
201 static const gchar *_edit_point_strings[] = {
208 static const gchar *_edit_mode_strings[] = {
216 static const gchar *_zoom_focus_strings[] = {
226 #ifdef USE_RUBBERBAND
227 static const gchar *_rb_opt_strings[] = {
230 N_("Balanced multitimbral mixture"),
231 N_("Unpitched percussion with stable notes"),
232 N_("Crisp monophonic instrumental"),
233 N_("Unpitched solo percussion"),
234 N_("Resample without preserving pitch"),
239 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
242 : PublicEditor (global_hpacker)
243 , editor_mixer_strip_width (Wide)
244 , constructed (false)
245 , _playlist_selector (0)
247 , no_save_visual (false)
249 , samples_per_pixel (2048)
250 , zoom_focus (ZoomFocusPlayhead)
251 , mouse_mode (MouseObject)
252 , pre_internal_snap_type (SnapToBeat)
253 , pre_internal_snap_mode (SnapOff)
254 , internal_snap_type (SnapToBeat)
255 , internal_snap_mode (SnapOff)
256 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
257 , _notebook_shrunk (false)
258 , location_marker_color (0)
259 , location_range_color (0)
260 , location_loop_color (0)
261 , location_punch_color (0)
262 , location_cd_marker_color (0)
264 , _show_marker_lines (false)
265 , clicked_axisview (0)
266 , clicked_routeview (0)
267 , clicked_regionview (0)
268 , clicked_selection (0)
269 , clicked_control_point (0)
270 , button_release_can_deselect (true)
271 , _mouse_changed_selection (false)
272 , region_edit_menu_split_item (0)
273 , region_edit_menu_split_multichannel_item (0)
274 , track_region_edit_playlist_menu (0)
275 , track_edit_playlist_submenu (0)
276 , track_selection_edit_playlist_submenu (0)
277 , _popup_region_menu_item (0)
279 , _track_canvas_viewport (0)
280 , within_track_canvas (false)
281 , _verbose_cursor (0)
285 , range_marker_group (0)
286 , transport_marker_group (0)
287 , cd_marker_group (0)
288 , _time_markers_group (0)
289 , hv_scroll_group (0)
291 , cursor_scroll_group (0)
292 , no_scroll_group (0)
293 , _trackview_group (0)
294 , _drag_motion_group (0)
295 , _canvas_drop_zone (0)
296 , no_ruler_shown_update (false)
297 , ruler_grabbed_widget (0)
299 , minsec_mark_interval (0)
300 , minsec_mark_modulo (0)
302 , timecode_mark_modulo (0)
303 , timecode_nmarks (0)
304 , _samples_ruler_interval (0)
307 , bbt_bar_helper_on (0)
308 , bbt_accent_modulo (0)
313 , visible_timebars (0)
314 , editor_ruler_menu (0)
318 , range_marker_bar (0)
319 , transport_marker_bar (0)
321 , minsec_label (_("Mins:Secs"))
322 , bbt_label (_("Bars:Beats"))
323 , timecode_label (_("Timecode"))
324 , samples_label (_("Samples"))
325 , tempo_label (_("Tempo"))
326 , meter_label (_("Meter"))
327 , mark_label (_("Location Markers"))
328 , range_mark_label (_("Range Markers"))
329 , transport_mark_label (_("Loop/Punch Ranges"))
330 , cd_mark_label (_("CD Markers"))
331 , videotl_label (_("Video Timeline"))
333 , playhead_cursor (0)
334 , edit_packer (4, 4, true)
335 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
336 , horizontal_adjustment (0.0, 0.0, 1e16)
337 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
338 , controls_layout (unused_adjustment, vertical_adjustment)
339 , _scroll_callbacks (0)
340 , _visible_canvas_width (0)
341 , _visible_canvas_height (0)
342 , _full_canvas_height (0)
343 , edit_controls_left_menu (0)
344 , edit_controls_right_menu (0)
345 , last_update_frame (0)
346 , cut_buffer_start (0)
347 , cut_buffer_length (0)
348 , button_bindings (0)
352 , current_interthread_info (0)
353 , analysis_window (0)
354 , select_new_marker (false)
356 , scrubbing_direction (0)
357 , scrub_reversals (0)
358 , scrub_reverse_distance (0)
359 , have_pending_keyboard_selection (false)
360 , pending_keyboard_selection_start (0)
361 , _snap_type (SnapToBeat)
362 , _snap_mode (SnapOff)
363 , snap_threshold (5.0)
364 , ignore_gui_changes (false)
365 , _drags (new DragManager (this))
367 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
368 , _dragging_playhead (false)
369 , _dragging_edit_point (false)
370 , _show_measures (true)
371 , _follow_playhead (true)
372 , _stationary_playhead (false)
375 , global_rect_group (0)
376 , time_line_group (0)
377 , tempo_marker_menu (0)
378 , meter_marker_menu (0)
380 , range_marker_menu (0)
381 , transport_marker_menu (0)
382 , new_transport_marker_menu (0)
384 , marker_menu_item (0)
385 , bbt_beat_subdivision (4)
386 , _visible_track_count (-1)
387 , toolbar_selection_clock_table (2,3)
388 , automation_mode_button (_("mode"))
389 , selection (new Selection (this))
390 , cut_buffer (new Selection (this))
391 , _selection_memento (new SelectionMemento())
392 , _all_region_actions_sensitized (false)
393 , _ignore_region_action (false)
394 , _last_region_menu_was_main (false)
395 , _ignore_follow_edits (false)
396 , cd_marker_bar_drag_rect (0)
397 , range_bar_drag_rect (0)
398 , transport_bar_drag_rect (0)
399 , transport_bar_range_rect (0)
400 , transport_bar_preroll_rect (0)
401 , transport_bar_postroll_rect (0)
402 , transport_loop_range_rect (0)
403 , transport_punch_range_rect (0)
404 , transport_punchin_line (0)
405 , transport_punchout_line (0)
406 , transport_preroll_rect (0)
407 , transport_postroll_rect (0)
409 , rubberband_rect (0)
415 , autoscroll_horizontal_allowed (false)
416 , autoscroll_vertical_allowed (false)
418 , autoscroll_widget (0)
419 , show_gain_after_trim (false)
420 , selection_op_cmd_depth (0)
421 , selection_op_history_it (0)
422 , no_save_instant (false)
424 , current_mixer_strip (0)
425 , show_editor_mixer_when_tracks_arrive (false)
426 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
427 , current_stepping_trackview (0)
428 , last_track_height_step_timestamp (0)
430 , entered_regionview (0)
431 , clear_entered_track (false)
432 , _edit_point (EditAtMouse)
433 , meters_running (false)
435 , _have_idled (false)
436 , resize_idle_id (-1)
437 , _pending_resize_amount (0)
438 , _pending_resize_view (0)
439 , _pending_locate_request (false)
440 , _pending_initial_locate (false)
444 , layering_order_editor (0)
445 , _last_cut_copy_source_track (0)
446 , _region_selection_change_updates_region_list (true)
448 , _following_mixer_selection (false)
449 , _control_point_toggled_on_press (false)
450 , _stepping_axis_view (0)
451 , quantize_dialog (0)
452 , _main_menu_disabler (0)
453 , myactions (X_("editor"))
455 /* we are a singleton */
457 PublicEditor::_instance = this;
461 last_event_time.tv_sec = 0;
462 last_event_time.tv_usec = 0;
464 selection_op_history.clear();
467 snap_type_strings = I18N (_snap_type_strings);
468 snap_mode_strings = I18N (_snap_mode_strings);
469 zoom_focus_strings = I18N (_zoom_focus_strings);
470 edit_mode_strings = I18N (_edit_mode_strings);
471 edit_point_strings = I18N (_edit_point_strings);
472 #ifdef USE_RUBBERBAND
473 rb_opt_strings = I18N (_rb_opt_strings);
477 build_edit_mode_menu();
478 build_zoom_focus_menu();
479 build_track_count_menu();
480 build_snap_mode_menu();
481 build_snap_type_menu();
482 build_edit_point_menu();
484 location_marker_color = UIConfiguration::instance().color ("location marker");
485 location_range_color = UIConfiguration::instance().color ("location range");
486 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
487 location_loop_color = UIConfiguration::instance().color ("location loop");
488 location_punch_color = UIConfiguration::instance().color ("location punch");
490 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
492 TimeAxisView::setup_sizes ();
493 ArdourMarker::setup_sizes (timebar_height);
494 TempoCurve::setup_sizes (timebar_height);
496 bbt_label.set_name ("EditorRulerLabel");
497 bbt_label.set_size_request (-1, (int)timebar_height);
498 bbt_label.set_alignment (1.0, 0.5);
499 bbt_label.set_padding (5,0);
501 bbt_label.set_no_show_all();
502 minsec_label.set_name ("EditorRulerLabel");
503 minsec_label.set_size_request (-1, (int)timebar_height);
504 minsec_label.set_alignment (1.0, 0.5);
505 minsec_label.set_padding (5,0);
506 minsec_label.hide ();
507 minsec_label.set_no_show_all();
508 timecode_label.set_name ("EditorRulerLabel");
509 timecode_label.set_size_request (-1, (int)timebar_height);
510 timecode_label.set_alignment (1.0, 0.5);
511 timecode_label.set_padding (5,0);
512 timecode_label.hide ();
513 timecode_label.set_no_show_all();
514 samples_label.set_name ("EditorRulerLabel");
515 samples_label.set_size_request (-1, (int)timebar_height);
516 samples_label.set_alignment (1.0, 0.5);
517 samples_label.set_padding (5,0);
518 samples_label.hide ();
519 samples_label.set_no_show_all();
521 tempo_label.set_name ("EditorRulerLabel");
522 tempo_label.set_size_request (-1, (int)timebar_height);
523 tempo_label.set_alignment (1.0, 0.5);
524 tempo_label.set_padding (5,0);
526 tempo_label.set_no_show_all();
528 meter_label.set_name ("EditorRulerLabel");
529 meter_label.set_size_request (-1, (int)timebar_height);
530 meter_label.set_alignment (1.0, 0.5);
531 meter_label.set_padding (5,0);
533 meter_label.set_no_show_all();
535 if (Profile->get_trx()) {
536 mark_label.set_text (_("Markers"));
538 mark_label.set_name ("EditorRulerLabel");
539 mark_label.set_size_request (-1, (int)timebar_height);
540 mark_label.set_alignment (1.0, 0.5);
541 mark_label.set_padding (5,0);
543 mark_label.set_no_show_all();
545 cd_mark_label.set_name ("EditorRulerLabel");
546 cd_mark_label.set_size_request (-1, (int)timebar_height);
547 cd_mark_label.set_alignment (1.0, 0.5);
548 cd_mark_label.set_padding (5,0);
549 cd_mark_label.hide();
550 cd_mark_label.set_no_show_all();
552 videotl_bar_height = 4;
553 videotl_label.set_name ("EditorRulerLabel");
554 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
555 videotl_label.set_alignment (1.0, 0.5);
556 videotl_label.set_padding (5,0);
557 videotl_label.hide();
558 videotl_label.set_no_show_all();
560 range_mark_label.set_name ("EditorRulerLabel");
561 range_mark_label.set_size_request (-1, (int)timebar_height);
562 range_mark_label.set_alignment (1.0, 0.5);
563 range_mark_label.set_padding (5,0);
564 range_mark_label.hide();
565 range_mark_label.set_no_show_all();
567 transport_mark_label.set_name ("EditorRulerLabel");
568 transport_mark_label.set_size_request (-1, (int)timebar_height);
569 transport_mark_label.set_alignment (1.0, 0.5);
570 transport_mark_label.set_padding (5,0);
571 transport_mark_label.hide();
572 transport_mark_label.set_no_show_all();
574 initialize_canvas ();
576 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
578 _summary = new EditorSummary (this);
580 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
581 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
583 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
585 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
586 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
588 edit_controls_vbox.set_spacing (0);
589 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
590 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
592 HBox* h = manage (new HBox);
593 _group_tabs = new EditorGroupTabs (this);
594 if (!ARDOUR::Profile->get_trx()) {
595 h->pack_start (*_group_tabs, PACK_SHRINK);
597 h->pack_start (edit_controls_vbox);
598 controls_layout.add (*h);
600 controls_layout.set_name ("EditControlsBase");
601 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
602 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
603 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
605 _cursors = new MouseCursors;
606 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
607 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
609 /* Push default cursor to ever-present bottom of cursor stack. */
610 push_canvas_cursor(_cursors->grabber);
612 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
614 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
615 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
616 pad_line_1->set_outline_color (0xFF0000FF);
622 edit_packer.set_col_spacings (0);
623 edit_packer.set_row_spacings (0);
624 edit_packer.set_homogeneous (false);
625 edit_packer.set_border_width (0);
626 edit_packer.set_name ("EditorWindow");
628 time_bars_event_box.add (time_bars_vbox);
629 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
630 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
632 /* labels for the time bars */
633 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
635 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
637 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
639 bottom_hbox.set_border_width (2);
640 bottom_hbox.set_spacing (3);
642 _route_groups = new EditorRouteGroups (this);
643 _routes = new EditorRoutes (this);
644 _regions = new EditorRegions (this);
645 _snapshots = new EditorSnapshots (this);
646 _locations = new EditorLocations (this);
647 _time_info_box = new TimeInfoBox ();
649 /* these are static location signals */
651 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
655 add_notebook_page (_("Regions"), _regions->widget ());
656 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
657 add_notebook_page (_("Snapshots"), _snapshots->widget ());
658 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
659 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
661 _the_notebook.set_show_tabs (true);
662 _the_notebook.set_scrollable (true);
663 _the_notebook.popup_disable ();
664 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
665 _the_notebook.show_all ();
667 _notebook_shrunk = false;
670 /* Pick up some settings we need to cache, early */
672 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
675 if (settings && (prop = settings->property ("notebook-shrunk"))) {
676 _notebook_shrunk = string_is_affirmative (prop->value ());
679 editor_summary_pane.set_check_divider_position (true);
680 editor_summary_pane.add (edit_packer);
682 Button* summary_arrows_left_left = manage (new Button);
683 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
684 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
685 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
687 Button* summary_arrows_left_right = manage (new Button);
688 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
689 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
690 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
692 VBox* summary_arrows_left = manage (new VBox);
693 summary_arrows_left->pack_start (*summary_arrows_left_left);
694 summary_arrows_left->pack_start (*summary_arrows_left_right);
696 Button* summary_arrows_right_up = manage (new Button);
697 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
698 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
699 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
701 Button* summary_arrows_right_down = manage (new Button);
702 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
703 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
704 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
706 VBox* summary_arrows_right = manage (new VBox);
707 summary_arrows_right->pack_start (*summary_arrows_right_up);
708 summary_arrows_right->pack_start (*summary_arrows_right_down);
710 Frame* summary_frame = manage (new Frame);
711 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
713 summary_frame->add (*_summary);
714 summary_frame->show ();
716 _summary_hbox.pack_start (*summary_arrows_left, false, false);
717 _summary_hbox.pack_start (*summary_frame, true, true);
718 _summary_hbox.pack_start (*summary_arrows_right, false, false);
720 if (!ARDOUR::Profile->get_trx()) {
721 editor_summary_pane.add (_summary_hbox);
724 edit_pane.set_check_divider_position (true);
725 edit_pane.add (editor_summary_pane);
726 if (!ARDOUR::Profile->get_trx()) {
727 VBox* editor_list_vbox = manage (new VBox);
728 editor_list_vbox->pack_start (*_time_info_box, false, false, 0);
729 editor_list_vbox->pack_start (_the_notebook);
730 edit_pane.add (*editor_list_vbox);
731 edit_pane.set_child_minsize (*editor_list_vbox, 30); /* rough guess at width of notebook tabs */
734 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
735 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
742 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
743 /* initial allocation is 90% to canvas, 10% to notebook */
744 edit_pane.set_divider (0, 0.90);
746 edit_pane.set_divider (0, fract);
749 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
750 /* initial allocation is 90% to canvas, 10% to summary */
751 editor_summary_pane.set_divider (0, 0.90);
754 editor_summary_pane.set_divider (0, fract);
758 global_vpacker.set_spacing (2);
759 global_vpacker.set_border_width (0);
760 global_vpacker.pack_start (toolbar_hbox, false, false);
761 global_vpacker.pack_start (edit_pane, true, true);
762 global_hpacker.pack_start (global_vpacker, true, true);
764 /* need to show the "contents" widget so that notebook will show if tab is switched to
767 global_hpacker.show ();
769 /* register actions now so that set_state() can find them and set toggles/checks etc */
776 _playlist_selector = new PlaylistSelector();
777 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
779 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
783 nudge_forward_button.set_name ("nudge button");
784 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
786 nudge_backward_button.set_name ("nudge button");
787 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
789 fade_context_menu.set_name ("ArdourContextMenu");
791 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
793 /* allow external control surfaces/protocols to do various things */
795 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
796 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
797 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
798 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
799 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
800 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
801 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
802 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
803 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
804 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
805 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
806 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
807 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
808 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
810 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
811 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
812 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
813 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
814 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
816 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
820 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
822 /* problematic: has to return a value and thus cannot be x-thread */
824 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
826 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
827 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
829 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
831 _ignore_region_action = false;
832 _last_region_menu_was_main = false;
833 _popup_region_menu_item = 0;
835 _ignore_follow_edits = false;
837 _show_marker_lines = false;
839 /* Button bindings */
841 button_bindings = new Bindings ("editor-mouse");
843 XMLNode* node = button_settings();
845 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
846 button_bindings->load_operation (**i);
852 /* grab current parameter state */
853 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
854 UIConfiguration::instance().map_parameters (pc);
856 setup_fade_images ();
858 LuaInstance::instance(); // instantiate
859 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
866 delete button_bindings;
868 delete _route_groups;
869 delete _track_canvas_viewport;
872 delete _verbose_cursor;
873 delete quantize_dialog;
879 delete _playlist_selector;
880 delete _time_info_box;
882 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
888 Editor::button_settings () const
890 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
891 XMLNode* node = find_named_node (*settings, X_("Buttons"));
894 node = new XMLNode (X_("Buttons"));
901 Editor::get_smart_mode () const
903 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
907 Editor::catch_vanishing_regionview (RegionView *rv)
909 /* note: the selection will take care of the vanishing
910 audioregionview by itself.
913 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
917 if (clicked_regionview == rv) {
918 clicked_regionview = 0;
921 if (entered_regionview == rv) {
922 set_entered_regionview (0);
925 if (!_all_region_actions_sensitized) {
926 sensitize_all_region_actions (true);
931 Editor::set_entered_regionview (RegionView* rv)
933 if (rv == entered_regionview) {
937 if (entered_regionview) {
938 entered_regionview->exited ();
941 entered_regionview = rv;
943 if (entered_regionview != 0) {
944 entered_regionview->entered ();
947 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
948 /* This RegionView entry might have changed what region actions
949 are allowed, so sensitize them all in case a key is pressed.
951 sensitize_all_region_actions (true);
956 Editor::set_entered_track (TimeAxisView* tav)
959 entered_track->exited ();
965 entered_track->entered ();
970 Editor::instant_save ()
972 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
977 _session->add_instant_xml(get_state());
979 Config->add_instant_xml(get_state());
984 Editor::control_vertical_zoom_in_all ()
986 tav_zoom_smooth (false, true);
990 Editor::control_vertical_zoom_out_all ()
992 tav_zoom_smooth (true, true);
996 Editor::control_vertical_zoom_in_selected ()
998 tav_zoom_smooth (false, false);
1002 Editor::control_vertical_zoom_out_selected ()
1004 tav_zoom_smooth (true, false);
1008 Editor::control_view (uint32_t view)
1010 goto_visual_state (view);
1014 Editor::control_unselect ()
1016 selection->clear_tracks ();
1020 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1022 TimeAxisView* tav = axis_view_from_stripable (s);
1026 case Selection::Add:
1027 selection->add (tav);
1029 case Selection::Toggle:
1030 selection->toggle (tav);
1032 case Selection::Extend:
1034 case Selection::Set:
1035 selection->set (tav);
1039 selection->clear_tracks ();
1044 Editor::control_step_tracks_up ()
1046 scroll_tracks_up_line ();
1050 Editor::control_step_tracks_down ()
1052 scroll_tracks_down_line ();
1056 Editor::control_scroll (float fraction)
1058 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1064 double step = fraction * current_page_samples();
1067 _control_scroll_target is an optional<T>
1069 it acts like a pointer to an framepos_t, with
1070 a operator conversion to boolean to check
1071 that it has a value could possibly use
1072 playhead_cursor->current_frame to store the
1073 value and a boolean in the class to know
1074 when it's out of date
1077 if (!_control_scroll_target) {
1078 _control_scroll_target = _session->transport_frame();
1079 _dragging_playhead = true;
1082 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1083 *_control_scroll_target = 0;
1084 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1085 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1087 *_control_scroll_target += (framepos_t) trunc (step);
1090 /* move visuals, we'll catch up with it later */
1092 playhead_cursor->set_position (*_control_scroll_target);
1093 UpdateAllTransportClocks (*_control_scroll_target);
1095 if (*_control_scroll_target > (current_page_samples() / 2)) {
1096 /* try to center PH in window */
1097 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1103 Now we do a timeout to actually bring the session to the right place
1104 according to the playhead. This is to avoid reading disk buffers on every
1105 call to control_scroll, which is driven by ScrollTimeline and therefore
1106 probably by a control surface wheel which can generate lots of events.
1108 /* cancel the existing timeout */
1110 control_scroll_connection.disconnect ();
1112 /* add the next timeout */
1114 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1118 Editor::deferred_control_scroll (framepos_t /*target*/)
1120 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1121 // reset for next stream
1122 _control_scroll_target = boost::none;
1123 _dragging_playhead = false;
1128 Editor::access_action (std::string action_group, std::string action_item)
1134 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1137 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1145 Editor::on_realize ()
1149 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1150 start_lock_event_timing ();
1155 Editor::start_lock_event_timing ()
1157 /* check if we should lock the GUI every 30 seconds */
1159 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1163 Editor::generic_event_handler (GdkEvent* ev)
1166 case GDK_BUTTON_PRESS:
1167 case GDK_BUTTON_RELEASE:
1168 case GDK_MOTION_NOTIFY:
1170 case GDK_KEY_RELEASE:
1171 if (contents().is_mapped()) {
1172 gettimeofday (&last_event_time, 0);
1176 case GDK_LEAVE_NOTIFY:
1177 switch (ev->crossing.detail) {
1178 case GDK_NOTIFY_UNKNOWN:
1179 case GDK_NOTIFY_INFERIOR:
1180 case GDK_NOTIFY_ANCESTOR:
1182 case GDK_NOTIFY_VIRTUAL:
1183 case GDK_NOTIFY_NONLINEAR:
1184 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1185 /* leaving window, so reset focus, thus ending any and
1186 all text entry operations.
1188 ARDOUR_UI::instance()->reset_focus (&contents());
1201 Editor::lock_timeout_callback ()
1203 struct timeval now, delta;
1205 gettimeofday (&now, 0);
1207 timersub (&now, &last_event_time, &delta);
1209 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1211 /* don't call again. Returning false will effectively
1212 disconnect us from the timer callback.
1214 unlock() will call start_lock_event_timing() to get things
1224 Editor::map_position_change (framepos_t frame)
1226 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1228 if (_session == 0) {
1232 if (_follow_playhead) {
1233 center_screen (frame);
1236 playhead_cursor->set_position (frame);
1240 Editor::center_screen (framepos_t frame)
1242 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1244 /* if we're off the page, then scroll.
1247 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1248 center_screen_internal (frame, page);
1253 Editor::center_screen_internal (framepos_t frame, float page)
1258 frame -= (framepos_t) page;
1263 reset_x_origin (frame);
1268 Editor::update_title ()
1270 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1272 if (!own_window()) {
1277 bool dirty = _session->dirty();
1279 string session_name;
1281 if (_session->snap_name() != _session->name()) {
1282 session_name = _session->snap_name();
1284 session_name = _session->name();
1288 session_name = "*" + session_name;
1291 WindowTitle title(session_name);
1292 title += S_("Window|Editor");
1293 title += Glib::get_application_name();
1294 own_window()->set_title (title.get_string());
1296 /* ::session_going_away() will have taken care of it */
1301 Editor::set_session (Session *t)
1303 SessionHandlePtr::set_session (t);
1309 _playlist_selector->set_session (_session);
1310 nudge_clock->set_session (_session);
1311 _summary->set_session (_session);
1312 _group_tabs->set_session (_session);
1313 _route_groups->set_session (_session);
1314 _regions->set_session (_session);
1315 _snapshots->set_session (_session);
1316 _routes->set_session (_session);
1317 _locations->set_session (_session);
1318 _time_info_box->set_session (_session);
1320 if (rhythm_ferret) {
1321 rhythm_ferret->set_session (_session);
1324 if (analysis_window) {
1325 analysis_window->set_session (_session);
1329 sfbrowser->set_session (_session);
1332 compute_fixed_ruler_scale ();
1334 /* Make sure we have auto loop and auto punch ranges */
1336 Location* loc = _session->locations()->auto_loop_location();
1338 loc->set_name (_("Loop"));
1341 loc = _session->locations()->auto_punch_location();
1344 loc->set_name (_("Punch"));
1347 refresh_location_display ();
1349 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1350 the selected Marker; this needs the LocationMarker list to be available.
1352 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1353 set_state (*node, Stateful::loading_state_version);
1355 /* catch up with the playhead */
1357 _session->request_locate (playhead_cursor->current_frame ());
1358 _pending_initial_locate = true;
1362 /* These signals can all be emitted by a non-GUI thread. Therefore the
1363 handlers for them must not attempt to directly interact with the GUI,
1364 but use PBD::Signal<T>::connect() which accepts an event loop
1365 ("context") where the handler will be asked to run.
1368 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1369 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1370 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1371 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1372 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1373 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1374 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1375 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1376 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1377 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1378 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1379 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1380 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1381 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1382 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1384 playhead_cursor->show ();
1386 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1387 Config->map_parameters (pc);
1388 _session->config.map_parameters (pc);
1390 restore_ruler_visibility ();
1391 //tempo_map_changed (PropertyChange (0));
1392 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1394 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1395 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1398 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1399 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1402 switch (_snap_type) {
1403 case SnapToRegionStart:
1404 case SnapToRegionEnd:
1405 case SnapToRegionSync:
1406 case SnapToRegionBoundary:
1407 build_region_boundary_cache ();
1414 /* catch up on selection of stripables (other selection state is lost
1415 * when a session is closed
1420 _session->get_stripables (sl);
1421 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1422 if ((*s)->presentation_info().selected()) {
1423 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1425 tl.push_back (rtav);
1430 selection->set (tl);
1433 /* register for undo history */
1434 _session->register_with_memento_command_factory(id(), this);
1435 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1437 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1439 LuaInstance::instance()->set_session(_session);
1441 start_updating_meters ();
1445 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1447 if (a->get_name() == "RegionMenu") {
1448 /* When the main menu's region menu is opened, we setup the actions so that they look right
1449 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1450 so we resensitize all region actions when the entered regionview or the region selection
1451 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1452 happens after the region context menu is opened. So we set a flag here, too.
1456 sensitize_the_right_region_actions ();
1457 _last_region_menu_was_main = true;
1462 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1464 using namespace Menu_Helpers;
1466 void (Editor::*emf)(FadeShape);
1467 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1470 images = &_xfade_in_images;
1471 emf = &Editor::set_fade_in_shape;
1473 images = &_xfade_out_images;
1474 emf = &Editor::set_fade_out_shape;
1479 _("Linear (for highly correlated material)"),
1480 *(*images)[FadeLinear],
1481 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1485 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1489 _("Constant power"),
1490 *(*images)[FadeConstantPower],
1491 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1494 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 *(*images)[FadeSymmetric],
1500 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1504 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1509 *(*images)[FadeSlow],
1510 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1513 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1518 *(*images)[FadeFast],
1519 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1522 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1525 /** Pop up a context menu for when the user clicks on a start crossfade */
1527 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1529 using namespace Menu_Helpers;
1530 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1535 MenuList& items (xfade_in_context_menu.items());
1538 if (arv->audio_region()->fade_in_active()) {
1539 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1541 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1544 items.push_back (SeparatorElem());
1545 fill_xfade_menu (items, true);
1547 xfade_in_context_menu.popup (button, time);
1550 /** Pop up a context menu for when the user clicks on an end crossfade */
1552 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1554 using namespace Menu_Helpers;
1555 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1560 MenuList& items (xfade_out_context_menu.items());
1563 if (arv->audio_region()->fade_out_active()) {
1564 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1566 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1569 items.push_back (SeparatorElem());
1570 fill_xfade_menu (items, false);
1572 xfade_out_context_menu.popup (button, time);
1576 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1578 using namespace Menu_Helpers;
1579 Menu* (Editor::*build_menu_function)();
1582 switch (item_type) {
1584 case RegionViewName:
1585 case RegionViewNameHighlight:
1586 case LeftFrameHandle:
1587 case RightFrameHandle:
1588 if (with_selection) {
1589 build_menu_function = &Editor::build_track_selection_context_menu;
1591 build_menu_function = &Editor::build_track_region_context_menu;
1596 if (with_selection) {
1597 build_menu_function = &Editor::build_track_selection_context_menu;
1599 build_menu_function = &Editor::build_track_context_menu;
1604 if (clicked_routeview->track()) {
1605 build_menu_function = &Editor::build_track_context_menu;
1607 build_menu_function = &Editor::build_track_bus_context_menu;
1612 /* probably shouldn't happen but if it does, we don't care */
1616 menu = (this->*build_menu_function)();
1617 menu->set_name ("ArdourContextMenu");
1619 /* now handle specific situations */
1621 switch (item_type) {
1623 case RegionViewName:
1624 case RegionViewNameHighlight:
1625 case LeftFrameHandle:
1626 case RightFrameHandle:
1627 if (!with_selection) {
1628 if (region_edit_menu_split_item) {
1629 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1630 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1632 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1635 if (region_edit_menu_split_multichannel_item) {
1636 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1637 region_edit_menu_split_multichannel_item->set_sensitive (true);
1639 region_edit_menu_split_multichannel_item->set_sensitive (false);
1652 /* probably shouldn't happen but if it does, we don't care */
1656 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1658 /* Bounce to disk */
1660 using namespace Menu_Helpers;
1661 MenuList& edit_items = menu->items();
1663 edit_items.push_back (SeparatorElem());
1665 switch (clicked_routeview->audio_track()->freeze_state()) {
1666 case AudioTrack::NoFreeze:
1667 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1670 case AudioTrack::Frozen:
1671 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1674 case AudioTrack::UnFrozen:
1675 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1681 if (item_type == StreamItem && clicked_routeview) {
1682 clicked_routeview->build_underlay_menu(menu);
1685 /* When the region menu is opened, we setup the actions so that they look right
1688 sensitize_the_right_region_actions ();
1689 _last_region_menu_was_main = false;
1691 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1692 menu->popup (button, time);
1696 Editor::build_track_context_menu ()
1698 using namespace Menu_Helpers;
1700 MenuList& edit_items = track_context_menu.items();
1703 add_dstream_context_items (edit_items);
1704 return &track_context_menu;
1708 Editor::build_track_bus_context_menu ()
1710 using namespace Menu_Helpers;
1712 MenuList& edit_items = track_context_menu.items();
1715 add_bus_context_items (edit_items);
1716 return &track_context_menu;
1720 Editor::build_track_region_context_menu ()
1722 using namespace Menu_Helpers;
1723 MenuList& edit_items = track_region_context_menu.items();
1726 /* we've just cleared the track region context menu, so the menu that these
1727 two items were on will have disappeared; stop them dangling.
1729 region_edit_menu_split_item = 0;
1730 region_edit_menu_split_multichannel_item = 0;
1732 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1735 boost::shared_ptr<Track> tr;
1736 boost::shared_ptr<Playlist> pl;
1738 if ((tr = rtv->track())) {
1739 add_region_context_items (edit_items, tr);
1743 add_dstream_context_items (edit_items);
1745 return &track_region_context_menu;
1749 Editor::loudness_analyze_region_selection ()
1754 Selection& s (PublicEditor::instance ().get_selection ());
1755 RegionSelection ars = s.regions;
1756 ARDOUR::AnalysisGraph ag (_session);
1757 framecnt_t total_work = 0;
1759 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1760 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1764 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1767 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1768 total_work += arv->region ()->length ();
1771 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1773 ag.set_total_frames (total_work);
1774 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1777 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1778 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1782 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1786 ag.analyze_region (ar);
1789 if (!ag.canceled ()) {
1790 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1796 Editor::loudness_analyze_range_selection ()
1801 Selection& s (PublicEditor::instance ().get_selection ());
1802 TimeSelection ts = s.time;
1803 ARDOUR::AnalysisGraph ag (_session);
1804 framecnt_t total_work = 0;
1806 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1807 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1811 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1815 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1816 total_work += j->length ();
1820 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1822 ag.set_total_frames (total_work);
1823 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1826 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1827 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1831 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1835 ag.analyze_range (rui->route (), pl, ts);
1838 if (!ag.canceled ()) {
1839 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1845 Editor::spectral_analyze_region_selection ()
1847 if (analysis_window == 0) {
1848 analysis_window = new AnalysisWindow();
1851 analysis_window->set_session(_session);
1853 analysis_window->show_all();
1856 analysis_window->set_regionmode();
1857 analysis_window->analyze();
1859 analysis_window->present();
1863 Editor::spectral_analyze_range_selection()
1865 if (analysis_window == 0) {
1866 analysis_window = new AnalysisWindow();
1869 analysis_window->set_session(_session);
1871 analysis_window->show_all();
1874 analysis_window->set_rangemode();
1875 analysis_window->analyze();
1877 analysis_window->present();
1881 Editor::build_track_selection_context_menu ()
1883 using namespace Menu_Helpers;
1884 MenuList& edit_items = track_selection_context_menu.items();
1885 edit_items.clear ();
1887 add_selection_context_items (edit_items);
1888 // edit_items.push_back (SeparatorElem());
1889 // add_dstream_context_items (edit_items);
1891 return &track_selection_context_menu;
1895 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1897 using namespace Menu_Helpers;
1899 /* OK, stick the region submenu at the top of the list, and then add
1903 RegionSelection rs = get_regions_from_selection_and_entered ();
1905 string::size_type pos = 0;
1906 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1908 /* we have to hack up the region name because "_" has a special
1909 meaning for menu titles.
1912 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1913 menu_item_name.replace (pos, 1, "__");
1917 if (_popup_region_menu_item == 0) {
1918 _popup_region_menu_item = new MenuItem (menu_item_name);
1919 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1920 _popup_region_menu_item->show ();
1922 _popup_region_menu_item->set_label (menu_item_name);
1925 /* No latering allowed in later is higher layering model */
1926 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1927 if (act && Config->get_layer_model() == LaterHigher) {
1928 act->set_sensitive (false);
1930 act->set_sensitive (true);
1933 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1935 edit_items.push_back (*_popup_region_menu_item);
1936 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1937 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1939 edit_items.push_back (SeparatorElem());
1942 /** Add context menu items relevant to selection ranges.
1943 * @param edit_items List to add the items to.
1946 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1948 using namespace Menu_Helpers;
1950 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1951 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1953 edit_items.push_back (SeparatorElem());
1954 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1956 edit_items.push_back (SeparatorElem());
1957 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1958 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1960 edit_items.push_back (SeparatorElem());
1962 edit_items.push_back (
1964 _("Move Range Start to Previous Region Boundary"),
1965 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1969 edit_items.push_back (
1971 _("Move Range Start to Next Region Boundary"),
1972 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1976 edit_items.push_back (
1978 _("Move Range End to Previous Region Boundary"),
1979 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1983 edit_items.push_back (
1985 _("Move Range End to Next Region Boundary"),
1986 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1990 edit_items.push_back (SeparatorElem());
1991 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1992 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1994 edit_items.push_back (SeparatorElem());
1995 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1997 edit_items.push_back (SeparatorElem());
1998 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1999 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2000 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2002 edit_items.push_back (SeparatorElem());
2003 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2005 edit_items.push_back (SeparatorElem());
2006 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2007 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2009 edit_items.push_back (SeparatorElem());
2010 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2011 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2012 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2013 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2014 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2015 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2016 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2022 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2024 using namespace Menu_Helpers;
2028 Menu *play_menu = manage (new Menu);
2029 MenuList& play_items = play_menu->items();
2030 play_menu->set_name ("ArdourContextMenu");
2032 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2033 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2034 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2035 play_items.push_back (SeparatorElem());
2036 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2038 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2042 Menu *select_menu = manage (new Menu);
2043 MenuList& select_items = select_menu->items();
2044 select_menu->set_name ("ArdourContextMenu");
2046 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2047 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2048 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2049 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2050 select_items.push_back (SeparatorElem());
2051 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2052 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2053 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2054 select_items.push_back (SeparatorElem());
2055 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2056 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2057 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2058 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2059 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2060 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2061 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2063 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2067 Menu *cutnpaste_menu = manage (new Menu);
2068 MenuList& cutnpaste_items = cutnpaste_menu->items();
2069 cutnpaste_menu->set_name ("ArdourContextMenu");
2071 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2072 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2073 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2075 cutnpaste_items.push_back (SeparatorElem());
2077 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2078 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2080 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2082 /* Adding new material */
2084 edit_items.push_back (SeparatorElem());
2085 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2086 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2090 Menu *nudge_menu = manage (new Menu());
2091 MenuList& nudge_items = nudge_menu->items();
2092 nudge_menu->set_name ("ArdourContextMenu");
2094 edit_items.push_back (SeparatorElem());
2095 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2096 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2097 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2098 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2100 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2104 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2106 using namespace Menu_Helpers;
2110 Menu *play_menu = manage (new Menu);
2111 MenuList& play_items = play_menu->items();
2112 play_menu->set_name ("ArdourContextMenu");
2114 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2115 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2116 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2120 Menu *select_menu = manage (new Menu);
2121 MenuList& select_items = select_menu->items();
2122 select_menu->set_name ("ArdourContextMenu");
2124 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2125 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2126 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2127 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2128 select_items.push_back (SeparatorElem());
2129 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2130 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2131 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2132 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2134 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2138 Menu *cutnpaste_menu = manage (new Menu);
2139 MenuList& cutnpaste_items = cutnpaste_menu->items();
2140 cutnpaste_menu->set_name ("ArdourContextMenu");
2142 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2143 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2144 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2146 Menu *nudge_menu = manage (new Menu());
2147 MenuList& nudge_items = nudge_menu->items();
2148 nudge_menu->set_name ("ArdourContextMenu");
2150 edit_items.push_back (SeparatorElem());
2151 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2152 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2153 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2154 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2156 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2160 Editor::snap_type() const
2166 Editor::snap_musical() const
2168 switch (_snap_type) {
2169 case SnapToBeatDiv128:
2170 case SnapToBeatDiv64:
2171 case SnapToBeatDiv32:
2172 case SnapToBeatDiv28:
2173 case SnapToBeatDiv24:
2174 case SnapToBeatDiv20:
2175 case SnapToBeatDiv16:
2176 case SnapToBeatDiv14:
2177 case SnapToBeatDiv12:
2178 case SnapToBeatDiv10:
2179 case SnapToBeatDiv8:
2180 case SnapToBeatDiv7:
2181 case SnapToBeatDiv6:
2182 case SnapToBeatDiv5:
2183 case SnapToBeatDiv4:
2184 case SnapToBeatDiv3:
2185 case SnapToBeatDiv2:
2197 Editor::snap_mode() const
2203 Editor::set_snap_to (SnapType st)
2205 unsigned int snap_ind = (unsigned int)st;
2207 if (internal_editing()) {
2208 internal_snap_type = st;
2210 pre_internal_snap_type = st;
2215 if (snap_ind > snap_type_strings.size() - 1) {
2217 _snap_type = (SnapType)snap_ind;
2220 string str = snap_type_strings[snap_ind];
2222 if (str != snap_type_selector.get_text()) {
2223 snap_type_selector.set_text (str);
2228 switch (_snap_type) {
2229 case SnapToBeatDiv128:
2230 case SnapToBeatDiv64:
2231 case SnapToBeatDiv32:
2232 case SnapToBeatDiv28:
2233 case SnapToBeatDiv24:
2234 case SnapToBeatDiv20:
2235 case SnapToBeatDiv16:
2236 case SnapToBeatDiv14:
2237 case SnapToBeatDiv12:
2238 case SnapToBeatDiv10:
2239 case SnapToBeatDiv8:
2240 case SnapToBeatDiv7:
2241 case SnapToBeatDiv6:
2242 case SnapToBeatDiv5:
2243 case SnapToBeatDiv4:
2244 case SnapToBeatDiv3:
2245 case SnapToBeatDiv2: {
2246 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2247 update_tempo_based_rulers ();
2251 case SnapToRegionStart:
2252 case SnapToRegionEnd:
2253 case SnapToRegionSync:
2254 case SnapToRegionBoundary:
2255 build_region_boundary_cache ();
2263 redisplay_tempo (false);
2265 SnapChanged (); /* EMIT SIGNAL */
2269 Editor::set_snap_mode (SnapMode mode)
2271 string str = snap_mode_strings[(int)mode];
2273 if (internal_editing()) {
2274 internal_snap_mode = mode;
2276 pre_internal_snap_mode = mode;
2281 if (str != snap_mode_selector.get_text ()) {
2282 snap_mode_selector.set_text (str);
2289 Editor::set_edit_point_preference (EditPoint ep, bool force)
2291 bool changed = (_edit_point != ep);
2294 if (Profile->get_mixbus())
2295 if (ep == EditAtSelectedMarker)
2296 ep = EditAtPlayhead;
2298 string str = edit_point_strings[(int)ep];
2299 if (str != edit_point_selector.get_text ()) {
2300 edit_point_selector.set_text (str);
2303 update_all_enter_cursors();
2305 if (!force && !changed) {
2309 const char* action=NULL;
2311 switch (_edit_point) {
2312 case EditAtPlayhead:
2313 action = "edit-at-playhead";
2315 case EditAtSelectedMarker:
2316 action = "edit-at-marker";
2319 action = "edit-at-mouse";
2323 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2325 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2329 bool in_track_canvas;
2331 if (!mouse_frame (foo, in_track_canvas)) {
2332 in_track_canvas = false;
2335 reset_canvas_action_sensitivity (in_track_canvas);
2341 Editor::set_state (const XMLNode& node, int version)
2343 XMLProperty const * prop;
2345 PBD::Unwinder<bool> nsi (no_save_instant, true);
2348 Tabbable::set_state (node, version);
2350 if (_session && (prop = node.property ("playhead"))) {
2352 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2354 playhead_cursor->set_position (pos);
2356 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2357 playhead_cursor->set_position (0);
2360 playhead_cursor->set_position (0);
2363 if ((prop = node.property ("mixer-width"))) {
2364 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2367 if ((prop = node.property ("zoom-focus"))) {
2368 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2370 zoom_focus_selection_done (zoom_focus);
2373 if ((prop = node.property ("zoom"))) {
2374 /* older versions of ardour used floating point samples_per_pixel */
2375 double f = PBD::atof (prop->value());
2376 reset_zoom (llrintf (f));
2378 reset_zoom (samples_per_pixel);
2381 if ((prop = node.property ("visible-track-count"))) {
2382 set_visible_track_count (PBD::atoi (prop->value()));
2385 if ((prop = node.property ("snap-to"))) {
2386 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2387 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2389 set_snap_to (_snap_type);
2392 if ((prop = node.property ("snap-mode"))) {
2393 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2394 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2395 * snap_mode_selection_done() will only mark an already active item as active
2396 * which does not trigger set_text().
2398 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2400 set_snap_mode (_snap_mode);
2403 if ((prop = node.property ("internal-snap-to"))) {
2404 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2407 if ((prop = node.property ("internal-snap-mode"))) {
2408 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2411 if ((prop = node.property ("pre-internal-snap-to"))) {
2412 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2415 if ((prop = node.property ("pre-internal-snap-mode"))) {
2416 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2419 if ((prop = node.property ("mouse-mode"))) {
2420 MouseMode m = str2mousemode(prop->value());
2421 set_mouse_mode (m, true);
2423 set_mouse_mode (MouseObject, true);
2426 if ((prop = node.property ("left-frame")) != 0) {
2428 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2432 reset_x_origin (pos);
2436 if ((prop = node.property ("y-origin")) != 0) {
2437 reset_y_origin (atof (prop->value ()));
2440 if ((prop = node.property ("join-object-range"))) {
2441 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2442 bool yn = string_is_affirmative (prop->value());
2444 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2445 tact->set_active (!yn);
2446 tact->set_active (yn);
2448 set_mouse_mode(mouse_mode, true);
2451 if ((prop = node.property ("edit-point"))) {
2452 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2454 set_edit_point_preference (_edit_point);
2457 if ((prop = node.property ("show-measures"))) {
2458 bool yn = string_is_affirmative (prop->value());
2459 _show_measures = yn;
2462 if ((prop = node.property ("follow-playhead"))) {
2463 bool yn = string_is_affirmative (prop->value());
2464 set_follow_playhead (yn);
2467 if ((prop = node.property ("stationary-playhead"))) {
2468 bool yn = string_is_affirmative (prop->value());
2469 set_stationary_playhead (yn);
2472 if ((prop = node.property ("region-list-sort-type"))) {
2473 RegionListSortType st;
2474 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2477 if ((prop = node.property ("show-editor-mixer"))) {
2479 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2482 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2483 bool yn = string_is_affirmative (prop->value());
2485 /* do it twice to force the change */
2487 tact->set_active (!yn);
2488 tact->set_active (yn);
2491 if ((prop = node.property ("show-editor-list"))) {
2493 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2496 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 bool yn = string_is_affirmative (prop->value());
2499 /* do it twice to force the change */
2501 tact->set_active (!yn);
2502 tact->set_active (yn);
2505 if ((prop = node.property (X_("editor-list-page")))) {
2506 _the_notebook.set_current_page (atoi (prop->value ()));
2509 if ((prop = node.property (X_("show-marker-lines")))) {
2510 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2512 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2513 bool yn = string_is_affirmative (prop->value ());
2515 tact->set_active (!yn);
2516 tact->set_active (yn);
2519 XMLNodeList children = node.children ();
2520 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2521 selection->set_state (**i, Stateful::current_state_version);
2522 _regions->set_state (**i);
2525 if ((prop = node.property ("maximised"))) {
2526 bool yn = string_is_affirmative (prop->value());
2527 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2529 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2530 bool fs = tact && tact->get_active();
2532 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2536 if ((prop = node.property ("nudge-clock-value"))) {
2538 sscanf (prop->value().c_str(), "%" PRId64, &f);
2539 nudge_clock->set (f);
2541 nudge_clock->set_mode (AudioClock::Timecode);
2542 nudge_clock->set (_session->frame_rate() * 5, true);
2547 * Not all properties may have been in XML, but
2548 * those that are linked to a private variable may need changing
2553 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2555 yn = _show_measures;
2556 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2557 /* do it twice to force the change */
2558 tact->set_active (!yn);
2559 tact->set_active (yn);
2562 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2563 yn = _follow_playhead;
2565 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2566 if (tact->get_active() != yn) {
2567 tact->set_active (yn);
2571 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2572 yn = _stationary_playhead;
2574 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2575 if (tact->get_active() != yn) {
2576 tact->set_active (yn);
2581 return LuaInstance::instance()->set_state(node);
2585 Editor::get_state ()
2587 XMLNode* node = new XMLNode (X_("Editor"));
2591 id().print (buf, sizeof (buf));
2592 node->add_property ("id", buf);
2594 node->add_child_nocopy (Tabbable::get_state());
2596 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2597 node->add_property("edit-horizontal-pane-pos", string(buf));
2598 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2599 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2600 node->add_property("edit-vertical-pane-pos", string(buf));
2602 maybe_add_mixer_strip_width (*node);
2604 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2606 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2607 node->add_property ("zoom", buf);
2608 node->add_property ("snap-to", enum_2_string (_snap_type));
2609 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2610 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2611 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2612 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2613 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2614 node->add_property ("edit-point", enum_2_string (_edit_point));
2615 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2616 node->add_property ("visible-track-count", buf);
2618 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2619 node->add_property ("playhead", buf);
2620 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2621 node->add_property ("left-frame", buf);
2622 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2623 node->add_property ("y-origin", buf);
2625 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2626 node->add_property ("maximised", _maximised ? "yes" : "no");
2627 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2628 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2629 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2630 node->add_property ("mouse-mode", enum2str(mouse_mode));
2631 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2633 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2635 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2636 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2639 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2641 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2642 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2645 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2646 node->add_property (X_("editor-list-page"), buf);
2648 if (button_bindings) {
2649 XMLNode* bb = new XMLNode (X_("Buttons"));
2650 button_bindings->save (*bb);
2651 node->add_child_nocopy (*bb);
2654 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2656 node->add_child_nocopy (selection->get_state ());
2657 node->add_child_nocopy (_regions->get_state ());
2659 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2660 node->add_property ("nudge-clock-value", buf);
2662 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2663 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2668 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2669 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2671 * @return pair: TimeAxisView that y is over, layer index.
2673 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2674 * in stacked or expanded region display mode, otherwise 0.
2676 std::pair<TimeAxisView *, double>
2677 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2679 if (!trackview_relative_offset) {
2680 y -= _trackview_group->canvas_origin().y;
2684 return std::make_pair ( (TimeAxisView *) 0, 0);
2687 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2689 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2696 return std::make_pair ( (TimeAxisView *) 0, 0);
2699 /** Snap a position to the grid, if appropriate, taking into account current
2700 * grid settings and also the state of any snap modifier keys that may be pressed.
2701 * @param start Position to snap.
2702 * @param event Event to get current key modifier information from, or 0.
2705 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2707 if (!_session || !event) {
2711 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2712 if (_snap_mode == SnapOff) {
2713 snap_to_internal (start, direction, for_mark);
2716 if (_snap_mode != SnapOff) {
2717 snap_to_internal (start, direction, for_mark);
2718 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2719 /* SnapOff, but we pressed the snap_delta modifier */
2720 snap_to_internal (start, direction, for_mark);
2726 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2728 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2732 snap_to_internal (start, direction, for_mark, ensure_snap);
2736 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2738 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2739 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2741 switch (_snap_type) {
2742 case SnapToTimecodeFrame:
2743 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2744 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2745 /* start is already on a whole timecode frame, do nothing */
2746 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2747 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2749 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2753 case SnapToTimecodeSeconds:
2754 if (_session->config.get_timecode_offset_negative()) {
2755 start += _session->config.get_timecode_offset ();
2757 start -= _session->config.get_timecode_offset ();
2759 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2760 (start % one_timecode_second == 0)) {
2761 /* start is already on a whole second, do nothing */
2762 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2763 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2765 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2768 if (_session->config.get_timecode_offset_negative()) {
2769 start -= _session->config.get_timecode_offset ();
2771 start += _session->config.get_timecode_offset ();
2775 case SnapToTimecodeMinutes:
2776 if (_session->config.get_timecode_offset_negative()) {
2777 start += _session->config.get_timecode_offset ();
2779 start -= _session->config.get_timecode_offset ();
2781 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2782 (start % one_timecode_minute == 0)) {
2783 /* start is already on a whole minute, do nothing */
2784 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2785 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2787 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2789 if (_session->config.get_timecode_offset_negative()) {
2790 start -= _session->config.get_timecode_offset ();
2792 start += _session->config.get_timecode_offset ();
2796 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2797 abort(); /*NOTREACHED*/
2802 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2804 const framepos_t one_second = _session->frame_rate();
2805 const framepos_t one_minute = _session->frame_rate() * 60;
2806 framepos_t presnap = start;
2810 switch (_snap_type) {
2811 case SnapToTimecodeFrame:
2812 case SnapToTimecodeSeconds:
2813 case SnapToTimecodeMinutes:
2814 return timecode_snap_to_internal (start, direction, for_mark);
2817 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2818 start % (one_second/75) == 0) {
2819 /* start is already on a whole CD frame, do nothing */
2820 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2821 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2823 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2828 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2829 start % one_second == 0) {
2830 /* start is already on a whole second, do nothing */
2831 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2832 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2834 start = (framepos_t) floor ((double) start / one_second) * one_second;
2839 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2840 start % one_minute == 0) {
2841 /* start is already on a whole minute, do nothing */
2842 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2843 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2845 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2850 start = _session->tempo_map().round_to_bar (start, direction);
2854 start = _session->tempo_map().round_to_beat (start, direction);
2857 case SnapToBeatDiv128:
2858 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2860 case SnapToBeatDiv64:
2861 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2863 case SnapToBeatDiv32:
2864 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2866 case SnapToBeatDiv28:
2867 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2869 case SnapToBeatDiv24:
2870 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2872 case SnapToBeatDiv20:
2873 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2875 case SnapToBeatDiv16:
2876 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2878 case SnapToBeatDiv14:
2879 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2881 case SnapToBeatDiv12:
2882 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2884 case SnapToBeatDiv10:
2885 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2887 case SnapToBeatDiv8:
2888 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2890 case SnapToBeatDiv7:
2891 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2893 case SnapToBeatDiv6:
2894 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2896 case SnapToBeatDiv5:
2897 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2899 case SnapToBeatDiv4:
2900 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2902 case SnapToBeatDiv3:
2903 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2905 case SnapToBeatDiv2:
2906 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2914 _session->locations()->marks_either_side (start, before, after);
2916 if (before == max_framepos && after == max_framepos) {
2917 /* No marks to snap to, so just don't snap */
2919 } else if (before == max_framepos) {
2921 } else if (after == max_framepos) {
2923 } else if (before != max_framepos && after != max_framepos) {
2924 /* have before and after */
2925 if ((start - before) < (after - start)) {
2934 case SnapToRegionStart:
2935 case SnapToRegionEnd:
2936 case SnapToRegionSync:
2937 case SnapToRegionBoundary:
2938 if (!region_boundary_cache.empty()) {
2940 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2941 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2943 if (direction > 0) {
2944 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2946 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2949 if (next != region_boundary_cache.begin ()) {
2954 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2955 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2957 if (start > (p + n) / 2) {
2966 switch (_snap_mode) {
2976 if (presnap > start) {
2977 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2981 } else if (presnap < start) {
2982 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2988 /* handled at entry */
2996 Editor::setup_toolbar ()
2998 HBox* mode_box = manage(new HBox);
2999 mode_box->set_border_width (2);
3000 mode_box->set_spacing(2);
3002 HBox* mouse_mode_box = manage (new HBox);
3003 HBox* mouse_mode_hbox = manage (new HBox);
3004 VBox* mouse_mode_vbox = manage (new VBox);
3005 Alignment* mouse_mode_align = manage (new Alignment);
3007 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3008 mouse_mode_size_group->add_widget (smart_mode_button);
3009 mouse_mode_size_group->add_widget (mouse_move_button);
3010 mouse_mode_size_group->add_widget (mouse_cut_button);
3011 mouse_mode_size_group->add_widget (mouse_select_button);
3012 mouse_mode_size_group->add_widget (mouse_timefx_button);
3013 mouse_mode_size_group->add_widget (mouse_audition_button);
3014 mouse_mode_size_group->add_widget (mouse_draw_button);
3015 mouse_mode_size_group->add_widget (mouse_content_button);
3017 mouse_mode_size_group->add_widget (zoom_in_button);
3018 mouse_mode_size_group->add_widget (zoom_out_button);
3019 mouse_mode_size_group->add_widget (zoom_preset_selector);
3020 mouse_mode_size_group->add_widget (zoom_out_full_button);
3021 mouse_mode_size_group->add_widget (zoom_focus_selector);
3023 mouse_mode_size_group->add_widget (tav_shrink_button);
3024 mouse_mode_size_group->add_widget (tav_expand_button);
3025 mouse_mode_size_group->add_widget (visible_tracks_selector);
3027 mouse_mode_size_group->add_widget (snap_type_selector);
3028 mouse_mode_size_group->add_widget (snap_mode_selector);
3030 mouse_mode_size_group->add_widget (edit_point_selector);
3031 mouse_mode_size_group->add_widget (edit_mode_selector);
3033 mouse_mode_size_group->add_widget (*nudge_clock);
3034 mouse_mode_size_group->add_widget (nudge_forward_button);
3035 mouse_mode_size_group->add_widget (nudge_backward_button);
3037 mouse_mode_hbox->set_spacing (2);
3039 if (!ARDOUR::Profile->get_trx()) {
3040 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3043 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3044 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3046 if (!ARDOUR::Profile->get_mixbus()) {
3047 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3050 if (!ARDOUR::Profile->get_trx()) {
3051 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3052 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3053 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3054 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3057 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3059 mouse_mode_align->add (*mouse_mode_vbox);
3060 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3062 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3064 edit_mode_selector.set_name ("mouse mode button");
3066 if (!ARDOUR::Profile->get_trx()) {
3067 mode_box->pack_start (edit_mode_selector, false, false);
3070 mode_box->pack_start (*mouse_mode_box, false, false);
3074 _zoom_box.set_spacing (2);
3075 _zoom_box.set_border_width (2);
3079 zoom_preset_selector.set_name ("zoom button");
3080 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3081 zoom_preset_selector.set_size_request (42, -1);
3083 zoom_in_button.set_name ("zoom button");
3084 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3085 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3086 zoom_in_button.set_related_action (act);
3088 zoom_out_button.set_name ("zoom button");
3089 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3090 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3091 zoom_out_button.set_related_action (act);
3093 zoom_out_full_button.set_name ("zoom button");
3094 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3095 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3096 zoom_out_full_button.set_related_action (act);
3098 zoom_focus_selector.set_name ("zoom button");
3100 if (ARDOUR::Profile->get_mixbus()) {
3101 _zoom_box.pack_start (zoom_preset_selector, false, false);
3102 } else if (ARDOUR::Profile->get_trx()) {
3103 mode_box->pack_start (zoom_out_button, false, false);
3104 mode_box->pack_start (zoom_in_button, false, false);
3106 _zoom_box.pack_start (zoom_out_button, false, false);
3107 _zoom_box.pack_start (zoom_in_button, false, false);
3108 _zoom_box.pack_start (zoom_out_full_button, false, false);
3109 _zoom_box.pack_start (zoom_focus_selector, false, false);
3112 /* Track zoom buttons */
3113 visible_tracks_selector.set_name ("zoom button");
3114 if (Profile->get_mixbus()) {
3115 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3116 visible_tracks_selector.set_size_request (42, -1);
3118 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3121 tav_expand_button.set_name ("zoom button");
3122 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3123 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3124 tav_expand_button.set_related_action (act);
3126 tav_shrink_button.set_name ("zoom button");
3127 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3128 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3129 tav_shrink_button.set_related_action (act);
3131 if (ARDOUR::Profile->get_mixbus()) {
3132 _zoom_box.pack_start (visible_tracks_selector);
3133 } else if (ARDOUR::Profile->get_trx()) {
3134 _zoom_box.pack_start (tav_shrink_button);
3135 _zoom_box.pack_start (tav_expand_button);
3137 _zoom_box.pack_start (visible_tracks_selector);
3138 _zoom_box.pack_start (tav_shrink_button);
3139 _zoom_box.pack_start (tav_expand_button);
3142 snap_box.set_spacing (2);
3143 snap_box.set_border_width (2);
3145 snap_type_selector.set_name ("mouse mode button");
3147 snap_mode_selector.set_name ("mouse mode button");
3149 edit_point_selector.set_name ("mouse mode button");
3151 snap_box.pack_start (snap_mode_selector, false, false);
3152 snap_box.pack_start (snap_type_selector, false, false);
3153 snap_box.pack_start (edit_point_selector, false, false);
3157 HBox *nudge_box = manage (new HBox);
3158 nudge_box->set_spacing (2);
3159 nudge_box->set_border_width (2);
3161 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3162 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3164 nudge_box->pack_start (nudge_backward_button, false, false);
3165 nudge_box->pack_start (nudge_forward_button, false, false);
3166 nudge_box->pack_start (*nudge_clock, false, false);
3169 /* Pack everything in... */
3171 HBox* hbox = manage (new HBox);
3172 hbox->set_spacing(2);
3174 toolbar_hbox.set_spacing (2);
3175 toolbar_hbox.set_border_width (2);
3177 toolbar_hbox.pack_start (*mode_box, false, false);
3178 if (!ARDOUR::Profile->get_trx()) {
3179 toolbar_hbox.pack_start (_zoom_box, false, false);
3180 toolbar_hbox.pack_start (*hbox, false, false);
3183 if (!ARDOUR::Profile->get_trx()) {
3184 hbox->pack_start (snap_box, false, false);
3185 hbox->pack_start (*nudge_box, false, false);
3192 Editor::build_edit_point_menu ()
3194 using namespace Menu_Helpers;
3196 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3197 if(!Profile->get_mixbus())
3198 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3199 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3201 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3205 Editor::build_edit_mode_menu ()
3207 using namespace Menu_Helpers;
3209 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3210 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3211 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3212 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3214 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3218 Editor::build_snap_mode_menu ()
3220 using namespace Menu_Helpers;
3222 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3223 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3224 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3226 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3230 Editor::build_snap_type_menu ()
3232 using namespace Menu_Helpers;
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3265 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3270 Editor::setup_tooltips ()
3272 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3273 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3274 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3275 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3276 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3277 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3278 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3279 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3280 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3281 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3282 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3283 set_tooltip (zoom_in_button, _("Zoom In"));
3284 set_tooltip (zoom_out_button, _("Zoom Out"));
3285 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3286 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3287 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3288 set_tooltip (tav_expand_button, _("Expand Tracks"));
3289 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3290 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3291 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3292 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3293 set_tooltip (edit_point_selector, _("Edit Point"));
3294 set_tooltip (edit_mode_selector, _("Edit Mode"));
3295 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3299 Editor::convert_drop_to_paths (
3300 vector<string>& paths,
3301 const RefPtr<Gdk::DragContext>& /*context*/,
3304 const SelectionData& data,
3308 if (_session == 0) {
3312 vector<string> uris = data.get_uris();
3316 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3317 are actually URI lists. So do it by hand.
3320 if (data.get_target() != "text/plain") {
3324 /* Parse the "uri-list" format that Nautilus provides,
3325 where each pathname is delimited by \r\n.
3327 THERE MAY BE NO NULL TERMINATING CHAR!!!
3330 string txt = data.get_text();
3334 p = (char *) malloc (txt.length() + 1);
3335 txt.copy (p, txt.length(), 0);
3336 p[txt.length()] = '\0';
3342 while (g_ascii_isspace (*p))
3346 while (*q && (*q != '\n') && (*q != '\r')) {
3353 while (q > p && g_ascii_isspace (*q))
3358 uris.push_back (string (p, q - p + 1));
3362 p = strchr (p, '\n');
3374 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3375 if ((*i).substr (0,7) == "file://") {
3376 paths.push_back (Glib::filename_from_uri (*i));
3384 Editor::new_tempo_section ()
3389 Editor::map_transport_state ()
3391 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3393 if (_session && _session->transport_stopped()) {
3394 have_pending_keyboard_selection = false;
3397 update_loop_range_view ();
3403 Editor::begin_selection_op_history ()
3405 selection_op_cmd_depth = 0;
3406 selection_op_history_it = 0;
3408 while(!selection_op_history.empty()) {
3409 delete selection_op_history.front();
3410 selection_op_history.pop_front();
3413 selection_undo_action->set_sensitive (false);
3414 selection_redo_action->set_sensitive (false);
3415 selection_op_history.push_front (&_selection_memento->get_state ());
3419 Editor::begin_reversible_selection_op (string name)
3422 //cerr << name << endl;
3423 /* begin/commit pairs can be nested */
3424 selection_op_cmd_depth++;
3429 Editor::commit_reversible_selection_op ()
3432 if (selection_op_cmd_depth == 1) {
3434 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3436 The user has undone some selection ops and then made a new one,
3437 making anything earlier in the list invalid.
3440 list<XMLNode *>::iterator it = selection_op_history.begin();
3441 list<XMLNode *>::iterator e_it = it;
3442 advance (e_it, selection_op_history_it);
3444 for ( ; it != e_it; ++it) {
3447 selection_op_history.erase (selection_op_history.begin(), e_it);
3450 selection_op_history.push_front (&_selection_memento->get_state ());
3451 selection_op_history_it = 0;
3453 selection_undo_action->set_sensitive (true);
3454 selection_redo_action->set_sensitive (false);
3457 if (selection_op_cmd_depth > 0) {
3458 selection_op_cmd_depth--;
3464 Editor::undo_selection_op ()
3467 selection_op_history_it++;
3469 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3470 if (n == selection_op_history_it) {
3471 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3472 selection_redo_action->set_sensitive (true);
3476 /* is there an earlier entry? */
3477 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3478 selection_undo_action->set_sensitive (false);
3484 Editor::redo_selection_op ()
3487 if (selection_op_history_it > 0) {
3488 selection_op_history_it--;
3491 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3492 if (n == selection_op_history_it) {
3493 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3494 selection_undo_action->set_sensitive (true);
3499 if (selection_op_history_it == 0) {
3500 selection_redo_action->set_sensitive (false);
3506 Editor::begin_reversible_command (string name)
3509 before.push_back (&_selection_memento->get_state ());
3510 _session->begin_reversible_command (name);
3515 Editor::begin_reversible_command (GQuark q)
3518 before.push_back (&_selection_memento->get_state ());
3519 _session->begin_reversible_command (q);
3524 Editor::abort_reversible_command ()
3527 while(!before.empty()) {
3528 delete before.front();
3531 _session->abort_reversible_command ();
3536 Editor::commit_reversible_command ()
3539 if (before.size() == 1) {
3540 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3541 redo_action->set_sensitive(false);
3542 undo_action->set_sensitive(true);
3543 begin_selection_op_history ();
3546 if (before.empty()) {
3547 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3552 _session->commit_reversible_command ();
3557 Editor::history_changed ()
3561 if (undo_action && _session) {
3562 if (_session->undo_depth() == 0) {
3563 label = S_("Command|Undo");
3565 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3567 undo_action->property_label() = label;
3570 if (redo_action && _session) {
3571 if (_session->redo_depth() == 0) {
3573 redo_action->set_sensitive (false);
3575 label = string_compose(_("Redo (%1)"), _session->next_redo());
3576 redo_action->set_sensitive (true);
3578 redo_action->property_label() = label;
3583 Editor::duplicate_range (bool with_dialog)
3587 RegionSelection rs = get_regions_from_selection_and_entered ();
3589 if ( selection->time.length() == 0 && rs.empty()) {
3595 ArdourDialog win (_("Duplicate"));
3596 Label label (_("Number of duplications:"));
3597 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3598 SpinButton spinner (adjustment, 0.0, 1);
3601 win.get_vbox()->set_spacing (12);
3602 win.get_vbox()->pack_start (hbox);
3603 hbox.set_border_width (6);
3604 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3606 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3607 place, visually. so do this by hand.
3610 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3611 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3612 spinner.grab_focus();
3618 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3619 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3620 win.set_default_response (RESPONSE_ACCEPT);
3622 spinner.grab_focus ();
3624 switch (win.run ()) {
3625 case RESPONSE_ACCEPT:
3631 times = adjustment.get_value();
3634 if ((current_mouse_mode() == Editing::MouseRange)) {
3635 if (selection->time.length()) {
3636 duplicate_selection (times);
3638 } else if (get_smart_mode()) {
3639 if (selection->time.length()) {
3640 duplicate_selection (times);
3642 duplicate_some_regions (rs, times);
3644 duplicate_some_regions (rs, times);
3649 Editor::set_edit_mode (EditMode m)
3651 Config->set_edit_mode (m);
3655 Editor::cycle_edit_mode ()
3657 switch (Config->get_edit_mode()) {
3659 Config->set_edit_mode (Ripple);
3663 Config->set_edit_mode (Lock);
3666 Config->set_edit_mode (Slide);
3672 Editor::edit_mode_selection_done ( EditMode m )
3674 Config->set_edit_mode ( m );
3678 Editor::snap_type_selection_done (SnapType snaptype)
3680 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3682 ract->set_active ();
3687 Editor::snap_mode_selection_done (SnapMode mode)
3689 RefPtr<RadioAction> ract = snap_mode_action (mode);
3692 ract->set_active (true);
3697 Editor::cycle_edit_point (bool with_marker)
3699 if(Profile->get_mixbus())
3700 with_marker = false;
3702 switch (_edit_point) {
3704 set_edit_point_preference (EditAtPlayhead);
3706 case EditAtPlayhead:
3708 set_edit_point_preference (EditAtSelectedMarker);
3710 set_edit_point_preference (EditAtMouse);
3713 case EditAtSelectedMarker:
3714 set_edit_point_preference (EditAtMouse);
3720 Editor::edit_point_selection_done (EditPoint ep)
3722 set_edit_point_preference ( ep );
3726 Editor::build_zoom_focus_menu ()
3728 using namespace Menu_Helpers;
3730 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3731 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3732 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3733 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3734 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3735 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3737 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3741 Editor::zoom_focus_selection_done ( ZoomFocus f )
3743 RefPtr<RadioAction> ract = zoom_focus_action (f);
3745 ract->set_active ();
3750 Editor::build_track_count_menu ()
3752 using namespace Menu_Helpers;
3754 if (!Profile->get_mixbus()) {
3755 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3756 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3757 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3758 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3759 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3760 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3763 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3764 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3780 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3781 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3782 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3783 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3784 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3785 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3786 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3787 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3788 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3789 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3790 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3795 Editor::set_zoom_preset (int64_t ms)
3798 temporal_zoom_session();
3802 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3803 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3807 Editor::set_visible_track_count (int32_t n)
3809 _visible_track_count = n;
3811 /* if the canvas hasn't really been allocated any size yet, just
3812 record the desired number of visible tracks and return. when canvas
3813 allocation happens, we will get called again and then we can do the
3817 if (_visible_canvas_height <= 1) {
3823 DisplaySuspender ds;
3825 if (_visible_track_count > 0) {
3826 h = trackviews_height() / _visible_track_count;
3827 std::ostringstream s;
3828 s << _visible_track_count;
3830 } else if (_visible_track_count == 0) {
3832 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3833 if ((*i)->marked_for_display()) {
3837 h = trackviews_height() / n;
3840 /* negative value means that the visible track count has
3841 been overridden by explicit track height changes.
3843 visible_tracks_selector.set_text (X_("*"));
3847 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3848 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3851 if (str != visible_tracks_selector.get_text()) {
3852 visible_tracks_selector.set_text (str);
3857 Editor::override_visible_track_count ()
3859 _visible_track_count = -1;
3860 visible_tracks_selector.set_text ( _("*") );
3864 Editor::edit_controls_button_release (GdkEventButton* ev)
3866 if (Keyboard::is_context_menu_event (ev)) {
3867 ARDOUR_UI::instance()->add_route ();
3868 } else if (ev->button == 1) {
3869 selection->clear_tracks ();
3876 Editor::mouse_select_button_release (GdkEventButton* ev)
3878 /* this handles just right-clicks */
3880 if (ev->button != 3) {
3888 Editor::set_zoom_focus (ZoomFocus f)
3890 string str = zoom_focus_strings[(int)f];
3892 if (str != zoom_focus_selector.get_text()) {
3893 zoom_focus_selector.set_text (str);
3896 if (zoom_focus != f) {
3903 Editor::cycle_zoom_focus ()
3905 switch (zoom_focus) {
3907 set_zoom_focus (ZoomFocusRight);
3909 case ZoomFocusRight:
3910 set_zoom_focus (ZoomFocusCenter);
3912 case ZoomFocusCenter:
3913 set_zoom_focus (ZoomFocusPlayhead);
3915 case ZoomFocusPlayhead:
3916 set_zoom_focus (ZoomFocusMouse);
3918 case ZoomFocusMouse:
3919 set_zoom_focus (ZoomFocusEdit);
3922 set_zoom_focus (ZoomFocusLeft);
3928 Editor::set_show_measures (bool yn)
3930 if (_show_measures != yn) {
3933 if ((_show_measures = yn) == true) {
3935 tempo_lines->show();
3938 std::vector<TempoMap::BBTPoint> grid;
3939 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3940 draw_measures (grid);
3948 Editor::toggle_follow_playhead ()
3950 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3952 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3953 set_follow_playhead (tact->get_active());
3957 /** @param yn true to follow playhead, otherwise false.
3958 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3961 Editor::set_follow_playhead (bool yn, bool catch_up)
3963 if (_follow_playhead != yn) {
3964 if ((_follow_playhead = yn) == true && catch_up) {
3966 reset_x_origin_to_follow_playhead ();
3973 Editor::toggle_stationary_playhead ()
3975 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3977 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3978 set_stationary_playhead (tact->get_active());
3983 Editor::set_stationary_playhead (bool yn)
3985 if (_stationary_playhead != yn) {
3986 if ((_stationary_playhead = yn) == true) {
3988 // FIXME need a 3.0 equivalent of this 2.X call
3989 // update_current_screen ();
3996 Editor::playlist_selector () const
3998 return *_playlist_selector;
4002 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4004 if (paste_count == 0) {
4005 /* don't bother calculating an offset that will be zero anyway */
4009 /* calculate basic unsnapped multi-paste offset */
4010 framecnt_t offset = paste_count * duration;
4012 /* snap offset so pos + offset is aligned to the grid */
4013 framepos_t offset_pos = pos + offset;
4014 snap_to(offset_pos, RoundUpMaybe);
4015 offset = offset_pos - pos;
4021 Editor::get_grid_beat_divisions(framepos_t position)
4023 switch (_snap_type) {
4024 case SnapToBeatDiv128: return 128;
4025 case SnapToBeatDiv64: return 64;
4026 case SnapToBeatDiv32: return 32;
4027 case SnapToBeatDiv28: return 28;
4028 case SnapToBeatDiv24: return 24;
4029 case SnapToBeatDiv20: return 20;
4030 case SnapToBeatDiv16: return 16;
4031 case SnapToBeatDiv14: return 14;
4032 case SnapToBeatDiv12: return 12;
4033 case SnapToBeatDiv10: return 10;
4034 case SnapToBeatDiv8: return 8;
4035 case SnapToBeatDiv7: return 7;
4036 case SnapToBeatDiv6: return 6;
4037 case SnapToBeatDiv5: return 5;
4038 case SnapToBeatDiv4: return 4;
4039 case SnapToBeatDiv3: return 3;
4040 case SnapToBeatDiv2: return 2;
4046 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4047 if the grid is non-musical, returns 0.
4048 if the grid is snapped to bars, returns -1.
4049 @param event_state the current keyboard modifier mask.
4052 Editor::get_grid_music_divisions (uint32_t event_state)
4054 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4058 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4062 switch (_snap_type) {
4063 case SnapToBeatDiv128: return 128;
4064 case SnapToBeatDiv64: return 64;
4065 case SnapToBeatDiv32: return 32;
4066 case SnapToBeatDiv28: return 28;
4067 case SnapToBeatDiv24: return 24;
4068 case SnapToBeatDiv20: return 20;
4069 case SnapToBeatDiv16: return 16;
4070 case SnapToBeatDiv14: return 14;
4071 case SnapToBeatDiv12: return 12;
4072 case SnapToBeatDiv10: return 10;
4073 case SnapToBeatDiv8: return 8;
4074 case SnapToBeatDiv7: return 7;
4075 case SnapToBeatDiv6: return 6;
4076 case SnapToBeatDiv5: return 5;
4077 case SnapToBeatDiv4: return 4;
4078 case SnapToBeatDiv3: return 3;
4079 case SnapToBeatDiv2: return 2;
4080 case SnapToBeat: return 1;
4081 case SnapToBar : return -1;
4088 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4092 const unsigned divisions = get_grid_beat_divisions(position);
4094 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4097 switch (_snap_type) {
4099 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4102 const Meter& m = _session->tempo_map().meter_at_frame (position);
4103 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4111 return Evoral::Beats();
4115 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4119 ret = nudge_clock->current_duration (pos);
4120 next = ret + 1; /* XXXX fix me */
4126 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4128 ArdourDialog dialog (_("Playlist Deletion"));
4129 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4130 "If it is kept, its audio files will not be cleaned.\n"
4131 "If it is deleted, audio files used by it alone will be cleaned."),
4134 dialog.set_position (WIN_POS_CENTER);
4135 dialog.get_vbox()->pack_start (label);
4139 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4140 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4141 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4142 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4143 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4145 // by default gtk uses the left most button
4146 keep->grab_focus ();
4148 switch (dialog.run ()) {
4150 /* keep this and all remaining ones */
4155 /* delete this and all others */
4159 case RESPONSE_ACCEPT:
4160 /* delete the playlist */
4164 case RESPONSE_REJECT:
4165 /* keep the playlist */
4177 Editor::audio_region_selection_covers (framepos_t where)
4179 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4180 if ((*a)->region()->covers (where)) {
4189 Editor::prepare_for_cleanup ()
4191 cut_buffer->clear_regions ();
4192 cut_buffer->clear_playlists ();
4194 selection->clear_regions ();
4195 selection->clear_playlists ();
4197 _regions->suspend_redisplay ();
4201 Editor::finish_cleanup ()
4203 _regions->resume_redisplay ();
4207 Editor::transport_loop_location()
4210 return _session->locations()->auto_loop_location();
4217 Editor::transport_punch_location()
4220 return _session->locations()->auto_punch_location();
4227 Editor::control_layout_scroll (GdkEventScroll* ev)
4229 /* Just forward to the normal canvas scroll method. The coordinate
4230 systems are different but since the canvas is always larger than the
4231 track headers, and aligned with the trackview area, this will work.
4233 In the not too distant future this layout is going away anyway and
4234 headers will be on the canvas.
4236 return canvas_scroll_event (ev, false);
4240 Editor::session_state_saved (string)
4243 _snapshots->redisplay ();
4247 Editor::maximise_editing_space ()
4253 Gtk::Window* toplevel = current_toplevel();
4256 toplevel->fullscreen ();
4262 Editor::restore_editing_space ()
4268 Gtk::Window* toplevel = current_toplevel();
4271 toplevel->unfullscreen();
4277 * Make new playlists for a given track and also any others that belong
4278 * to the same active route group with the `select' property.
4283 Editor::new_playlists (TimeAxisView* v)
4285 begin_reversible_command (_("new playlists"));
4286 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4287 _session->playlists->get (playlists);
4288 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4289 commit_reversible_command ();
4293 * Use a copy of the current playlist for a given track and also any others that belong
4294 * to the same active route group with the `select' property.
4299 Editor::copy_playlists (TimeAxisView* v)
4301 begin_reversible_command (_("copy playlists"));
4302 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4303 _session->playlists->get (playlists);
4304 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4305 commit_reversible_command ();
4308 /** Clear the current playlist for a given track and also any others that belong
4309 * to the same active route group with the `select' property.
4314 Editor::clear_playlists (TimeAxisView* v)
4316 begin_reversible_command (_("clear playlists"));
4317 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4318 _session->playlists->get (playlists);
4319 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4320 commit_reversible_command ();
4324 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4326 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4330 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4332 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4336 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4338 atv.clear_playlist ();
4342 Editor::get_y_origin () const
4344 return vertical_adjustment.get_value ();
4347 /** Queue up a change to the viewport x origin.
4348 * @param frame New x origin.
4351 Editor::reset_x_origin (framepos_t frame)
4353 pending_visual_change.add (VisualChange::TimeOrigin);
4354 pending_visual_change.time_origin = frame;
4355 ensure_visual_change_idle_handler ();
4359 Editor::reset_y_origin (double y)
4361 pending_visual_change.add (VisualChange::YOrigin);
4362 pending_visual_change.y_origin = y;
4363 ensure_visual_change_idle_handler ();
4367 Editor::reset_zoom (framecnt_t spp)
4369 if (spp == samples_per_pixel) {
4373 pending_visual_change.add (VisualChange::ZoomLevel);
4374 pending_visual_change.samples_per_pixel = spp;
4375 ensure_visual_change_idle_handler ();
4379 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4381 reset_x_origin (frame);
4384 if (!no_save_visual) {
4385 undo_visual_stack.push_back (current_visual_state(false));
4389 Editor::VisualState::VisualState (bool with_tracks)
4390 : gui_state (with_tracks ? new GUIObjectState : 0)
4394 Editor::VisualState::~VisualState ()
4399 Editor::VisualState*
4400 Editor::current_visual_state (bool with_tracks)
4402 VisualState* vs = new VisualState (with_tracks);
4403 vs->y_position = vertical_adjustment.get_value();
4404 vs->samples_per_pixel = samples_per_pixel;
4405 vs->leftmost_frame = leftmost_frame;
4406 vs->zoom_focus = zoom_focus;
4409 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4416 Editor::undo_visual_state ()
4418 if (undo_visual_stack.empty()) {
4422 VisualState* vs = undo_visual_stack.back();
4423 undo_visual_stack.pop_back();
4426 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4429 use_visual_state (*vs);
4434 Editor::redo_visual_state ()
4436 if (redo_visual_stack.empty()) {
4440 VisualState* vs = redo_visual_stack.back();
4441 redo_visual_stack.pop_back();
4443 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4444 // why do we check here?
4445 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4448 use_visual_state (*vs);
4453 Editor::swap_visual_state ()
4455 if (undo_visual_stack.empty()) {
4456 redo_visual_state ();
4458 undo_visual_state ();
4463 Editor::use_visual_state (VisualState& vs)
4465 PBD::Unwinder<bool> nsv (no_save_visual, true);
4466 DisplaySuspender ds;
4468 vertical_adjustment.set_value (vs.y_position);
4470 set_zoom_focus (vs.zoom_focus);
4471 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4474 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4476 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4477 (*i)->clear_property_cache();
4478 (*i)->reset_visual_state ();
4482 _routes->update_visibility ();
4485 /** This is the core function that controls the zoom level of the canvas. It is called
4486 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4487 * @param spp new number of samples per pixel
4490 Editor::set_samples_per_pixel (framecnt_t spp)
4496 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4497 const framecnt_t lots_of_pixels = 4000;
4499 /* if the zoom level is greater than what you'd get trying to display 3
4500 * days of audio on a really big screen, then it's too big.
4503 if (spp * lots_of_pixels > three_days) {
4507 samples_per_pixel = spp;
4510 tempo_lines->tempo_map_changed();
4513 bool const showing_time_selection = selection->time.length() > 0;
4515 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4516 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4517 (*i)->reshow_selection (selection->time);
4521 ZoomChanged (); /* EMIT_SIGNAL */
4523 ArdourCanvas::GtkCanvasViewport* c;
4525 c = get_track_canvas();
4527 c->canvas()->zoomed ();
4530 if (playhead_cursor) {
4531 playhead_cursor->set_position (playhead_cursor->current_frame ());
4534 refresh_location_display();
4535 _summary->set_overlays_dirty ();
4537 update_marker_labels ();
4543 Editor::playhead_cursor_sample () const
4545 return playhead_cursor->current_frame();
4549 Editor::queue_visual_videotimeline_update ()
4552 * pending_visual_change.add (VisualChange::VideoTimeline);
4553 * or maybe even more specific: which videotimeline-image
4554 * currently it calls update_video_timeline() to update
4555 * _all outdated_ images on the video-timeline.
4556 * see 'exposeimg()' in video_image_frame.cc
4558 ensure_visual_change_idle_handler ();
4562 Editor::ensure_visual_change_idle_handler ()
4564 if (pending_visual_change.idle_handler_id < 0) {
4565 // see comment in add_to_idle_resize above.
4566 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4567 pending_visual_change.being_handled = false;
4572 Editor::_idle_visual_changer (void* arg)
4574 return static_cast<Editor*>(arg)->idle_visual_changer ();
4578 Editor::idle_visual_changer ()
4580 /* set_horizontal_position() below (and maybe other calls) call
4581 gtk_main_iteration(), so it's possible that a signal will be handled
4582 half-way through this method. If this signal wants an
4583 idle_visual_changer we must schedule another one after this one, so
4584 mark the idle_handler_id as -1 here to allow that. Also make a note
4585 that we are doing the visual change, so that changes in response to
4586 super-rapid-screen-update can be dropped if we are still processing
4590 pending_visual_change.idle_handler_id = -1;
4591 pending_visual_change.being_handled = true;
4593 VisualChange vc = pending_visual_change;
4595 pending_visual_change.pending = (VisualChange::Type) 0;
4597 visual_changer (vc);
4599 pending_visual_change.being_handled = false;
4601 return 0; /* this is always a one-shot call */
4605 Editor::visual_changer (const VisualChange& vc)
4607 double const last_time_origin = horizontal_position ();
4609 if (vc.pending & VisualChange::ZoomLevel) {
4610 set_samples_per_pixel (vc.samples_per_pixel);
4612 compute_fixed_ruler_scale ();
4614 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4615 update_tempo_based_rulers ();
4617 update_video_timeline();
4620 if (vc.pending & VisualChange::TimeOrigin) {
4621 set_horizontal_position (vc.time_origin / samples_per_pixel);
4624 if (vc.pending & VisualChange::YOrigin) {
4625 vertical_adjustment.set_value (vc.y_origin);
4628 if (last_time_origin == horizontal_position ()) {
4629 /* changed signal not emitted */
4630 update_fixed_rulers ();
4631 redisplay_tempo (true);
4634 if (!(vc.pending & VisualChange::ZoomLevel)) {
4635 update_video_timeline();
4638 _summary->set_overlays_dirty ();
4641 struct EditorOrderTimeAxisSorter {
4642 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4643 return a->order () < b->order ();
4648 Editor::sort_track_selection (TrackViewList& sel)
4650 EditorOrderTimeAxisSorter cmp;
4655 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4658 framepos_t where = 0;
4659 EditPoint ep = _edit_point;
4661 if (Profile->get_mixbus()) {
4662 if (ep == EditAtSelectedMarker) {
4663 ep = EditAtPlayhead;
4667 if (from_outside_canvas && (ep == EditAtMouse)) {
4668 ep = EditAtPlayhead;
4669 } else if (from_context_menu && (ep == EditAtMouse)) {
4670 return canvas_event_sample (&context_click_event, 0, 0);
4673 if (entered_marker) {
4674 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4675 return entered_marker->position();
4678 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4679 ep = EditAtSelectedMarker;
4682 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4683 ep = EditAtPlayhead;
4687 case EditAtPlayhead:
4688 if (_dragging_playhead) {
4689 where = *_control_scroll_target;
4691 where = _session->audible_frame();
4693 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4696 case EditAtSelectedMarker:
4697 if (!selection->markers.empty()) {
4699 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4702 where = loc->start();
4706 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4714 if (!mouse_frame (where, ignored)) {
4715 /* XXX not right but what can we do ? */
4719 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4727 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4729 if (!_session) return;
4731 begin_reversible_command (cmd);
4735 if ((tll = transport_loop_location()) == 0) {
4736 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4737 XMLNode &before = _session->locations()->get_state();
4738 _session->locations()->add (loc, true);
4739 _session->set_auto_loop_location (loc);
4740 XMLNode &after = _session->locations()->get_state();
4741 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4743 XMLNode &before = tll->get_state();
4744 tll->set_hidden (false, this);
4745 tll->set (start, end);
4746 XMLNode &after = tll->get_state();
4747 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4750 commit_reversible_command ();
4754 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4756 if (!_session) return;
4758 begin_reversible_command (cmd);
4762 if ((tpl = transport_punch_location()) == 0) {
4763 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4764 XMLNode &before = _session->locations()->get_state();
4765 _session->locations()->add (loc, true);
4766 _session->set_auto_punch_location (loc);
4767 XMLNode &after = _session->locations()->get_state();
4768 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4770 XMLNode &before = tpl->get_state();
4771 tpl->set_hidden (false, this);
4772 tpl->set (start, end);
4773 XMLNode &after = tpl->get_state();
4774 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4777 commit_reversible_command ();
4780 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4781 * @param rs List to which found regions are added.
4782 * @param where Time to look at.
4783 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4786 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4788 const TrackViewList* tracks;
4791 tracks = &track_views;
4796 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4798 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4801 boost::shared_ptr<Track> tr;
4802 boost::shared_ptr<Playlist> pl;
4804 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4806 boost::shared_ptr<RegionList> regions = pl->regions_at (
4807 (framepos_t) floor ( (double) where * tr->speed()));
4809 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4810 RegionView* rv = rtv->view()->find_view (*i);
4821 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4823 const TrackViewList* tracks;
4826 tracks = &track_views;
4831 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4832 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4834 boost::shared_ptr<Track> tr;
4835 boost::shared_ptr<Playlist> pl;
4837 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4839 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4840 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4842 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4844 RegionView* rv = rtv->view()->find_view (*i);
4855 /** Get regions using the following method:
4857 * Make a region list using:
4858 * (a) any selected regions
4859 * (b) the intersection of any selected tracks and the edit point(*)
4860 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4862 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4864 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4868 Editor::get_regions_from_selection_and_edit_point ()
4870 RegionSelection regions;
4872 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4873 regions.add (entered_regionview);
4875 regions = selection->regions;
4878 if ( regions.empty() ) {
4879 TrackViewList tracks = selection->tracks;
4881 if (!tracks.empty()) {
4882 /* no region selected or entered, but some selected tracks:
4883 * act on all regions on the selected tracks at the edit point
4885 framepos_t const where = get_preferred_edit_position ();
4886 get_regions_at(regions, where, tracks);
4893 /** Get regions using the following method:
4895 * Make a region list using:
4896 * (a) any selected regions
4897 * (b) the intersection of any selected tracks and the edit point(*)
4898 * (c) if neither exists, then whatever region is under the mouse
4900 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4902 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4905 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4907 RegionSelection regions;
4909 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4910 regions.add (entered_regionview);
4912 regions = selection->regions;
4915 if ( regions.empty() ) {
4916 TrackViewList tracks = selection->tracks;
4918 if (!tracks.empty()) {
4919 /* no region selected or entered, but some selected tracks:
4920 * act on all regions on the selected tracks at the edit point
4922 get_regions_at(regions, pos, tracks);
4929 /** Start with regions that are selected, or the entered regionview if none are selected.
4930 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4931 * of the regions that we started with.
4935 Editor::get_regions_from_selection_and_entered () const
4937 RegionSelection regions = selection->regions;
4939 if (regions.empty() && entered_regionview) {
4940 regions.add (entered_regionview);
4947 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4949 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4950 RouteTimeAxisView* rtav;
4952 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4953 boost::shared_ptr<Playlist> pl;
4954 std::vector<boost::shared_ptr<Region> > results;
4955 boost::shared_ptr<Track> tr;
4957 if ((tr = rtav->track()) == 0) {
4962 if ((pl = (tr->playlist())) != 0) {
4963 boost::shared_ptr<Region> r = pl->region_by_id (id);
4965 RegionView* rv = rtav->view()->find_view (r);
4967 regions.push_back (rv);
4976 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4979 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4980 MidiTimeAxisView* mtav;
4982 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4984 mtav->get_per_region_note_selection (selection);
4991 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4993 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4995 RouteTimeAxisView* tatv;
4997 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4999 boost::shared_ptr<Playlist> pl;
5000 vector<boost::shared_ptr<Region> > results;
5002 boost::shared_ptr<Track> tr;
5004 if ((tr = tatv->track()) == 0) {
5009 if ((pl = (tr->playlist())) != 0) {
5010 if (src_comparison) {
5011 pl->get_source_equivalent_regions (region, results);
5013 pl->get_region_list_equivalent_regions (region, results);
5017 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5018 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5019 regions.push_back (marv);
5028 Editor::show_rhythm_ferret ()
5030 if (rhythm_ferret == 0) {
5031 rhythm_ferret = new RhythmFerret(*this);
5034 rhythm_ferret->set_session (_session);
5035 rhythm_ferret->show ();
5036 rhythm_ferret->present ();
5040 Editor::first_idle ()
5042 MessageDialog* dialog = 0;
5044 if (track_views.size() > 1) {
5045 Timers::TimerSuspender t;
5046 dialog = new MessageDialog (
5047 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5051 ARDOUR_UI::instance()->flush_pending (60);
5054 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5058 // first idle adds route children (automation tracks), so we need to redisplay here
5059 _routes->redisplay ();
5063 if (_session->undo_depth() == 0) {
5064 undo_action->set_sensitive(false);
5066 redo_action->set_sensitive(false);
5067 begin_selection_op_history ();
5073 Editor::_idle_resize (gpointer arg)
5075 return ((Editor*)arg)->idle_resize ();
5079 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5081 if (resize_idle_id < 0) {
5082 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5083 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5084 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5086 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5087 _pending_resize_amount = 0;
5090 /* make a note of the smallest resulting height, so that we can clamp the
5091 lower limit at TimeAxisView::hSmall */
5093 int32_t min_resulting = INT32_MAX;
5095 _pending_resize_amount += h;
5096 _pending_resize_view = view;
5098 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5100 if (selection->tracks.contains (_pending_resize_view)) {
5101 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5102 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5106 if (min_resulting < 0) {
5111 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5112 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5116 /** Handle pending resizing of tracks */
5118 Editor::idle_resize ()
5120 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5122 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5123 selection->tracks.contains (_pending_resize_view)) {
5125 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5126 if (*i != _pending_resize_view) {
5127 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5132 _pending_resize_amount = 0;
5133 _group_tabs->set_dirty ();
5134 resize_idle_id = -1;
5142 ENSURE_GUI_THREAD (*this, &Editor::located);
5145 playhead_cursor->set_position (_session->audible_frame ());
5146 if (_follow_playhead && !_pending_initial_locate) {
5147 reset_x_origin_to_follow_playhead ();
5151 _pending_locate_request = false;
5152 _pending_initial_locate = false;
5156 Editor::region_view_added (RegionView * rv)
5158 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5159 if (rv->region ()->id () == (*pr)) {
5160 selection->add (rv);
5161 selection->regions.pending.erase (pr);
5166 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5168 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5169 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5170 if (rv->region()->id () == (*rnote).first) {
5171 mrv->select_notes ((*rnote).second);
5172 selection->pending_midi_note_selection.erase(rnote);
5178 _summary->set_background_dirty ();
5182 Editor::region_view_removed ()
5184 _summary->set_background_dirty ();
5188 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5190 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5191 if ((*j)->stripable() == s) {
5201 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5205 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5206 TimeAxisView* tv = axis_view_from_stripable (*i);
5216 Editor::suspend_route_redisplay ()
5219 _routes->suspend_redisplay();
5224 Editor::resume_route_redisplay ()
5227 _routes->redisplay(); // queue redisplay
5228 _routes->resume_redisplay();
5233 Editor::add_vcas (VCAList& vlist)
5237 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5238 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5241 add_stripables (sl);
5245 Editor::add_routes (RouteList& rlist)
5249 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5253 add_stripables (sl);
5257 Editor::add_stripables (StripableList& sl)
5259 list<TimeAxisView*> new_views;
5260 boost::shared_ptr<VCA> v;
5261 boost::shared_ptr<Route> r;
5262 TrackViewList new_selection;
5263 bool from_scratch = (track_views.size() == 0);
5265 sl.sort (StripablePresentationInfoSorter());
5267 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5269 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5271 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5273 new_views.push_back (vtv);
5275 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5277 if (r->is_auditioner() || r->is_monitor()) {
5281 RouteTimeAxisView* rtv;
5282 DataType dt = r->input()->default_type();
5284 if (dt == ARDOUR::DataType::AUDIO) {
5285 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5287 } else if (dt == ARDOUR::DataType::MIDI) {
5288 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5291 throw unknown_type();
5294 new_views.push_back (rtv);
5295 track_views.push_back (rtv);
5296 new_selection.push_back (rtv);
5298 rtv->effective_gain_display ();
5300 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5301 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5305 if (new_views.size() > 0) {
5306 _routes->time_axis_views_added (new_views);
5307 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5310 /* note: !new_selection.empty() means that we got some routes rather
5314 if (!from_scratch && !new_selection.empty()) {
5315 selection->tracks.clear();
5316 selection->add (new_selection);
5317 begin_selection_op_history();
5320 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5321 show_editor_mixer (true);
5324 editor_list_button.set_sensitive (true);
5328 Editor::timeaxisview_deleted (TimeAxisView *tv)
5330 if (tv == entered_track) {
5334 if (_session && _session->deletion_in_progress()) {
5335 /* the situation is under control */
5339 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5341 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5343 _routes->route_removed (tv);
5345 TimeAxisView::Children c = tv->get_child_list ();
5346 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5347 if (entered_track == i->get()) {
5352 /* remove it from the list of track views */
5354 TrackViewList::iterator i;
5356 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5357 i = track_views.erase (i);
5360 /* update whatever the current mixer strip is displaying, if revelant */
5362 boost::shared_ptr<Route> route;
5365 route = rtav->route ();
5368 if (current_mixer_strip && current_mixer_strip->route() == route) {
5370 TimeAxisView* next_tv;
5372 if (track_views.empty()) {
5374 } else if (i == track_views.end()) {
5375 next_tv = track_views.front();
5382 set_selected_mixer_strip (*next_tv);
5384 /* make the editor mixer strip go away setting the
5385 * button to inactive (which also unticks the menu option)
5388 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5394 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5396 if (apply_to_selection) {
5397 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5399 TrackSelection::iterator j = i;
5402 hide_track_in_display (*i, false);
5407 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5409 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5410 // this will hide the mixer strip
5411 set_selected_mixer_strip (*tv);
5414 _routes->hide_track_in_display (*tv);
5419 Editor::sync_track_view_list_and_routes ()
5421 track_views = TrackViewList (_routes->views ());
5423 _summary->set_background_dirty();
5424 _group_tabs->set_dirty ();
5426 return false; // do not call again (until needed)
5430 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5432 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5437 /** Find a RouteTimeAxisView by the ID of its route */
5439 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5441 RouteTimeAxisView* v;
5443 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5444 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5445 if(v->route()->id() == id) {
5455 Editor::fit_route_group (RouteGroup *g)
5457 TrackViewList ts = axis_views_from_routes (g->route_list ());
5462 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5464 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5467 _session->cancel_audition ();
5471 if (_session->is_auditioning()) {
5472 _session->cancel_audition ();
5473 if (r == last_audition_region) {
5478 _session->audition_region (r);
5479 last_audition_region = r;
5484 Editor::hide_a_region (boost::shared_ptr<Region> r)
5486 r->set_hidden (true);
5490 Editor::show_a_region (boost::shared_ptr<Region> r)
5492 r->set_hidden (false);
5496 Editor::audition_region_from_region_list ()
5498 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5502 Editor::hide_region_from_region_list ()
5504 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5508 Editor::show_region_in_region_list ()
5510 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5514 Editor::step_edit_status_change (bool yn)
5517 start_step_editing ();
5519 stop_step_editing ();
5524 Editor::start_step_editing ()
5526 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5530 Editor::stop_step_editing ()
5532 step_edit_connection.disconnect ();
5536 Editor::check_step_edit ()
5538 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5539 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5541 mtv->check_step_edit ();
5545 return true; // do it again, till we stop
5549 Editor::scroll_press (Direction dir)
5551 ++_scroll_callbacks;
5553 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5554 /* delay the first auto-repeat */
5560 scroll_backward (1);
5568 scroll_up_one_track ();
5572 scroll_down_one_track ();
5576 /* do hacky auto-repeat */
5577 if (!_scroll_connection.connected ()) {
5579 _scroll_connection = Glib::signal_timeout().connect (
5580 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5583 _scroll_callbacks = 0;
5590 Editor::scroll_release ()
5592 _scroll_connection.disconnect ();
5595 /** Queue a change for the Editor viewport x origin to follow the playhead */
5597 Editor::reset_x_origin_to_follow_playhead ()
5599 framepos_t const frame = playhead_cursor->current_frame ();
5601 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5603 if (_session->transport_speed() < 0) {
5605 if (frame > (current_page_samples() / 2)) {
5606 center_screen (frame-(current_page_samples()/2));
5608 center_screen (current_page_samples()/2);
5615 if (frame < leftmost_frame) {
5617 if (_session->transport_rolling()) {
5618 /* rolling; end up with the playhead at the right of the page */
5619 l = frame - current_page_samples ();
5621 /* not rolling: end up with the playhead 1/4 of the way along the page */
5622 l = frame - current_page_samples() / 4;
5626 if (_session->transport_rolling()) {
5627 /* rolling: end up with the playhead on the left of the page */
5630 /* not rolling: end up with the playhead 3/4 of the way along the page */
5631 l = frame - 3 * current_page_samples() / 4;
5639 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5645 Editor::super_rapid_screen_update ()
5647 if (!_session || !_session->engine().running()) {
5651 /* METERING / MIXER STRIPS */
5653 /* update track meters, if required */
5654 if (contents().is_mapped() && meters_running) {
5655 RouteTimeAxisView* rtv;
5656 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5657 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5658 rtv->fast_update ();
5663 /* and any current mixer strip */
5664 if (current_mixer_strip) {
5665 current_mixer_strip->fast_update ();
5668 /* PLAYHEAD AND VIEWPORT */
5670 framepos_t const frame = _session->audible_frame();
5672 /* There are a few reasons why we might not update the playhead / viewport stuff:
5674 * 1. we don't update things when there's a pending locate request, otherwise
5675 * when the editor requests a locate there is a chance that this method
5676 * will move the playhead before the locate request is processed, causing
5678 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5679 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5682 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5684 last_update_frame = frame;
5686 if (!_dragging_playhead) {
5687 playhead_cursor->set_position (frame);
5690 if (!_stationary_playhead) {
5692 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5693 /* We only do this if we aren't already
5694 handling a visual change (ie if
5695 pending_visual_change.being_handled is
5696 false) so that these requests don't stack
5697 up there are too many of them to handle in
5700 reset_x_origin_to_follow_playhead ();
5705 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5706 framepos_t const frame = playhead_cursor->current_frame ();
5707 double target = ((double)frame - (double)current_page_samples()/2.0);
5708 if (target <= 0.0) {
5711 // compare to EditorCursor::set_position()
5712 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5713 double const new_pos = sample_to_pixel_unrounded (target);
5714 if (rint (new_pos) != rint (old_pos)) {
5715 reset_x_origin (pixel_to_sample (floor (new_pos)));
5726 Editor::session_going_away ()
5728 _have_idled = false;
5730 _session_connections.drop_connections ();
5732 super_rapid_screen_update_connection.disconnect ();
5734 selection->clear ();
5735 cut_buffer->clear ();
5737 clicked_regionview = 0;
5738 clicked_axisview = 0;
5739 clicked_routeview = 0;
5740 entered_regionview = 0;
5742 last_update_frame = 0;
5745 playhead_cursor->hide ();
5747 /* rip everything out of the list displays */
5751 _route_groups->clear ();
5753 /* do this first so that deleting a track doesn't reset cms to null
5754 and thus cause a leak.
5757 if (current_mixer_strip) {
5758 if (current_mixer_strip->get_parent() != 0) {
5759 global_hpacker.remove (*current_mixer_strip);
5761 delete current_mixer_strip;
5762 current_mixer_strip = 0;
5765 /* delete all trackviews */
5767 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5770 track_views.clear ();
5772 nudge_clock->set_session (0);
5774 editor_list_button.set_active(false);
5775 editor_list_button.set_sensitive(false);
5777 /* clear tempo/meter rulers */
5778 remove_metric_marks ();
5780 clear_marker_display ();
5782 stop_step_editing ();
5786 /* get rid of any existing editor mixer strip */
5788 WindowTitle title(Glib::get_application_name());
5789 title += _("Editor");
5791 own_window()->set_title (title.get_string());
5794 SessionHandlePtr::session_going_away ();
5798 Editor::trigger_script (int i)
5800 LuaInstance::instance()-> call_action (i);
5804 Editor::set_script_action_name (int i, const std::string& n)
5806 string const a = string_compose (X_("script-action-%1"), i + 1);
5807 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5810 act->set_label (string_compose (_("Unset #%1"), i + 1));
5811 act->set_tooltip (_("no action bound"));
5812 act->set_sensitive (false);
5815 act->set_tooltip (n);
5816 act->set_sensitive (true);
5818 KeyEditor::UpdateBindings ();
5822 Editor::show_editor_list (bool yn)
5825 _the_notebook.show ();
5827 _the_notebook.hide ();
5832 Editor::change_region_layering_order (bool from_context_menu)
5834 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5836 if (!clicked_routeview) {
5837 if (layering_order_editor) {
5838 layering_order_editor->hide ();
5843 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5849 boost::shared_ptr<Playlist> pl = track->playlist();
5855 if (layering_order_editor == 0) {
5856 layering_order_editor = new RegionLayeringOrderEditor (*this);
5859 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5860 layering_order_editor->maybe_present ();
5864 Editor::update_region_layering_order_editor ()
5866 if (layering_order_editor && layering_order_editor->is_visible ()) {
5867 change_region_layering_order (true);
5872 Editor::setup_fade_images ()
5874 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5875 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5876 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5877 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5878 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5880 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5881 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5882 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5883 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5884 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5886 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5887 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5888 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5889 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5890 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5892 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5893 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5894 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5895 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5896 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5900 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5902 Editor::action_menu_item (std::string const & name)
5904 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5907 return *manage (a->create_menu_item ());
5911 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5913 EventBox* b = manage (new EventBox);
5914 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5915 Label* l = manage (new Label (name));
5919 _the_notebook.append_page (widget, *b);
5923 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5925 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5926 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5929 if (ev->type == GDK_2BUTTON_PRESS) {
5931 /* double-click on a notebook tab shrinks or expands the notebook */
5933 if (_notebook_shrunk) {
5934 if (pre_notebook_shrink_pane_width) {
5935 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5937 _notebook_shrunk = false;
5939 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5941 /* this expands the LHS of the edit pane to cover the notebook
5942 PAGE but leaves the tabs visible.
5944 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5945 _notebook_shrunk = true;
5953 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5955 using namespace Menu_Helpers;
5957 MenuList& items = _control_point_context_menu.items ();
5960 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5961 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5962 if (!can_remove_control_point (item)) {
5963 items.back().set_sensitive (false);
5966 _control_point_context_menu.popup (event->button.button, event->button.time);
5970 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5972 using namespace Menu_Helpers;
5974 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5979 /* We need to get the selection here and pass it to the operations, since
5980 popping up the menu will cause a region leave event which clears
5981 entered_regionview. */
5983 MidiRegionView& mrv = note->region_view();
5984 const RegionSelection rs = get_regions_from_selection_and_entered ();
5985 const uint32_t sel_size = mrv.selection_size ();
5987 MenuList& items = _note_context_menu.items();
5991 items.push_back(MenuElem(_("Delete"),
5992 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5995 items.push_back(MenuElem(_("Edit..."),
5996 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5997 if (sel_size != 1) {
5998 items.back().set_sensitive (false);
6001 items.push_back(MenuElem(_("Transpose..."),
6002 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6005 items.push_back(MenuElem(_("Legatize"),
6006 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6008 items.back().set_sensitive (false);
6011 items.push_back(MenuElem(_("Quantize..."),
6012 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6014 items.push_back(MenuElem(_("Remove Overlap"),
6015 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6017 items.back().set_sensitive (false);
6020 items.push_back(MenuElem(_("Transform..."),
6021 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6023 _note_context_menu.popup (event->button.button, event->button.time);
6027 Editor::zoom_vertical_modifier_released()
6029 _stepping_axis_view = 0;
6033 Editor::ui_parameter_changed (string parameter)
6035 if (parameter == "icon-set") {
6036 while (!_cursor_stack.empty()) {
6037 _cursor_stack.pop_back();
6039 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6040 _cursor_stack.push_back(_cursors->grabber);
6041 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6042 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6044 } else if (parameter == "draggable-playhead") {
6045 if (_verbose_cursor) {
6046 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6052 Editor::use_own_window (bool and_fill_it)
6054 bool new_window = !own_window();
6056 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6058 if (win && new_window) {
6059 win->set_name ("EditorWindow");
6061 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6063 // win->signal_realize().connect (*this, &Editor::on_realize);
6064 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6065 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6066 win->set_data ("ardour-bindings", bindings);
6071 DisplaySuspender ds;
6072 contents().show_all ();
6074 /* XXX: this is a bit unfortunate; it would probably
6075 be nicer if we could just call show () above rather
6076 than needing the show_all ()
6079 /* re-hide stuff if necessary */
6080 editor_list_button_toggled ();
6081 parameter_changed ("show-summary");
6082 parameter_changed ("show-group-tabs");
6083 parameter_changed ("show-zoom-tools");
6085 /* now reset all audio_time_axis heights, because widgets might need
6091 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6092 tv = (static_cast<TimeAxisView*>(*i));
6093 tv->reset_height ();
6096 if (current_mixer_strip) {
6097 current_mixer_strip->hide_things ();
6098 current_mixer_strip->parameter_changed ("mixer-element-visibility");