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_group.h"
76 #include "ardour/session_playlists.h"
77 #include "ardour/tempo.h"
78 #include "ardour/utils.h"
80 #include "canvas/debug.h"
81 #include "canvas/text.h"
83 #include "control_protocol/control_protocol.h"
86 #include "analysis_window.h"
87 #include "audio_clock.h"
88 #include "audio_region_view.h"
89 #include "audio_streamview.h"
90 #include "audio_time_axis.h"
91 #include "automation_time_axis.h"
92 #include "bundle_manager.h"
93 #include "crossfade_edit.h"
97 #include "editor_cursors.h"
98 #include "editor_drag.h"
99 #include "editor_group_tabs.h"
100 #include "editor_locations.h"
101 #include "editor_regions.h"
102 #include "editor_route_groups.h"
103 #include "editor_routes.h"
104 #include "editor_snapshots.h"
105 #include "editor_summary.h"
106 #include "export_report.h"
107 #include "global_port_matrix.h"
108 #include "gui_object.h"
109 #include "gui_thread.h"
110 #include "keyboard.h"
111 #include "keyeditor.h"
112 #include "luainstance.h"
114 #include "midi_region_view.h"
115 #include "midi_time_axis.h"
116 #include "mixer_strip.h"
117 #include "mixer_ui.h"
118 #include "mouse_cursors.h"
119 #include "note_base.h"
120 #include "playlist_selector.h"
121 #include "public_editor.h"
122 #include "quantize_dialog.h"
123 #include "region_layering_order_editor.h"
124 #include "rgb_macros.h"
125 #include "rhythm_ferret.h"
126 #include "selection.h"
127 #include "simple_progress_dialog.h"
129 #include "tempo_lines.h"
130 #include "time_axis_view.h"
132 #include "tooltips.h"
133 #include "ui_config.h"
135 #include "verbose_cursor.h"
140 using namespace ARDOUR;
141 using namespace ARDOUR_UI_UTILS;
144 using namespace Glib;
145 using namespace Gtkmm2ext;
146 using namespace Editing;
148 using PBD::internationalize;
150 using Gtkmm2ext::Keyboard;
152 double Editor::timebar_height = 15.0;
154 static const gchar *_snap_type_strings[] = {
188 static const gchar *_snap_mode_strings[] = {
195 static const gchar *_edit_point_strings[] = {
202 static const gchar *_edit_mode_strings[] = {
210 static const gchar *_zoom_focus_strings[] = {
220 #ifdef USE_RUBBERBAND
221 static const gchar *_rb_opt_strings[] = {
224 N_("Balanced multitimbral mixture"),
225 N_("Unpitched percussion with stable notes"),
226 N_("Crisp monophonic instrumental"),
227 N_("Unpitched solo percussion"),
228 N_("Resample without preserving pitch"),
233 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
236 pane_size_watcher (Paned* pane)
238 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
242 Quartz: impossible to access
244 so stop that by preventing it from ever getting too narrow. 35
245 pixels is basically a rough guess at the tab width.
250 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
252 gint pos = pane->get_position ();
254 if (pos > max_width_of_lhs) {
255 pane->set_position (max_width_of_lhs);
260 : PublicEditor (global_hpacker)
261 , editor_mixer_strip_width (Wide)
262 , constructed (false)
263 , _playlist_selector (0)
264 , no_save_visual (false)
266 , samples_per_pixel (2048)
267 , zoom_focus (ZoomFocusPlayhead)
268 , mouse_mode (MouseObject)
269 , pre_internal_snap_type (SnapToBeat)
270 , pre_internal_snap_mode (SnapOff)
271 , internal_snap_type (SnapToBeat)
272 , internal_snap_mode (SnapOff)
273 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
274 , _notebook_shrunk (false)
275 , location_marker_color (0)
276 , location_range_color (0)
277 , location_loop_color (0)
278 , location_punch_color (0)
279 , location_cd_marker_color (0)
281 , _show_marker_lines (false)
282 , clicked_axisview (0)
283 , clicked_routeview (0)
284 , clicked_regionview (0)
285 , clicked_selection (0)
286 , clicked_control_point (0)
287 , button_release_can_deselect (true)
288 , _mouse_changed_selection (false)
289 , region_edit_menu_split_item (0)
290 , region_edit_menu_split_multichannel_item (0)
291 , track_region_edit_playlist_menu (0)
292 , track_edit_playlist_submenu (0)
293 , track_selection_edit_playlist_submenu (0)
294 , _popup_region_menu_item (0)
296 , _track_canvas_viewport (0)
297 , within_track_canvas (false)
298 , _verbose_cursor (0)
302 , range_marker_group (0)
303 , transport_marker_group (0)
304 , cd_marker_group (0)
305 , _time_markers_group (0)
306 , hv_scroll_group (0)
308 , cursor_scroll_group (0)
309 , no_scroll_group (0)
310 , _trackview_group (0)
311 , _drag_motion_group (0)
312 , _canvas_drop_zone (0)
313 , no_ruler_shown_update (false)
314 , ruler_grabbed_widget (0)
316 , minsec_mark_interval (0)
317 , minsec_mark_modulo (0)
319 , timecode_mark_modulo (0)
320 , timecode_nmarks (0)
321 , _samples_ruler_interval (0)
324 , bbt_bar_helper_on (0)
325 , bbt_accent_modulo (0)
330 , visible_timebars (0)
331 , editor_ruler_menu (0)
335 , range_marker_bar (0)
336 , transport_marker_bar (0)
338 , minsec_label (_("Mins:Secs"))
339 , bbt_label (_("Bars:Beats"))
340 , timecode_label (_("Timecode"))
341 , samples_label (_("Samples"))
342 , tempo_label (_("Tempo"))
343 , meter_label (_("Meter"))
344 , mark_label (_("Location Markers"))
345 , range_mark_label (_("Range Markers"))
346 , transport_mark_label (_("Loop/Punch Ranges"))
347 , cd_mark_label (_("CD Markers"))
348 , videotl_label (_("Video Timeline"))
350 , playhead_cursor (0)
351 , edit_packer (4, 4, true)
352 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
353 , horizontal_adjustment (0.0, 0.0, 1e16)
354 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
355 , controls_layout (unused_adjustment, vertical_adjustment)
356 , _scroll_callbacks (0)
357 , _visible_canvas_width (0)
358 , _visible_canvas_height (0)
359 , _full_canvas_height (0)
360 , edit_controls_left_menu (0)
361 , edit_controls_right_menu (0)
362 , last_update_frame (0)
363 , cut_buffer_start (0)
364 , cut_buffer_length (0)
365 , button_bindings (0)
369 , current_interthread_info (0)
370 , analysis_window (0)
371 , select_new_marker (false)
373 , scrubbing_direction (0)
374 , scrub_reversals (0)
375 , scrub_reverse_distance (0)
376 , have_pending_keyboard_selection (false)
377 , pending_keyboard_selection_start (0)
378 , _snap_type (SnapToBeat)
379 , _snap_mode (SnapOff)
380 , snap_threshold (5.0)
381 , ignore_gui_changes (false)
382 , _drags (new DragManager (this))
384 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
385 , _dragging_playhead (false)
386 , _dragging_edit_point (false)
387 , _show_measures (true)
388 , _follow_playhead (true)
389 , _stationary_playhead (false)
392 , global_rect_group (0)
393 , time_line_group (0)
394 , tempo_marker_menu (0)
395 , meter_marker_menu (0)
397 , range_marker_menu (0)
398 , transport_marker_menu (0)
399 , new_transport_marker_menu (0)
401 , marker_menu_item (0)
402 , bbt_beat_subdivision (4)
403 , _visible_track_count (-1)
404 , toolbar_selection_clock_table (2,3)
405 , automation_mode_button (_("mode"))
406 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
407 , selection (new Selection (this))
408 , cut_buffer (new Selection (this))
409 , _selection_memento (new SelectionMemento())
410 , _all_region_actions_sensitized (false)
411 , _ignore_region_action (false)
412 , _last_region_menu_was_main (false)
413 , _ignore_follow_edits (false)
414 , cd_marker_bar_drag_rect (0)
415 , range_bar_drag_rect (0)
416 , transport_bar_drag_rect (0)
417 , transport_bar_range_rect (0)
418 , transport_bar_preroll_rect (0)
419 , transport_bar_postroll_rect (0)
420 , transport_loop_range_rect (0)
421 , transport_punch_range_rect (0)
422 , transport_punchin_line (0)
423 , transport_punchout_line (0)
424 , transport_preroll_rect (0)
425 , transport_postroll_rect (0)
427 , rubberband_rect (0)
433 , autoscroll_horizontal_allowed (false)
434 , autoscroll_vertical_allowed (false)
436 , autoscroll_widget (0)
437 , show_gain_after_trim (false)
438 , selection_op_cmd_depth (0)
439 , selection_op_history_it (0)
440 , no_save_instant (false)
442 , current_mixer_strip (0)
443 , show_editor_mixer_when_tracks_arrive (false)
444 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
445 , current_stepping_trackview (0)
446 , last_track_height_step_timestamp (0)
448 , entered_regionview (0)
449 , clear_entered_track (false)
450 , _edit_point (EditAtMouse)
451 , meters_running (false)
453 , _have_idled (false)
454 , resize_idle_id (-1)
455 , _pending_resize_amount (0)
456 , _pending_resize_view (0)
457 , _pending_locate_request (false)
458 , _pending_initial_locate (false)
462 , layering_order_editor (0)
463 , _last_cut_copy_source_track (0)
464 , _region_selection_change_updates_region_list (true)
466 , _following_mixer_selection (false)
467 , _control_point_toggled_on_press (false)
468 , _stepping_axis_view (0)
469 , quantize_dialog (0)
470 , _main_menu_disabler (0)
471 , myactions (X_("editor"))
473 /* we are a singleton */
475 PublicEditor::_instance = this;
479 last_event_time.tv_sec = 0;
480 last_event_time.tv_usec = 0;
482 selection_op_history.clear();
485 snap_type_strings = I18N (_snap_type_strings);
486 snap_mode_strings = I18N (_snap_mode_strings);
487 zoom_focus_strings = I18N (_zoom_focus_strings);
488 edit_mode_strings = I18N (_edit_mode_strings);
489 edit_point_strings = I18N (_edit_point_strings);
490 #ifdef USE_RUBBERBAND
491 rb_opt_strings = I18N (_rb_opt_strings);
495 build_edit_mode_menu();
496 build_zoom_focus_menu();
497 build_track_count_menu();
498 build_snap_mode_menu();
499 build_snap_type_menu();
500 build_edit_point_menu();
502 location_marker_color = UIConfiguration::instance().color ("location marker");
503 location_range_color = UIConfiguration::instance().color ("location range");
504 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
505 location_loop_color = UIConfiguration::instance().color ("location loop");
506 location_punch_color = UIConfiguration::instance().color ("location punch");
508 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
510 TimeAxisView::setup_sizes ();
511 ArdourMarker::setup_sizes (timebar_height);
512 TempoCurve::setup_sizes (timebar_height);
514 bbt_label.set_name ("EditorRulerLabel");
515 bbt_label.set_size_request (-1, (int)timebar_height);
516 bbt_label.set_alignment (1.0, 0.5);
517 bbt_label.set_padding (5,0);
519 bbt_label.set_no_show_all();
520 minsec_label.set_name ("EditorRulerLabel");
521 minsec_label.set_size_request (-1, (int)timebar_height);
522 minsec_label.set_alignment (1.0, 0.5);
523 minsec_label.set_padding (5,0);
524 minsec_label.hide ();
525 minsec_label.set_no_show_all();
526 timecode_label.set_name ("EditorRulerLabel");
527 timecode_label.set_size_request (-1, (int)timebar_height);
528 timecode_label.set_alignment (1.0, 0.5);
529 timecode_label.set_padding (5,0);
530 timecode_label.hide ();
531 timecode_label.set_no_show_all();
532 samples_label.set_name ("EditorRulerLabel");
533 samples_label.set_size_request (-1, (int)timebar_height);
534 samples_label.set_alignment (1.0, 0.5);
535 samples_label.set_padding (5,0);
536 samples_label.hide ();
537 samples_label.set_no_show_all();
539 tempo_label.set_name ("EditorRulerLabel");
540 tempo_label.set_size_request (-1, (int)timebar_height);
541 tempo_label.set_alignment (1.0, 0.5);
542 tempo_label.set_padding (5,0);
544 tempo_label.set_no_show_all();
546 meter_label.set_name ("EditorRulerLabel");
547 meter_label.set_size_request (-1, (int)timebar_height);
548 meter_label.set_alignment (1.0, 0.5);
549 meter_label.set_padding (5,0);
551 meter_label.set_no_show_all();
553 if (Profile->get_trx()) {
554 mark_label.set_text (_("Markers"));
556 mark_label.set_name ("EditorRulerLabel");
557 mark_label.set_size_request (-1, (int)timebar_height);
558 mark_label.set_alignment (1.0, 0.5);
559 mark_label.set_padding (5,0);
561 mark_label.set_no_show_all();
563 cd_mark_label.set_name ("EditorRulerLabel");
564 cd_mark_label.set_size_request (-1, (int)timebar_height);
565 cd_mark_label.set_alignment (1.0, 0.5);
566 cd_mark_label.set_padding (5,0);
567 cd_mark_label.hide();
568 cd_mark_label.set_no_show_all();
570 videotl_bar_height = 4;
571 videotl_label.set_name ("EditorRulerLabel");
572 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
573 videotl_label.set_alignment (1.0, 0.5);
574 videotl_label.set_padding (5,0);
575 videotl_label.hide();
576 videotl_label.set_no_show_all();
578 range_mark_label.set_name ("EditorRulerLabel");
579 range_mark_label.set_size_request (-1, (int)timebar_height);
580 range_mark_label.set_alignment (1.0, 0.5);
581 range_mark_label.set_padding (5,0);
582 range_mark_label.hide();
583 range_mark_label.set_no_show_all();
585 transport_mark_label.set_name ("EditorRulerLabel");
586 transport_mark_label.set_size_request (-1, (int)timebar_height);
587 transport_mark_label.set_alignment (1.0, 0.5);
588 transport_mark_label.set_padding (5,0);
589 transport_mark_label.hide();
590 transport_mark_label.set_no_show_all();
592 initialize_canvas ();
594 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
596 _summary = new EditorSummary (this);
598 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
599 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
601 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
603 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
604 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
606 edit_controls_vbox.set_spacing (0);
607 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
608 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
610 HBox* h = manage (new HBox);
611 _group_tabs = new EditorGroupTabs (this);
612 if (!ARDOUR::Profile->get_trx()) {
613 h->pack_start (*_group_tabs, PACK_SHRINK);
615 h->pack_start (edit_controls_vbox);
616 controls_layout.add (*h);
618 controls_layout.set_name ("EditControlsBase");
619 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
620 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
621 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
623 _cursors = new MouseCursors;
624 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
625 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
627 /* Push default cursor to ever-present bottom of cursor stack. */
628 push_canvas_cursor(_cursors->grabber);
630 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
632 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
633 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
634 pad_line_1->set_outline_color (0xFF0000FF);
640 edit_packer.set_col_spacings (0);
641 edit_packer.set_row_spacings (0);
642 edit_packer.set_homogeneous (false);
643 edit_packer.set_border_width (0);
644 edit_packer.set_name ("EditorWindow");
646 time_bars_event_box.add (time_bars_vbox);
647 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
648 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
650 /* labels for the time bars */
651 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
653 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
655 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
657 bottom_hbox.set_border_width (2);
658 bottom_hbox.set_spacing (3);
660 _route_groups = new EditorRouteGroups (this);
661 _routes = new EditorRoutes (this);
662 _regions = new EditorRegions (this);
663 _snapshots = new EditorSnapshots (this);
664 _locations = new EditorLocations (this);
666 /* these are static location signals */
668 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
669 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
670 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
672 add_notebook_page (_("Regions"), _regions->widget ());
673 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
674 add_notebook_page (_("Snapshots"), _snapshots->widget ());
675 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
676 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
678 _the_notebook.set_show_tabs (true);
679 _the_notebook.set_scrollable (true);
680 _the_notebook.popup_disable ();
681 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
682 _the_notebook.show_all ();
684 _notebook_shrunk = false;
686 editor_summary_pane.pack1(edit_packer);
688 Button* summary_arrows_left_left = manage (new Button);
689 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
690 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
691 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
693 Button* summary_arrows_left_right = manage (new Button);
694 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
695 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
696 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
698 VBox* summary_arrows_left = manage (new VBox);
699 summary_arrows_left->pack_start (*summary_arrows_left_left);
700 summary_arrows_left->pack_start (*summary_arrows_left_right);
702 Button* summary_arrows_right_up = manage (new Button);
703 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
704 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
705 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
707 Button* summary_arrows_right_down = manage (new Button);
708 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
709 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
710 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
712 VBox* summary_arrows_right = manage (new VBox);
713 summary_arrows_right->pack_start (*summary_arrows_right_up);
714 summary_arrows_right->pack_start (*summary_arrows_right_down);
716 Frame* summary_frame = manage (new Frame);
717 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
719 summary_frame->add (*_summary);
720 summary_frame->show ();
722 _summary_hbox.pack_start (*summary_arrows_left, false, false);
723 _summary_hbox.pack_start (*summary_frame, true, true);
724 _summary_hbox.pack_start (*summary_arrows_right, false, false);
726 if (!ARDOUR::Profile->get_trx()) {
727 editor_summary_pane.pack2 (_summary_hbox);
730 edit_pane.pack1 (editor_summary_pane, true, true);
731 if (!ARDOUR::Profile->get_trx()) {
732 edit_pane.pack2 (_the_notebook, false, true);
735 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
737 /* XXX: editor_summary_pane might need similar to the edit_pane */
739 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
741 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
742 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
744 top_hbox.pack_start (toolbar_frame);
746 HBox *hbox = manage (new HBox);
747 hbox->pack_start (edit_pane, true, true);
749 global_vpacker.pack_start (top_hbox, false, false);
750 global_vpacker.pack_start (*hbox, true, true);
751 global_hpacker.pack_start (global_vpacker, true, true);
753 /* need to show the "contents" widget so that notebook will show if tab is switched to
756 global_hpacker.show ();
758 /* register actions now so that set_state() can find them and set toggles/checks etc */
765 _playlist_selector = new PlaylistSelector();
766 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
768 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
772 nudge_forward_button.set_name ("nudge button");
773 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
775 nudge_backward_button.set_name ("nudge button");
776 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
778 fade_context_menu.set_name ("ArdourContextMenu");
780 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
782 /* allow external control surfaces/protocols to do various things */
784 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
785 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
786 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
787 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
788 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
789 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
790 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
791 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
792 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
793 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
794 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
795 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
796 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
797 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
799 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
800 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
801 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
802 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
803 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
805 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
807 /* problematic: has to return a value and thus cannot be x-thread */
809 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
811 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
812 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
814 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
816 _ignore_region_action = false;
817 _last_region_menu_was_main = false;
818 _popup_region_menu_item = 0;
820 _ignore_follow_edits = false;
822 _show_marker_lines = false;
824 /* Button bindings */
826 button_bindings = new Bindings ("editor-mouse");
828 XMLNode* node = button_settings();
830 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
831 button_bindings->load_operation (**i);
837 /* grab current parameter state */
838 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
839 UIConfiguration::instance().map_parameters (pc);
841 setup_fade_images ();
843 LuaInstance::instance(); // instantiate
844 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
851 delete button_bindings;
853 delete _route_groups;
854 delete _track_canvas_viewport;
857 delete quantize_dialog;
863 delete _playlist_selector;
865 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
871 Editor::button_settings () const
873 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
874 XMLNode* node = find_named_node (*settings, X_("Buttons"));
877 node = new XMLNode (X_("Buttons"));
884 Editor::get_smart_mode () const
886 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
890 Editor::catch_vanishing_regionview (RegionView *rv)
892 /* note: the selection will take care of the vanishing
893 audioregionview by itself.
896 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
900 if (clicked_regionview == rv) {
901 clicked_regionview = 0;
904 if (entered_regionview == rv) {
905 set_entered_regionview (0);
908 if (!_all_region_actions_sensitized) {
909 sensitize_all_region_actions (true);
914 Editor::set_entered_regionview (RegionView* rv)
916 if (rv == entered_regionview) {
920 if (entered_regionview) {
921 entered_regionview->exited ();
924 entered_regionview = rv;
926 if (entered_regionview != 0) {
927 entered_regionview->entered ();
930 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
931 /* This RegionView entry might have changed what region actions
932 are allowed, so sensitize them all in case a key is pressed.
934 sensitize_all_region_actions (true);
939 Editor::set_entered_track (TimeAxisView* tav)
942 entered_track->exited ();
948 entered_track->entered ();
953 Editor::instant_save ()
955 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
960 _session->add_instant_xml(get_state());
962 Config->add_instant_xml(get_state());
967 Editor::control_vertical_zoom_in_all ()
969 tav_zoom_smooth (false, true);
973 Editor::control_vertical_zoom_out_all ()
975 tav_zoom_smooth (true, true);
979 Editor::control_vertical_zoom_in_selected ()
981 tav_zoom_smooth (false, false);
985 Editor::control_vertical_zoom_out_selected ()
987 tav_zoom_smooth (true, false);
991 Editor::control_view (uint32_t view)
993 goto_visual_state (view);
997 Editor::control_unselect ()
999 selection->clear_tracks ();
1003 Editor::control_select (PresentationInfo::global_order_t global_order, Selection::Operation op)
1005 /* handles the (static) signal from the ControlProtocol class that
1006 * requests setting the selected track to a given RID
1013 PresentationInfo::Flag select_flags;
1015 if (global_order & ~0xffffffff) {
1016 /* some flags are set, so the PresentationInfo constructor
1019 select_flags = PresentationInfo::Flag (0);
1021 /* no type flags set in the global order ID, so assume caller
1022 * wants to select a Route
1024 select_flags = PresentationInfo::Route;
1027 PresentationInfo pi (global_order, select_flags);
1028 boost::shared_ptr<Stripable> s = _session->get_remote_nth_stripable (pi.group_order(), pi.flags());
1030 /* selected object may not be a Route */
1032 boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
1038 TimeAxisView* tav = axis_view_from_route (r);
1042 case Selection::Add:
1043 selection->add (tav);
1045 case Selection::Toggle:
1046 selection->toggle (tav);
1048 case Selection::Extend:
1050 case Selection::Set:
1051 selection->set (tav);
1055 selection->clear_tracks ();
1060 Editor::control_step_tracks_up ()
1062 scroll_tracks_up_line ();
1066 Editor::control_step_tracks_down ()
1068 scroll_tracks_down_line ();
1072 Editor::control_scroll (float fraction)
1074 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1080 double step = fraction * current_page_samples();
1083 _control_scroll_target is an optional<T>
1085 it acts like a pointer to an framepos_t, with
1086 a operator conversion to boolean to check
1087 that it has a value could possibly use
1088 playhead_cursor->current_frame to store the
1089 value and a boolean in the class to know
1090 when it's out of date
1093 if (!_control_scroll_target) {
1094 _control_scroll_target = _session->transport_frame();
1095 _dragging_playhead = true;
1098 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1099 *_control_scroll_target = 0;
1100 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1101 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1103 *_control_scroll_target += (framepos_t) trunc (step);
1106 /* move visuals, we'll catch up with it later */
1108 playhead_cursor->set_position (*_control_scroll_target);
1109 UpdateAllTransportClocks (*_control_scroll_target);
1111 if (*_control_scroll_target > (current_page_samples() / 2)) {
1112 /* try to center PH in window */
1113 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1119 Now we do a timeout to actually bring the session to the right place
1120 according to the playhead. This is to avoid reading disk buffers on every
1121 call to control_scroll, which is driven by ScrollTimeline and therefore
1122 probably by a control surface wheel which can generate lots of events.
1124 /* cancel the existing timeout */
1126 control_scroll_connection.disconnect ();
1128 /* add the next timeout */
1130 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1134 Editor::deferred_control_scroll (framepos_t /*target*/)
1136 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1137 // reset for next stream
1138 _control_scroll_target = boost::none;
1139 _dragging_playhead = false;
1144 Editor::access_action (std::string action_group, std::string action_item)
1150 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1153 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1161 Editor::on_realize ()
1165 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1166 start_lock_event_timing ();
1171 Editor::start_lock_event_timing ()
1173 /* check if we should lock the GUI every 30 seconds */
1175 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1179 Editor::generic_event_handler (GdkEvent* ev)
1182 case GDK_BUTTON_PRESS:
1183 case GDK_BUTTON_RELEASE:
1184 case GDK_MOTION_NOTIFY:
1186 case GDK_KEY_RELEASE:
1187 if (contents().is_mapped()) {
1188 gettimeofday (&last_event_time, 0);
1192 case GDK_LEAVE_NOTIFY:
1193 switch (ev->crossing.detail) {
1194 case GDK_NOTIFY_UNKNOWN:
1195 case GDK_NOTIFY_INFERIOR:
1196 case GDK_NOTIFY_ANCESTOR:
1198 case GDK_NOTIFY_VIRTUAL:
1199 case GDK_NOTIFY_NONLINEAR:
1200 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1201 /* leaving window, so reset focus, thus ending any and
1202 all text entry operations.
1204 reset_focus (&contents());
1217 Editor::lock_timeout_callback ()
1219 struct timeval now, delta;
1221 gettimeofday (&now, 0);
1223 timersub (&now, &last_event_time, &delta);
1225 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1227 /* don't call again. Returning false will effectively
1228 disconnect us from the timer callback.
1230 unlock() will call start_lock_event_timing() to get things
1240 Editor::map_position_change (framepos_t frame)
1242 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1244 if (_session == 0) {
1248 if (_follow_playhead) {
1249 center_screen (frame);
1252 playhead_cursor->set_position (frame);
1256 Editor::center_screen (framepos_t frame)
1258 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1260 /* if we're off the page, then scroll.
1263 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1264 center_screen_internal (frame, page);
1269 Editor::center_screen_internal (framepos_t frame, float page)
1274 frame -= (framepos_t) page;
1279 reset_x_origin (frame);
1284 Editor::update_title ()
1286 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1288 if (!own_window()) {
1293 bool dirty = _session->dirty();
1295 string session_name;
1297 if (_session->snap_name() != _session->name()) {
1298 session_name = _session->snap_name();
1300 session_name = _session->name();
1304 session_name = "*" + session_name;
1307 WindowTitle title(session_name);
1308 title += S_("Window|Editor");
1309 title += Glib::get_application_name();
1310 own_window()->set_title (title.get_string());
1312 /* ::session_going_away() will have taken care of it */
1317 Editor::set_session (Session *t)
1319 SessionHandlePtr::set_session (t);
1325 _playlist_selector->set_session (_session);
1326 nudge_clock->set_session (_session);
1327 _summary->set_session (_session);
1328 _group_tabs->set_session (_session);
1329 _route_groups->set_session (_session);
1330 _regions->set_session (_session);
1331 _snapshots->set_session (_session);
1332 _routes->set_session (_session);
1333 _locations->set_session (_session);
1335 if (rhythm_ferret) {
1336 rhythm_ferret->set_session (_session);
1339 if (analysis_window) {
1340 analysis_window->set_session (_session);
1344 sfbrowser->set_session (_session);
1347 compute_fixed_ruler_scale ();
1349 /* Make sure we have auto loop and auto punch ranges */
1351 Location* loc = _session->locations()->auto_loop_location();
1353 loc->set_name (_("Loop"));
1356 loc = _session->locations()->auto_punch_location();
1359 loc->set_name (_("Punch"));
1362 refresh_location_display ();
1364 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1365 the selected Marker; this needs the LocationMarker list to be available.
1367 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1368 set_state (*node, Stateful::loading_state_version);
1370 /* catch up with the playhead */
1372 _session->request_locate (playhead_cursor->current_frame ());
1373 _pending_initial_locate = true;
1377 /* These signals can all be emitted by a non-GUI thread. Therefore the
1378 handlers for them must not attempt to directly interact with the GUI,
1379 but use PBD::Signal<T>::connect() which accepts an event loop
1380 ("context") where the handler will be asked to run.
1383 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1384 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1385 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1386 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1387 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1388 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1389 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1390 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1391 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1392 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1393 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1394 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1395 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1396 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1398 playhead_cursor->show ();
1400 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1401 Config->map_parameters (pc);
1402 _session->config.map_parameters (pc);
1404 restore_ruler_visibility ();
1405 //tempo_map_changed (PropertyChange (0));
1406 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1408 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1409 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1412 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1413 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1416 switch (_snap_type) {
1417 case SnapToRegionStart:
1418 case SnapToRegionEnd:
1419 case SnapToRegionSync:
1420 case SnapToRegionBoundary:
1421 build_region_boundary_cache ();
1428 /* register for undo history */
1429 _session->register_with_memento_command_factory(id(), this);
1430 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1432 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1434 LuaInstance::instance()->set_session(_session);
1436 start_updating_meters ();
1440 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1442 if (a->get_name() == "RegionMenu") {
1443 /* When the main menu's region menu is opened, we setup the actions so that they look right
1444 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1445 so we resensitize all region actions when the entered regionview or the region selection
1446 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1447 happens after the region context menu is opened. So we set a flag here, too.
1451 sensitize_the_right_region_actions ();
1452 _last_region_menu_was_main = true;
1457 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1459 using namespace Menu_Helpers;
1461 void (Editor::*emf)(FadeShape);
1462 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1465 images = &_xfade_in_images;
1466 emf = &Editor::set_fade_in_shape;
1468 images = &_xfade_out_images;
1469 emf = &Editor::set_fade_out_shape;
1474 _("Linear (for highly correlated material)"),
1475 *(*images)[FadeLinear],
1476 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1484 _("Constant power"),
1485 *(*images)[FadeConstantPower],
1486 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 *(*images)[FadeSymmetric],
1495 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1499 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1504 *(*images)[FadeSlow],
1505 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 *(*images)[FadeFast],
1514 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1517 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 /** Pop up a context menu for when the user clicks on a start crossfade */
1522 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1524 using namespace Menu_Helpers;
1525 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1530 MenuList& items (xfade_in_context_menu.items());
1533 if (arv->audio_region()->fade_in_active()) {
1534 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1536 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1539 items.push_back (SeparatorElem());
1540 fill_xfade_menu (items, true);
1542 xfade_in_context_menu.popup (button, time);
1545 /** Pop up a context menu for when the user clicks on an end crossfade */
1547 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1549 using namespace Menu_Helpers;
1550 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1555 MenuList& items (xfade_out_context_menu.items());
1558 if (arv->audio_region()->fade_out_active()) {
1559 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1561 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1564 items.push_back (SeparatorElem());
1565 fill_xfade_menu (items, false);
1567 xfade_out_context_menu.popup (button, time);
1571 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1573 using namespace Menu_Helpers;
1574 Menu* (Editor::*build_menu_function)();
1577 switch (item_type) {
1579 case RegionViewName:
1580 case RegionViewNameHighlight:
1581 case LeftFrameHandle:
1582 case RightFrameHandle:
1583 if (with_selection) {
1584 build_menu_function = &Editor::build_track_selection_context_menu;
1586 build_menu_function = &Editor::build_track_region_context_menu;
1591 if (with_selection) {
1592 build_menu_function = &Editor::build_track_selection_context_menu;
1594 build_menu_function = &Editor::build_track_context_menu;
1599 if (clicked_routeview->track()) {
1600 build_menu_function = &Editor::build_track_context_menu;
1602 build_menu_function = &Editor::build_track_bus_context_menu;
1607 /* probably shouldn't happen but if it does, we don't care */
1611 menu = (this->*build_menu_function)();
1612 menu->set_name ("ArdourContextMenu");
1614 /* now handle specific situations */
1616 switch (item_type) {
1618 case RegionViewName:
1619 case RegionViewNameHighlight:
1620 case LeftFrameHandle:
1621 case RightFrameHandle:
1622 if (!with_selection) {
1623 if (region_edit_menu_split_item) {
1624 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1625 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1627 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1630 if (region_edit_menu_split_multichannel_item) {
1631 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1632 region_edit_menu_split_multichannel_item->set_sensitive (true);
1634 region_edit_menu_split_multichannel_item->set_sensitive (false);
1647 /* probably shouldn't happen but if it does, we don't care */
1651 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1653 /* Bounce to disk */
1655 using namespace Menu_Helpers;
1656 MenuList& edit_items = menu->items();
1658 edit_items.push_back (SeparatorElem());
1660 switch (clicked_routeview->audio_track()->freeze_state()) {
1661 case AudioTrack::NoFreeze:
1662 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1665 case AudioTrack::Frozen:
1666 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1669 case AudioTrack::UnFrozen:
1670 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1676 if (item_type == StreamItem && clicked_routeview) {
1677 clicked_routeview->build_underlay_menu(menu);
1680 /* When the region menu is opened, we setup the actions so that they look right
1683 sensitize_the_right_region_actions ();
1684 _last_region_menu_was_main = false;
1686 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1687 menu->popup (button, time);
1691 Editor::build_track_context_menu ()
1693 using namespace Menu_Helpers;
1695 MenuList& edit_items = track_context_menu.items();
1698 add_dstream_context_items (edit_items);
1699 return &track_context_menu;
1703 Editor::build_track_bus_context_menu ()
1705 using namespace Menu_Helpers;
1707 MenuList& edit_items = track_context_menu.items();
1710 add_bus_context_items (edit_items);
1711 return &track_context_menu;
1715 Editor::build_track_region_context_menu ()
1717 using namespace Menu_Helpers;
1718 MenuList& edit_items = track_region_context_menu.items();
1721 /* we've just cleared the track region context menu, so the menu that these
1722 two items were on will have disappeared; stop them dangling.
1724 region_edit_menu_split_item = 0;
1725 region_edit_menu_split_multichannel_item = 0;
1727 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1730 boost::shared_ptr<Track> tr;
1731 boost::shared_ptr<Playlist> pl;
1733 if ((tr = rtv->track())) {
1734 add_region_context_items (edit_items, tr);
1738 add_dstream_context_items (edit_items);
1740 return &track_region_context_menu;
1744 Editor::loudness_analyze_region_selection ()
1749 Selection& s (PublicEditor::instance ().get_selection ());
1750 RegionSelection ars = s.regions;
1751 ARDOUR::AnalysisGraph ag (_session);
1752 framecnt_t total_work = 0;
1754 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1755 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1759 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1762 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1763 total_work += arv->region ()->length ();
1766 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1768 ag.set_total_frames (total_work);
1769 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1772 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1773 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1777 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1781 ag.analyze_region (ar);
1784 if (!ag.canceled ()) {
1785 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1791 Editor::loudness_analyze_range_selection ()
1796 Selection& s (PublicEditor::instance ().get_selection ());
1797 TimeSelection ts = s.time;
1798 ARDOUR::AnalysisGraph ag (_session);
1799 framecnt_t total_work = 0;
1801 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1802 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1806 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1810 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1811 total_work += j->length ();
1815 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1817 ag.set_total_frames (total_work);
1818 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1821 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1822 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1826 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1830 ag.analyze_range (rui->route (), pl, ts);
1833 if (!ag.canceled ()) {
1834 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1840 Editor::spectral_analyze_region_selection ()
1842 if (analysis_window == 0) {
1843 analysis_window = new AnalysisWindow();
1846 analysis_window->set_session(_session);
1848 analysis_window->show_all();
1851 analysis_window->set_regionmode();
1852 analysis_window->analyze();
1854 analysis_window->present();
1858 Editor::spectral_analyze_range_selection()
1860 if (analysis_window == 0) {
1861 analysis_window = new AnalysisWindow();
1864 analysis_window->set_session(_session);
1866 analysis_window->show_all();
1869 analysis_window->set_rangemode();
1870 analysis_window->analyze();
1872 analysis_window->present();
1876 Editor::build_track_selection_context_menu ()
1878 using namespace Menu_Helpers;
1879 MenuList& edit_items = track_selection_context_menu.items();
1880 edit_items.clear ();
1882 add_selection_context_items (edit_items);
1883 // edit_items.push_back (SeparatorElem());
1884 // add_dstream_context_items (edit_items);
1886 return &track_selection_context_menu;
1890 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1892 using namespace Menu_Helpers;
1894 /* OK, stick the region submenu at the top of the list, and then add
1898 RegionSelection rs = get_regions_from_selection_and_entered ();
1900 string::size_type pos = 0;
1901 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1903 /* we have to hack up the region name because "_" has a special
1904 meaning for menu titles.
1907 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1908 menu_item_name.replace (pos, 1, "__");
1912 if (_popup_region_menu_item == 0) {
1913 _popup_region_menu_item = new MenuItem (menu_item_name);
1914 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1915 _popup_region_menu_item->show ();
1917 _popup_region_menu_item->set_label (menu_item_name);
1920 /* No latering allowed in later is higher layering model */
1921 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1922 if (act && Config->get_layer_model() == LaterHigher) {
1923 act->set_sensitive (false);
1925 act->set_sensitive (true);
1928 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1930 edit_items.push_back (*_popup_region_menu_item);
1931 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1932 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1934 edit_items.push_back (SeparatorElem());
1937 /** Add context menu items relevant to selection ranges.
1938 * @param edit_items List to add the items to.
1941 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1943 using namespace Menu_Helpers;
1945 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1946 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1948 edit_items.push_back (SeparatorElem());
1949 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1951 edit_items.push_back (SeparatorElem());
1952 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1953 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1955 edit_items.push_back (SeparatorElem());
1957 edit_items.push_back (
1959 _("Move Range Start to Previous Region Boundary"),
1960 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1964 edit_items.push_back (
1966 _("Move Range Start to Next Region Boundary"),
1967 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1971 edit_items.push_back (
1973 _("Move Range End to Previous Region Boundary"),
1974 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1978 edit_items.push_back (
1980 _("Move Range End to Next Region Boundary"),
1981 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1985 edit_items.push_back (SeparatorElem());
1986 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1987 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1989 edit_items.push_back (SeparatorElem());
1990 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1992 edit_items.push_back (SeparatorElem());
1993 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1994 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1995 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1997 edit_items.push_back (SeparatorElem());
1998 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2000 edit_items.push_back (SeparatorElem());
2001 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2002 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2004 edit_items.push_back (SeparatorElem());
2005 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2006 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2007 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2008 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2009 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2010 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2011 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2017 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2019 using namespace Menu_Helpers;
2023 Menu *play_menu = manage (new Menu);
2024 MenuList& play_items = play_menu->items();
2025 play_menu->set_name ("ArdourContextMenu");
2027 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2028 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2029 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2030 play_items.push_back (SeparatorElem());
2031 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2033 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2037 Menu *select_menu = manage (new Menu);
2038 MenuList& select_items = select_menu->items();
2039 select_menu->set_name ("ArdourContextMenu");
2041 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2042 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2043 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2044 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2045 select_items.push_back (SeparatorElem());
2046 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2047 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2048 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2049 select_items.push_back (SeparatorElem());
2050 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2051 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2052 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2053 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2054 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2055 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2056 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2058 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2062 Menu *cutnpaste_menu = manage (new Menu);
2063 MenuList& cutnpaste_items = cutnpaste_menu->items();
2064 cutnpaste_menu->set_name ("ArdourContextMenu");
2066 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2067 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2068 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2070 cutnpaste_items.push_back (SeparatorElem());
2072 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2073 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2075 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2077 /* Adding new material */
2079 edit_items.push_back (SeparatorElem());
2080 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2081 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2085 Menu *nudge_menu = manage (new Menu());
2086 MenuList& nudge_items = nudge_menu->items();
2087 nudge_menu->set_name ("ArdourContextMenu");
2089 edit_items.push_back (SeparatorElem());
2090 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2091 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2092 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2093 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2095 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2099 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2101 using namespace Menu_Helpers;
2105 Menu *play_menu = manage (new Menu);
2106 MenuList& play_items = play_menu->items();
2107 play_menu->set_name ("ArdourContextMenu");
2109 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2110 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2111 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2115 Menu *select_menu = manage (new Menu);
2116 MenuList& select_items = select_menu->items();
2117 select_menu->set_name ("ArdourContextMenu");
2119 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2120 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2121 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2122 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2123 select_items.push_back (SeparatorElem());
2124 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2125 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2126 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2127 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2129 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2133 Menu *cutnpaste_menu = manage (new Menu);
2134 MenuList& cutnpaste_items = cutnpaste_menu->items();
2135 cutnpaste_menu->set_name ("ArdourContextMenu");
2137 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2138 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2139 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2141 Menu *nudge_menu = manage (new Menu());
2142 MenuList& nudge_items = nudge_menu->items();
2143 nudge_menu->set_name ("ArdourContextMenu");
2145 edit_items.push_back (SeparatorElem());
2146 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2147 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2148 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2149 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2151 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2155 Editor::snap_type() const
2161 Editor::snap_musical() const
2163 switch (_snap_type) {
2164 case SnapToBeatDiv128:
2165 case SnapToBeatDiv64:
2166 case SnapToBeatDiv32:
2167 case SnapToBeatDiv28:
2168 case SnapToBeatDiv24:
2169 case SnapToBeatDiv20:
2170 case SnapToBeatDiv16:
2171 case SnapToBeatDiv14:
2172 case SnapToBeatDiv12:
2173 case SnapToBeatDiv10:
2174 case SnapToBeatDiv8:
2175 case SnapToBeatDiv7:
2176 case SnapToBeatDiv6:
2177 case SnapToBeatDiv5:
2178 case SnapToBeatDiv4:
2179 case SnapToBeatDiv3:
2180 case SnapToBeatDiv2:
2192 Editor::snap_mode() const
2198 Editor::set_snap_to (SnapType st)
2200 unsigned int snap_ind = (unsigned int)st;
2202 if (internal_editing()) {
2203 internal_snap_type = st;
2205 pre_internal_snap_type = st;
2210 if (snap_ind > snap_type_strings.size() - 1) {
2212 _snap_type = (SnapType)snap_ind;
2215 string str = snap_type_strings[snap_ind];
2217 if (str != snap_type_selector.get_text()) {
2218 snap_type_selector.set_text (str);
2223 switch (_snap_type) {
2224 case SnapToBeatDiv128:
2225 case SnapToBeatDiv64:
2226 case SnapToBeatDiv32:
2227 case SnapToBeatDiv28:
2228 case SnapToBeatDiv24:
2229 case SnapToBeatDiv20:
2230 case SnapToBeatDiv16:
2231 case SnapToBeatDiv14:
2232 case SnapToBeatDiv12:
2233 case SnapToBeatDiv10:
2234 case SnapToBeatDiv8:
2235 case SnapToBeatDiv7:
2236 case SnapToBeatDiv6:
2237 case SnapToBeatDiv5:
2238 case SnapToBeatDiv4:
2239 case SnapToBeatDiv3:
2240 case SnapToBeatDiv2: {
2241 std::vector<TempoMap::BBTPoint> grid;
2242 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2243 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2244 update_tempo_based_rulers (grid);
2248 case SnapToRegionStart:
2249 case SnapToRegionEnd:
2250 case SnapToRegionSync:
2251 case SnapToRegionBoundary:
2252 build_region_boundary_cache ();
2260 redisplay_tempo (false);
2262 SnapChanged (); /* EMIT SIGNAL */
2266 Editor::set_snap_mode (SnapMode mode)
2268 string str = snap_mode_strings[(int)mode];
2270 if (internal_editing()) {
2271 internal_snap_mode = mode;
2273 pre_internal_snap_mode = mode;
2278 if (str != snap_mode_selector.get_text ()) {
2279 snap_mode_selector.set_text (str);
2286 Editor::set_edit_point_preference (EditPoint ep, bool force)
2288 bool changed = (_edit_point != ep);
2291 if (Profile->get_mixbus())
2292 if (ep == EditAtSelectedMarker)
2293 ep = EditAtPlayhead;
2295 string str = edit_point_strings[(int)ep];
2296 if (str != edit_point_selector.get_text ()) {
2297 edit_point_selector.set_text (str);
2300 update_all_enter_cursors();
2302 if (!force && !changed) {
2306 const char* action=NULL;
2308 switch (_edit_point) {
2309 case EditAtPlayhead:
2310 action = "edit-at-playhead";
2312 case EditAtSelectedMarker:
2313 action = "edit-at-marker";
2316 action = "edit-at-mouse";
2320 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2322 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2326 bool in_track_canvas;
2328 if (!mouse_frame (foo, in_track_canvas)) {
2329 in_track_canvas = false;
2332 reset_canvas_action_sensitivity (in_track_canvas);
2338 Editor::set_state (const XMLNode& node, int version)
2340 XMLProperty const * prop;
2342 PBD::Unwinder<bool> nsi (no_save_instant, true);
2344 Tabbable::set_state (node, version);
2346 if (_session && (prop = node.property ("playhead"))) {
2348 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2350 playhead_cursor->set_position (pos);
2352 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2353 playhead_cursor->set_position (0);
2356 playhead_cursor->set_position (0);
2359 if ((prop = node.property ("mixer-width"))) {
2360 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2363 if ((prop = node.property ("zoom-focus"))) {
2364 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2367 if ((prop = node.property ("zoom"))) {
2368 /* older versions of ardour used floating point samples_per_pixel */
2369 double f = PBD::atof (prop->value());
2370 reset_zoom (llrintf (f));
2372 reset_zoom (samples_per_pixel);
2375 if ((prop = node.property ("visible-track-count"))) {
2376 set_visible_track_count (PBD::atoi (prop->value()));
2379 if ((prop = node.property ("snap-to"))) {
2380 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2381 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2384 if ((prop = node.property ("snap-mode"))) {
2385 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2386 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2387 * snap_mode_selection_done() will only mark an already active item as active
2388 * which does not trigger set_text().
2390 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2393 if ((prop = node.property ("internal-snap-to"))) {
2394 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2397 if ((prop = node.property ("internal-snap-mode"))) {
2398 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2401 if ((prop = node.property ("pre-internal-snap-to"))) {
2402 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2405 if ((prop = node.property ("pre-internal-snap-mode"))) {
2406 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2409 if ((prop = node.property ("mouse-mode"))) {
2410 MouseMode m = str2mousemode(prop->value());
2411 set_mouse_mode (m, true);
2413 set_mouse_mode (MouseObject, true);
2416 if ((prop = node.property ("left-frame")) != 0) {
2418 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2422 reset_x_origin (pos);
2426 if ((prop = node.property ("y-origin")) != 0) {
2427 reset_y_origin (atof (prop->value ()));
2430 if ((prop = node.property ("join-object-range"))) {
2431 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2432 bool yn = string_is_affirmative (prop->value());
2434 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2435 tact->set_active (!yn);
2436 tact->set_active (yn);
2438 set_mouse_mode(mouse_mode, true);
2441 if ((prop = node.property ("edit-point"))) {
2442 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2445 if ((prop = node.property ("show-measures"))) {
2446 bool yn = string_is_affirmative (prop->value());
2447 _show_measures = yn;
2450 if ((prop = node.property ("follow-playhead"))) {
2451 bool yn = string_is_affirmative (prop->value());
2452 set_follow_playhead (yn);
2455 if ((prop = node.property ("stationary-playhead"))) {
2456 bool yn = string_is_affirmative (prop->value());
2457 set_stationary_playhead (yn);
2460 if ((prop = node.property ("region-list-sort-type"))) {
2461 RegionListSortType st;
2462 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2465 if ((prop = node.property ("show-editor-mixer"))) {
2467 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2470 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2471 bool yn = string_is_affirmative (prop->value());
2473 /* do it twice to force the change */
2475 tact->set_active (!yn);
2476 tact->set_active (yn);
2479 if ((prop = node.property ("show-editor-list"))) {
2481 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2484 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2485 bool yn = string_is_affirmative (prop->value());
2487 /* do it twice to force the change */
2489 tact->set_active (!yn);
2490 tact->set_active (yn);
2493 if ((prop = node.property (X_("editor-list-page")))) {
2494 _the_notebook.set_current_page (atoi (prop->value ()));
2497 if ((prop = node.property (X_("show-marker-lines")))) {
2498 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2500 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2501 bool yn = string_is_affirmative (prop->value ());
2503 tact->set_active (!yn);
2504 tact->set_active (yn);
2507 XMLNodeList children = node.children ();
2508 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2509 selection->set_state (**i, Stateful::current_state_version);
2510 _regions->set_state (**i);
2513 if ((prop = node.property ("maximised"))) {
2514 bool yn = string_is_affirmative (prop->value());
2515 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2517 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2518 bool fs = tact && tact->get_active();
2520 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2524 if ((prop = node.property ("nudge-clock-value"))) {
2526 sscanf (prop->value().c_str(), "%" PRId64, &f);
2527 nudge_clock->set (f);
2529 nudge_clock->set_mode (AudioClock::Timecode);
2530 nudge_clock->set (_session->frame_rate() * 5, true);
2535 * Not all properties may have been in XML, but
2536 * those that are linked to a private variable may need changing
2541 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2543 yn = _show_measures;
2544 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2545 /* do it twice to force the change */
2546 tact->set_active (!yn);
2547 tact->set_active (yn);
2550 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2551 yn = _follow_playhead;
2553 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2554 if (tact->get_active() != yn) {
2555 tact->set_active (yn);
2559 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2560 yn = _stationary_playhead;
2562 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2563 if (tact->get_active() != yn) {
2564 tact->set_active (yn);
2569 return LuaInstance::instance()->set_state(node);
2573 Editor::get_state ()
2575 XMLNode* node = new XMLNode (X_("Editor"));
2578 id().print (buf, sizeof (buf));
2579 node->add_property ("id", buf);
2581 node->add_child_nocopy (Tabbable::get_state());
2583 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (edit_pane, false));
2584 node->add_property("edit-horizontal-pane-pos", string(buf));
2585 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2586 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (editor_summary_pane, true));
2587 node->add_property("edit-vertical-pane-pos", string(buf));
2589 maybe_add_mixer_strip_width (*node);
2591 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2593 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2594 node->add_property ("zoom", buf);
2595 node->add_property ("snap-to", enum_2_string (_snap_type));
2596 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2597 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2598 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2599 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2600 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2601 node->add_property ("edit-point", enum_2_string (_edit_point));
2602 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2603 node->add_property ("visible-track-count", buf);
2605 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2606 node->add_property ("playhead", buf);
2607 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2608 node->add_property ("left-frame", buf);
2609 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2610 node->add_property ("y-origin", buf);
2612 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2613 node->add_property ("maximised", _maximised ? "yes" : "no");
2614 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2615 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2616 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2617 node->add_property ("mouse-mode", enum2str(mouse_mode));
2618 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2620 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2622 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2623 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2626 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2628 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2629 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2632 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2633 node->add_property (X_("editor-list-page"), buf);
2635 if (button_bindings) {
2636 XMLNode* bb = new XMLNode (X_("Buttons"));
2637 button_bindings->save (*bb);
2638 node->add_child_nocopy (*bb);
2641 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2643 node->add_child_nocopy (selection->get_state ());
2644 node->add_child_nocopy (_regions->get_state ());
2646 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2647 node->add_property ("nudge-clock-value", buf);
2649 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2650 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2655 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2656 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2658 * @return pair: TimeAxisView that y is over, layer index.
2660 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2661 * in stacked or expanded region display mode, otherwise 0.
2663 std::pair<TimeAxisView *, double>
2664 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2666 if (!trackview_relative_offset) {
2667 y -= _trackview_group->canvas_origin().y;
2671 return std::make_pair ( (TimeAxisView *) 0, 0);
2674 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2676 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2683 return std::make_pair ( (TimeAxisView *) 0, 0);
2686 /** Snap a position to the grid, if appropriate, taking into account current
2687 * grid settings and also the state of any snap modifier keys that may be pressed.
2688 * @param start Position to snap.
2689 * @param event Event to get current key modifier information from, or 0.
2692 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2694 if (!_session || !event) {
2698 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2699 if (_snap_mode == SnapOff) {
2700 snap_to_internal (start, direction, for_mark);
2703 if (_snap_mode != SnapOff) {
2704 snap_to_internal (start, direction, for_mark);
2705 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2706 /* SnapOff, but we pressed the snap_delta modifier */
2707 snap_to_internal (start, direction, for_mark);
2713 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2715 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2719 snap_to_internal (start, direction, for_mark, ensure_snap);
2723 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2725 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2726 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2728 switch (_snap_type) {
2729 case SnapToTimecodeFrame:
2730 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2731 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2732 /* start is already on a whole timecode frame, do nothing */
2733 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2734 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2736 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2740 case SnapToTimecodeSeconds:
2741 if (_session->config.get_timecode_offset_negative()) {
2742 start += _session->config.get_timecode_offset ();
2744 start -= _session->config.get_timecode_offset ();
2746 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2747 (start % one_timecode_second == 0)) {
2748 /* start is already on a whole second, do nothing */
2749 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2750 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2752 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2755 if (_session->config.get_timecode_offset_negative()) {
2756 start -= _session->config.get_timecode_offset ();
2758 start += _session->config.get_timecode_offset ();
2762 case SnapToTimecodeMinutes:
2763 if (_session->config.get_timecode_offset_negative()) {
2764 start += _session->config.get_timecode_offset ();
2766 start -= _session->config.get_timecode_offset ();
2768 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2769 (start % one_timecode_minute == 0)) {
2770 /* start is already on a whole minute, do nothing */
2771 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2772 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2774 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2776 if (_session->config.get_timecode_offset_negative()) {
2777 start -= _session->config.get_timecode_offset ();
2779 start += _session->config.get_timecode_offset ();
2783 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2784 abort(); /*NOTREACHED*/
2789 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2791 const framepos_t one_second = _session->frame_rate();
2792 const framepos_t one_minute = _session->frame_rate() * 60;
2793 framepos_t presnap = start;
2797 switch (_snap_type) {
2798 case SnapToTimecodeFrame:
2799 case SnapToTimecodeSeconds:
2800 case SnapToTimecodeMinutes:
2801 return timecode_snap_to_internal (start, direction, for_mark);
2804 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2805 start % (one_second/75) == 0) {
2806 /* start is already on a whole CD frame, do nothing */
2807 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2808 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2810 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2815 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2816 start % one_second == 0) {
2817 /* start is already on a whole second, do nothing */
2818 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2819 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2821 start = (framepos_t) floor ((double) start / one_second) * one_second;
2826 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2827 start % one_minute == 0) {
2828 /* start is already on a whole minute, do nothing */
2829 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2830 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2832 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2837 start = _session->tempo_map().round_to_bar (start, direction);
2841 start = _session->tempo_map().round_to_beat (start, direction);
2844 case SnapToBeatDiv128:
2845 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2847 case SnapToBeatDiv64:
2848 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2850 case SnapToBeatDiv32:
2851 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2853 case SnapToBeatDiv28:
2854 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2856 case SnapToBeatDiv24:
2857 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2859 case SnapToBeatDiv20:
2860 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2862 case SnapToBeatDiv16:
2863 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2865 case SnapToBeatDiv14:
2866 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2868 case SnapToBeatDiv12:
2869 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2871 case SnapToBeatDiv10:
2872 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2874 case SnapToBeatDiv8:
2875 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2877 case SnapToBeatDiv7:
2878 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2880 case SnapToBeatDiv6:
2881 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2883 case SnapToBeatDiv5:
2884 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2886 case SnapToBeatDiv4:
2887 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2889 case SnapToBeatDiv3:
2890 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2892 case SnapToBeatDiv2:
2893 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2901 _session->locations()->marks_either_side (start, before, after);
2903 if (before == max_framepos && after == max_framepos) {
2904 /* No marks to snap to, so just don't snap */
2906 } else if (before == max_framepos) {
2908 } else if (after == max_framepos) {
2910 } else if (before != max_framepos && after != max_framepos) {
2911 /* have before and after */
2912 if ((start - before) < (after - start)) {
2921 case SnapToRegionStart:
2922 case SnapToRegionEnd:
2923 case SnapToRegionSync:
2924 case SnapToRegionBoundary:
2925 if (!region_boundary_cache.empty()) {
2927 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2928 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2930 if (direction > 0) {
2931 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2933 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2936 if (next != region_boundary_cache.begin ()) {
2941 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2942 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2944 if (start > (p + n) / 2) {
2953 switch (_snap_mode) {
2963 if (presnap > start) {
2964 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2968 } else if (presnap < start) {
2969 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2975 /* handled at entry */
2983 Editor::setup_toolbar ()
2985 HBox* mode_box = manage(new HBox);
2986 mode_box->set_border_width (2);
2987 mode_box->set_spacing(2);
2989 HBox* mouse_mode_box = manage (new HBox);
2990 HBox* mouse_mode_hbox = manage (new HBox);
2991 VBox* mouse_mode_vbox = manage (new VBox);
2992 Alignment* mouse_mode_align = manage (new Alignment);
2994 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2995 mouse_mode_size_group->add_widget (smart_mode_button);
2996 mouse_mode_size_group->add_widget (mouse_move_button);
2997 mouse_mode_size_group->add_widget (mouse_cut_button);
2998 mouse_mode_size_group->add_widget (mouse_select_button);
2999 mouse_mode_size_group->add_widget (mouse_timefx_button);
3000 mouse_mode_size_group->add_widget (mouse_audition_button);
3001 mouse_mode_size_group->add_widget (mouse_draw_button);
3002 mouse_mode_size_group->add_widget (mouse_content_button);
3004 mouse_mode_size_group->add_widget (zoom_in_button);
3005 mouse_mode_size_group->add_widget (zoom_out_button);
3006 mouse_mode_size_group->add_widget (zoom_preset_selector);
3007 mouse_mode_size_group->add_widget (zoom_out_full_button);
3008 mouse_mode_size_group->add_widget (zoom_focus_selector);
3010 mouse_mode_size_group->add_widget (tav_shrink_button);
3011 mouse_mode_size_group->add_widget (tav_expand_button);
3012 mouse_mode_size_group->add_widget (visible_tracks_selector);
3014 mouse_mode_size_group->add_widget (snap_type_selector);
3015 mouse_mode_size_group->add_widget (snap_mode_selector);
3017 mouse_mode_size_group->add_widget (edit_point_selector);
3018 mouse_mode_size_group->add_widget (edit_mode_selector);
3020 mouse_mode_size_group->add_widget (*nudge_clock);
3021 mouse_mode_size_group->add_widget (nudge_forward_button);
3022 mouse_mode_size_group->add_widget (nudge_backward_button);
3024 mouse_mode_hbox->set_spacing (2);
3026 if (!ARDOUR::Profile->get_trx()) {
3027 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3030 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3031 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3033 if (!ARDOUR::Profile->get_mixbus()) {
3034 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3037 if (!ARDOUR::Profile->get_trx()) {
3038 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3039 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3040 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3041 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3044 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3046 mouse_mode_align->add (*mouse_mode_vbox);
3047 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3049 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3051 edit_mode_selector.set_name ("mouse mode button");
3053 if (!ARDOUR::Profile->get_trx()) {
3054 mode_box->pack_start (edit_mode_selector, false, false);
3057 mode_box->pack_start (*mouse_mode_box, false, false);
3061 _zoom_box.set_spacing (2);
3062 _zoom_box.set_border_width (2);
3066 zoom_preset_selector.set_name ("zoom button");
3067 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3068 zoom_preset_selector.set_size_request (42, -1);
3070 zoom_in_button.set_name ("zoom button");
3071 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3072 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3073 zoom_in_button.set_related_action (act);
3075 zoom_out_button.set_name ("zoom button");
3076 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3077 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3078 zoom_out_button.set_related_action (act);
3080 zoom_out_full_button.set_name ("zoom button");
3081 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3082 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3083 zoom_out_full_button.set_related_action (act);
3085 zoom_focus_selector.set_name ("zoom button");
3087 if (ARDOUR::Profile->get_mixbus()) {
3088 _zoom_box.pack_start (zoom_preset_selector, false, false);
3089 } else if (ARDOUR::Profile->get_trx()) {
3090 mode_box->pack_start (zoom_out_button, false, false);
3091 mode_box->pack_start (zoom_in_button, false, false);
3093 _zoom_box.pack_start (zoom_out_button, false, false);
3094 _zoom_box.pack_start (zoom_in_button, false, false);
3095 _zoom_box.pack_start (zoom_out_full_button, false, false);
3096 _zoom_box.pack_start (zoom_focus_selector, false, false);
3099 /* Track zoom buttons */
3100 visible_tracks_selector.set_name ("zoom button");
3101 if (Profile->get_mixbus()) {
3102 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3103 visible_tracks_selector.set_size_request (42, -1);
3105 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3108 tav_expand_button.set_name ("zoom button");
3109 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3110 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3111 tav_expand_button.set_related_action (act);
3113 tav_shrink_button.set_name ("zoom button");
3114 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3115 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3116 tav_shrink_button.set_related_action (act);
3118 if (ARDOUR::Profile->get_mixbus()) {
3119 _zoom_box.pack_start (visible_tracks_selector);
3120 } else if (ARDOUR::Profile->get_trx()) {
3121 _zoom_box.pack_start (tav_shrink_button);
3122 _zoom_box.pack_start (tav_expand_button);
3124 _zoom_box.pack_start (visible_tracks_selector);
3125 _zoom_box.pack_start (tav_shrink_button);
3126 _zoom_box.pack_start (tav_expand_button);
3129 snap_box.set_spacing (2);
3130 snap_box.set_border_width (2);
3132 snap_type_selector.set_name ("mouse mode button");
3134 snap_mode_selector.set_name ("mouse mode button");
3136 edit_point_selector.set_name ("mouse mode button");
3138 snap_box.pack_start (snap_mode_selector, false, false);
3139 snap_box.pack_start (snap_type_selector, false, false);
3140 snap_box.pack_start (edit_point_selector, false, false);
3144 HBox *nudge_box = manage (new HBox);
3145 nudge_box->set_spacing (2);
3146 nudge_box->set_border_width (2);
3148 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3149 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3151 nudge_box->pack_start (nudge_backward_button, false, false);
3152 nudge_box->pack_start (nudge_forward_button, false, false);
3153 nudge_box->pack_start (*nudge_clock, false, false);
3156 /* Pack everything in... */
3158 HBox* hbox = manage (new HBox);
3159 hbox->set_spacing(2);
3161 toolbar_hbox.set_spacing (2);
3162 toolbar_hbox.set_border_width (1);
3164 toolbar_hbox.pack_start (*mode_box, false, false);
3165 if (!ARDOUR::Profile->get_trx()) {
3166 toolbar_hbox.pack_start (_zoom_box, false, false);
3167 toolbar_hbox.pack_start (*hbox, false, false);
3170 if (!ARDOUR::Profile->get_trx()) {
3171 hbox->pack_start (snap_box, false, false);
3172 hbox->pack_start (*nudge_box, false, false);
3177 toolbar_base.set_name ("ToolBarBase");
3178 toolbar_base.add (toolbar_hbox);
3180 _toolbar_viewport.add (toolbar_base);
3181 /* stick to the required height but allow width to vary if there's not enough room */
3182 _toolbar_viewport.set_size_request (1, -1);
3184 toolbar_frame.set_shadow_type (SHADOW_OUT);
3185 toolbar_frame.set_name ("BaseFrame");
3186 toolbar_frame.add (_toolbar_viewport);
3190 Editor::build_edit_point_menu ()
3192 using namespace Menu_Helpers;
3194 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3195 if(!Profile->get_mixbus())
3196 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3197 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3199 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3203 Editor::build_edit_mode_menu ()
3205 using namespace Menu_Helpers;
3207 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3208 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3209 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3210 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3212 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3216 Editor::build_snap_mode_menu ()
3218 using namespace Menu_Helpers;
3220 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3221 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3222 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3224 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3228 Editor::build_snap_type_menu ()
3230 using namespace Menu_Helpers;
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3263 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3268 Editor::setup_tooltips ()
3270 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3271 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3272 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3273 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3274 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3275 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3276 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3277 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3278 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3279 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3280 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3281 set_tooltip (zoom_in_button, _("Zoom In"));
3282 set_tooltip (zoom_out_button, _("Zoom Out"));
3283 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3284 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3285 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3286 set_tooltip (tav_expand_button, _("Expand Tracks"));
3287 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3288 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3289 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3290 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3291 set_tooltip (edit_point_selector, _("Edit Point"));
3292 set_tooltip (edit_mode_selector, _("Edit Mode"));
3293 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3297 Editor::convert_drop_to_paths (
3298 vector<string>& paths,
3299 const RefPtr<Gdk::DragContext>& /*context*/,
3302 const SelectionData& data,
3306 if (_session == 0) {
3310 vector<string> uris = data.get_uris();
3314 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3315 are actually URI lists. So do it by hand.
3318 if (data.get_target() != "text/plain") {
3322 /* Parse the "uri-list" format that Nautilus provides,
3323 where each pathname is delimited by \r\n.
3325 THERE MAY BE NO NULL TERMINATING CHAR!!!
3328 string txt = data.get_text();
3332 p = (char *) malloc (txt.length() + 1);
3333 txt.copy (p, txt.length(), 0);
3334 p[txt.length()] = '\0';
3340 while (g_ascii_isspace (*p))
3344 while (*q && (*q != '\n') && (*q != '\r')) {
3351 while (q > p && g_ascii_isspace (*q))
3356 uris.push_back (string (p, q - p + 1));
3360 p = strchr (p, '\n');
3372 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3373 if ((*i).substr (0,7) == "file://") {
3374 paths.push_back (Glib::filename_from_uri (*i));
3382 Editor::new_tempo_section ()
3387 Editor::map_transport_state ()
3389 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3391 if (_session && _session->transport_stopped()) {
3392 have_pending_keyboard_selection = false;
3395 update_loop_range_view ();
3401 Editor::begin_selection_op_history ()
3403 selection_op_cmd_depth = 0;
3404 selection_op_history_it = 0;
3406 while(!selection_op_history.empty()) {
3407 delete selection_op_history.front();
3408 selection_op_history.pop_front();
3411 selection_undo_action->set_sensitive (false);
3412 selection_redo_action->set_sensitive (false);
3413 selection_op_history.push_front (&_selection_memento->get_state ());
3417 Editor::begin_reversible_selection_op (string name)
3420 //cerr << name << endl;
3421 /* begin/commit pairs can be nested */
3422 selection_op_cmd_depth++;
3427 Editor::commit_reversible_selection_op ()
3430 if (selection_op_cmd_depth == 1) {
3432 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3434 The user has undone some selection ops and then made a new one,
3435 making anything earlier in the list invalid.
3438 list<XMLNode *>::iterator it = selection_op_history.begin();
3439 list<XMLNode *>::iterator e_it = it;
3440 advance (e_it, selection_op_history_it);
3442 for ( ; it != e_it; ++it) {
3445 selection_op_history.erase (selection_op_history.begin(), e_it);
3448 selection_op_history.push_front (&_selection_memento->get_state ());
3449 selection_op_history_it = 0;
3451 selection_undo_action->set_sensitive (true);
3452 selection_redo_action->set_sensitive (false);
3455 if (selection_op_cmd_depth > 0) {
3456 selection_op_cmd_depth--;
3462 Editor::undo_selection_op ()
3465 selection_op_history_it++;
3467 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3468 if (n == selection_op_history_it) {
3469 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3470 selection_redo_action->set_sensitive (true);
3474 /* is there an earlier entry? */
3475 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3476 selection_undo_action->set_sensitive (false);
3482 Editor::redo_selection_op ()
3485 if (selection_op_history_it > 0) {
3486 selection_op_history_it--;
3489 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3490 if (n == selection_op_history_it) {
3491 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3492 selection_undo_action->set_sensitive (true);
3497 if (selection_op_history_it == 0) {
3498 selection_redo_action->set_sensitive (false);
3504 Editor::begin_reversible_command (string name)
3507 before.push_back (&_selection_memento->get_state ());
3508 _session->begin_reversible_command (name);
3513 Editor::begin_reversible_command (GQuark q)
3516 before.push_back (&_selection_memento->get_state ());
3517 _session->begin_reversible_command (q);
3522 Editor::abort_reversible_command ()
3525 while(!before.empty()) {
3526 delete before.front();
3529 _session->abort_reversible_command ();
3534 Editor::commit_reversible_command ()
3537 if (before.size() == 1) {
3538 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3539 redo_action->set_sensitive(false);
3540 undo_action->set_sensitive(true);
3541 begin_selection_op_history ();
3544 if (before.empty()) {
3545 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3550 _session->commit_reversible_command ();
3555 Editor::history_changed ()
3559 if (undo_action && _session) {
3560 if (_session->undo_depth() == 0) {
3561 label = S_("Command|Undo");
3563 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3565 undo_action->property_label() = label;
3568 if (redo_action && _session) {
3569 if (_session->redo_depth() == 0) {
3571 redo_action->set_sensitive (false);
3573 label = string_compose(_("Redo (%1)"), _session->next_redo());
3574 redo_action->set_sensitive (true);
3576 redo_action->property_label() = label;
3581 Editor::duplicate_range (bool with_dialog)
3585 RegionSelection rs = get_regions_from_selection_and_entered ();
3587 if ( selection->time.length() == 0 && rs.empty()) {
3593 ArdourDialog win (_("Duplicate"));
3594 Label label (_("Number of duplications:"));
3595 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3596 SpinButton spinner (adjustment, 0.0, 1);
3599 win.get_vbox()->set_spacing (12);
3600 win.get_vbox()->pack_start (hbox);
3601 hbox.set_border_width (6);
3602 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3604 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3605 place, visually. so do this by hand.
3608 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3609 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3610 spinner.grab_focus();
3616 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3617 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3618 win.set_default_response (RESPONSE_ACCEPT);
3620 spinner.grab_focus ();
3622 switch (win.run ()) {
3623 case RESPONSE_ACCEPT:
3629 times = adjustment.get_value();
3632 if ((current_mouse_mode() == Editing::MouseRange)) {
3633 if (selection->time.length()) {
3634 duplicate_selection (times);
3636 } else if (get_smart_mode()) {
3637 if (selection->time.length()) {
3638 duplicate_selection (times);
3640 duplicate_some_regions (rs, times);
3642 duplicate_some_regions (rs, times);
3647 Editor::set_edit_mode (EditMode m)
3649 Config->set_edit_mode (m);
3653 Editor::cycle_edit_mode ()
3655 switch (Config->get_edit_mode()) {
3657 Config->set_edit_mode (Ripple);
3661 Config->set_edit_mode (Lock);
3664 Config->set_edit_mode (Slide);
3670 Editor::edit_mode_selection_done ( EditMode m )
3672 Config->set_edit_mode ( m );
3676 Editor::snap_type_selection_done (SnapType snaptype)
3678 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3680 ract->set_active ();
3685 Editor::snap_mode_selection_done (SnapMode mode)
3687 RefPtr<RadioAction> ract = snap_mode_action (mode);
3690 ract->set_active (true);
3695 Editor::cycle_edit_point (bool with_marker)
3697 if(Profile->get_mixbus())
3698 with_marker = false;
3700 switch (_edit_point) {
3702 set_edit_point_preference (EditAtPlayhead);
3704 case EditAtPlayhead:
3706 set_edit_point_preference (EditAtSelectedMarker);
3708 set_edit_point_preference (EditAtMouse);
3711 case EditAtSelectedMarker:
3712 set_edit_point_preference (EditAtMouse);
3718 Editor::edit_point_selection_done (EditPoint ep)
3720 set_edit_point_preference ( ep );
3724 Editor::build_zoom_focus_menu ()
3726 using namespace Menu_Helpers;
3728 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3729 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3730 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3731 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3732 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3733 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3735 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3739 Editor::zoom_focus_selection_done ( ZoomFocus f )
3741 RefPtr<RadioAction> ract = zoom_focus_action (f);
3743 ract->set_active ();
3748 Editor::build_track_count_menu ()
3750 using namespace Menu_Helpers;
3752 if (!Profile->get_mixbus()) {
3753 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3754 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3755 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3756 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3757 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3758 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3759 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3760 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3763 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3764 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3778 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3779 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3780 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3781 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3782 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3783 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3784 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3785 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3786 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3787 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3788 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3793 Editor::set_zoom_preset (int64_t ms)
3796 temporal_zoom_session();
3800 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3801 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3805 Editor::set_visible_track_count (int32_t n)
3807 _visible_track_count = n;
3809 /* if the canvas hasn't really been allocated any size yet, just
3810 record the desired number of visible tracks and return. when canvas
3811 allocation happens, we will get called again and then we can do the
3815 if (_visible_canvas_height <= 1) {
3821 DisplaySuspender ds;
3823 if (_visible_track_count > 0) {
3824 h = trackviews_height() / _visible_track_count;
3825 std::ostringstream s;
3826 s << _visible_track_count;
3828 } else if (_visible_track_count == 0) {
3830 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3831 if ((*i)->marked_for_display()) {
3835 h = trackviews_height() / n;
3838 /* negative value means that the visible track count has
3839 been overridden by explicit track height changes.
3841 visible_tracks_selector.set_text (X_("*"));
3845 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3846 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3849 if (str != visible_tracks_selector.get_text()) {
3850 visible_tracks_selector.set_text (str);
3855 Editor::override_visible_track_count ()
3857 _visible_track_count = -1;
3858 visible_tracks_selector.set_text ( _("*") );
3862 Editor::edit_controls_button_release (GdkEventButton* ev)
3864 if (Keyboard::is_context_menu_event (ev)) {
3865 ARDOUR_UI::instance()->add_route ();
3866 } else if (ev->button == 1) {
3867 selection->clear_tracks ();
3874 Editor::mouse_select_button_release (GdkEventButton* ev)
3876 /* this handles just right-clicks */
3878 if (ev->button != 3) {
3886 Editor::set_zoom_focus (ZoomFocus f)
3888 string str = zoom_focus_strings[(int)f];
3890 if (str != zoom_focus_selector.get_text()) {
3891 zoom_focus_selector.set_text (str);
3894 if (zoom_focus != f) {
3901 Editor::cycle_zoom_focus ()
3903 switch (zoom_focus) {
3905 set_zoom_focus (ZoomFocusRight);
3907 case ZoomFocusRight:
3908 set_zoom_focus (ZoomFocusCenter);
3910 case ZoomFocusCenter:
3911 set_zoom_focus (ZoomFocusPlayhead);
3913 case ZoomFocusPlayhead:
3914 set_zoom_focus (ZoomFocusMouse);
3916 case ZoomFocusMouse:
3917 set_zoom_focus (ZoomFocusEdit);
3920 set_zoom_focus (ZoomFocusLeft);
3926 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3928 /* recover or initialize pane positions. do this here rather than earlier because
3929 we don't want the positions to change the child allocations, which they seem to do.
3931 See comments in mixer_ui.cc about how this works.
3936 XMLNode* geometry = ARDOUR_UI::instance()->editor_settings();
3945 if (which == static_cast<Paned*> (&edit_pane)) {
3947 if (done & Horizontal) {
3951 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3952 _notebook_shrunk = string_is_affirmative (prop->value ());
3955 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3956 /* initial allocation is 90% to canvas, 10% to notebook */
3957 pos = (int) floor (alloc.get_width() * 0.90f);
3959 pos = atof (prop->value());
3963 /* older versions of Ardour stored absolute position */
3964 if (alloc.get_width() > pos) {
3965 edit_pane.set_position (pos);
3966 done = (Pane) (done | Horizontal);
3969 if (alloc.get_width() > 1.0/pos) {
3970 paned_set_position_as_fraction (edit_pane, pos, false);
3971 done = (Pane) (done | Horizontal);
3975 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3977 if (done & Vertical) {
3981 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3982 /* initial allocation is 90% to canvas, 10% to summary */
3983 pos = (int) floor (alloc.get_height() * 0.90f);
3986 pos = atof (prop->value());
3990 /* older versions of Ardour stored absolute position */
3991 if (alloc.get_height() > pos) {
3992 editor_summary_pane.set_position (pos);
3993 done = (Pane) (done | Vertical);
3996 if (alloc.get_height() > 1.0/pos) {
3997 paned_set_position_as_fraction (editor_summary_pane, pos, true);
3998 done = (Pane) (done | Vertical);
4005 Editor::set_show_measures (bool yn)
4007 if (_show_measures != yn) {
4010 if ((_show_measures = yn) == true) {
4012 tempo_lines->show();
4015 std::vector<TempoMap::BBTPoint> grid;
4016 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
4017 draw_measures (grid);
4025 Editor::toggle_follow_playhead ()
4027 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4029 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4030 set_follow_playhead (tact->get_active());
4034 /** @param yn true to follow playhead, otherwise false.
4035 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4038 Editor::set_follow_playhead (bool yn, bool catch_up)
4040 if (_follow_playhead != yn) {
4041 if ((_follow_playhead = yn) == true && catch_up) {
4043 reset_x_origin_to_follow_playhead ();
4050 Editor::toggle_stationary_playhead ()
4052 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4054 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4055 set_stationary_playhead (tact->get_active());
4060 Editor::set_stationary_playhead (bool yn)
4062 if (_stationary_playhead != yn) {
4063 if ((_stationary_playhead = yn) == true) {
4065 // FIXME need a 3.0 equivalent of this 2.X call
4066 // update_current_screen ();
4073 Editor::playlist_selector () const
4075 return *_playlist_selector;
4079 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4081 if (paste_count == 0) {
4082 /* don't bother calculating an offset that will be zero anyway */
4086 /* calculate basic unsnapped multi-paste offset */
4087 framecnt_t offset = paste_count * duration;
4089 /* snap offset so pos + offset is aligned to the grid */
4090 framepos_t offset_pos = pos + offset;
4091 snap_to(offset_pos, RoundUpMaybe);
4092 offset = offset_pos - pos;
4098 Editor::get_grid_beat_divisions(framepos_t position)
4100 switch (_snap_type) {
4101 case SnapToBeatDiv128: return 128;
4102 case SnapToBeatDiv64: return 64;
4103 case SnapToBeatDiv32: return 32;
4104 case SnapToBeatDiv28: return 28;
4105 case SnapToBeatDiv24: return 24;
4106 case SnapToBeatDiv20: return 20;
4107 case SnapToBeatDiv16: return 16;
4108 case SnapToBeatDiv14: return 14;
4109 case SnapToBeatDiv12: return 12;
4110 case SnapToBeatDiv10: return 10;
4111 case SnapToBeatDiv8: return 8;
4112 case SnapToBeatDiv7: return 7;
4113 case SnapToBeatDiv6: return 6;
4114 case SnapToBeatDiv5: return 5;
4115 case SnapToBeatDiv4: return 4;
4116 case SnapToBeatDiv3: return 3;
4117 case SnapToBeatDiv2: return 2;
4124 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4128 const unsigned divisions = get_grid_beat_divisions(position);
4130 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4133 switch (_snap_type) {
4135 return Evoral::Beats(1.0);
4138 return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar());
4146 return Evoral::Beats();
4150 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4154 ret = nudge_clock->current_duration (pos);
4155 next = ret + 1; /* XXXX fix me */
4161 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4163 ArdourDialog dialog (_("Playlist Deletion"));
4164 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4165 "If it is kept, its audio files will not be cleaned.\n"
4166 "If it is deleted, audio files used by it alone will be cleaned."),
4169 dialog.set_position (WIN_POS_CENTER);
4170 dialog.get_vbox()->pack_start (label);
4174 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4175 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4176 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4177 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4178 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4180 // by default gtk uses the left most button
4181 keep->grab_focus ();
4183 switch (dialog.run ()) {
4185 /* keep this and all remaining ones */
4190 /* delete this and all others */
4194 case RESPONSE_ACCEPT:
4195 /* delete the playlist */
4199 case RESPONSE_REJECT:
4200 /* keep the playlist */
4212 Editor::audio_region_selection_covers (framepos_t where)
4214 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4215 if ((*a)->region()->covers (where)) {
4224 Editor::prepare_for_cleanup ()
4226 cut_buffer->clear_regions ();
4227 cut_buffer->clear_playlists ();
4229 selection->clear_regions ();
4230 selection->clear_playlists ();
4232 _regions->suspend_redisplay ();
4236 Editor::finish_cleanup ()
4238 _regions->resume_redisplay ();
4242 Editor::transport_loop_location()
4245 return _session->locations()->auto_loop_location();
4252 Editor::transport_punch_location()
4255 return _session->locations()->auto_punch_location();
4262 Editor::control_layout_scroll (GdkEventScroll* ev)
4264 /* Just forward to the normal canvas scroll method. The coordinate
4265 systems are different but since the canvas is always larger than the
4266 track headers, and aligned with the trackview area, this will work.
4268 In the not too distant future this layout is going away anyway and
4269 headers will be on the canvas.
4271 return canvas_scroll_event (ev, false);
4275 Editor::session_state_saved (string)
4278 _snapshots->redisplay ();
4282 Editor::maximise_editing_space ()
4288 Gtk::Window* toplevel = current_toplevel();
4291 toplevel->fullscreen ();
4297 Editor::restore_editing_space ()
4303 Gtk::Window* toplevel = current_toplevel();
4306 toplevel->unfullscreen();
4312 * Make new playlists for a given track and also any others that belong
4313 * to the same active route group with the `select' property.
4318 Editor::new_playlists (TimeAxisView* v)
4320 begin_reversible_command (_("new playlists"));
4321 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4322 _session->playlists->get (playlists);
4323 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4324 commit_reversible_command ();
4328 * Use a copy of the current playlist for a given track and also any others that belong
4329 * to the same active route group with the `select' property.
4334 Editor::copy_playlists (TimeAxisView* v)
4336 begin_reversible_command (_("copy playlists"));
4337 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4338 _session->playlists->get (playlists);
4339 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4340 commit_reversible_command ();
4343 /** Clear the current playlist for a given track and also any others that belong
4344 * to the same active route group with the `select' property.
4349 Editor::clear_playlists (TimeAxisView* v)
4351 begin_reversible_command (_("clear playlists"));
4352 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4353 _session->playlists->get (playlists);
4354 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4355 commit_reversible_command ();
4359 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4361 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4365 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4367 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4371 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4373 atv.clear_playlist ();
4377 Editor::get_y_origin () const
4379 return vertical_adjustment.get_value ();
4382 /** Queue up a change to the viewport x origin.
4383 * @param frame New x origin.
4386 Editor::reset_x_origin (framepos_t frame)
4388 pending_visual_change.add (VisualChange::TimeOrigin);
4389 pending_visual_change.time_origin = frame;
4390 ensure_visual_change_idle_handler ();
4394 Editor::reset_y_origin (double y)
4396 pending_visual_change.add (VisualChange::YOrigin);
4397 pending_visual_change.y_origin = y;
4398 ensure_visual_change_idle_handler ();
4402 Editor::reset_zoom (framecnt_t spp)
4404 if (spp == samples_per_pixel) {
4408 pending_visual_change.add (VisualChange::ZoomLevel);
4409 pending_visual_change.samples_per_pixel = spp;
4410 ensure_visual_change_idle_handler ();
4414 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4416 reset_x_origin (frame);
4419 if (!no_save_visual) {
4420 undo_visual_stack.push_back (current_visual_state(false));
4424 Editor::VisualState::VisualState (bool with_tracks)
4425 : gui_state (with_tracks ? new GUIObjectState : 0)
4429 Editor::VisualState::~VisualState ()
4434 Editor::VisualState*
4435 Editor::current_visual_state (bool with_tracks)
4437 VisualState* vs = new VisualState (with_tracks);
4438 vs->y_position = vertical_adjustment.get_value();
4439 vs->samples_per_pixel = samples_per_pixel;
4440 vs->leftmost_frame = leftmost_frame;
4441 vs->zoom_focus = zoom_focus;
4444 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4451 Editor::undo_visual_state ()
4453 if (undo_visual_stack.empty()) {
4457 VisualState* vs = undo_visual_stack.back();
4458 undo_visual_stack.pop_back();
4461 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4464 use_visual_state (*vs);
4469 Editor::redo_visual_state ()
4471 if (redo_visual_stack.empty()) {
4475 VisualState* vs = redo_visual_stack.back();
4476 redo_visual_stack.pop_back();
4478 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4479 // why do we check here?
4480 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4483 use_visual_state (*vs);
4488 Editor::swap_visual_state ()
4490 if (undo_visual_stack.empty()) {
4491 redo_visual_state ();
4493 undo_visual_state ();
4498 Editor::use_visual_state (VisualState& vs)
4500 PBD::Unwinder<bool> nsv (no_save_visual, true);
4501 DisplaySuspender ds;
4503 vertical_adjustment.set_value (vs.y_position);
4505 set_zoom_focus (vs.zoom_focus);
4506 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4509 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4511 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4512 (*i)->clear_property_cache();
4513 (*i)->reset_visual_state ();
4517 _routes->update_visibility ();
4520 /** This is the core function that controls the zoom level of the canvas. It is called
4521 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4522 * @param spp new number of samples per pixel
4525 Editor::set_samples_per_pixel (framecnt_t spp)
4531 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4532 const framecnt_t lots_of_pixels = 4000;
4534 /* if the zoom level is greater than what you'd get trying to display 3
4535 * days of audio on a really big screen, then it's too big.
4538 if (spp * lots_of_pixels > three_days) {
4542 samples_per_pixel = spp;
4545 tempo_lines->tempo_map_changed();
4548 bool const showing_time_selection = selection->time.length() > 0;
4550 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4551 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4552 (*i)->reshow_selection (selection->time);
4556 ZoomChanged (); /* EMIT_SIGNAL */
4558 ArdourCanvas::GtkCanvasViewport* c;
4560 c = get_track_canvas();
4562 c->canvas()->zoomed ();
4565 if (playhead_cursor) {
4566 playhead_cursor->set_position (playhead_cursor->current_frame ());
4569 refresh_location_display();
4570 _summary->set_overlays_dirty ();
4572 update_marker_labels ();
4578 Editor::queue_visual_videotimeline_update ()
4581 * pending_visual_change.add (VisualChange::VideoTimeline);
4582 * or maybe even more specific: which videotimeline-image
4583 * currently it calls update_video_timeline() to update
4584 * _all outdated_ images on the video-timeline.
4585 * see 'exposeimg()' in video_image_frame.cc
4587 ensure_visual_change_idle_handler ();
4591 Editor::ensure_visual_change_idle_handler ()
4593 if (pending_visual_change.idle_handler_id < 0) {
4594 // see comment in add_to_idle_resize above.
4595 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4596 pending_visual_change.being_handled = false;
4601 Editor::_idle_visual_changer (void* arg)
4603 return static_cast<Editor*>(arg)->idle_visual_changer ();
4607 Editor::idle_visual_changer ()
4609 /* set_horizontal_position() below (and maybe other calls) call
4610 gtk_main_iteration(), so it's possible that a signal will be handled
4611 half-way through this method. If this signal wants an
4612 idle_visual_changer we must schedule another one after this one, so
4613 mark the idle_handler_id as -1 here to allow that. Also make a note
4614 that we are doing the visual change, so that changes in response to
4615 super-rapid-screen-update can be dropped if we are still processing
4619 pending_visual_change.idle_handler_id = -1;
4620 pending_visual_change.being_handled = true;
4622 VisualChange vc = pending_visual_change;
4624 pending_visual_change.pending = (VisualChange::Type) 0;
4626 visual_changer (vc);
4628 pending_visual_change.being_handled = false;
4630 return 0; /* this is always a one-shot call */
4634 Editor::visual_changer (const VisualChange& vc)
4636 double const last_time_origin = horizontal_position ();
4638 if (vc.pending & VisualChange::ZoomLevel) {
4639 set_samples_per_pixel (vc.samples_per_pixel);
4641 compute_fixed_ruler_scale ();
4643 std::vector<TempoMap::BBTPoint> grid;
4644 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4645 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4646 update_tempo_based_rulers (grid);
4648 update_video_timeline();
4651 if (vc.pending & VisualChange::TimeOrigin) {
4652 set_horizontal_position (vc.time_origin / samples_per_pixel);
4655 if (vc.pending & VisualChange::YOrigin) {
4656 vertical_adjustment.set_value (vc.y_origin);
4659 if (last_time_origin == horizontal_position ()) {
4660 /* changed signal not emitted */
4661 update_fixed_rulers ();
4662 redisplay_tempo (true);
4665 if (!(vc.pending & VisualChange::ZoomLevel)) {
4666 update_video_timeline();
4669 _summary->set_overlays_dirty ();
4672 struct EditorOrderTimeAxisSorter {
4673 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4674 return a->order () < b->order ();
4679 Editor::sort_track_selection (TrackViewList& sel)
4681 EditorOrderTimeAxisSorter cmp;
4686 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4689 framepos_t where = 0;
4690 EditPoint ep = _edit_point;
4692 if (Profile->get_mixbus())
4693 if (ep == EditAtSelectedMarker)
4694 ep = EditAtPlayhead;
4696 if (from_outside_canvas && (ep == EditAtMouse)) {
4697 ep = EditAtPlayhead;
4698 } else if (from_context_menu && (ep == EditAtMouse)) {
4699 return canvas_event_sample (&context_click_event, 0, 0);
4702 if (entered_marker) {
4703 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4704 return entered_marker->position();
4707 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4708 ep = EditAtSelectedMarker;
4711 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4712 ep = EditAtPlayhead;
4716 case EditAtPlayhead:
4717 if (_dragging_playhead) {
4718 where = *_control_scroll_target;
4720 where = _session->audible_frame();
4722 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4725 case EditAtSelectedMarker:
4726 if (!selection->markers.empty()) {
4728 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4731 where = loc->start();
4735 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4743 if (!mouse_frame (where, ignored)) {
4744 /* XXX not right but what can we do ? */
4748 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4756 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4758 if (!_session) return;
4760 begin_reversible_command (cmd);
4764 if ((tll = transport_loop_location()) == 0) {
4765 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4766 XMLNode &before = _session->locations()->get_state();
4767 _session->locations()->add (loc, true);
4768 _session->set_auto_loop_location (loc);
4769 XMLNode &after = _session->locations()->get_state();
4770 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4772 XMLNode &before = tll->get_state();
4773 tll->set_hidden (false, this);
4774 tll->set (start, end);
4775 XMLNode &after = tll->get_state();
4776 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4779 commit_reversible_command ();
4783 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4785 if (!_session) return;
4787 begin_reversible_command (cmd);
4791 if ((tpl = transport_punch_location()) == 0) {
4792 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4793 XMLNode &before = _session->locations()->get_state();
4794 _session->locations()->add (loc, true);
4795 _session->set_auto_punch_location (loc);
4796 XMLNode &after = _session->locations()->get_state();
4797 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4799 XMLNode &before = tpl->get_state();
4800 tpl->set_hidden (false, this);
4801 tpl->set (start, end);
4802 XMLNode &after = tpl->get_state();
4803 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4806 commit_reversible_command ();
4809 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4810 * @param rs List to which found regions are added.
4811 * @param where Time to look at.
4812 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4815 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4817 const TrackViewList* tracks;
4820 tracks = &track_views;
4825 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4827 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4830 boost::shared_ptr<Track> tr;
4831 boost::shared_ptr<Playlist> pl;
4833 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4835 boost::shared_ptr<RegionList> regions = pl->regions_at (
4836 (framepos_t) floor ( (double) where * tr->speed()));
4838 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4839 RegionView* rv = rtv->view()->find_view (*i);
4850 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4852 const TrackViewList* tracks;
4855 tracks = &track_views;
4860 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4861 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4863 boost::shared_ptr<Track> tr;
4864 boost::shared_ptr<Playlist> pl;
4866 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4868 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4869 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4871 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4873 RegionView* rv = rtv->view()->find_view (*i);
4884 /** Get regions using the following method:
4886 * Make a region list using:
4887 * (a) any selected regions
4888 * (b) the intersection of any selected tracks and the edit point(*)
4889 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4891 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4893 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4897 Editor::get_regions_from_selection_and_edit_point ()
4899 RegionSelection regions;
4901 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4902 regions.add (entered_regionview);
4904 regions = selection->regions;
4907 if ( regions.empty() ) {
4908 TrackViewList tracks = selection->tracks;
4910 if (!tracks.empty()) {
4911 /* no region selected or entered, but some selected tracks:
4912 * act on all regions on the selected tracks at the edit point
4914 framepos_t const where = get_preferred_edit_position ();
4915 get_regions_at(regions, where, tracks);
4922 /** Get regions using the following method:
4924 * Make a region list using:
4925 * (a) any selected regions
4926 * (b) the intersection of any selected tracks and the edit point(*)
4927 * (c) if neither exists, then whatever region is under the mouse
4929 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4931 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4934 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4936 RegionSelection regions;
4938 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4939 regions.add (entered_regionview);
4941 regions = selection->regions;
4944 if ( regions.empty() ) {
4945 TrackViewList tracks = selection->tracks;
4947 if (!tracks.empty()) {
4948 /* no region selected or entered, but some selected tracks:
4949 * act on all regions on the selected tracks at the edit point
4951 get_regions_at(regions, pos, tracks);
4958 /** Start with regions that are selected, or the entered regionview if none are selected.
4959 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4960 * of the regions that we started with.
4964 Editor::get_regions_from_selection_and_entered () const
4966 RegionSelection regions = selection->regions;
4968 if (regions.empty() && entered_regionview) {
4969 regions.add (entered_regionview);
4976 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4978 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4979 RouteTimeAxisView* rtav;
4981 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4982 boost::shared_ptr<Playlist> pl;
4983 std::vector<boost::shared_ptr<Region> > results;
4984 boost::shared_ptr<Track> tr;
4986 if ((tr = rtav->track()) == 0) {
4991 if ((pl = (tr->playlist())) != 0) {
4992 boost::shared_ptr<Region> r = pl->region_by_id (id);
4994 RegionView* rv = rtav->view()->find_view (r);
4996 regions.push_back (rv);
5005 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5008 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5009 MidiTimeAxisView* mtav;
5011 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5013 mtav->get_per_region_note_selection (selection);
5020 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5022 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5024 RouteTimeAxisView* tatv;
5026 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5028 boost::shared_ptr<Playlist> pl;
5029 vector<boost::shared_ptr<Region> > results;
5031 boost::shared_ptr<Track> tr;
5033 if ((tr = tatv->track()) == 0) {
5038 if ((pl = (tr->playlist())) != 0) {
5039 if (src_comparison) {
5040 pl->get_source_equivalent_regions (region, results);
5042 pl->get_region_list_equivalent_regions (region, results);
5046 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5047 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5048 regions.push_back (marv);
5057 Editor::show_rhythm_ferret ()
5059 if (rhythm_ferret == 0) {
5060 rhythm_ferret = new RhythmFerret(*this);
5063 rhythm_ferret->set_session (_session);
5064 rhythm_ferret->show ();
5065 rhythm_ferret->present ();
5069 Editor::first_idle ()
5071 MessageDialog* dialog = 0;
5073 if (track_views.size() > 1) {
5074 Timers::TimerSuspender t;
5075 dialog = new MessageDialog (
5076 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5080 ARDOUR_UI::instance()->flush_pending ();
5083 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5087 // first idle adds route children (automation tracks), so we need to redisplay here
5088 _routes->redisplay ();
5092 if (_session->undo_depth() == 0) {
5093 undo_action->set_sensitive(false);
5095 redo_action->set_sensitive(false);
5096 begin_selection_op_history ();
5102 Editor::_idle_resize (gpointer arg)
5104 return ((Editor*)arg)->idle_resize ();
5108 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5110 if (resize_idle_id < 0) {
5111 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5112 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5113 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5115 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5116 _pending_resize_amount = 0;
5119 /* make a note of the smallest resulting height, so that we can clamp the
5120 lower limit at TimeAxisView::hSmall */
5122 int32_t min_resulting = INT32_MAX;
5124 _pending_resize_amount += h;
5125 _pending_resize_view = view;
5127 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5129 if (selection->tracks.contains (_pending_resize_view)) {
5130 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5131 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5135 if (min_resulting < 0) {
5140 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5141 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5145 /** Handle pending resizing of tracks */
5147 Editor::idle_resize ()
5149 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5151 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5152 selection->tracks.contains (_pending_resize_view)) {
5154 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5155 if (*i != _pending_resize_view) {
5156 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5161 _pending_resize_amount = 0;
5162 _group_tabs->set_dirty ();
5163 resize_idle_id = -1;
5171 ENSURE_GUI_THREAD (*this, &Editor::located);
5174 playhead_cursor->set_position (_session->audible_frame ());
5175 if (_follow_playhead && !_pending_initial_locate) {
5176 reset_x_origin_to_follow_playhead ();
5180 _pending_locate_request = false;
5181 _pending_initial_locate = false;
5185 Editor::region_view_added (RegionView * rv)
5187 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5188 if (rv->region ()->id () == (*pr)) {
5189 selection->add (rv);
5190 selection->regions.pending.erase (pr);
5195 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5197 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5198 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5199 if (rv->region()->id () == (*rnote).first) {
5200 mrv->select_notes ((*rnote).second);
5201 selection->pending_midi_note_selection.erase(rnote);
5207 _summary->set_background_dirty ();
5211 Editor::region_view_removed ()
5213 _summary->set_background_dirty ();
5217 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5219 TrackViewList::const_iterator j = track_views.begin ();
5220 while (j != track_views.end()) {
5221 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5222 if (rtv && rtv->route() == r) {
5233 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5237 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5238 TimeAxisView* tv = axis_view_from_route (*i);
5248 Editor::suspend_route_redisplay ()
5251 _routes->suspend_redisplay();
5256 Editor::resume_route_redisplay ()
5259 _routes->redisplay(); // queue redisplay
5260 _routes->resume_redisplay();
5265 Editor::add_routes (RouteList& routes)
5267 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5269 RouteTimeAxisView *rtv;
5270 list<RouteTimeAxisView*> new_views;
5271 TrackViewList new_selection;
5272 bool from_scratch = (track_views.size() == 0);
5274 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5275 boost::shared_ptr<Route> route = (*x);
5277 if (route->is_auditioner() || route->is_monitor()) {
5281 DataType dt = route->input()->default_type();
5283 if (dt == ARDOUR::DataType::AUDIO) {
5284 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5285 rtv->set_route (route);
5286 } else if (dt == ARDOUR::DataType::MIDI) {
5287 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5288 rtv->set_route (route);
5290 throw unknown_type();
5293 new_views.push_back (rtv);
5294 track_views.push_back (rtv);
5295 new_selection.push_back (rtv);
5297 rtv->effective_gain_display ();
5299 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5300 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5303 if (new_views.size() > 0) {
5304 _routes->routes_added (new_views);
5305 _summary->routes_added (new_views);
5308 if (!from_scratch) {
5309 selection->tracks.clear();
5310 selection->add (new_selection);
5311 begin_selection_op_history();
5314 if (show_editor_mixer_when_tracks_arrive) {
5315 show_editor_mixer (true);
5318 editor_list_button.set_sensitive (true);
5322 Editor::timeaxisview_deleted (TimeAxisView *tv)
5324 if (tv == entered_track) {
5328 if (_session && _session->deletion_in_progress()) {
5329 /* the situation is under control */
5333 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5335 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5337 _routes->route_removed (tv);
5339 TimeAxisView::Children c = tv->get_child_list ();
5340 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5341 if (entered_track == i->get()) {
5346 /* remove it from the list of track views */
5348 TrackViewList::iterator i;
5350 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5351 i = track_views.erase (i);
5354 /* update whatever the current mixer strip is displaying, if revelant */
5356 boost::shared_ptr<Route> route;
5359 route = rtav->route ();
5362 if (current_mixer_strip && current_mixer_strip->route() == route) {
5364 TimeAxisView* next_tv;
5366 if (track_views.empty()) {
5368 } else if (i == track_views.end()) {
5369 next_tv = track_views.front();
5376 set_selected_mixer_strip (*next_tv);
5378 /* make the editor mixer strip go away setting the
5379 * button to inactive (which also unticks the menu option)
5382 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5388 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5390 if (apply_to_selection) {
5391 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5393 TrackSelection::iterator j = i;
5396 hide_track_in_display (*i, false);
5401 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5403 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5404 // this will hide the mixer strip
5405 set_selected_mixer_strip (*tv);
5408 _routes->hide_track_in_display (*tv);
5413 Editor::sync_track_view_list_and_routes ()
5415 track_views = TrackViewList (_routes->views ());
5417 _summary->set_background_dirty();
5418 _group_tabs->set_dirty ();
5420 return false; // do not call again (until needed)
5424 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5426 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5431 /** Find a RouteTimeAxisView by the ID of its route */
5433 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5435 RouteTimeAxisView* v;
5437 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5438 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5439 if(v->route()->id() == id) {
5449 Editor::fit_route_group (RouteGroup *g)
5451 TrackViewList ts = axis_views_from_routes (g->route_list ());
5456 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5458 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5461 _session->cancel_audition ();
5465 if (_session->is_auditioning()) {
5466 _session->cancel_audition ();
5467 if (r == last_audition_region) {
5472 _session->audition_region (r);
5473 last_audition_region = r;
5478 Editor::hide_a_region (boost::shared_ptr<Region> r)
5480 r->set_hidden (true);
5484 Editor::show_a_region (boost::shared_ptr<Region> r)
5486 r->set_hidden (false);
5490 Editor::audition_region_from_region_list ()
5492 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5496 Editor::hide_region_from_region_list ()
5498 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5502 Editor::show_region_in_region_list ()
5504 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5508 Editor::step_edit_status_change (bool yn)
5511 start_step_editing ();
5513 stop_step_editing ();
5518 Editor::start_step_editing ()
5520 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5524 Editor::stop_step_editing ()
5526 step_edit_connection.disconnect ();
5530 Editor::check_step_edit ()
5532 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5533 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5535 mtv->check_step_edit ();
5539 return true; // do it again, till we stop
5543 Editor::scroll_press (Direction dir)
5545 ++_scroll_callbacks;
5547 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5548 /* delay the first auto-repeat */
5554 scroll_backward (1);
5562 scroll_up_one_track ();
5566 scroll_down_one_track ();
5570 /* do hacky auto-repeat */
5571 if (!_scroll_connection.connected ()) {
5573 _scroll_connection = Glib::signal_timeout().connect (
5574 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5577 _scroll_callbacks = 0;
5584 Editor::scroll_release ()
5586 _scroll_connection.disconnect ();
5589 /** Queue a change for the Editor viewport x origin to follow the playhead */
5591 Editor::reset_x_origin_to_follow_playhead ()
5593 framepos_t const frame = playhead_cursor->current_frame ();
5595 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5597 if (_session->transport_speed() < 0) {
5599 if (frame > (current_page_samples() / 2)) {
5600 center_screen (frame-(current_page_samples()/2));
5602 center_screen (current_page_samples()/2);
5609 if (frame < leftmost_frame) {
5611 if (_session->transport_rolling()) {
5612 /* rolling; end up with the playhead at the right of the page */
5613 l = frame - current_page_samples ();
5615 /* not rolling: end up with the playhead 1/4 of the way along the page */
5616 l = frame - current_page_samples() / 4;
5620 if (_session->transport_rolling()) {
5621 /* rolling: end up with the playhead on the left of the page */
5624 /* not rolling: end up with the playhead 3/4 of the way along the page */
5625 l = frame - 3 * current_page_samples() / 4;
5633 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5639 Editor::super_rapid_screen_update ()
5641 if (!_session || !_session->engine().running()) {
5645 /* METERING / MIXER STRIPS */
5647 /* update track meters, if required */
5648 if (contents().is_mapped() && meters_running) {
5649 RouteTimeAxisView* rtv;
5650 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5651 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5652 rtv->fast_update ();
5657 /* and any current mixer strip */
5658 if (current_mixer_strip) {
5659 current_mixer_strip->fast_update ();
5662 /* PLAYHEAD AND VIEWPORT */
5664 framepos_t const frame = _session->audible_frame();
5666 /* There are a few reasons why we might not update the playhead / viewport stuff:
5668 * 1. we don't update things when there's a pending locate request, otherwise
5669 * when the editor requests a locate there is a chance that this method
5670 * will move the playhead before the locate request is processed, causing
5672 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5673 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5676 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5678 last_update_frame = frame;
5680 if (!_dragging_playhead) {
5681 playhead_cursor->set_position (frame);
5684 if (!_stationary_playhead) {
5686 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5687 /* We only do this if we aren't already
5688 handling a visual change (ie if
5689 pending_visual_change.being_handled is
5690 false) so that these requests don't stack
5691 up there are too many of them to handle in
5694 reset_x_origin_to_follow_playhead ();
5699 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5700 framepos_t const frame = playhead_cursor->current_frame ();
5701 double target = ((double)frame - (double)current_page_samples()/2.0);
5702 if (target <= 0.0) {
5705 // compare to EditorCursor::set_position()
5706 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5707 double const new_pos = sample_to_pixel_unrounded (target);
5708 if (rint (new_pos) != rint (old_pos)) {
5709 reset_x_origin (pixel_to_sample (floor (new_pos)));
5720 Editor::session_going_away ()
5722 _have_idled = false;
5724 _session_connections.drop_connections ();
5726 super_rapid_screen_update_connection.disconnect ();
5728 selection->clear ();
5729 cut_buffer->clear ();
5731 clicked_regionview = 0;
5732 clicked_axisview = 0;
5733 clicked_routeview = 0;
5734 entered_regionview = 0;
5736 last_update_frame = 0;
5739 playhead_cursor->hide ();
5741 /* rip everything out of the list displays */
5745 _route_groups->clear ();
5747 /* do this first so that deleting a track doesn't reset cms to null
5748 and thus cause a leak.
5751 if (current_mixer_strip) {
5752 if (current_mixer_strip->get_parent() != 0) {
5753 global_hpacker.remove (*current_mixer_strip);
5755 delete current_mixer_strip;
5756 current_mixer_strip = 0;
5759 /* delete all trackviews */
5761 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5764 track_views.clear ();
5766 nudge_clock->set_session (0);
5768 editor_list_button.set_active(false);
5769 editor_list_button.set_sensitive(false);
5771 /* clear tempo/meter rulers */
5772 remove_metric_marks ();
5774 clear_marker_display ();
5776 stop_step_editing ();
5780 /* get rid of any existing editor mixer strip */
5782 WindowTitle title(Glib::get_application_name());
5783 title += _("Editor");
5785 own_window()->set_title (title.get_string());
5788 SessionHandlePtr::session_going_away ();
5792 Editor::trigger_script (int i)
5794 LuaInstance::instance()-> call_action (i);
5798 Editor::set_script_action_name (int i, const std::string& n)
5800 string const a = string_compose (X_("script-action-%1"), i + 1);
5801 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5804 act->set_label (string_compose (_("Unset #%1"), i + 1));
5805 act->set_tooltip (_("no action bound"));
5806 act->set_sensitive (false);
5809 act->set_tooltip (n);
5810 act->set_sensitive (true);
5812 KeyEditor::UpdateBindings ();
5816 Editor::show_editor_list (bool yn)
5819 _the_notebook.show ();
5821 _the_notebook.hide ();
5826 Editor::change_region_layering_order (bool from_context_menu)
5828 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5830 if (!clicked_routeview) {
5831 if (layering_order_editor) {
5832 layering_order_editor->hide ();
5837 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5843 boost::shared_ptr<Playlist> pl = track->playlist();
5849 if (layering_order_editor == 0) {
5850 layering_order_editor = new RegionLayeringOrderEditor (*this);
5853 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5854 layering_order_editor->maybe_present ();
5858 Editor::update_region_layering_order_editor ()
5860 if (layering_order_editor && layering_order_editor->is_visible ()) {
5861 change_region_layering_order (true);
5866 Editor::setup_fade_images ()
5868 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5869 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5870 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5871 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5872 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5874 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5875 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5876 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5877 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5878 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5880 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5881 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5882 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5883 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5884 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5886 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5887 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5888 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5889 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5890 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5894 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5896 Editor::action_menu_item (std::string const & name)
5898 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5901 return *manage (a->create_menu_item ());
5905 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5907 EventBox* b = manage (new EventBox);
5908 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5909 Label* l = manage (new Label (name));
5913 _the_notebook.append_page (widget, *b);
5917 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5919 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5920 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5923 if (ev->type == GDK_2BUTTON_PRESS) {
5925 /* double-click on a notebook tab shrinks or expands the notebook */
5927 if (_notebook_shrunk) {
5928 if (pre_notebook_shrink_pane_width) {
5929 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5931 _notebook_shrunk = false;
5933 pre_notebook_shrink_pane_width = edit_pane.get_position();
5935 /* this expands the LHS of the edit pane to cover the notebook
5936 PAGE but leaves the tabs visible.
5938 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5939 _notebook_shrunk = true;
5947 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5949 using namespace Menu_Helpers;
5951 MenuList& items = _control_point_context_menu.items ();
5954 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5955 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5956 if (!can_remove_control_point (item)) {
5957 items.back().set_sensitive (false);
5960 _control_point_context_menu.popup (event->button.button, event->button.time);
5964 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5966 using namespace Menu_Helpers;
5968 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5973 /* We need to get the selection here and pass it to the operations, since
5974 popping up the menu will cause a region leave event which clears
5975 entered_regionview. */
5977 MidiRegionView& mrv = note->region_view();
5978 const RegionSelection rs = get_regions_from_selection_and_entered ();
5979 const uint32_t sel_size = mrv.selection_size ();
5981 MenuList& items = _note_context_menu.items();
5985 items.push_back(MenuElem(_("Delete"),
5986 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5989 items.push_back(MenuElem(_("Edit..."),
5990 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5991 if (sel_size != 1) {
5992 items.back().set_sensitive (false);
5995 items.push_back(MenuElem(_("Transpose..."),
5996 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5999 items.push_back(MenuElem(_("Legatize"),
6000 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6002 items.back().set_sensitive (false);
6005 items.push_back(MenuElem(_("Quantize..."),
6006 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6008 items.push_back(MenuElem(_("Remove Overlap"),
6009 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6011 items.back().set_sensitive (false);
6014 items.push_back(MenuElem(_("Transform..."),
6015 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6017 _note_context_menu.popup (event->button.button, event->button.time);
6021 Editor::zoom_vertical_modifier_released()
6023 _stepping_axis_view = 0;
6027 Editor::ui_parameter_changed (string parameter)
6029 if (parameter == "icon-set") {
6030 while (!_cursor_stack.empty()) {
6031 _cursor_stack.pop_back();
6033 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6034 _cursor_stack.push_back(_cursors->grabber);
6035 } else if (parameter == "draggable-playhead") {
6036 if (_verbose_cursor) {
6037 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6043 Editor::use_own_window (bool and_fill_it)
6045 bool new_window = !own_window();
6047 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6049 if (win && new_window) {
6050 win->set_name ("EditorWindow");
6052 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6054 // win->signal_realize().connect (*this, &Editor::on_realize);
6055 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6056 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6057 win->set_data ("ardour-bindings", bindings);
6062 DisplaySuspender ds;
6063 contents().show_all ();
6065 /* XXX: this is a bit unfortunate; it would probably
6066 be nicer if we could just call show () above rather
6067 than needing the show_all ()
6070 /* re-hide stuff if necessary */
6071 editor_list_button_toggled ();
6072 parameter_changed ("show-summary");
6073 parameter_changed ("show-group-tabs");
6074 parameter_changed ("show-zoom-tools");
6076 /* now reset all audio_time_axis heights, because widgets might need
6082 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6083 tv = (static_cast<TimeAxisView*>(*i));
6084 tv->reset_height ();
6087 if (current_mixer_strip) {
6088 current_mixer_strip->hide_things ();
6089 current_mixer_strip->parameter_changed ("mixer-element-visibility");