2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
86 #include "control_protocol/control_protocol.h"
89 #include "analysis_window.h"
90 #include "audio_clock.h"
91 #include "audio_region_view.h"
92 #include "audio_streamview.h"
93 #include "audio_time_axis.h"
94 #include "automation_time_axis.h"
95 #include "bundle_manager.h"
96 #include "crossfade_edit.h"
100 #include "editor_cursors.h"
101 #include "editor_drag.h"
102 #include "editor_group_tabs.h"
103 #include "editor_locations.h"
104 #include "editor_regions.h"
105 #include "editor_route_groups.h"
106 #include "editor_routes.h"
107 #include "editor_snapshots.h"
108 #include "editor_summary.h"
109 #include "export_report.h"
110 #include "global_port_matrix.h"
111 #include "gui_object.h"
112 #include "gui_thread.h"
113 #include "keyboard.h"
114 #include "keyeditor.h"
115 #include "luainstance.h"
117 #include "midi_region_view.h"
118 #include "midi_time_axis.h"
119 #include "mixer_strip.h"
120 #include "mixer_ui.h"
121 #include "mouse_cursors.h"
122 #include "note_base.h"
123 #include "playlist_selector.h"
124 #include "public_editor.h"
125 #include "quantize_dialog.h"
126 #include "region_layering_order_editor.h"
127 #include "rgb_macros.h"
128 #include "rhythm_ferret.h"
129 #include "route_sorter.h"
130 #include "selection.h"
131 #include "simple_progress_dialog.h"
133 #include "tempo_lines.h"
134 #include "time_axis_view.h"
136 #include "tooltips.h"
137 #include "ui_config.h"
139 #include "vca_time_axis.h"
140 #include "verbose_cursor.h"
145 using namespace ARDOUR;
146 using namespace ARDOUR_UI_UTILS;
149 using namespace Glib;
150 using namespace Gtkmm2ext;
151 using namespace Editing;
153 using PBD::internationalize;
155 using Gtkmm2ext::Keyboard;
157 double Editor::timebar_height = 15.0;
159 static const gchar *_snap_type_strings[] = {
193 static const gchar *_snap_mode_strings[] = {
200 static const gchar *_edit_point_strings[] = {
207 static const gchar *_edit_mode_strings[] = {
215 static const gchar *_zoom_focus_strings[] = {
225 #ifdef USE_RUBBERBAND
226 static const gchar *_rb_opt_strings[] = {
229 N_("Balanced multitimbral mixture"),
230 N_("Unpitched percussion with stable notes"),
231 N_("Crisp monophonic instrumental"),
232 N_("Unpitched solo percussion"),
233 N_("Resample without preserving pitch"),
238 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
241 : PublicEditor (global_hpacker)
242 , editor_mixer_strip_width (Wide)
243 , constructed (false)
244 , _playlist_selector (0)
245 , no_save_visual (false)
247 , samples_per_pixel (2048)
248 , zoom_focus (ZoomFocusPlayhead)
249 , mouse_mode (MouseObject)
250 , pre_internal_snap_type (SnapToBeat)
251 , pre_internal_snap_mode (SnapOff)
252 , internal_snap_type (SnapToBeat)
253 , internal_snap_mode (SnapOff)
254 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
255 , _notebook_shrunk (false)
256 , location_marker_color (0)
257 , location_range_color (0)
258 , location_loop_color (0)
259 , location_punch_color (0)
260 , location_cd_marker_color (0)
262 , _show_marker_lines (false)
263 , clicked_axisview (0)
264 , clicked_routeview (0)
265 , clicked_regionview (0)
266 , clicked_selection (0)
267 , clicked_control_point (0)
268 , button_release_can_deselect (true)
269 , _mouse_changed_selection (false)
270 , region_edit_menu_split_item (0)
271 , region_edit_menu_split_multichannel_item (0)
272 , track_region_edit_playlist_menu (0)
273 , track_edit_playlist_submenu (0)
274 , track_selection_edit_playlist_submenu (0)
275 , _popup_region_menu_item (0)
277 , _track_canvas_viewport (0)
278 , within_track_canvas (false)
279 , _verbose_cursor (0)
283 , range_marker_group (0)
284 , transport_marker_group (0)
285 , cd_marker_group (0)
286 , _time_markers_group (0)
287 , hv_scroll_group (0)
289 , cursor_scroll_group (0)
290 , no_scroll_group (0)
291 , _trackview_group (0)
292 , _drag_motion_group (0)
293 , _canvas_drop_zone (0)
294 , no_ruler_shown_update (false)
295 , ruler_grabbed_widget (0)
297 , minsec_mark_interval (0)
298 , minsec_mark_modulo (0)
300 , timecode_mark_modulo (0)
301 , timecode_nmarks (0)
302 , _samples_ruler_interval (0)
305 , bbt_bar_helper_on (0)
306 , bbt_accent_modulo (0)
311 , visible_timebars (0)
312 , editor_ruler_menu (0)
316 , range_marker_bar (0)
317 , transport_marker_bar (0)
319 , minsec_label (_("Mins:Secs"))
320 , bbt_label (_("Bars:Beats"))
321 , timecode_label (_("Timecode"))
322 , samples_label (_("Samples"))
323 , tempo_label (_("Tempo"))
324 , meter_label (_("Meter"))
325 , mark_label (_("Location Markers"))
326 , range_mark_label (_("Range Markers"))
327 , transport_mark_label (_("Loop/Punch Ranges"))
328 , cd_mark_label (_("CD Markers"))
329 , videotl_label (_("Video Timeline"))
331 , playhead_cursor (0)
332 , edit_packer (4, 4, true)
333 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
334 , horizontal_adjustment (0.0, 0.0, 1e16)
335 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
336 , controls_layout (unused_adjustment, vertical_adjustment)
337 , _scroll_callbacks (0)
338 , _visible_canvas_width (0)
339 , _visible_canvas_height (0)
340 , _full_canvas_height (0)
341 , edit_controls_left_menu (0)
342 , edit_controls_right_menu (0)
343 , last_update_frame (0)
344 , cut_buffer_start (0)
345 , cut_buffer_length (0)
346 , button_bindings (0)
350 , current_interthread_info (0)
351 , analysis_window (0)
352 , select_new_marker (false)
354 , scrubbing_direction (0)
355 , scrub_reversals (0)
356 , scrub_reverse_distance (0)
357 , have_pending_keyboard_selection (false)
358 , pending_keyboard_selection_start (0)
359 , _snap_type (SnapToBeat)
360 , _snap_mode (SnapOff)
361 , snap_threshold (5.0)
362 , ignore_gui_changes (false)
363 , _drags (new DragManager (this))
365 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
366 , _dragging_playhead (false)
367 , _dragging_edit_point (false)
368 , _show_measures (true)
369 , _follow_playhead (true)
370 , _stationary_playhead (false)
373 , global_rect_group (0)
374 , time_line_group (0)
375 , tempo_marker_menu (0)
376 , meter_marker_menu (0)
378 , range_marker_menu (0)
379 , transport_marker_menu (0)
380 , new_transport_marker_menu (0)
382 , marker_menu_item (0)
383 , bbt_beat_subdivision (4)
384 , _visible_track_count (-1)
385 , toolbar_selection_clock_table (2,3)
386 , automation_mode_button (_("mode"))
387 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
388 , selection (new Selection (this))
389 , cut_buffer (new Selection (this))
390 , _selection_memento (new SelectionMemento())
391 , _all_region_actions_sensitized (false)
392 , _ignore_region_action (false)
393 , _last_region_menu_was_main (false)
394 , _ignore_follow_edits (false)
395 , cd_marker_bar_drag_rect (0)
396 , range_bar_drag_rect (0)
397 , transport_bar_drag_rect (0)
398 , transport_bar_range_rect (0)
399 , transport_bar_preroll_rect (0)
400 , transport_bar_postroll_rect (0)
401 , transport_loop_range_rect (0)
402 , transport_punch_range_rect (0)
403 , transport_punchin_line (0)
404 , transport_punchout_line (0)
405 , transport_preroll_rect (0)
406 , transport_postroll_rect (0)
408 , rubberband_rect (0)
414 , autoscroll_horizontal_allowed (false)
415 , autoscroll_vertical_allowed (false)
417 , autoscroll_widget (0)
418 , show_gain_after_trim (false)
419 , selection_op_cmd_depth (0)
420 , selection_op_history_it (0)
421 , no_save_instant (false)
423 , current_mixer_strip (0)
424 , show_editor_mixer_when_tracks_arrive (false)
425 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
426 , current_stepping_trackview (0)
427 , last_track_height_step_timestamp (0)
429 , entered_regionview (0)
430 , clear_entered_track (false)
431 , _edit_point (EditAtMouse)
432 , meters_running (false)
434 , _have_idled (false)
435 , resize_idle_id (-1)
436 , _pending_resize_amount (0)
437 , _pending_resize_view (0)
438 , _pending_locate_request (false)
439 , _pending_initial_locate (false)
443 , layering_order_editor (0)
444 , _last_cut_copy_source_track (0)
445 , _region_selection_change_updates_region_list (true)
447 , _following_mixer_selection (false)
448 , _control_point_toggled_on_press (false)
449 , _stepping_axis_view (0)
450 , quantize_dialog (0)
451 , _main_menu_disabler (0)
452 , myactions (X_("editor"))
454 /* we are a singleton */
456 PublicEditor::_instance = this;
460 last_event_time.tv_sec = 0;
461 last_event_time.tv_usec = 0;
463 selection_op_history.clear();
466 snap_type_strings = I18N (_snap_type_strings);
467 snap_mode_strings = I18N (_snap_mode_strings);
468 zoom_focus_strings = I18N (_zoom_focus_strings);
469 edit_mode_strings = I18N (_edit_mode_strings);
470 edit_point_strings = I18N (_edit_point_strings);
471 #ifdef USE_RUBBERBAND
472 rb_opt_strings = I18N (_rb_opt_strings);
476 build_edit_mode_menu();
477 build_zoom_focus_menu();
478 build_track_count_menu();
479 build_snap_mode_menu();
480 build_snap_type_menu();
481 build_edit_point_menu();
483 location_marker_color = UIConfiguration::instance().color ("location marker");
484 location_range_color = UIConfiguration::instance().color ("location range");
485 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
486 location_loop_color = UIConfiguration::instance().color ("location loop");
487 location_punch_color = UIConfiguration::instance().color ("location punch");
489 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
491 TimeAxisView::setup_sizes ();
492 ArdourMarker::setup_sizes (timebar_height);
493 TempoCurve::setup_sizes (timebar_height);
495 bbt_label.set_name ("EditorRulerLabel");
496 bbt_label.set_size_request (-1, (int)timebar_height);
497 bbt_label.set_alignment (1.0, 0.5);
498 bbt_label.set_padding (5,0);
500 bbt_label.set_no_show_all();
501 minsec_label.set_name ("EditorRulerLabel");
502 minsec_label.set_size_request (-1, (int)timebar_height);
503 minsec_label.set_alignment (1.0, 0.5);
504 minsec_label.set_padding (5,0);
505 minsec_label.hide ();
506 minsec_label.set_no_show_all();
507 timecode_label.set_name ("EditorRulerLabel");
508 timecode_label.set_size_request (-1, (int)timebar_height);
509 timecode_label.set_alignment (1.0, 0.5);
510 timecode_label.set_padding (5,0);
511 timecode_label.hide ();
512 timecode_label.set_no_show_all();
513 samples_label.set_name ("EditorRulerLabel");
514 samples_label.set_size_request (-1, (int)timebar_height);
515 samples_label.set_alignment (1.0, 0.5);
516 samples_label.set_padding (5,0);
517 samples_label.hide ();
518 samples_label.set_no_show_all();
520 tempo_label.set_name ("EditorRulerLabel");
521 tempo_label.set_size_request (-1, (int)timebar_height);
522 tempo_label.set_alignment (1.0, 0.5);
523 tempo_label.set_padding (5,0);
525 tempo_label.set_no_show_all();
527 meter_label.set_name ("EditorRulerLabel");
528 meter_label.set_size_request (-1, (int)timebar_height);
529 meter_label.set_alignment (1.0, 0.5);
530 meter_label.set_padding (5,0);
532 meter_label.set_no_show_all();
534 if (Profile->get_trx()) {
535 mark_label.set_text (_("Markers"));
537 mark_label.set_name ("EditorRulerLabel");
538 mark_label.set_size_request (-1, (int)timebar_height);
539 mark_label.set_alignment (1.0, 0.5);
540 mark_label.set_padding (5,0);
542 mark_label.set_no_show_all();
544 cd_mark_label.set_name ("EditorRulerLabel");
545 cd_mark_label.set_size_request (-1, (int)timebar_height);
546 cd_mark_label.set_alignment (1.0, 0.5);
547 cd_mark_label.set_padding (5,0);
548 cd_mark_label.hide();
549 cd_mark_label.set_no_show_all();
551 videotl_bar_height = 4;
552 videotl_label.set_name ("EditorRulerLabel");
553 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
554 videotl_label.set_alignment (1.0, 0.5);
555 videotl_label.set_padding (5,0);
556 videotl_label.hide();
557 videotl_label.set_no_show_all();
559 range_mark_label.set_name ("EditorRulerLabel");
560 range_mark_label.set_size_request (-1, (int)timebar_height);
561 range_mark_label.set_alignment (1.0, 0.5);
562 range_mark_label.set_padding (5,0);
563 range_mark_label.hide();
564 range_mark_label.set_no_show_all();
566 transport_mark_label.set_name ("EditorRulerLabel");
567 transport_mark_label.set_size_request (-1, (int)timebar_height);
568 transport_mark_label.set_alignment (1.0, 0.5);
569 transport_mark_label.set_padding (5,0);
570 transport_mark_label.hide();
571 transport_mark_label.set_no_show_all();
573 initialize_canvas ();
575 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
577 _summary = new EditorSummary (this);
579 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
580 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
582 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
584 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
585 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
587 edit_controls_vbox.set_spacing (0);
588 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
589 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
591 HBox* h = manage (new HBox);
592 _group_tabs = new EditorGroupTabs (this);
593 if (!ARDOUR::Profile->get_trx()) {
594 h->pack_start (*_group_tabs, PACK_SHRINK);
596 h->pack_start (edit_controls_vbox);
597 controls_layout.add (*h);
599 controls_layout.set_name ("EditControlsBase");
600 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
601 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
602 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
604 _cursors = new MouseCursors;
605 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
606 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
608 /* Push default cursor to ever-present bottom of cursor stack. */
609 push_canvas_cursor(_cursors->grabber);
611 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
613 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
614 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
615 pad_line_1->set_outline_color (0xFF0000FF);
621 edit_packer.set_col_spacings (0);
622 edit_packer.set_row_spacings (0);
623 edit_packer.set_homogeneous (false);
624 edit_packer.set_border_width (0);
625 edit_packer.set_name ("EditorWindow");
627 time_bars_event_box.add (time_bars_vbox);
628 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
629 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
631 /* labels for the time bars */
632 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
634 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
636 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
638 bottom_hbox.set_border_width (2);
639 bottom_hbox.set_spacing (3);
641 _route_groups = new EditorRouteGroups (this);
642 _routes = new EditorRoutes (this);
643 _regions = new EditorRegions (this);
644 _snapshots = new EditorSnapshots (this);
645 _locations = new EditorLocations (this);
647 /* these are static location signals */
649 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
650 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
651 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 add_notebook_page (_("Regions"), _regions->widget ());
654 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
655 add_notebook_page (_("Snapshots"), _snapshots->widget ());
656 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
657 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
659 _the_notebook.set_show_tabs (true);
660 _the_notebook.set_scrollable (true);
661 _the_notebook.popup_disable ();
662 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
663 _the_notebook.show_all ();
665 _notebook_shrunk = false;
668 /* Pick up some settings we need to cache, early */
670 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
673 if (settings && (prop = settings->property ("notebook-shrunk"))) {
674 _notebook_shrunk = string_is_affirmative (prop->value ());
677 editor_summary_pane.set_check_divider_position (true);
678 editor_summary_pane.add (edit_packer);
680 Button* summary_arrows_left_left = manage (new Button);
681 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
682 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
683 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
685 Button* summary_arrows_left_right = manage (new Button);
686 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
687 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
688 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
690 VBox* summary_arrows_left = manage (new VBox);
691 summary_arrows_left->pack_start (*summary_arrows_left_left);
692 summary_arrows_left->pack_start (*summary_arrows_left_right);
694 Button* summary_arrows_right_up = manage (new Button);
695 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
696 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
697 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
699 Button* summary_arrows_right_down = manage (new Button);
700 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
701 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
702 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
704 VBox* summary_arrows_right = manage (new VBox);
705 summary_arrows_right->pack_start (*summary_arrows_right_up);
706 summary_arrows_right->pack_start (*summary_arrows_right_down);
708 Frame* summary_frame = manage (new Frame);
709 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
711 summary_frame->add (*_summary);
712 summary_frame->show ();
714 _summary_hbox.pack_start (*summary_arrows_left, false, false);
715 _summary_hbox.pack_start (*summary_frame, true, true);
716 _summary_hbox.pack_start (*summary_arrows_right, false, false);
718 if (!ARDOUR::Profile->get_trx()) {
719 editor_summary_pane.add (_summary_hbox);
722 edit_pane.set_check_divider_position (true);
723 edit_pane.add (editor_summary_pane);
724 if (!ARDOUR::Profile->get_trx()) {
725 edit_pane.add (_the_notebook);
728 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
729 edit_pane.set_child_minsize (_the_notebook, 30); /* rough guess at width of notebook tabs */
730 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
737 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
738 /* initial allocation is 90% to canvas, 10% to notebook */
739 edit_pane.set_divider (0, 0.90);
741 edit_pane.set_divider (0, fract);
744 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
745 /* initial allocation is 90% to canvas, 10% to summary */
746 editor_summary_pane.set_divider (0, 0.90);
749 editor_summary_pane.set_divider (0, fract);
753 top_hbox.pack_start (toolbar_frame);
755 HBox *hbox = manage (new HBox);
756 hbox->pack_start (edit_pane, true, true);
758 global_vpacker.pack_start (top_hbox, false, false);
759 global_vpacker.pack_start (*hbox, true, true);
760 global_hpacker.pack_start (global_vpacker, true, true);
762 /* need to show the "contents" widget so that notebook will show if tab is switched to
765 global_hpacker.show ();
767 /* register actions now so that set_state() can find them and set toggles/checks etc */
774 _playlist_selector = new PlaylistSelector();
775 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
777 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
781 nudge_forward_button.set_name ("nudge button");
782 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
784 nudge_backward_button.set_name ("nudge button");
785 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
787 fade_context_menu.set_name ("ArdourContextMenu");
789 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
791 /* allow external control surfaces/protocols to do various things */
793 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
794 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
795 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
796 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
797 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
798 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
799 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
800 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
801 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
802 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
803 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
804 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
805 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
806 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
808 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
812 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
814 /* problematic: has to return a value and thus cannot be x-thread */
816 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
818 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
819 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
821 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
823 _ignore_region_action = false;
824 _last_region_menu_was_main = false;
825 _popup_region_menu_item = 0;
827 _ignore_follow_edits = false;
829 _show_marker_lines = false;
831 /* Button bindings */
833 button_bindings = new Bindings ("editor-mouse");
835 XMLNode* node = button_settings();
837 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
838 button_bindings->load_operation (**i);
844 /* grab current parameter state */
845 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
846 UIConfiguration::instance().map_parameters (pc);
848 setup_fade_images ();
850 LuaInstance::instance(); // instantiate
851 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
858 delete button_bindings;
860 delete _route_groups;
861 delete _track_canvas_viewport;
864 delete quantize_dialog;
870 delete _playlist_selector;
872 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
878 Editor::button_settings () const
880 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
881 XMLNode* node = find_named_node (*settings, X_("Buttons"));
884 node = new XMLNode (X_("Buttons"));
891 Editor::get_smart_mode () const
893 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
897 Editor::catch_vanishing_regionview (RegionView *rv)
899 /* note: the selection will take care of the vanishing
900 audioregionview by itself.
903 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
907 if (clicked_regionview == rv) {
908 clicked_regionview = 0;
911 if (entered_regionview == rv) {
912 set_entered_regionview (0);
915 if (!_all_region_actions_sensitized) {
916 sensitize_all_region_actions (true);
921 Editor::set_entered_regionview (RegionView* rv)
923 if (rv == entered_regionview) {
927 if (entered_regionview) {
928 entered_regionview->exited ();
931 entered_regionview = rv;
933 if (entered_regionview != 0) {
934 entered_regionview->entered ();
937 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
938 /* This RegionView entry might have changed what region actions
939 are allowed, so sensitize them all in case a key is pressed.
941 sensitize_all_region_actions (true);
946 Editor::set_entered_track (TimeAxisView* tav)
949 entered_track->exited ();
955 entered_track->entered ();
960 Editor::instant_save ()
962 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
967 _session->add_instant_xml(get_state());
969 Config->add_instant_xml(get_state());
974 Editor::control_vertical_zoom_in_all ()
976 tav_zoom_smooth (false, true);
980 Editor::control_vertical_zoom_out_all ()
982 tav_zoom_smooth (true, true);
986 Editor::control_vertical_zoom_in_selected ()
988 tav_zoom_smooth (false, false);
992 Editor::control_vertical_zoom_out_selected ()
994 tav_zoom_smooth (true, false);
998 Editor::control_view (uint32_t view)
1000 goto_visual_state (view);
1004 Editor::control_unselect ()
1006 selection->clear_tracks ();
1010 Editor::control_step_tracks_up ()
1012 scroll_tracks_up_line ();
1016 Editor::control_step_tracks_down ()
1018 scroll_tracks_down_line ();
1022 Editor::control_scroll (float fraction)
1024 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1030 double step = fraction * current_page_samples();
1033 _control_scroll_target is an optional<T>
1035 it acts like a pointer to an framepos_t, with
1036 a operator conversion to boolean to check
1037 that it has a value could possibly use
1038 playhead_cursor->current_frame to store the
1039 value and a boolean in the class to know
1040 when it's out of date
1043 if (!_control_scroll_target) {
1044 _control_scroll_target = _session->transport_frame();
1045 _dragging_playhead = true;
1048 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1049 *_control_scroll_target = 0;
1050 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1051 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1053 *_control_scroll_target += (framepos_t) trunc (step);
1056 /* move visuals, we'll catch up with it later */
1058 playhead_cursor->set_position (*_control_scroll_target);
1059 UpdateAllTransportClocks (*_control_scroll_target);
1061 if (*_control_scroll_target > (current_page_samples() / 2)) {
1062 /* try to center PH in window */
1063 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1069 Now we do a timeout to actually bring the session to the right place
1070 according to the playhead. This is to avoid reading disk buffers on every
1071 call to control_scroll, which is driven by ScrollTimeline and therefore
1072 probably by a control surface wheel which can generate lots of events.
1074 /* cancel the existing timeout */
1076 control_scroll_connection.disconnect ();
1078 /* add the next timeout */
1080 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1084 Editor::deferred_control_scroll (framepos_t /*target*/)
1086 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1087 // reset for next stream
1088 _control_scroll_target = boost::none;
1089 _dragging_playhead = false;
1094 Editor::access_action (std::string action_group, std::string action_item)
1100 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1103 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1111 Editor::on_realize ()
1115 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1116 start_lock_event_timing ();
1121 Editor::start_lock_event_timing ()
1123 /* check if we should lock the GUI every 30 seconds */
1125 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1129 Editor::generic_event_handler (GdkEvent* ev)
1132 case GDK_BUTTON_PRESS:
1133 case GDK_BUTTON_RELEASE:
1134 case GDK_MOTION_NOTIFY:
1136 case GDK_KEY_RELEASE:
1137 if (contents().is_mapped()) {
1138 gettimeofday (&last_event_time, 0);
1142 case GDK_LEAVE_NOTIFY:
1143 switch (ev->crossing.detail) {
1144 case GDK_NOTIFY_UNKNOWN:
1145 case GDK_NOTIFY_INFERIOR:
1146 case GDK_NOTIFY_ANCESTOR:
1148 case GDK_NOTIFY_VIRTUAL:
1149 case GDK_NOTIFY_NONLINEAR:
1150 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1151 /* leaving window, so reset focus, thus ending any and
1152 all text entry operations.
1154 reset_focus (&contents());
1167 Editor::lock_timeout_callback ()
1169 struct timeval now, delta;
1171 gettimeofday (&now, 0);
1173 timersub (&now, &last_event_time, &delta);
1175 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1177 /* don't call again. Returning false will effectively
1178 disconnect us from the timer callback.
1180 unlock() will call start_lock_event_timing() to get things
1190 Editor::map_position_change (framepos_t frame)
1192 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1194 if (_session == 0) {
1198 if (_follow_playhead) {
1199 center_screen (frame);
1202 playhead_cursor->set_position (frame);
1206 Editor::center_screen (framepos_t frame)
1208 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1210 /* if we're off the page, then scroll.
1213 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1214 center_screen_internal (frame, page);
1219 Editor::center_screen_internal (framepos_t frame, float page)
1224 frame -= (framepos_t) page;
1229 reset_x_origin (frame);
1234 Editor::update_title ()
1236 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1238 if (!own_window()) {
1243 bool dirty = _session->dirty();
1245 string session_name;
1247 if (_session->snap_name() != _session->name()) {
1248 session_name = _session->snap_name();
1250 session_name = _session->name();
1254 session_name = "*" + session_name;
1257 WindowTitle title(session_name);
1258 title += S_("Window|Editor");
1259 title += Glib::get_application_name();
1260 own_window()->set_title (title.get_string());
1262 /* ::session_going_away() will have taken care of it */
1267 Editor::set_session (Session *t)
1269 SessionHandlePtr::set_session (t);
1275 _playlist_selector->set_session (_session);
1276 nudge_clock->set_session (_session);
1277 _summary->set_session (_session);
1278 _group_tabs->set_session (_session);
1279 _route_groups->set_session (_session);
1280 _regions->set_session (_session);
1281 _snapshots->set_session (_session);
1282 _routes->set_session (_session);
1283 _locations->set_session (_session);
1285 if (rhythm_ferret) {
1286 rhythm_ferret->set_session (_session);
1289 if (analysis_window) {
1290 analysis_window->set_session (_session);
1294 sfbrowser->set_session (_session);
1297 compute_fixed_ruler_scale ();
1299 /* Make sure we have auto loop and auto punch ranges */
1301 Location* loc = _session->locations()->auto_loop_location();
1303 loc->set_name (_("Loop"));
1306 loc = _session->locations()->auto_punch_location();
1309 loc->set_name (_("Punch"));
1312 refresh_location_display ();
1314 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1315 the selected Marker; this needs the LocationMarker list to be available.
1317 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1318 set_state (*node, Stateful::loading_state_version);
1320 /* catch up with the playhead */
1322 _session->request_locate (playhead_cursor->current_frame ());
1323 _pending_initial_locate = true;
1327 /* These signals can all be emitted by a non-GUI thread. Therefore the
1328 handlers for them must not attempt to directly interact with the GUI,
1329 but use PBD::Signal<T>::connect() which accepts an event loop
1330 ("context") where the handler will be asked to run.
1333 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1334 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1335 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1336 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1337 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1338 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1339 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1340 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1341 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1342 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1343 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1344 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1345 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1346 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1347 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1349 playhead_cursor->show ();
1351 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1352 Config->map_parameters (pc);
1353 _session->config.map_parameters (pc);
1355 restore_ruler_visibility ();
1356 //tempo_map_changed (PropertyChange (0));
1357 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1359 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1360 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1363 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1364 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1367 switch (_snap_type) {
1368 case SnapToRegionStart:
1369 case SnapToRegionEnd:
1370 case SnapToRegionSync:
1371 case SnapToRegionBoundary:
1372 build_region_boundary_cache ();
1379 /* catch up on selection of stripables (other selection state is lost
1380 * when a session is closed
1385 _session->get_stripables (sl);
1386 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1387 if ((*s)->presentation_info().selected()) {
1388 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1390 tl.push_back (rtav);
1395 selection->set (tl);
1398 /* register for undo history */
1399 _session->register_with_memento_command_factory(id(), this);
1400 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1402 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1404 LuaInstance::instance()->set_session(_session);
1406 start_updating_meters ();
1410 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1412 if (a->get_name() == "RegionMenu") {
1413 /* When the main menu's region menu is opened, we setup the actions so that they look right
1414 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1415 so we resensitize all region actions when the entered regionview or the region selection
1416 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1417 happens after the region context menu is opened. So we set a flag here, too.
1421 sensitize_the_right_region_actions ();
1422 _last_region_menu_was_main = true;
1427 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1429 using namespace Menu_Helpers;
1431 void (Editor::*emf)(FadeShape);
1432 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1435 images = &_xfade_in_images;
1436 emf = &Editor::set_fade_in_shape;
1438 images = &_xfade_out_images;
1439 emf = &Editor::set_fade_out_shape;
1444 _("Linear (for highly correlated material)"),
1445 *(*images)[FadeLinear],
1446 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1450 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1454 _("Constant power"),
1455 *(*images)[FadeConstantPower],
1456 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1459 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1464 *(*images)[FadeSymmetric],
1465 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1469 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1474 *(*images)[FadeSlow],
1475 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1478 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1483 *(*images)[FadeFast],
1484 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1490 /** Pop up a context menu for when the user clicks on a start crossfade */
1492 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1494 using namespace Menu_Helpers;
1495 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1500 MenuList& items (xfade_in_context_menu.items());
1503 if (arv->audio_region()->fade_in_active()) {
1504 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1506 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1509 items.push_back (SeparatorElem());
1510 fill_xfade_menu (items, true);
1512 xfade_in_context_menu.popup (button, time);
1515 /** Pop up a context menu for when the user clicks on an end crossfade */
1517 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1519 using namespace Menu_Helpers;
1520 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1525 MenuList& items (xfade_out_context_menu.items());
1528 if (arv->audio_region()->fade_out_active()) {
1529 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1531 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1534 items.push_back (SeparatorElem());
1535 fill_xfade_menu (items, false);
1537 xfade_out_context_menu.popup (button, time);
1541 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1543 using namespace Menu_Helpers;
1544 Menu* (Editor::*build_menu_function)();
1547 switch (item_type) {
1549 case RegionViewName:
1550 case RegionViewNameHighlight:
1551 case LeftFrameHandle:
1552 case RightFrameHandle:
1553 if (with_selection) {
1554 build_menu_function = &Editor::build_track_selection_context_menu;
1556 build_menu_function = &Editor::build_track_region_context_menu;
1561 if (with_selection) {
1562 build_menu_function = &Editor::build_track_selection_context_menu;
1564 build_menu_function = &Editor::build_track_context_menu;
1569 if (clicked_routeview->track()) {
1570 build_menu_function = &Editor::build_track_context_menu;
1572 build_menu_function = &Editor::build_track_bus_context_menu;
1577 /* probably shouldn't happen but if it does, we don't care */
1581 menu = (this->*build_menu_function)();
1582 menu->set_name ("ArdourContextMenu");
1584 /* now handle specific situations */
1586 switch (item_type) {
1588 case RegionViewName:
1589 case RegionViewNameHighlight:
1590 case LeftFrameHandle:
1591 case RightFrameHandle:
1592 if (!with_selection) {
1593 if (region_edit_menu_split_item) {
1594 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1595 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1597 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1600 if (region_edit_menu_split_multichannel_item) {
1601 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1602 region_edit_menu_split_multichannel_item->set_sensitive (true);
1604 region_edit_menu_split_multichannel_item->set_sensitive (false);
1617 /* probably shouldn't happen but if it does, we don't care */
1621 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1623 /* Bounce to disk */
1625 using namespace Menu_Helpers;
1626 MenuList& edit_items = menu->items();
1628 edit_items.push_back (SeparatorElem());
1630 switch (clicked_routeview->audio_track()->freeze_state()) {
1631 case AudioTrack::NoFreeze:
1632 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1635 case AudioTrack::Frozen:
1636 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1639 case AudioTrack::UnFrozen:
1640 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1646 if (item_type == StreamItem && clicked_routeview) {
1647 clicked_routeview->build_underlay_menu(menu);
1650 /* When the region menu is opened, we setup the actions so that they look right
1653 sensitize_the_right_region_actions ();
1654 _last_region_menu_was_main = false;
1656 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1657 menu->popup (button, time);
1661 Editor::build_track_context_menu ()
1663 using namespace Menu_Helpers;
1665 MenuList& edit_items = track_context_menu.items();
1668 add_dstream_context_items (edit_items);
1669 return &track_context_menu;
1673 Editor::build_track_bus_context_menu ()
1675 using namespace Menu_Helpers;
1677 MenuList& edit_items = track_context_menu.items();
1680 add_bus_context_items (edit_items);
1681 return &track_context_menu;
1685 Editor::build_track_region_context_menu ()
1687 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_region_context_menu.items();
1691 /* we've just cleared the track region context menu, so the menu that these
1692 two items were on will have disappeared; stop them dangling.
1694 region_edit_menu_split_item = 0;
1695 region_edit_menu_split_multichannel_item = 0;
1697 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1700 boost::shared_ptr<Track> tr;
1701 boost::shared_ptr<Playlist> pl;
1703 if ((tr = rtv->track())) {
1704 add_region_context_items (edit_items, tr);
1708 add_dstream_context_items (edit_items);
1710 return &track_region_context_menu;
1714 Editor::loudness_analyze_region_selection ()
1719 Selection& s (PublicEditor::instance ().get_selection ());
1720 RegionSelection ars = s.regions;
1721 ARDOUR::AnalysisGraph ag (_session);
1722 framecnt_t total_work = 0;
1724 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1725 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1729 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1732 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1733 total_work += arv->region ()->length ();
1736 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1738 ag.set_total_frames (total_work);
1739 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1742 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1743 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1747 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1751 ag.analyze_region (ar);
1754 if (!ag.canceled ()) {
1755 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1761 Editor::loudness_analyze_range_selection ()
1766 Selection& s (PublicEditor::instance ().get_selection ());
1767 TimeSelection ts = s.time;
1768 ARDOUR::AnalysisGraph ag (_session);
1769 framecnt_t total_work = 0;
1771 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1772 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1776 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1780 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1781 total_work += j->length ();
1785 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1787 ag.set_total_frames (total_work);
1788 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1791 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1792 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1796 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1800 ag.analyze_range (rui->route (), pl, ts);
1803 if (!ag.canceled ()) {
1804 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1810 Editor::spectral_analyze_region_selection ()
1812 if (analysis_window == 0) {
1813 analysis_window = new AnalysisWindow();
1816 analysis_window->set_session(_session);
1818 analysis_window->show_all();
1821 analysis_window->set_regionmode();
1822 analysis_window->analyze();
1824 analysis_window->present();
1828 Editor::spectral_analyze_range_selection()
1830 if (analysis_window == 0) {
1831 analysis_window = new AnalysisWindow();
1834 analysis_window->set_session(_session);
1836 analysis_window->show_all();
1839 analysis_window->set_rangemode();
1840 analysis_window->analyze();
1842 analysis_window->present();
1846 Editor::build_track_selection_context_menu ()
1848 using namespace Menu_Helpers;
1849 MenuList& edit_items = track_selection_context_menu.items();
1850 edit_items.clear ();
1852 add_selection_context_items (edit_items);
1853 // edit_items.push_back (SeparatorElem());
1854 // add_dstream_context_items (edit_items);
1856 return &track_selection_context_menu;
1860 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1862 using namespace Menu_Helpers;
1864 /* OK, stick the region submenu at the top of the list, and then add
1868 RegionSelection rs = get_regions_from_selection_and_entered ();
1870 string::size_type pos = 0;
1871 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1873 /* we have to hack up the region name because "_" has a special
1874 meaning for menu titles.
1877 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1878 menu_item_name.replace (pos, 1, "__");
1882 if (_popup_region_menu_item == 0) {
1883 _popup_region_menu_item = new MenuItem (menu_item_name);
1884 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1885 _popup_region_menu_item->show ();
1887 _popup_region_menu_item->set_label (menu_item_name);
1890 /* No latering allowed in later is higher layering model */
1891 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1892 if (act && Config->get_layer_model() == LaterHigher) {
1893 act->set_sensitive (false);
1895 act->set_sensitive (true);
1898 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1900 edit_items.push_back (*_popup_region_menu_item);
1901 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1902 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1904 edit_items.push_back (SeparatorElem());
1907 /** Add context menu items relevant to selection ranges.
1908 * @param edit_items List to add the items to.
1911 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1913 using namespace Menu_Helpers;
1915 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1916 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1918 edit_items.push_back (SeparatorElem());
1919 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1921 edit_items.push_back (SeparatorElem());
1922 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1923 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1925 edit_items.push_back (SeparatorElem());
1927 edit_items.push_back (
1929 _("Move Range Start to Previous Region Boundary"),
1930 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1934 edit_items.push_back (
1936 _("Move Range Start to Next Region Boundary"),
1937 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1941 edit_items.push_back (
1943 _("Move Range End to Previous Region Boundary"),
1944 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1948 edit_items.push_back (
1950 _("Move Range End to Next Region Boundary"),
1951 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1955 edit_items.push_back (SeparatorElem());
1956 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1957 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1959 edit_items.push_back (SeparatorElem());
1960 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1962 edit_items.push_back (SeparatorElem());
1963 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1964 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1965 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1967 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1970 edit_items.push_back (SeparatorElem());
1971 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1972 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1974 edit_items.push_back (SeparatorElem());
1975 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1976 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1977 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1978 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1979 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1980 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1981 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1987 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1989 using namespace Menu_Helpers;
1993 Menu *play_menu = manage (new Menu);
1994 MenuList& play_items = play_menu->items();
1995 play_menu->set_name ("ArdourContextMenu");
1997 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1998 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1999 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2000 play_items.push_back (SeparatorElem());
2001 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2003 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2007 Menu *select_menu = manage (new Menu);
2008 MenuList& select_items = select_menu->items();
2009 select_menu->set_name ("ArdourContextMenu");
2011 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2012 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2013 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2014 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2015 select_items.push_back (SeparatorElem());
2016 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2017 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2018 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2019 select_items.push_back (SeparatorElem());
2020 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2021 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2022 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2023 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2024 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2025 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2026 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2028 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2032 Menu *cutnpaste_menu = manage (new Menu);
2033 MenuList& cutnpaste_items = cutnpaste_menu->items();
2034 cutnpaste_menu->set_name ("ArdourContextMenu");
2036 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2037 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2038 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2040 cutnpaste_items.push_back (SeparatorElem());
2042 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2043 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2045 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2047 /* Adding new material */
2049 edit_items.push_back (SeparatorElem());
2050 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2051 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2055 Menu *nudge_menu = manage (new Menu());
2056 MenuList& nudge_items = nudge_menu->items();
2057 nudge_menu->set_name ("ArdourContextMenu");
2059 edit_items.push_back (SeparatorElem());
2060 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2061 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2062 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2063 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2065 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2069 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2071 using namespace Menu_Helpers;
2075 Menu *play_menu = manage (new Menu);
2076 MenuList& play_items = play_menu->items();
2077 play_menu->set_name ("ArdourContextMenu");
2079 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2080 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2081 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2085 Menu *select_menu = manage (new Menu);
2086 MenuList& select_items = select_menu->items();
2087 select_menu->set_name ("ArdourContextMenu");
2089 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2090 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2091 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2092 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2093 select_items.push_back (SeparatorElem());
2094 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2095 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2096 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2097 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2099 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2103 Menu *cutnpaste_menu = manage (new Menu);
2104 MenuList& cutnpaste_items = cutnpaste_menu->items();
2105 cutnpaste_menu->set_name ("ArdourContextMenu");
2107 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2108 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2109 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2111 Menu *nudge_menu = manage (new Menu());
2112 MenuList& nudge_items = nudge_menu->items();
2113 nudge_menu->set_name ("ArdourContextMenu");
2115 edit_items.push_back (SeparatorElem());
2116 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2117 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2118 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2119 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2121 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2125 Editor::snap_type() const
2131 Editor::snap_musical() const
2133 switch (_snap_type) {
2134 case SnapToBeatDiv128:
2135 case SnapToBeatDiv64:
2136 case SnapToBeatDiv32:
2137 case SnapToBeatDiv28:
2138 case SnapToBeatDiv24:
2139 case SnapToBeatDiv20:
2140 case SnapToBeatDiv16:
2141 case SnapToBeatDiv14:
2142 case SnapToBeatDiv12:
2143 case SnapToBeatDiv10:
2144 case SnapToBeatDiv8:
2145 case SnapToBeatDiv7:
2146 case SnapToBeatDiv6:
2147 case SnapToBeatDiv5:
2148 case SnapToBeatDiv4:
2149 case SnapToBeatDiv3:
2150 case SnapToBeatDiv2:
2162 Editor::snap_mode() const
2168 Editor::set_snap_to (SnapType st)
2170 unsigned int snap_ind = (unsigned int)st;
2172 if (internal_editing()) {
2173 internal_snap_type = st;
2175 pre_internal_snap_type = st;
2180 if (snap_ind > snap_type_strings.size() - 1) {
2182 _snap_type = (SnapType)snap_ind;
2185 string str = snap_type_strings[snap_ind];
2187 if (str != snap_type_selector.get_text()) {
2188 snap_type_selector.set_text (str);
2193 switch (_snap_type) {
2194 case SnapToBeatDiv128:
2195 case SnapToBeatDiv64:
2196 case SnapToBeatDiv32:
2197 case SnapToBeatDiv28:
2198 case SnapToBeatDiv24:
2199 case SnapToBeatDiv20:
2200 case SnapToBeatDiv16:
2201 case SnapToBeatDiv14:
2202 case SnapToBeatDiv12:
2203 case SnapToBeatDiv10:
2204 case SnapToBeatDiv8:
2205 case SnapToBeatDiv7:
2206 case SnapToBeatDiv6:
2207 case SnapToBeatDiv5:
2208 case SnapToBeatDiv4:
2209 case SnapToBeatDiv3:
2210 case SnapToBeatDiv2: {
2211 std::vector<TempoMap::BBTPoint> grid;
2212 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2213 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2214 update_tempo_based_rulers (grid);
2218 case SnapToRegionStart:
2219 case SnapToRegionEnd:
2220 case SnapToRegionSync:
2221 case SnapToRegionBoundary:
2222 build_region_boundary_cache ();
2230 redisplay_tempo (false);
2232 SnapChanged (); /* EMIT SIGNAL */
2236 Editor::set_snap_mode (SnapMode mode)
2238 string str = snap_mode_strings[(int)mode];
2240 if (internal_editing()) {
2241 internal_snap_mode = mode;
2243 pre_internal_snap_mode = mode;
2248 if (str != snap_mode_selector.get_text ()) {
2249 snap_mode_selector.set_text (str);
2256 Editor::set_edit_point_preference (EditPoint ep, bool force)
2258 bool changed = (_edit_point != ep);
2261 if (Profile->get_mixbus())
2262 if (ep == EditAtSelectedMarker)
2263 ep = EditAtPlayhead;
2265 string str = edit_point_strings[(int)ep];
2266 if (str != edit_point_selector.get_text ()) {
2267 edit_point_selector.set_text (str);
2270 update_all_enter_cursors();
2272 if (!force && !changed) {
2276 const char* action=NULL;
2278 switch (_edit_point) {
2279 case EditAtPlayhead:
2280 action = "edit-at-playhead";
2282 case EditAtSelectedMarker:
2283 action = "edit-at-marker";
2286 action = "edit-at-mouse";
2290 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2292 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2296 bool in_track_canvas;
2298 if (!mouse_frame (foo, in_track_canvas)) {
2299 in_track_canvas = false;
2302 reset_canvas_action_sensitivity (in_track_canvas);
2308 Editor::set_state (const XMLNode& node, int version)
2310 XMLProperty const * prop;
2312 PBD::Unwinder<bool> nsi (no_save_instant, true);
2315 Tabbable::set_state (node, version);
2317 if (_session && (prop = node.property ("playhead"))) {
2319 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2321 playhead_cursor->set_position (pos);
2323 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2324 playhead_cursor->set_position (0);
2327 playhead_cursor->set_position (0);
2330 if ((prop = node.property ("mixer-width"))) {
2331 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2334 if ((prop = node.property ("zoom-focus"))) {
2335 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2337 zoom_focus_selection_done (zoom_focus);
2340 if ((prop = node.property ("zoom"))) {
2341 /* older versions of ardour used floating point samples_per_pixel */
2342 double f = PBD::atof (prop->value());
2343 reset_zoom (llrintf (f));
2345 reset_zoom (samples_per_pixel);
2348 if ((prop = node.property ("visible-track-count"))) {
2349 set_visible_track_count (PBD::atoi (prop->value()));
2352 if ((prop = node.property ("snap-to"))) {
2353 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2354 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2356 set_snap_to (_snap_type);
2359 if ((prop = node.property ("snap-mode"))) {
2360 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2361 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2362 * snap_mode_selection_done() will only mark an already active item as active
2363 * which does not trigger set_text().
2365 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2367 set_snap_mode (_snap_mode);
2370 if ((prop = node.property ("internal-snap-to"))) {
2371 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2374 if ((prop = node.property ("internal-snap-mode"))) {
2375 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2378 if ((prop = node.property ("pre-internal-snap-to"))) {
2379 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2382 if ((prop = node.property ("pre-internal-snap-mode"))) {
2383 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2386 if ((prop = node.property ("mouse-mode"))) {
2387 MouseMode m = str2mousemode(prop->value());
2388 set_mouse_mode (m, true);
2390 set_mouse_mode (MouseObject, true);
2393 if ((prop = node.property ("left-frame")) != 0) {
2395 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2399 reset_x_origin (pos);
2403 if ((prop = node.property ("y-origin")) != 0) {
2404 reset_y_origin (atof (prop->value ()));
2407 if ((prop = node.property ("join-object-range"))) {
2408 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2409 bool yn = string_is_affirmative (prop->value());
2411 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2412 tact->set_active (!yn);
2413 tact->set_active (yn);
2415 set_mouse_mode(mouse_mode, true);
2418 if ((prop = node.property ("edit-point"))) {
2419 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2421 set_edit_point_preference (_edit_point);
2424 if ((prop = node.property ("show-measures"))) {
2425 bool yn = string_is_affirmative (prop->value());
2426 _show_measures = yn;
2429 if ((prop = node.property ("follow-playhead"))) {
2430 bool yn = string_is_affirmative (prop->value());
2431 set_follow_playhead (yn);
2434 if ((prop = node.property ("stationary-playhead"))) {
2435 bool yn = string_is_affirmative (prop->value());
2436 set_stationary_playhead (yn);
2439 if ((prop = node.property ("region-list-sort-type"))) {
2440 RegionListSortType st;
2441 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2444 if ((prop = node.property ("show-editor-mixer"))) {
2446 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2449 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2450 bool yn = string_is_affirmative (prop->value());
2452 /* do it twice to force the change */
2454 tact->set_active (!yn);
2455 tact->set_active (yn);
2458 if ((prop = node.property ("show-editor-list"))) {
2460 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2463 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2464 bool yn = string_is_affirmative (prop->value());
2466 /* do it twice to force the change */
2468 tact->set_active (!yn);
2469 tact->set_active (yn);
2472 if ((prop = node.property (X_("editor-list-page")))) {
2473 _the_notebook.set_current_page (atoi (prop->value ()));
2476 if ((prop = node.property (X_("show-marker-lines")))) {
2477 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2479 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2480 bool yn = string_is_affirmative (prop->value ());
2482 tact->set_active (!yn);
2483 tact->set_active (yn);
2486 XMLNodeList children = node.children ();
2487 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2488 selection->set_state (**i, Stateful::current_state_version);
2489 _regions->set_state (**i);
2492 if ((prop = node.property ("maximised"))) {
2493 bool yn = string_is_affirmative (prop->value());
2494 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2496 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 bool fs = tact && tact->get_active();
2499 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2503 if ((prop = node.property ("nudge-clock-value"))) {
2505 sscanf (prop->value().c_str(), "%" PRId64, &f);
2506 nudge_clock->set (f);
2508 nudge_clock->set_mode (AudioClock::Timecode);
2509 nudge_clock->set (_session->frame_rate() * 5, true);
2514 * Not all properties may have been in XML, but
2515 * those that are linked to a private variable may need changing
2520 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2522 yn = _show_measures;
2523 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2524 /* do it twice to force the change */
2525 tact->set_active (!yn);
2526 tact->set_active (yn);
2529 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2530 yn = _follow_playhead;
2532 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2533 if (tact->get_active() != yn) {
2534 tact->set_active (yn);
2538 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2539 yn = _stationary_playhead;
2541 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2542 if (tact->get_active() != yn) {
2543 tact->set_active (yn);
2548 return LuaInstance::instance()->set_state(node);
2552 Editor::get_state ()
2554 XMLNode* node = new XMLNode (X_("Editor"));
2558 id().print (buf, sizeof (buf));
2559 node->add_property ("id", buf);
2561 node->add_child_nocopy (Tabbable::get_state());
2563 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2564 node->add_property("edit-horizontal-pane-pos", string(buf));
2565 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2566 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2567 node->add_property("edit-vertical-pane-pos", string(buf));
2569 maybe_add_mixer_strip_width (*node);
2571 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2573 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2574 node->add_property ("zoom", buf);
2575 node->add_property ("snap-to", enum_2_string (_snap_type));
2576 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2577 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2578 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2579 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2580 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2581 node->add_property ("edit-point", enum_2_string (_edit_point));
2582 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2583 node->add_property ("visible-track-count", buf);
2585 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2586 node->add_property ("playhead", buf);
2587 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2588 node->add_property ("left-frame", buf);
2589 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2590 node->add_property ("y-origin", buf);
2592 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2593 node->add_property ("maximised", _maximised ? "yes" : "no");
2594 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2595 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2596 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2597 node->add_property ("mouse-mode", enum2str(mouse_mode));
2598 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2600 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2602 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2603 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2606 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2608 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2609 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2612 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2613 node->add_property (X_("editor-list-page"), buf);
2615 if (button_bindings) {
2616 XMLNode* bb = new XMLNode (X_("Buttons"));
2617 button_bindings->save (*bb);
2618 node->add_child_nocopy (*bb);
2621 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2623 node->add_child_nocopy (selection->get_state ());
2624 node->add_child_nocopy (_regions->get_state ());
2626 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2627 node->add_property ("nudge-clock-value", buf);
2629 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2630 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2635 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2636 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2638 * @return pair: TimeAxisView that y is over, layer index.
2640 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2641 * in stacked or expanded region display mode, otherwise 0.
2643 std::pair<TimeAxisView *, double>
2644 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2646 if (!trackview_relative_offset) {
2647 y -= _trackview_group->canvas_origin().y;
2651 return std::make_pair ( (TimeAxisView *) 0, 0);
2654 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2656 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2663 return std::make_pair ( (TimeAxisView *) 0, 0);
2666 /** Snap a position to the grid, if appropriate, taking into account current
2667 * grid settings and also the state of any snap modifier keys that may be pressed.
2668 * @param start Position to snap.
2669 * @param event Event to get current key modifier information from, or 0.
2672 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2674 if (!_session || !event) {
2678 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2679 if (_snap_mode == SnapOff) {
2680 snap_to_internal (start, direction, for_mark);
2683 if (_snap_mode != SnapOff) {
2684 snap_to_internal (start, direction, for_mark);
2685 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2686 /* SnapOff, but we pressed the snap_delta modifier */
2687 snap_to_internal (start, direction, for_mark);
2693 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2695 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2699 snap_to_internal (start, direction, for_mark, ensure_snap);
2703 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2705 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2706 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2708 switch (_snap_type) {
2709 case SnapToTimecodeFrame:
2710 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2711 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2712 /* start is already on a whole timecode frame, do nothing */
2713 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2714 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2716 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2720 case SnapToTimecodeSeconds:
2721 if (_session->config.get_timecode_offset_negative()) {
2722 start += _session->config.get_timecode_offset ();
2724 start -= _session->config.get_timecode_offset ();
2726 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2727 (start % one_timecode_second == 0)) {
2728 /* start is already on a whole second, do nothing */
2729 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2730 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2732 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2735 if (_session->config.get_timecode_offset_negative()) {
2736 start -= _session->config.get_timecode_offset ();
2738 start += _session->config.get_timecode_offset ();
2742 case SnapToTimecodeMinutes:
2743 if (_session->config.get_timecode_offset_negative()) {
2744 start += _session->config.get_timecode_offset ();
2746 start -= _session->config.get_timecode_offset ();
2748 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2749 (start % one_timecode_minute == 0)) {
2750 /* start is already on a whole minute, do nothing */
2751 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2752 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2754 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2756 if (_session->config.get_timecode_offset_negative()) {
2757 start -= _session->config.get_timecode_offset ();
2759 start += _session->config.get_timecode_offset ();
2763 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2764 abort(); /*NOTREACHED*/
2769 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2771 const framepos_t one_second = _session->frame_rate();
2772 const framepos_t one_minute = _session->frame_rate() * 60;
2773 framepos_t presnap = start;
2777 switch (_snap_type) {
2778 case SnapToTimecodeFrame:
2779 case SnapToTimecodeSeconds:
2780 case SnapToTimecodeMinutes:
2781 return timecode_snap_to_internal (start, direction, for_mark);
2784 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2785 start % (one_second/75) == 0) {
2786 /* start is already on a whole CD frame, do nothing */
2787 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2788 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2790 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2795 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2796 start % one_second == 0) {
2797 /* start is already on a whole second, do nothing */
2798 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2799 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2801 start = (framepos_t) floor ((double) start / one_second) * one_second;
2806 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2807 start % one_minute == 0) {
2808 /* start is already on a whole minute, do nothing */
2809 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2810 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2812 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2817 start = _session->tempo_map().round_to_bar (start, direction);
2821 start = _session->tempo_map().round_to_beat (start, direction);
2824 case SnapToBeatDiv128:
2825 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2827 case SnapToBeatDiv64:
2828 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2830 case SnapToBeatDiv32:
2831 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2833 case SnapToBeatDiv28:
2834 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2836 case SnapToBeatDiv24:
2837 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2839 case SnapToBeatDiv20:
2840 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2842 case SnapToBeatDiv16:
2843 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2845 case SnapToBeatDiv14:
2846 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2848 case SnapToBeatDiv12:
2849 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2851 case SnapToBeatDiv10:
2852 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2854 case SnapToBeatDiv8:
2855 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2857 case SnapToBeatDiv7:
2858 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2860 case SnapToBeatDiv6:
2861 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2863 case SnapToBeatDiv5:
2864 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2866 case SnapToBeatDiv4:
2867 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2869 case SnapToBeatDiv3:
2870 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2872 case SnapToBeatDiv2:
2873 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2881 _session->locations()->marks_either_side (start, before, after);
2883 if (before == max_framepos && after == max_framepos) {
2884 /* No marks to snap to, so just don't snap */
2886 } else if (before == max_framepos) {
2888 } else if (after == max_framepos) {
2890 } else if (before != max_framepos && after != max_framepos) {
2891 /* have before and after */
2892 if ((start - before) < (after - start)) {
2901 case SnapToRegionStart:
2902 case SnapToRegionEnd:
2903 case SnapToRegionSync:
2904 case SnapToRegionBoundary:
2905 if (!region_boundary_cache.empty()) {
2907 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2908 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2910 if (direction > 0) {
2911 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2913 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2916 if (next != region_boundary_cache.begin ()) {
2921 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2922 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2924 if (start > (p + n) / 2) {
2933 switch (_snap_mode) {
2943 if (presnap > start) {
2944 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2948 } else if (presnap < start) {
2949 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2955 /* handled at entry */
2963 Editor::setup_toolbar ()
2965 HBox* mode_box = manage(new HBox);
2966 mode_box->set_border_width (2);
2967 mode_box->set_spacing(2);
2969 HBox* mouse_mode_box = manage (new HBox);
2970 HBox* mouse_mode_hbox = manage (new HBox);
2971 VBox* mouse_mode_vbox = manage (new VBox);
2972 Alignment* mouse_mode_align = manage (new Alignment);
2974 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2975 mouse_mode_size_group->add_widget (smart_mode_button);
2976 mouse_mode_size_group->add_widget (mouse_move_button);
2977 mouse_mode_size_group->add_widget (mouse_cut_button);
2978 mouse_mode_size_group->add_widget (mouse_select_button);
2979 mouse_mode_size_group->add_widget (mouse_timefx_button);
2980 mouse_mode_size_group->add_widget (mouse_audition_button);
2981 mouse_mode_size_group->add_widget (mouse_draw_button);
2982 mouse_mode_size_group->add_widget (mouse_content_button);
2984 mouse_mode_size_group->add_widget (zoom_in_button);
2985 mouse_mode_size_group->add_widget (zoom_out_button);
2986 mouse_mode_size_group->add_widget (zoom_preset_selector);
2987 mouse_mode_size_group->add_widget (zoom_out_full_button);
2988 mouse_mode_size_group->add_widget (zoom_focus_selector);
2990 mouse_mode_size_group->add_widget (tav_shrink_button);
2991 mouse_mode_size_group->add_widget (tav_expand_button);
2992 mouse_mode_size_group->add_widget (visible_tracks_selector);
2994 mouse_mode_size_group->add_widget (snap_type_selector);
2995 mouse_mode_size_group->add_widget (snap_mode_selector);
2997 mouse_mode_size_group->add_widget (edit_point_selector);
2998 mouse_mode_size_group->add_widget (edit_mode_selector);
3000 mouse_mode_size_group->add_widget (*nudge_clock);
3001 mouse_mode_size_group->add_widget (nudge_forward_button);
3002 mouse_mode_size_group->add_widget (nudge_backward_button);
3004 mouse_mode_hbox->set_spacing (2);
3006 if (!ARDOUR::Profile->get_trx()) {
3007 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3010 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3011 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3013 if (!ARDOUR::Profile->get_mixbus()) {
3014 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3017 if (!ARDOUR::Profile->get_trx()) {
3018 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3019 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3020 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3021 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3024 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3026 mouse_mode_align->add (*mouse_mode_vbox);
3027 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3029 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3031 edit_mode_selector.set_name ("mouse mode button");
3033 if (!ARDOUR::Profile->get_trx()) {
3034 mode_box->pack_start (edit_mode_selector, false, false);
3037 mode_box->pack_start (*mouse_mode_box, false, false);
3041 _zoom_box.set_spacing (2);
3042 _zoom_box.set_border_width (2);
3046 zoom_preset_selector.set_name ("zoom button");
3047 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3048 zoom_preset_selector.set_size_request (42, -1);
3050 zoom_in_button.set_name ("zoom button");
3051 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3052 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3053 zoom_in_button.set_related_action (act);
3055 zoom_out_button.set_name ("zoom button");
3056 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3057 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3058 zoom_out_button.set_related_action (act);
3060 zoom_out_full_button.set_name ("zoom button");
3061 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3062 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3063 zoom_out_full_button.set_related_action (act);
3065 zoom_focus_selector.set_name ("zoom button");
3067 if (ARDOUR::Profile->get_mixbus()) {
3068 _zoom_box.pack_start (zoom_preset_selector, false, false);
3069 } else if (ARDOUR::Profile->get_trx()) {
3070 mode_box->pack_start (zoom_out_button, false, false);
3071 mode_box->pack_start (zoom_in_button, false, false);
3073 _zoom_box.pack_start (zoom_out_button, false, false);
3074 _zoom_box.pack_start (zoom_in_button, false, false);
3075 _zoom_box.pack_start (zoom_out_full_button, false, false);
3076 _zoom_box.pack_start (zoom_focus_selector, false, false);
3079 /* Track zoom buttons */
3080 visible_tracks_selector.set_name ("zoom button");
3081 if (Profile->get_mixbus()) {
3082 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3083 visible_tracks_selector.set_size_request (42, -1);
3085 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3088 tav_expand_button.set_name ("zoom button");
3089 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3090 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3091 tav_expand_button.set_related_action (act);
3093 tav_shrink_button.set_name ("zoom button");
3094 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3095 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3096 tav_shrink_button.set_related_action (act);
3098 if (ARDOUR::Profile->get_mixbus()) {
3099 _zoom_box.pack_start (visible_tracks_selector);
3100 } else if (ARDOUR::Profile->get_trx()) {
3101 _zoom_box.pack_start (tav_shrink_button);
3102 _zoom_box.pack_start (tav_expand_button);
3104 _zoom_box.pack_start (visible_tracks_selector);
3105 _zoom_box.pack_start (tav_shrink_button);
3106 _zoom_box.pack_start (tav_expand_button);
3109 snap_box.set_spacing (2);
3110 snap_box.set_border_width (2);
3112 snap_type_selector.set_name ("mouse mode button");
3114 snap_mode_selector.set_name ("mouse mode button");
3116 edit_point_selector.set_name ("mouse mode button");
3118 snap_box.pack_start (snap_mode_selector, false, false);
3119 snap_box.pack_start (snap_type_selector, false, false);
3120 snap_box.pack_start (edit_point_selector, false, false);
3124 HBox *nudge_box = manage (new HBox);
3125 nudge_box->set_spacing (2);
3126 nudge_box->set_border_width (2);
3128 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3129 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3131 nudge_box->pack_start (nudge_backward_button, false, false);
3132 nudge_box->pack_start (nudge_forward_button, false, false);
3133 nudge_box->pack_start (*nudge_clock, false, false);
3136 /* Pack everything in... */
3138 HBox* hbox = manage (new HBox);
3139 hbox->set_spacing(2);
3141 toolbar_hbox.set_spacing (2);
3142 toolbar_hbox.set_border_width (1);
3144 toolbar_hbox.pack_start (*mode_box, false, false);
3145 if (!ARDOUR::Profile->get_trx()) {
3146 toolbar_hbox.pack_start (_zoom_box, false, false);
3147 toolbar_hbox.pack_start (*hbox, false, false);
3150 if (!ARDOUR::Profile->get_trx()) {
3151 hbox->pack_start (snap_box, false, false);
3152 hbox->pack_start (*nudge_box, false, false);
3157 toolbar_base.set_name ("ToolBarBase");
3158 toolbar_base.add (toolbar_hbox);
3160 _toolbar_viewport.add (toolbar_base);
3161 /* stick to the required height but allow width to vary if there's not enough room */
3162 _toolbar_viewport.set_size_request (1, -1);
3164 toolbar_frame.set_shadow_type (SHADOW_OUT);
3165 toolbar_frame.set_name ("BaseFrame");
3166 toolbar_frame.add (_toolbar_viewport);
3170 Editor::build_edit_point_menu ()
3172 using namespace Menu_Helpers;
3174 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3175 if(!Profile->get_mixbus())
3176 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3177 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3179 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3183 Editor::build_edit_mode_menu ()
3185 using namespace Menu_Helpers;
3187 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3188 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3189 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3190 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3192 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3196 Editor::build_snap_mode_menu ()
3198 using namespace Menu_Helpers;
3200 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3201 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3202 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3204 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3208 Editor::build_snap_type_menu ()
3210 using namespace Menu_Helpers;
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3243 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3248 Editor::setup_tooltips ()
3250 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3251 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3252 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3253 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3254 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3255 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3256 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3257 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3258 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3259 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3260 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3261 set_tooltip (zoom_in_button, _("Zoom In"));
3262 set_tooltip (zoom_out_button, _("Zoom Out"));
3263 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3264 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3265 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3266 set_tooltip (tav_expand_button, _("Expand Tracks"));
3267 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3268 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3269 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3270 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3271 set_tooltip (edit_point_selector, _("Edit Point"));
3272 set_tooltip (edit_mode_selector, _("Edit Mode"));
3273 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3277 Editor::convert_drop_to_paths (
3278 vector<string>& paths,
3279 const RefPtr<Gdk::DragContext>& /*context*/,
3282 const SelectionData& data,
3286 if (_session == 0) {
3290 vector<string> uris = data.get_uris();
3294 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3295 are actually URI lists. So do it by hand.
3298 if (data.get_target() != "text/plain") {
3302 /* Parse the "uri-list" format that Nautilus provides,
3303 where each pathname is delimited by \r\n.
3305 THERE MAY BE NO NULL TERMINATING CHAR!!!
3308 string txt = data.get_text();
3312 p = (char *) malloc (txt.length() + 1);
3313 txt.copy (p, txt.length(), 0);
3314 p[txt.length()] = '\0';
3320 while (g_ascii_isspace (*p))
3324 while (*q && (*q != '\n') && (*q != '\r')) {
3331 while (q > p && g_ascii_isspace (*q))
3336 uris.push_back (string (p, q - p + 1));
3340 p = strchr (p, '\n');
3352 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3353 if ((*i).substr (0,7) == "file://") {
3354 paths.push_back (Glib::filename_from_uri (*i));
3362 Editor::new_tempo_section ()
3367 Editor::map_transport_state ()
3369 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3371 if (_session && _session->transport_stopped()) {
3372 have_pending_keyboard_selection = false;
3375 update_loop_range_view ();
3381 Editor::begin_selection_op_history ()
3383 selection_op_cmd_depth = 0;
3384 selection_op_history_it = 0;
3386 while(!selection_op_history.empty()) {
3387 delete selection_op_history.front();
3388 selection_op_history.pop_front();
3391 selection_undo_action->set_sensitive (false);
3392 selection_redo_action->set_sensitive (false);
3393 selection_op_history.push_front (&_selection_memento->get_state ());
3397 Editor::begin_reversible_selection_op (string name)
3400 //cerr << name << endl;
3401 /* begin/commit pairs can be nested */
3402 selection_op_cmd_depth++;
3407 Editor::commit_reversible_selection_op ()
3410 if (selection_op_cmd_depth == 1) {
3412 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3414 The user has undone some selection ops and then made a new one,
3415 making anything earlier in the list invalid.
3418 list<XMLNode *>::iterator it = selection_op_history.begin();
3419 list<XMLNode *>::iterator e_it = it;
3420 advance (e_it, selection_op_history_it);
3422 for ( ; it != e_it; ++it) {
3425 selection_op_history.erase (selection_op_history.begin(), e_it);
3428 selection_op_history.push_front (&_selection_memento->get_state ());
3429 selection_op_history_it = 0;
3431 selection_undo_action->set_sensitive (true);
3432 selection_redo_action->set_sensitive (false);
3435 if (selection_op_cmd_depth > 0) {
3436 selection_op_cmd_depth--;
3442 Editor::undo_selection_op ()
3445 selection_op_history_it++;
3447 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3448 if (n == selection_op_history_it) {
3449 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3450 selection_redo_action->set_sensitive (true);
3454 /* is there an earlier entry? */
3455 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3456 selection_undo_action->set_sensitive (false);
3462 Editor::redo_selection_op ()
3465 if (selection_op_history_it > 0) {
3466 selection_op_history_it--;
3469 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3470 if (n == selection_op_history_it) {
3471 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3472 selection_undo_action->set_sensitive (true);
3477 if (selection_op_history_it == 0) {
3478 selection_redo_action->set_sensitive (false);
3484 Editor::begin_reversible_command (string name)
3487 before.push_back (&_selection_memento->get_state ());
3488 _session->begin_reversible_command (name);
3493 Editor::begin_reversible_command (GQuark q)
3496 before.push_back (&_selection_memento->get_state ());
3497 _session->begin_reversible_command (q);
3502 Editor::abort_reversible_command ()
3505 while(!before.empty()) {
3506 delete before.front();
3509 _session->abort_reversible_command ();
3514 Editor::commit_reversible_command ()
3517 if (before.size() == 1) {
3518 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3519 redo_action->set_sensitive(false);
3520 undo_action->set_sensitive(true);
3521 begin_selection_op_history ();
3524 if (before.empty()) {
3525 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3530 _session->commit_reversible_command ();
3535 Editor::history_changed ()
3539 if (undo_action && _session) {
3540 if (_session->undo_depth() == 0) {
3541 label = S_("Command|Undo");
3543 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3545 undo_action->property_label() = label;
3548 if (redo_action && _session) {
3549 if (_session->redo_depth() == 0) {
3551 redo_action->set_sensitive (false);
3553 label = string_compose(_("Redo (%1)"), _session->next_redo());
3554 redo_action->set_sensitive (true);
3556 redo_action->property_label() = label;
3561 Editor::duplicate_range (bool with_dialog)
3565 RegionSelection rs = get_regions_from_selection_and_entered ();
3567 if ( selection->time.length() == 0 && rs.empty()) {
3573 ArdourDialog win (_("Duplicate"));
3574 Label label (_("Number of duplications:"));
3575 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3576 SpinButton spinner (adjustment, 0.0, 1);
3579 win.get_vbox()->set_spacing (12);
3580 win.get_vbox()->pack_start (hbox);
3581 hbox.set_border_width (6);
3582 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3584 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3585 place, visually. so do this by hand.
3588 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3589 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3590 spinner.grab_focus();
3596 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3597 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3598 win.set_default_response (RESPONSE_ACCEPT);
3600 spinner.grab_focus ();
3602 switch (win.run ()) {
3603 case RESPONSE_ACCEPT:
3609 times = adjustment.get_value();
3612 if ((current_mouse_mode() == Editing::MouseRange)) {
3613 if (selection->time.length()) {
3614 duplicate_selection (times);
3616 } else if (get_smart_mode()) {
3617 if (selection->time.length()) {
3618 duplicate_selection (times);
3620 duplicate_some_regions (rs, times);
3622 duplicate_some_regions (rs, times);
3627 Editor::set_edit_mode (EditMode m)
3629 Config->set_edit_mode (m);
3633 Editor::cycle_edit_mode ()
3635 switch (Config->get_edit_mode()) {
3637 Config->set_edit_mode (Ripple);
3641 Config->set_edit_mode (Lock);
3644 Config->set_edit_mode (Slide);
3650 Editor::edit_mode_selection_done ( EditMode m )
3652 Config->set_edit_mode ( m );
3656 Editor::snap_type_selection_done (SnapType snaptype)
3658 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3660 ract->set_active ();
3665 Editor::snap_mode_selection_done (SnapMode mode)
3667 RefPtr<RadioAction> ract = snap_mode_action (mode);
3670 ract->set_active (true);
3675 Editor::cycle_edit_point (bool with_marker)
3677 if(Profile->get_mixbus())
3678 with_marker = false;
3680 switch (_edit_point) {
3682 set_edit_point_preference (EditAtPlayhead);
3684 case EditAtPlayhead:
3686 set_edit_point_preference (EditAtSelectedMarker);
3688 set_edit_point_preference (EditAtMouse);
3691 case EditAtSelectedMarker:
3692 set_edit_point_preference (EditAtMouse);
3698 Editor::edit_point_selection_done (EditPoint ep)
3700 set_edit_point_preference ( ep );
3704 Editor::build_zoom_focus_menu ()
3706 using namespace Menu_Helpers;
3708 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3709 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3710 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3711 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3712 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3713 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3715 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3719 Editor::zoom_focus_selection_done ( ZoomFocus f )
3721 RefPtr<RadioAction> ract = zoom_focus_action (f);
3723 ract->set_active ();
3728 Editor::build_track_count_menu ()
3730 using namespace Menu_Helpers;
3732 if (!Profile->get_mixbus()) {
3733 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3740 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3744 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3745 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3747 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3748 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3749 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3750 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3751 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3752 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3753 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3754 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3755 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3756 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3758 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3759 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3760 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3761 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3762 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3763 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3764 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3765 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3766 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3767 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3768 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3773 Editor::set_zoom_preset (int64_t ms)
3776 temporal_zoom_session();
3780 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3781 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3785 Editor::set_visible_track_count (int32_t n)
3787 _visible_track_count = n;
3789 /* if the canvas hasn't really been allocated any size yet, just
3790 record the desired number of visible tracks and return. when canvas
3791 allocation happens, we will get called again and then we can do the
3795 if (_visible_canvas_height <= 1) {
3801 DisplaySuspender ds;
3803 if (_visible_track_count > 0) {
3804 h = trackviews_height() / _visible_track_count;
3805 std::ostringstream s;
3806 s << _visible_track_count;
3808 } else if (_visible_track_count == 0) {
3810 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3811 if ((*i)->marked_for_display()) {
3815 h = trackviews_height() / n;
3818 /* negative value means that the visible track count has
3819 been overridden by explicit track height changes.
3821 visible_tracks_selector.set_text (X_("*"));
3825 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3826 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3829 if (str != visible_tracks_selector.get_text()) {
3830 visible_tracks_selector.set_text (str);
3835 Editor::override_visible_track_count ()
3837 _visible_track_count = -1;
3838 visible_tracks_selector.set_text ( _("*") );
3842 Editor::edit_controls_button_release (GdkEventButton* ev)
3844 if (Keyboard::is_context_menu_event (ev)) {
3845 ARDOUR_UI::instance()->add_route ();
3846 } else if (ev->button == 1) {
3847 selection->clear_tracks ();
3854 Editor::mouse_select_button_release (GdkEventButton* ev)
3856 /* this handles just right-clicks */
3858 if (ev->button != 3) {
3866 Editor::set_zoom_focus (ZoomFocus f)
3868 string str = zoom_focus_strings[(int)f];
3870 if (str != zoom_focus_selector.get_text()) {
3871 zoom_focus_selector.set_text (str);
3874 if (zoom_focus != f) {
3881 Editor::cycle_zoom_focus ()
3883 switch (zoom_focus) {
3885 set_zoom_focus (ZoomFocusRight);
3887 case ZoomFocusRight:
3888 set_zoom_focus (ZoomFocusCenter);
3890 case ZoomFocusCenter:
3891 set_zoom_focus (ZoomFocusPlayhead);
3893 case ZoomFocusPlayhead:
3894 set_zoom_focus (ZoomFocusMouse);
3896 case ZoomFocusMouse:
3897 set_zoom_focus (ZoomFocusEdit);
3900 set_zoom_focus (ZoomFocusLeft);
3906 Editor::set_show_measures (bool yn)
3908 if (_show_measures != yn) {
3911 if ((_show_measures = yn) == true) {
3913 tempo_lines->show();
3916 std::vector<TempoMap::BBTPoint> grid;
3917 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3918 draw_measures (grid);
3926 Editor::toggle_follow_playhead ()
3928 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3930 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3931 set_follow_playhead (tact->get_active());
3935 /** @param yn true to follow playhead, otherwise false.
3936 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3939 Editor::set_follow_playhead (bool yn, bool catch_up)
3941 if (_follow_playhead != yn) {
3942 if ((_follow_playhead = yn) == true && catch_up) {
3944 reset_x_origin_to_follow_playhead ();
3951 Editor::toggle_stationary_playhead ()
3953 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3955 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3956 set_stationary_playhead (tact->get_active());
3961 Editor::set_stationary_playhead (bool yn)
3963 if (_stationary_playhead != yn) {
3964 if ((_stationary_playhead = yn) == true) {
3966 // FIXME need a 3.0 equivalent of this 2.X call
3967 // update_current_screen ();
3974 Editor::playlist_selector () const
3976 return *_playlist_selector;
3980 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3982 if (paste_count == 0) {
3983 /* don't bother calculating an offset that will be zero anyway */
3987 /* calculate basic unsnapped multi-paste offset */
3988 framecnt_t offset = paste_count * duration;
3990 /* snap offset so pos + offset is aligned to the grid */
3991 framepos_t offset_pos = pos + offset;
3992 snap_to(offset_pos, RoundUpMaybe);
3993 offset = offset_pos - pos;
3999 Editor::get_grid_beat_divisions(framepos_t position)
4001 switch (_snap_type) {
4002 case SnapToBeatDiv128: return 128;
4003 case SnapToBeatDiv64: return 64;
4004 case SnapToBeatDiv32: return 32;
4005 case SnapToBeatDiv28: return 28;
4006 case SnapToBeatDiv24: return 24;
4007 case SnapToBeatDiv20: return 20;
4008 case SnapToBeatDiv16: return 16;
4009 case SnapToBeatDiv14: return 14;
4010 case SnapToBeatDiv12: return 12;
4011 case SnapToBeatDiv10: return 10;
4012 case SnapToBeatDiv8: return 8;
4013 case SnapToBeatDiv7: return 7;
4014 case SnapToBeatDiv6: return 6;
4015 case SnapToBeatDiv5: return 5;
4016 case SnapToBeatDiv4: return 4;
4017 case SnapToBeatDiv3: return 3;
4018 case SnapToBeatDiv2: return 2;
4024 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4025 if the grid is non-musical, returns 0.
4026 if the grid is snapped to bars, returns -1.
4027 @param event_state the current keyboard modifier mask.
4030 Editor::get_grid_music_divisions (uint32_t event_state)
4032 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4036 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4040 switch (_snap_type) {
4041 case SnapToBeatDiv128: return 128;
4042 case SnapToBeatDiv64: return 64;
4043 case SnapToBeatDiv32: return 32;
4044 case SnapToBeatDiv28: return 28;
4045 case SnapToBeatDiv24: return 24;
4046 case SnapToBeatDiv20: return 20;
4047 case SnapToBeatDiv16: return 16;
4048 case SnapToBeatDiv14: return 14;
4049 case SnapToBeatDiv12: return 12;
4050 case SnapToBeatDiv10: return 10;
4051 case SnapToBeatDiv8: return 8;
4052 case SnapToBeatDiv7: return 7;
4053 case SnapToBeatDiv6: return 6;
4054 case SnapToBeatDiv5: return 5;
4055 case SnapToBeatDiv4: return 4;
4056 case SnapToBeatDiv3: return 3;
4057 case SnapToBeatDiv2: return 2;
4058 case SnapToBeat: return 1;
4059 case SnapToBar : return -1;
4066 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4070 const unsigned divisions = get_grid_beat_divisions(position);
4072 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4075 switch (_snap_type) {
4077 return Evoral::Beats(1.0);
4080 return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar());
4088 return Evoral::Beats();
4092 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4096 ret = nudge_clock->current_duration (pos);
4097 next = ret + 1; /* XXXX fix me */
4103 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4105 ArdourDialog dialog (_("Playlist Deletion"));
4106 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4107 "If it is kept, its audio files will not be cleaned.\n"
4108 "If it is deleted, audio files used by it alone will be cleaned."),
4111 dialog.set_position (WIN_POS_CENTER);
4112 dialog.get_vbox()->pack_start (label);
4116 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4117 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4118 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4119 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4120 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4122 // by default gtk uses the left most button
4123 keep->grab_focus ();
4125 switch (dialog.run ()) {
4127 /* keep this and all remaining ones */
4132 /* delete this and all others */
4136 case RESPONSE_ACCEPT:
4137 /* delete the playlist */
4141 case RESPONSE_REJECT:
4142 /* keep the playlist */
4154 Editor::audio_region_selection_covers (framepos_t where)
4156 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4157 if ((*a)->region()->covers (where)) {
4166 Editor::prepare_for_cleanup ()
4168 cut_buffer->clear_regions ();
4169 cut_buffer->clear_playlists ();
4171 selection->clear_regions ();
4172 selection->clear_playlists ();
4174 _regions->suspend_redisplay ();
4178 Editor::finish_cleanup ()
4180 _regions->resume_redisplay ();
4184 Editor::transport_loop_location()
4187 return _session->locations()->auto_loop_location();
4194 Editor::transport_punch_location()
4197 return _session->locations()->auto_punch_location();
4204 Editor::control_layout_scroll (GdkEventScroll* ev)
4206 /* Just forward to the normal canvas scroll method. The coordinate
4207 systems are different but since the canvas is always larger than the
4208 track headers, and aligned with the trackview area, this will work.
4210 In the not too distant future this layout is going away anyway and
4211 headers will be on the canvas.
4213 return canvas_scroll_event (ev, false);
4217 Editor::session_state_saved (string)
4220 _snapshots->redisplay ();
4224 Editor::maximise_editing_space ()
4230 Gtk::Window* toplevel = current_toplevel();
4233 toplevel->fullscreen ();
4239 Editor::restore_editing_space ()
4245 Gtk::Window* toplevel = current_toplevel();
4248 toplevel->unfullscreen();
4254 * Make new playlists for a given track and also any others that belong
4255 * to the same active route group with the `select' property.
4260 Editor::new_playlists (TimeAxisView* v)
4262 begin_reversible_command (_("new playlists"));
4263 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4264 _session->playlists->get (playlists);
4265 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4266 commit_reversible_command ();
4270 * Use a copy of the current playlist for a given track and also any others that belong
4271 * to the same active route group with the `select' property.
4276 Editor::copy_playlists (TimeAxisView* v)
4278 begin_reversible_command (_("copy playlists"));
4279 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4280 _session->playlists->get (playlists);
4281 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4282 commit_reversible_command ();
4285 /** Clear the current playlist for a given track and also any others that belong
4286 * to the same active route group with the `select' property.
4291 Editor::clear_playlists (TimeAxisView* v)
4293 begin_reversible_command (_("clear playlists"));
4294 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4295 _session->playlists->get (playlists);
4296 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4297 commit_reversible_command ();
4301 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4303 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4307 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4309 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4313 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4315 atv.clear_playlist ();
4319 Editor::get_y_origin () const
4321 return vertical_adjustment.get_value ();
4324 /** Queue up a change to the viewport x origin.
4325 * @param frame New x origin.
4328 Editor::reset_x_origin (framepos_t frame)
4330 pending_visual_change.add (VisualChange::TimeOrigin);
4331 pending_visual_change.time_origin = frame;
4332 ensure_visual_change_idle_handler ();
4336 Editor::reset_y_origin (double y)
4338 pending_visual_change.add (VisualChange::YOrigin);
4339 pending_visual_change.y_origin = y;
4340 ensure_visual_change_idle_handler ();
4344 Editor::reset_zoom (framecnt_t spp)
4346 if (spp == samples_per_pixel) {
4350 pending_visual_change.add (VisualChange::ZoomLevel);
4351 pending_visual_change.samples_per_pixel = spp;
4352 ensure_visual_change_idle_handler ();
4356 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4358 reset_x_origin (frame);
4361 if (!no_save_visual) {
4362 undo_visual_stack.push_back (current_visual_state(false));
4366 Editor::VisualState::VisualState (bool with_tracks)
4367 : gui_state (with_tracks ? new GUIObjectState : 0)
4371 Editor::VisualState::~VisualState ()
4376 Editor::VisualState*
4377 Editor::current_visual_state (bool with_tracks)
4379 VisualState* vs = new VisualState (with_tracks);
4380 vs->y_position = vertical_adjustment.get_value();
4381 vs->samples_per_pixel = samples_per_pixel;
4382 vs->leftmost_frame = leftmost_frame;
4383 vs->zoom_focus = zoom_focus;
4386 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4393 Editor::undo_visual_state ()
4395 if (undo_visual_stack.empty()) {
4399 VisualState* vs = undo_visual_stack.back();
4400 undo_visual_stack.pop_back();
4403 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4406 use_visual_state (*vs);
4411 Editor::redo_visual_state ()
4413 if (redo_visual_stack.empty()) {
4417 VisualState* vs = redo_visual_stack.back();
4418 redo_visual_stack.pop_back();
4420 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4421 // why do we check here?
4422 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4425 use_visual_state (*vs);
4430 Editor::swap_visual_state ()
4432 if (undo_visual_stack.empty()) {
4433 redo_visual_state ();
4435 undo_visual_state ();
4440 Editor::use_visual_state (VisualState& vs)
4442 PBD::Unwinder<bool> nsv (no_save_visual, true);
4443 DisplaySuspender ds;
4445 vertical_adjustment.set_value (vs.y_position);
4447 set_zoom_focus (vs.zoom_focus);
4448 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4451 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4453 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4454 (*i)->clear_property_cache();
4455 (*i)->reset_visual_state ();
4459 _routes->update_visibility ();
4462 /** This is the core function that controls the zoom level of the canvas. It is called
4463 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4464 * @param spp new number of samples per pixel
4467 Editor::set_samples_per_pixel (framecnt_t spp)
4473 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4474 const framecnt_t lots_of_pixels = 4000;
4476 /* if the zoom level is greater than what you'd get trying to display 3
4477 * days of audio on a really big screen, then it's too big.
4480 if (spp * lots_of_pixels > three_days) {
4484 samples_per_pixel = spp;
4487 tempo_lines->tempo_map_changed();
4490 bool const showing_time_selection = selection->time.length() > 0;
4492 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4493 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4494 (*i)->reshow_selection (selection->time);
4498 ZoomChanged (); /* EMIT_SIGNAL */
4500 ArdourCanvas::GtkCanvasViewport* c;
4502 c = get_track_canvas();
4504 c->canvas()->zoomed ();
4507 if (playhead_cursor) {
4508 playhead_cursor->set_position (playhead_cursor->current_frame ());
4511 refresh_location_display();
4512 _summary->set_overlays_dirty ();
4514 update_marker_labels ();
4520 Editor::queue_visual_videotimeline_update ()
4523 * pending_visual_change.add (VisualChange::VideoTimeline);
4524 * or maybe even more specific: which videotimeline-image
4525 * currently it calls update_video_timeline() to update
4526 * _all outdated_ images on the video-timeline.
4527 * see 'exposeimg()' in video_image_frame.cc
4529 ensure_visual_change_idle_handler ();
4533 Editor::ensure_visual_change_idle_handler ()
4535 if (pending_visual_change.idle_handler_id < 0) {
4536 // see comment in add_to_idle_resize above.
4537 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4538 pending_visual_change.being_handled = false;
4543 Editor::_idle_visual_changer (void* arg)
4545 return static_cast<Editor*>(arg)->idle_visual_changer ();
4549 Editor::idle_visual_changer ()
4551 /* set_horizontal_position() below (and maybe other calls) call
4552 gtk_main_iteration(), so it's possible that a signal will be handled
4553 half-way through this method. If this signal wants an
4554 idle_visual_changer we must schedule another one after this one, so
4555 mark the idle_handler_id as -1 here to allow that. Also make a note
4556 that we are doing the visual change, so that changes in response to
4557 super-rapid-screen-update can be dropped if we are still processing
4561 pending_visual_change.idle_handler_id = -1;
4562 pending_visual_change.being_handled = true;
4564 VisualChange vc = pending_visual_change;
4566 pending_visual_change.pending = (VisualChange::Type) 0;
4568 visual_changer (vc);
4570 pending_visual_change.being_handled = false;
4572 return 0; /* this is always a one-shot call */
4576 Editor::visual_changer (const VisualChange& vc)
4578 double const last_time_origin = horizontal_position ();
4580 if (vc.pending & VisualChange::ZoomLevel) {
4581 set_samples_per_pixel (vc.samples_per_pixel);
4583 compute_fixed_ruler_scale ();
4585 std::vector<TempoMap::BBTPoint> grid;
4586 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4587 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4588 update_tempo_based_rulers (grid);
4590 update_video_timeline();
4593 if (vc.pending & VisualChange::TimeOrigin) {
4594 set_horizontal_position (vc.time_origin / samples_per_pixel);
4597 if (vc.pending & VisualChange::YOrigin) {
4598 vertical_adjustment.set_value (vc.y_origin);
4601 if (last_time_origin == horizontal_position ()) {
4602 /* changed signal not emitted */
4603 update_fixed_rulers ();
4604 redisplay_tempo (true);
4607 if (!(vc.pending & VisualChange::ZoomLevel)) {
4608 update_video_timeline();
4611 _summary->set_overlays_dirty ();
4614 struct EditorOrderTimeAxisSorter {
4615 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4616 return a->order () < b->order ();
4621 Editor::sort_track_selection (TrackViewList& sel)
4623 EditorOrderTimeAxisSorter cmp;
4628 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4631 framepos_t where = 0;
4632 EditPoint ep = _edit_point;
4634 if (Profile->get_mixbus())
4635 if (ep == EditAtSelectedMarker)
4636 ep = EditAtPlayhead;
4638 if (from_outside_canvas && (ep == EditAtMouse)) {
4639 ep = EditAtPlayhead;
4640 } else if (from_context_menu && (ep == EditAtMouse)) {
4641 return canvas_event_sample (&context_click_event, 0, 0);
4644 if (entered_marker) {
4645 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4646 return entered_marker->position();
4649 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4650 ep = EditAtSelectedMarker;
4653 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4654 ep = EditAtPlayhead;
4658 case EditAtPlayhead:
4659 if (_dragging_playhead) {
4660 where = *_control_scroll_target;
4662 where = _session->audible_frame();
4664 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4667 case EditAtSelectedMarker:
4668 if (!selection->markers.empty()) {
4670 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4673 where = loc->start();
4677 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4685 if (!mouse_frame (where, ignored)) {
4686 /* XXX not right but what can we do ? */
4690 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4698 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4700 if (!_session) return;
4702 begin_reversible_command (cmd);
4706 if ((tll = transport_loop_location()) == 0) {
4707 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4708 XMLNode &before = _session->locations()->get_state();
4709 _session->locations()->add (loc, true);
4710 _session->set_auto_loop_location (loc);
4711 XMLNode &after = _session->locations()->get_state();
4712 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4714 XMLNode &before = tll->get_state();
4715 tll->set_hidden (false, this);
4716 tll->set (start, end);
4717 XMLNode &after = tll->get_state();
4718 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4721 commit_reversible_command ();
4725 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4727 if (!_session) return;
4729 begin_reversible_command (cmd);
4733 if ((tpl = transport_punch_location()) == 0) {
4734 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4735 XMLNode &before = _session->locations()->get_state();
4736 _session->locations()->add (loc, true);
4737 _session->set_auto_punch_location (loc);
4738 XMLNode &after = _session->locations()->get_state();
4739 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4741 XMLNode &before = tpl->get_state();
4742 tpl->set_hidden (false, this);
4743 tpl->set (start, end);
4744 XMLNode &after = tpl->get_state();
4745 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4748 commit_reversible_command ();
4751 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4752 * @param rs List to which found regions are added.
4753 * @param where Time to look at.
4754 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4757 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4759 const TrackViewList* tracks;
4762 tracks = &track_views;
4767 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4769 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4772 boost::shared_ptr<Track> tr;
4773 boost::shared_ptr<Playlist> pl;
4775 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4777 boost::shared_ptr<RegionList> regions = pl->regions_at (
4778 (framepos_t) floor ( (double) where * tr->speed()));
4780 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4781 RegionView* rv = rtv->view()->find_view (*i);
4792 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4794 const TrackViewList* tracks;
4797 tracks = &track_views;
4802 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4803 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4805 boost::shared_ptr<Track> tr;
4806 boost::shared_ptr<Playlist> pl;
4808 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4810 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4811 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4813 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4815 RegionView* rv = rtv->view()->find_view (*i);
4826 /** Get regions using the following method:
4828 * Make a region list using:
4829 * (a) any selected regions
4830 * (b) the intersection of any selected tracks and the edit point(*)
4831 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4833 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4835 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4839 Editor::get_regions_from_selection_and_edit_point ()
4841 RegionSelection regions;
4843 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4844 regions.add (entered_regionview);
4846 regions = selection->regions;
4849 if ( regions.empty() ) {
4850 TrackViewList tracks = selection->tracks;
4852 if (!tracks.empty()) {
4853 /* no region selected or entered, but some selected tracks:
4854 * act on all regions on the selected tracks at the edit point
4856 framepos_t const where = get_preferred_edit_position ();
4857 get_regions_at(regions, where, tracks);
4864 /** Get regions using the following method:
4866 * Make a region list using:
4867 * (a) any selected regions
4868 * (b) the intersection of any selected tracks and the edit point(*)
4869 * (c) if neither exists, then whatever region is under the mouse
4871 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4873 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4876 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4878 RegionSelection regions;
4880 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4881 regions.add (entered_regionview);
4883 regions = selection->regions;
4886 if ( regions.empty() ) {
4887 TrackViewList tracks = selection->tracks;
4889 if (!tracks.empty()) {
4890 /* no region selected or entered, but some selected tracks:
4891 * act on all regions on the selected tracks at the edit point
4893 get_regions_at(regions, pos, tracks);
4900 /** Start with regions that are selected, or the entered regionview if none are selected.
4901 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4902 * of the regions that we started with.
4906 Editor::get_regions_from_selection_and_entered () const
4908 RegionSelection regions = selection->regions;
4910 if (regions.empty() && entered_regionview) {
4911 regions.add (entered_regionview);
4918 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4920 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4921 RouteTimeAxisView* rtav;
4923 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4924 boost::shared_ptr<Playlist> pl;
4925 std::vector<boost::shared_ptr<Region> > results;
4926 boost::shared_ptr<Track> tr;
4928 if ((tr = rtav->track()) == 0) {
4933 if ((pl = (tr->playlist())) != 0) {
4934 boost::shared_ptr<Region> r = pl->region_by_id (id);
4936 RegionView* rv = rtav->view()->find_view (r);
4938 regions.push_back (rv);
4947 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4950 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4951 MidiTimeAxisView* mtav;
4953 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4955 mtav->get_per_region_note_selection (selection);
4962 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4964 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4966 RouteTimeAxisView* tatv;
4968 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4970 boost::shared_ptr<Playlist> pl;
4971 vector<boost::shared_ptr<Region> > results;
4973 boost::shared_ptr<Track> tr;
4975 if ((tr = tatv->track()) == 0) {
4980 if ((pl = (tr->playlist())) != 0) {
4981 if (src_comparison) {
4982 pl->get_source_equivalent_regions (region, results);
4984 pl->get_region_list_equivalent_regions (region, results);
4988 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4989 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4990 regions.push_back (marv);
4999 Editor::show_rhythm_ferret ()
5001 if (rhythm_ferret == 0) {
5002 rhythm_ferret = new RhythmFerret(*this);
5005 rhythm_ferret->set_session (_session);
5006 rhythm_ferret->show ();
5007 rhythm_ferret->present ();
5011 Editor::first_idle ()
5013 MessageDialog* dialog = 0;
5015 if (track_views.size() > 1) {
5016 Timers::TimerSuspender t;
5017 dialog = new MessageDialog (
5018 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5022 ARDOUR_UI::instance()->flush_pending ();
5025 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5029 // first idle adds route children (automation tracks), so we need to redisplay here
5030 _routes->redisplay ();
5034 if (_session->undo_depth() == 0) {
5035 undo_action->set_sensitive(false);
5037 redo_action->set_sensitive(false);
5038 begin_selection_op_history ();
5044 Editor::_idle_resize (gpointer arg)
5046 return ((Editor*)arg)->idle_resize ();
5050 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5052 if (resize_idle_id < 0) {
5053 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5054 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5055 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5057 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5058 _pending_resize_amount = 0;
5061 /* make a note of the smallest resulting height, so that we can clamp the
5062 lower limit at TimeAxisView::hSmall */
5064 int32_t min_resulting = INT32_MAX;
5066 _pending_resize_amount += h;
5067 _pending_resize_view = view;
5069 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5071 if (selection->tracks.contains (_pending_resize_view)) {
5072 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5073 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5077 if (min_resulting < 0) {
5082 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5083 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5087 /** Handle pending resizing of tracks */
5089 Editor::idle_resize ()
5091 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5093 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5094 selection->tracks.contains (_pending_resize_view)) {
5096 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5097 if (*i != _pending_resize_view) {
5098 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5103 _pending_resize_amount = 0;
5104 _group_tabs->set_dirty ();
5105 resize_idle_id = -1;
5113 ENSURE_GUI_THREAD (*this, &Editor::located);
5116 playhead_cursor->set_position (_session->audible_frame ());
5117 if (_follow_playhead && !_pending_initial_locate) {
5118 reset_x_origin_to_follow_playhead ();
5122 _pending_locate_request = false;
5123 _pending_initial_locate = false;
5127 Editor::region_view_added (RegionView * rv)
5129 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5130 if (rv->region ()->id () == (*pr)) {
5131 selection->add (rv);
5132 selection->regions.pending.erase (pr);
5137 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5139 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5140 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5141 if (rv->region()->id () == (*rnote).first) {
5142 mrv->select_notes ((*rnote).second);
5143 selection->pending_midi_note_selection.erase(rnote);
5149 _summary->set_background_dirty ();
5153 Editor::region_view_removed ()
5155 _summary->set_background_dirty ();
5159 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5161 TrackViewList::const_iterator j = track_views.begin ();
5162 while (j != track_views.end()) {
5163 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5164 if (rtv && rtv->route() == r) {
5175 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5179 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5180 TimeAxisView* tv = axis_view_from_route (*i);
5190 Editor::suspend_route_redisplay ()
5193 _routes->suspend_redisplay();
5198 Editor::resume_route_redisplay ()
5201 _routes->redisplay(); // queue redisplay
5202 _routes->resume_redisplay();
5207 Editor::add_vcas (VCAList& vlist)
5211 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5212 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5215 add_stripables (sl);
5219 Editor::add_routes (RouteList& rlist)
5223 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5227 add_stripables (sl);
5231 Editor::add_stripables (StripableList& sl)
5233 list<TimeAxisView*> new_views;
5234 boost::shared_ptr<VCA> v;
5235 boost::shared_ptr<Route> r;
5236 TrackViewList new_selection;
5237 bool from_scratch = (track_views.size() == 0);
5239 sl.sort (StripablePresentationInfoSorter());
5241 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5243 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5245 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5247 new_views.push_back (vtv);
5249 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5251 if (r->is_auditioner() || r->is_monitor()) {
5255 RouteTimeAxisView* rtv;
5256 DataType dt = r->input()->default_type();
5258 if (dt == ARDOUR::DataType::AUDIO) {
5259 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5261 } else if (dt == ARDOUR::DataType::MIDI) {
5262 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5265 throw unknown_type();
5268 new_views.push_back (rtv);
5269 track_views.push_back (rtv);
5270 new_selection.push_back (rtv);
5272 rtv->effective_gain_display ();
5274 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5275 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5279 if (new_views.size() > 0) {
5280 _routes->time_axis_views_added (new_views);
5281 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5284 /* note: !new_selection.empty() means that we got some routes rather
5288 if (!from_scratch && !new_selection.empty()) {
5289 selection->tracks.clear();
5290 selection->add (new_selection);
5291 begin_selection_op_history();
5294 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5295 show_editor_mixer (true);
5298 editor_list_button.set_sensitive (true);
5302 Editor::timeaxisview_deleted (TimeAxisView *tv)
5304 if (tv == entered_track) {
5308 if (_session && _session->deletion_in_progress()) {
5309 /* the situation is under control */
5313 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5315 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5317 _routes->route_removed (tv);
5319 TimeAxisView::Children c = tv->get_child_list ();
5320 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5321 if (entered_track == i->get()) {
5326 /* remove it from the list of track views */
5328 TrackViewList::iterator i;
5330 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5331 i = track_views.erase (i);
5334 /* update whatever the current mixer strip is displaying, if revelant */
5336 boost::shared_ptr<Route> route;
5339 route = rtav->route ();
5342 if (current_mixer_strip && current_mixer_strip->route() == route) {
5344 TimeAxisView* next_tv;
5346 if (track_views.empty()) {
5348 } else if (i == track_views.end()) {
5349 next_tv = track_views.front();
5356 set_selected_mixer_strip (*next_tv);
5358 /* make the editor mixer strip go away setting the
5359 * button to inactive (which also unticks the menu option)
5362 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5368 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5370 if (apply_to_selection) {
5371 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5373 TrackSelection::iterator j = i;
5376 hide_track_in_display (*i, false);
5381 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5383 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5384 // this will hide the mixer strip
5385 set_selected_mixer_strip (*tv);
5388 _routes->hide_track_in_display (*tv);
5393 Editor::sync_track_view_list_and_routes ()
5395 track_views = TrackViewList (_routes->views ());
5397 _summary->set_background_dirty();
5398 _group_tabs->set_dirty ();
5400 return false; // do not call again (until needed)
5404 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5406 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5411 /** Find a RouteTimeAxisView by the ID of its route */
5413 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5415 RouteTimeAxisView* v;
5417 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5418 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5419 if(v->route()->id() == id) {
5429 Editor::fit_route_group (RouteGroup *g)
5431 TrackViewList ts = axis_views_from_routes (g->route_list ());
5436 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5438 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5441 _session->cancel_audition ();
5445 if (_session->is_auditioning()) {
5446 _session->cancel_audition ();
5447 if (r == last_audition_region) {
5452 _session->audition_region (r);
5453 last_audition_region = r;
5458 Editor::hide_a_region (boost::shared_ptr<Region> r)
5460 r->set_hidden (true);
5464 Editor::show_a_region (boost::shared_ptr<Region> r)
5466 r->set_hidden (false);
5470 Editor::audition_region_from_region_list ()
5472 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5476 Editor::hide_region_from_region_list ()
5478 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5482 Editor::show_region_in_region_list ()
5484 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5488 Editor::step_edit_status_change (bool yn)
5491 start_step_editing ();
5493 stop_step_editing ();
5498 Editor::start_step_editing ()
5500 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5504 Editor::stop_step_editing ()
5506 step_edit_connection.disconnect ();
5510 Editor::check_step_edit ()
5512 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5513 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5515 mtv->check_step_edit ();
5519 return true; // do it again, till we stop
5523 Editor::scroll_press (Direction dir)
5525 ++_scroll_callbacks;
5527 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5528 /* delay the first auto-repeat */
5534 scroll_backward (1);
5542 scroll_up_one_track ();
5546 scroll_down_one_track ();
5550 /* do hacky auto-repeat */
5551 if (!_scroll_connection.connected ()) {
5553 _scroll_connection = Glib::signal_timeout().connect (
5554 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5557 _scroll_callbacks = 0;
5564 Editor::scroll_release ()
5566 _scroll_connection.disconnect ();
5569 /** Queue a change for the Editor viewport x origin to follow the playhead */
5571 Editor::reset_x_origin_to_follow_playhead ()
5573 framepos_t const frame = playhead_cursor->current_frame ();
5575 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5577 if (_session->transport_speed() < 0) {
5579 if (frame > (current_page_samples() / 2)) {
5580 center_screen (frame-(current_page_samples()/2));
5582 center_screen (current_page_samples()/2);
5589 if (frame < leftmost_frame) {
5591 if (_session->transport_rolling()) {
5592 /* rolling; end up with the playhead at the right of the page */
5593 l = frame - current_page_samples ();
5595 /* not rolling: end up with the playhead 1/4 of the way along the page */
5596 l = frame - current_page_samples() / 4;
5600 if (_session->transport_rolling()) {
5601 /* rolling: end up with the playhead on the left of the page */
5604 /* not rolling: end up with the playhead 3/4 of the way along the page */
5605 l = frame - 3 * current_page_samples() / 4;
5613 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5619 Editor::super_rapid_screen_update ()
5621 if (!_session || !_session->engine().running()) {
5625 /* METERING / MIXER STRIPS */
5627 /* update track meters, if required */
5628 if (contents().is_mapped() && meters_running) {
5629 RouteTimeAxisView* rtv;
5630 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5631 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5632 rtv->fast_update ();
5637 /* and any current mixer strip */
5638 if (current_mixer_strip) {
5639 current_mixer_strip->fast_update ();
5642 /* PLAYHEAD AND VIEWPORT */
5644 framepos_t const frame = _session->audible_frame();
5646 /* There are a few reasons why we might not update the playhead / viewport stuff:
5648 * 1. we don't update things when there's a pending locate request, otherwise
5649 * when the editor requests a locate there is a chance that this method
5650 * will move the playhead before the locate request is processed, causing
5652 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5653 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5656 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5658 last_update_frame = frame;
5660 if (!_dragging_playhead) {
5661 playhead_cursor->set_position (frame);
5664 if (!_stationary_playhead) {
5666 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5667 /* We only do this if we aren't already
5668 handling a visual change (ie if
5669 pending_visual_change.being_handled is
5670 false) so that these requests don't stack
5671 up there are too many of them to handle in
5674 reset_x_origin_to_follow_playhead ();
5679 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5680 framepos_t const frame = playhead_cursor->current_frame ();
5681 double target = ((double)frame - (double)current_page_samples()/2.0);
5682 if (target <= 0.0) {
5685 // compare to EditorCursor::set_position()
5686 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5687 double const new_pos = sample_to_pixel_unrounded (target);
5688 if (rint (new_pos) != rint (old_pos)) {
5689 reset_x_origin (pixel_to_sample (floor (new_pos)));
5700 Editor::session_going_away ()
5702 _have_idled = false;
5704 _session_connections.drop_connections ();
5706 super_rapid_screen_update_connection.disconnect ();
5708 selection->clear ();
5709 cut_buffer->clear ();
5711 clicked_regionview = 0;
5712 clicked_axisview = 0;
5713 clicked_routeview = 0;
5714 entered_regionview = 0;
5716 last_update_frame = 0;
5719 playhead_cursor->hide ();
5721 /* rip everything out of the list displays */
5725 _route_groups->clear ();
5727 /* do this first so that deleting a track doesn't reset cms to null
5728 and thus cause a leak.
5731 if (current_mixer_strip) {
5732 if (current_mixer_strip->get_parent() != 0) {
5733 global_hpacker.remove (*current_mixer_strip);
5735 delete current_mixer_strip;
5736 current_mixer_strip = 0;
5739 /* delete all trackviews */
5741 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5744 track_views.clear ();
5746 nudge_clock->set_session (0);
5748 editor_list_button.set_active(false);
5749 editor_list_button.set_sensitive(false);
5751 /* clear tempo/meter rulers */
5752 remove_metric_marks ();
5754 clear_marker_display ();
5756 stop_step_editing ();
5760 /* get rid of any existing editor mixer strip */
5762 WindowTitle title(Glib::get_application_name());
5763 title += _("Editor");
5765 own_window()->set_title (title.get_string());
5768 SessionHandlePtr::session_going_away ();
5772 Editor::trigger_script (int i)
5774 LuaInstance::instance()-> call_action (i);
5778 Editor::set_script_action_name (int i, const std::string& n)
5780 string const a = string_compose (X_("script-action-%1"), i + 1);
5781 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5784 act->set_label (string_compose (_("Unset #%1"), i + 1));
5785 act->set_tooltip (_("no action bound"));
5786 act->set_sensitive (false);
5789 act->set_tooltip (n);
5790 act->set_sensitive (true);
5792 KeyEditor::UpdateBindings ();
5796 Editor::show_editor_list (bool yn)
5799 _the_notebook.show ();
5801 _the_notebook.hide ();
5806 Editor::change_region_layering_order (bool from_context_menu)
5808 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5810 if (!clicked_routeview) {
5811 if (layering_order_editor) {
5812 layering_order_editor->hide ();
5817 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5823 boost::shared_ptr<Playlist> pl = track->playlist();
5829 if (layering_order_editor == 0) {
5830 layering_order_editor = new RegionLayeringOrderEditor (*this);
5833 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5834 layering_order_editor->maybe_present ();
5838 Editor::update_region_layering_order_editor ()
5840 if (layering_order_editor && layering_order_editor->is_visible ()) {
5841 change_region_layering_order (true);
5846 Editor::setup_fade_images ()
5848 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5849 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5850 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5851 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5852 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5854 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5855 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5856 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5857 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5858 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5860 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5861 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5862 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5863 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5864 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5866 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5867 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5868 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5869 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5870 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5874 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5876 Editor::action_menu_item (std::string const & name)
5878 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5881 return *manage (a->create_menu_item ());
5885 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5887 EventBox* b = manage (new EventBox);
5888 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5889 Label* l = manage (new Label (name));
5893 _the_notebook.append_page (widget, *b);
5897 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5899 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5900 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5903 if (ev->type == GDK_2BUTTON_PRESS) {
5905 /* double-click on a notebook tab shrinks or expands the notebook */
5907 if (_notebook_shrunk) {
5908 if (pre_notebook_shrink_pane_width) {
5909 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5911 _notebook_shrunk = false;
5913 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5915 /* this expands the LHS of the edit pane to cover the notebook
5916 PAGE but leaves the tabs visible.
5918 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5919 _notebook_shrunk = true;
5927 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5929 using namespace Menu_Helpers;
5931 MenuList& items = _control_point_context_menu.items ();
5934 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5935 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5936 if (!can_remove_control_point (item)) {
5937 items.back().set_sensitive (false);
5940 _control_point_context_menu.popup (event->button.button, event->button.time);
5944 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5946 using namespace Menu_Helpers;
5948 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5953 /* We need to get the selection here and pass it to the operations, since
5954 popping up the menu will cause a region leave event which clears
5955 entered_regionview. */
5957 MidiRegionView& mrv = note->region_view();
5958 const RegionSelection rs = get_regions_from_selection_and_entered ();
5959 const uint32_t sel_size = mrv.selection_size ();
5961 MenuList& items = _note_context_menu.items();
5965 items.push_back(MenuElem(_("Delete"),
5966 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5969 items.push_back(MenuElem(_("Edit..."),
5970 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5971 if (sel_size != 1) {
5972 items.back().set_sensitive (false);
5975 items.push_back(MenuElem(_("Transpose..."),
5976 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5979 items.push_back(MenuElem(_("Legatize"),
5980 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5982 items.back().set_sensitive (false);
5985 items.push_back(MenuElem(_("Quantize..."),
5986 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5988 items.push_back(MenuElem(_("Remove Overlap"),
5989 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5991 items.back().set_sensitive (false);
5994 items.push_back(MenuElem(_("Transform..."),
5995 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5997 _note_context_menu.popup (event->button.button, event->button.time);
6001 Editor::zoom_vertical_modifier_released()
6003 _stepping_axis_view = 0;
6007 Editor::ui_parameter_changed (string parameter)
6009 if (parameter == "icon-set") {
6010 while (!_cursor_stack.empty()) {
6011 _cursor_stack.pop_back();
6013 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6014 _cursor_stack.push_back(_cursors->grabber);
6015 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6016 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6018 } else if (parameter == "draggable-playhead") {
6019 if (_verbose_cursor) {
6020 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6026 Editor::use_own_window (bool and_fill_it)
6028 bool new_window = !own_window();
6030 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6032 if (win && new_window) {
6033 win->set_name ("EditorWindow");
6035 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6037 // win->signal_realize().connect (*this, &Editor::on_realize);
6038 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6039 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6040 win->set_data ("ardour-bindings", bindings);
6045 DisplaySuspender ds;
6046 contents().show_all ();
6048 /* XXX: this is a bit unfortunate; it would probably
6049 be nicer if we could just call show () above rather
6050 than needing the show_all ()
6053 /* re-hide stuff if necessary */
6054 editor_list_button_toggled ();
6055 parameter_changed ("show-summary");
6056 parameter_changed ("show-group-tabs");
6057 parameter_changed ("show-zoom-tools");
6059 /* now reset all audio_time_axis heights, because widgets might need
6065 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6066 tv = (static_cast<TimeAxisView*>(*i));
6067 tv->reset_height ();
6070 if (current_mixer_strip) {
6071 current_mixer_strip->hide_things ();
6072 current_mixer_strip->parameter_changed ("mixer-element-visibility");