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 "ardour_spacer.h"
91 #include "audio_clock.h"
92 #include "audio_region_view.h"
93 #include "audio_streamview.h"
94 #include "audio_time_axis.h"
95 #include "automation_time_axis.h"
96 #include "bundle_manager.h"
97 #include "crossfade_edit.h"
101 #include "editor_cursors.h"
102 #include "editor_drag.h"
103 #include "editor_group_tabs.h"
104 #include "editor_locations.h"
105 #include "editor_regions.h"
106 #include "editor_route_groups.h"
107 #include "editor_routes.h"
108 #include "editor_snapshots.h"
109 #include "editor_summary.h"
110 #include "export_report.h"
111 #include "global_port_matrix.h"
112 #include "gui_object.h"
113 #include "gui_thread.h"
114 #include "keyboard.h"
115 #include "keyeditor.h"
116 #include "luainstance.h"
118 #include "midi_region_view.h"
119 #include "midi_time_axis.h"
120 #include "mixer_strip.h"
121 #include "mixer_ui.h"
122 #include "mouse_cursors.h"
123 #include "note_base.h"
124 #include "playlist_selector.h"
125 #include "public_editor.h"
126 #include "quantize_dialog.h"
127 #include "region_layering_order_editor.h"
128 #include "rgb_macros.h"
129 #include "rhythm_ferret.h"
130 #include "route_sorter.h"
131 #include "selection.h"
132 #include "simple_progress_dialog.h"
134 #include "tempo_lines.h"
135 #include "time_axis_view.h"
136 #include "time_info_box.h"
138 #include "tooltips.h"
139 #include "ui_config.h"
141 #include "vca_time_axis.h"
142 #include "verbose_cursor.h"
144 #include "pbd/i18n.h"
147 using namespace ARDOUR;
148 using namespace ARDOUR_UI_UTILS;
151 using namespace Glib;
152 using namespace Gtkmm2ext;
153 using namespace Editing;
155 using PBD::internationalize;
157 using Gtkmm2ext::Keyboard;
159 double Editor::timebar_height = 15.0;
161 static const gchar *_snap_type_strings[] = {
195 static const gchar *_snap_mode_strings[] = {
202 static const gchar *_edit_point_strings[] = {
209 static const gchar *_edit_mode_strings[] = {
217 static const gchar *_zoom_focus_strings[] = {
227 #ifdef USE_RUBBERBAND
228 static const gchar *_rb_opt_strings[] = {
231 N_("Balanced multitimbral mixture"),
232 N_("Unpitched percussion with stable notes"),
233 N_("Crisp monophonic instrumental"),
234 N_("Unpitched solo percussion"),
235 N_("Resample without preserving pitch"),
240 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
243 : PublicEditor (global_hpacker)
244 , editor_mixer_strip_width (Wide)
245 , constructed (false)
246 , _playlist_selector (0)
248 , no_save_visual (false)
250 , samples_per_pixel (2048)
251 , zoom_focus (ZoomFocusPlayhead)
252 , mouse_mode (MouseObject)
253 , pre_internal_snap_type (SnapToBeat)
254 , pre_internal_snap_mode (SnapOff)
255 , internal_snap_type (SnapToBeat)
256 , internal_snap_mode (SnapOff)
257 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
258 , _notebook_shrunk (false)
259 , location_marker_color (0)
260 , location_range_color (0)
261 , location_loop_color (0)
262 , location_punch_color (0)
263 , location_cd_marker_color (0)
265 , _show_marker_lines (false)
266 , clicked_axisview (0)
267 , clicked_routeview (0)
268 , clicked_regionview (0)
269 , clicked_selection (0)
270 , clicked_control_point (0)
271 , button_release_can_deselect (true)
272 , _mouse_changed_selection (false)
273 , region_edit_menu_split_item (0)
274 , region_edit_menu_split_multichannel_item (0)
275 , track_region_edit_playlist_menu (0)
276 , track_edit_playlist_submenu (0)
277 , track_selection_edit_playlist_submenu (0)
278 , _popup_region_menu_item (0)
280 , _track_canvas_viewport (0)
281 , within_track_canvas (false)
282 , _verbose_cursor (0)
286 , range_marker_group (0)
287 , transport_marker_group (0)
288 , cd_marker_group (0)
289 , _time_markers_group (0)
290 , hv_scroll_group (0)
292 , cursor_scroll_group (0)
293 , no_scroll_group (0)
294 , _trackview_group (0)
295 , _drag_motion_group (0)
296 , _canvas_drop_zone (0)
297 , no_ruler_shown_update (false)
298 , ruler_grabbed_widget (0)
300 , minsec_mark_interval (0)
301 , minsec_mark_modulo (0)
303 , timecode_mark_modulo (0)
304 , timecode_nmarks (0)
305 , _samples_ruler_interval (0)
308 , bbt_bar_helper_on (0)
309 , bbt_accent_modulo (0)
314 , visible_timebars (0)
315 , editor_ruler_menu (0)
319 , range_marker_bar (0)
320 , transport_marker_bar (0)
322 , minsec_label (_("Mins:Secs"))
323 , bbt_label (_("Bars:Beats"))
324 , timecode_label (_("Timecode"))
325 , samples_label (_("Samples"))
326 , tempo_label (_("Tempo"))
327 , meter_label (_("Meter"))
328 , mark_label (_("Location Markers"))
329 , range_mark_label (_("Range Markers"))
330 , transport_mark_label (_("Loop/Punch Ranges"))
331 , cd_mark_label (_("CD Markers"))
332 , videotl_label (_("Video Timeline"))
334 , playhead_cursor (0)
335 , edit_packer (4, 4, true)
336 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
337 , horizontal_adjustment (0.0, 0.0, 1e16)
338 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
339 , controls_layout (unused_adjustment, vertical_adjustment)
340 , _scroll_callbacks (0)
341 , _visible_canvas_width (0)
342 , _visible_canvas_height (0)
343 , _full_canvas_height (0)
344 , edit_controls_left_menu (0)
345 , edit_controls_right_menu (0)
346 , last_update_frame (0)
347 , cut_buffer_start (0)
348 , cut_buffer_length (0)
349 , button_bindings (0)
353 , current_interthread_info (0)
354 , analysis_window (0)
355 , select_new_marker (false)
357 , scrubbing_direction (0)
358 , scrub_reversals (0)
359 , scrub_reverse_distance (0)
360 , have_pending_keyboard_selection (false)
361 , pending_keyboard_selection_start (0)
362 , _snap_type (SnapToBeat)
363 , _snap_mode (SnapOff)
364 , snap_threshold (5.0)
365 , ignore_gui_changes (false)
366 , _drags (new DragManager (this))
368 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
369 , _dragging_playhead (false)
370 , _dragging_edit_point (false)
371 , _show_measures (true)
372 , _follow_playhead (true)
373 , _stationary_playhead (false)
376 , global_rect_group (0)
377 , time_line_group (0)
378 , tempo_marker_menu (0)
379 , meter_marker_menu (0)
381 , range_marker_menu (0)
382 , transport_marker_menu (0)
383 , new_transport_marker_menu (0)
385 , marker_menu_item (0)
386 , bbt_beat_subdivision (4)
387 , _visible_track_count (-1)
388 , toolbar_selection_clock_table (2,3)
389 , automation_mode_button (_("mode"))
390 , selection (new Selection (this))
391 , cut_buffer (new Selection (this))
392 , _selection_memento (new SelectionMemento())
393 , _all_region_actions_sensitized (false)
394 , _ignore_region_action (false)
395 , _last_region_menu_was_main (false)
396 , _ignore_follow_edits (false)
397 , cd_marker_bar_drag_rect (0)
398 , range_bar_drag_rect (0)
399 , transport_bar_drag_rect (0)
400 , transport_bar_range_rect (0)
401 , transport_bar_preroll_rect (0)
402 , transport_bar_postroll_rect (0)
403 , transport_loop_range_rect (0)
404 , transport_punch_range_rect (0)
405 , transport_punchin_line (0)
406 , transport_punchout_line (0)
407 , transport_preroll_rect (0)
408 , transport_postroll_rect (0)
410 , rubberband_rect (0)
416 , autoscroll_horizontal_allowed (false)
417 , autoscroll_vertical_allowed (false)
419 , autoscroll_widget (0)
420 , show_gain_after_trim (false)
421 , selection_op_cmd_depth (0)
422 , selection_op_history_it (0)
423 , no_save_instant (false)
425 , current_mixer_strip (0)
426 , show_editor_mixer_when_tracks_arrive (false)
427 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
428 , current_stepping_trackview (0)
429 , last_track_height_step_timestamp (0)
431 , entered_regionview (0)
432 , clear_entered_track (false)
433 , _edit_point (EditAtMouse)
434 , meters_running (false)
436 , _have_idled (false)
437 , resize_idle_id (-1)
438 , _pending_resize_amount (0)
439 , _pending_resize_view (0)
440 , _pending_locate_request (false)
441 , _pending_initial_locate (false)
445 , layering_order_editor (0)
446 , _last_cut_copy_source_track (0)
447 , _region_selection_change_updates_region_list (true)
449 , _following_mixer_selection (false)
450 , _control_point_toggled_on_press (false)
451 , _stepping_axis_view (0)
452 , quantize_dialog (0)
453 , _main_menu_disabler (0)
454 , myactions (X_("editor"))
456 /* we are a singleton */
458 PublicEditor::_instance = this;
462 last_event_time.tv_sec = 0;
463 last_event_time.tv_usec = 0;
465 selection_op_history.clear();
468 snap_type_strings = I18N (_snap_type_strings);
469 snap_mode_strings = I18N (_snap_mode_strings);
470 zoom_focus_strings = I18N (_zoom_focus_strings);
471 edit_mode_strings = I18N (_edit_mode_strings);
472 edit_point_strings = I18N (_edit_point_strings);
473 #ifdef USE_RUBBERBAND
474 rb_opt_strings = I18N (_rb_opt_strings);
478 build_edit_mode_menu();
479 build_zoom_focus_menu();
480 build_track_count_menu();
481 build_snap_mode_menu();
482 build_snap_type_menu();
483 build_edit_point_menu();
485 location_marker_color = UIConfiguration::instance().color ("location marker");
486 location_range_color = UIConfiguration::instance().color ("location range");
487 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
488 location_loop_color = UIConfiguration::instance().color ("location loop");
489 location_punch_color = UIConfiguration::instance().color ("location punch");
491 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
493 TimeAxisView::setup_sizes ();
494 ArdourMarker::setup_sizes (timebar_height);
495 TempoCurve::setup_sizes (timebar_height);
497 bbt_label.set_name ("EditorRulerLabel");
498 bbt_label.set_size_request (-1, (int)timebar_height);
499 bbt_label.set_alignment (1.0, 0.5);
500 bbt_label.set_padding (5,0);
502 bbt_label.set_no_show_all();
503 minsec_label.set_name ("EditorRulerLabel");
504 minsec_label.set_size_request (-1, (int)timebar_height);
505 minsec_label.set_alignment (1.0, 0.5);
506 minsec_label.set_padding (5,0);
507 minsec_label.hide ();
508 minsec_label.set_no_show_all();
509 timecode_label.set_name ("EditorRulerLabel");
510 timecode_label.set_size_request (-1, (int)timebar_height);
511 timecode_label.set_alignment (1.0, 0.5);
512 timecode_label.set_padding (5,0);
513 timecode_label.hide ();
514 timecode_label.set_no_show_all();
515 samples_label.set_name ("EditorRulerLabel");
516 samples_label.set_size_request (-1, (int)timebar_height);
517 samples_label.set_alignment (1.0, 0.5);
518 samples_label.set_padding (5,0);
519 samples_label.hide ();
520 samples_label.set_no_show_all();
522 tempo_label.set_name ("EditorRulerLabel");
523 tempo_label.set_size_request (-1, (int)timebar_height);
524 tempo_label.set_alignment (1.0, 0.5);
525 tempo_label.set_padding (5,0);
527 tempo_label.set_no_show_all();
529 meter_label.set_name ("EditorRulerLabel");
530 meter_label.set_size_request (-1, (int)timebar_height);
531 meter_label.set_alignment (1.0, 0.5);
532 meter_label.set_padding (5,0);
534 meter_label.set_no_show_all();
536 if (Profile->get_trx()) {
537 mark_label.set_text (_("Markers"));
539 mark_label.set_name ("EditorRulerLabel");
540 mark_label.set_size_request (-1, (int)timebar_height);
541 mark_label.set_alignment (1.0, 0.5);
542 mark_label.set_padding (5,0);
544 mark_label.set_no_show_all();
546 cd_mark_label.set_name ("EditorRulerLabel");
547 cd_mark_label.set_size_request (-1, (int)timebar_height);
548 cd_mark_label.set_alignment (1.0, 0.5);
549 cd_mark_label.set_padding (5,0);
550 cd_mark_label.hide();
551 cd_mark_label.set_no_show_all();
553 videotl_bar_height = 4;
554 videotl_label.set_name ("EditorRulerLabel");
555 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
556 videotl_label.set_alignment (1.0, 0.5);
557 videotl_label.set_padding (5,0);
558 videotl_label.hide();
559 videotl_label.set_no_show_all();
561 range_mark_label.set_name ("EditorRulerLabel");
562 range_mark_label.set_size_request (-1, (int)timebar_height);
563 range_mark_label.set_alignment (1.0, 0.5);
564 range_mark_label.set_padding (5,0);
565 range_mark_label.hide();
566 range_mark_label.set_no_show_all();
568 transport_mark_label.set_name ("EditorRulerLabel");
569 transport_mark_label.set_size_request (-1, (int)timebar_height);
570 transport_mark_label.set_alignment (1.0, 0.5);
571 transport_mark_label.set_padding (5,0);
572 transport_mark_label.hide();
573 transport_mark_label.set_no_show_all();
575 initialize_canvas ();
577 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
579 _summary = new EditorSummary (this);
581 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
582 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
584 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
586 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
587 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
589 edit_controls_vbox.set_spacing (0);
590 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
591 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
593 HBox* h = manage (new HBox);
594 _group_tabs = new EditorGroupTabs (this);
595 if (!ARDOUR::Profile->get_trx()) {
596 h->pack_start (*_group_tabs, PACK_SHRINK);
598 h->pack_start (edit_controls_vbox);
599 controls_layout.add (*h);
601 controls_layout.set_name ("EditControlsBase");
602 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
603 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
604 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
606 _cursors = new MouseCursors;
607 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
608 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
610 /* Push default cursor to ever-present bottom of cursor stack. */
611 push_canvas_cursor(_cursors->grabber);
613 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
615 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
616 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
617 pad_line_1->set_outline_color (0xFF0000FF);
623 edit_packer.set_col_spacings (0);
624 edit_packer.set_row_spacings (0);
625 edit_packer.set_homogeneous (false);
626 edit_packer.set_border_width (0);
627 edit_packer.set_name ("EditorWindow");
629 time_bars_event_box.add (time_bars_vbox);
630 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
631 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
633 /* labels for the time bars */
634 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
636 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
638 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
640 bottom_hbox.set_border_width (2);
641 bottom_hbox.set_spacing (3);
643 _route_groups = new EditorRouteGroups (this);
644 _routes = new EditorRoutes (this);
645 _regions = new EditorRegions (this);
646 _snapshots = new EditorSnapshots (this);
647 _locations = new EditorLocations (this);
648 _time_info_box = new TimeInfoBox ();
650 /* these are static location signals */
652 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
654 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
656 add_notebook_page (_("Regions"), _regions->widget ());
657 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
658 add_notebook_page (_("Snapshots"), _snapshots->widget ());
659 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
660 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
662 _the_notebook.set_show_tabs (true);
663 _the_notebook.set_scrollable (true);
664 _the_notebook.popup_disable ();
665 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
666 _the_notebook.show_all ();
668 _notebook_shrunk = false;
671 /* Pick up some settings we need to cache, early */
673 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
676 if (settings && (prop = settings->property ("notebook-shrunk"))) {
677 _notebook_shrunk = string_is_affirmative (prop->value ());
680 editor_summary_pane.set_check_divider_position (true);
681 editor_summary_pane.add (edit_packer);
683 Button* summary_arrows_left_left = manage (new Button);
684 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
685 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
686 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
688 Button* summary_arrows_left_right = manage (new Button);
689 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
690 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
691 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
693 VBox* summary_arrows_left = manage (new VBox);
694 summary_arrows_left->pack_start (*summary_arrows_left_left);
695 summary_arrows_left->pack_start (*summary_arrows_left_right);
697 Button* summary_arrows_right_up = manage (new Button);
698 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
699 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
700 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
702 Button* summary_arrows_right_down = manage (new Button);
703 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
704 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
705 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
707 VBox* summary_arrows_right = manage (new VBox);
708 summary_arrows_right->pack_start (*summary_arrows_right_up);
709 summary_arrows_right->pack_start (*summary_arrows_right_down);
711 Frame* summary_frame = manage (new Frame);
712 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
714 summary_frame->add (*_summary);
715 summary_frame->show ();
717 _summary_hbox.pack_start (*summary_arrows_left, false, false);
718 _summary_hbox.pack_start (*summary_frame, true, true);
719 _summary_hbox.pack_start (*summary_arrows_right, false, false);
721 if (!ARDOUR::Profile->get_trx()) {
722 editor_summary_pane.add (_summary_hbox);
725 edit_pane.set_check_divider_position (true);
726 edit_pane.add (editor_summary_pane);
727 if (!ARDOUR::Profile->get_trx()) {
728 VBox* editor_list_vbox = manage (new VBox);
729 editor_list_vbox->pack_start (*_time_info_box, false, false, 0);
730 editor_list_vbox->pack_start (_the_notebook);
731 edit_pane.add (*editor_list_vbox);
732 edit_pane.set_child_minsize (*editor_list_vbox, 30); /* rough guess at width of notebook tabs */
735 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
736 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
743 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
744 /* initial allocation is 90% to canvas, 10% to notebook */
745 edit_pane.set_divider (0, 0.90);
747 edit_pane.set_divider (0, fract);
750 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
751 /* initial allocation is 90% to canvas, 10% to summary */
752 editor_summary_pane.set_divider (0, 0.90);
755 editor_summary_pane.set_divider (0, fract);
759 global_vpacker.set_spacing (2);
760 global_vpacker.set_border_width (0);
762 global_vpacker.pack_start (toolbar_hbox, false, false);
763 global_vpacker.pack_start (edit_pane, true, true);
764 global_hpacker.pack_start (global_vpacker, true, true);
766 /* need to show the "contents" widget so that notebook will show if tab is switched to
769 global_hpacker.show ();
771 /* register actions now so that set_state() can find them and set toggles/checks etc */
778 _playlist_selector = new PlaylistSelector();
779 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
781 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
785 nudge_forward_button.set_name ("nudge button");
786 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
788 nudge_backward_button.set_name ("nudge button");
789 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
791 fade_context_menu.set_name ("ArdourContextMenu");
793 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
795 /* allow external control surfaces/protocols to do various things */
797 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
798 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
799 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
800 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
801 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
802 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
803 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
804 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
805 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
806 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
807 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
808 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
809 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
810 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
812 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
813 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
814 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
815 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
816 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
818 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
822 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
824 /* problematic: has to return a value and thus cannot be x-thread */
826 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
828 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
829 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
831 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
833 _ignore_region_action = false;
834 _last_region_menu_was_main = false;
835 _popup_region_menu_item = 0;
837 _ignore_follow_edits = false;
839 _show_marker_lines = false;
841 /* Button bindings */
843 button_bindings = new Bindings ("editor-mouse");
845 XMLNode* node = button_settings();
847 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
848 button_bindings->load_operation (**i);
854 /* grab current parameter state */
855 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
856 UIConfiguration::instance().map_parameters (pc);
858 setup_fade_images ();
860 LuaInstance::instance(); // instantiate
861 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
868 delete button_bindings;
870 delete _route_groups;
871 delete _track_canvas_viewport;
874 delete _verbose_cursor;
875 delete quantize_dialog;
881 delete _playlist_selector;
882 delete _time_info_box;
884 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
890 Editor::button_settings () const
892 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
893 XMLNode* node = find_named_node (*settings, X_("Buttons"));
896 node = new XMLNode (X_("Buttons"));
903 Editor::get_smart_mode () const
905 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
909 Editor::catch_vanishing_regionview (RegionView *rv)
911 /* note: the selection will take care of the vanishing
912 audioregionview by itself.
915 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
919 if (clicked_regionview == rv) {
920 clicked_regionview = 0;
923 if (entered_regionview == rv) {
924 set_entered_regionview (0);
927 if (!_all_region_actions_sensitized) {
928 sensitize_all_region_actions (true);
933 Editor::set_entered_regionview (RegionView* rv)
935 if (rv == entered_regionview) {
939 if (entered_regionview) {
940 entered_regionview->exited ();
943 entered_regionview = rv;
945 if (entered_regionview != 0) {
946 entered_regionview->entered ();
949 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
950 /* This RegionView entry might have changed what region actions
951 are allowed, so sensitize them all in case a key is pressed.
953 sensitize_all_region_actions (true);
958 Editor::set_entered_track (TimeAxisView* tav)
961 entered_track->exited ();
967 entered_track->entered ();
972 Editor::instant_save ()
974 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
979 _session->add_instant_xml(get_state());
981 Config->add_instant_xml(get_state());
986 Editor::control_vertical_zoom_in_all ()
988 tav_zoom_smooth (false, true);
992 Editor::control_vertical_zoom_out_all ()
994 tav_zoom_smooth (true, true);
998 Editor::control_vertical_zoom_in_selected ()
1000 tav_zoom_smooth (false, false);
1004 Editor::control_vertical_zoom_out_selected ()
1006 tav_zoom_smooth (true, false);
1010 Editor::control_view (uint32_t view)
1012 goto_visual_state (view);
1016 Editor::control_unselect ()
1018 selection->clear_tracks ();
1022 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1024 TimeAxisView* tav = axis_view_from_stripable (s);
1028 case Selection::Add:
1029 selection->add (tav);
1031 case Selection::Toggle:
1032 selection->toggle (tav);
1034 case Selection::Extend:
1036 case Selection::Set:
1037 selection->set (tav);
1041 selection->clear_tracks ();
1046 Editor::control_step_tracks_up ()
1048 scroll_tracks_up_line ();
1052 Editor::control_step_tracks_down ()
1054 scroll_tracks_down_line ();
1058 Editor::control_scroll (float fraction)
1060 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1066 double step = fraction * current_page_samples();
1069 _control_scroll_target is an optional<T>
1071 it acts like a pointer to an framepos_t, with
1072 a operator conversion to boolean to check
1073 that it has a value could possibly use
1074 playhead_cursor->current_frame to store the
1075 value and a boolean in the class to know
1076 when it's out of date
1079 if (!_control_scroll_target) {
1080 _control_scroll_target = _session->transport_frame();
1081 _dragging_playhead = true;
1084 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1085 *_control_scroll_target = 0;
1086 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1087 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1089 *_control_scroll_target += (framepos_t) trunc (step);
1092 /* move visuals, we'll catch up with it later */
1094 playhead_cursor->set_position (*_control_scroll_target);
1095 UpdateAllTransportClocks (*_control_scroll_target);
1097 if (*_control_scroll_target > (current_page_samples() / 2)) {
1098 /* try to center PH in window */
1099 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1105 Now we do a timeout to actually bring the session to the right place
1106 according to the playhead. This is to avoid reading disk buffers on every
1107 call to control_scroll, which is driven by ScrollTimeline and therefore
1108 probably by a control surface wheel which can generate lots of events.
1110 /* cancel the existing timeout */
1112 control_scroll_connection.disconnect ();
1114 /* add the next timeout */
1116 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1120 Editor::deferred_control_scroll (framepos_t /*target*/)
1122 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1123 // reset for next stream
1124 _control_scroll_target = boost::none;
1125 _dragging_playhead = false;
1130 Editor::access_action (std::string action_group, std::string action_item)
1136 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1139 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1147 Editor::on_realize ()
1151 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1152 start_lock_event_timing ();
1157 Editor::start_lock_event_timing ()
1159 /* check if we should lock the GUI every 30 seconds */
1161 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1165 Editor::generic_event_handler (GdkEvent* ev)
1168 case GDK_BUTTON_PRESS:
1169 case GDK_BUTTON_RELEASE:
1170 case GDK_MOTION_NOTIFY:
1172 case GDK_KEY_RELEASE:
1173 if (contents().is_mapped()) {
1174 gettimeofday (&last_event_time, 0);
1178 case GDK_LEAVE_NOTIFY:
1179 switch (ev->crossing.detail) {
1180 case GDK_NOTIFY_UNKNOWN:
1181 case GDK_NOTIFY_INFERIOR:
1182 case GDK_NOTIFY_ANCESTOR:
1184 case GDK_NOTIFY_VIRTUAL:
1185 case GDK_NOTIFY_NONLINEAR:
1186 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1187 /* leaving window, so reset focus, thus ending any and
1188 all text entry operations.
1190 ARDOUR_UI::instance()->reset_focus (&contents());
1203 Editor::lock_timeout_callback ()
1205 struct timeval now, delta;
1207 gettimeofday (&now, 0);
1209 timersub (&now, &last_event_time, &delta);
1211 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1213 /* don't call again. Returning false will effectively
1214 disconnect us from the timer callback.
1216 unlock() will call start_lock_event_timing() to get things
1226 Editor::map_position_change (framepos_t frame)
1228 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1230 if (_session == 0) {
1234 if (_follow_playhead) {
1235 center_screen (frame);
1238 playhead_cursor->set_position (frame);
1242 Editor::center_screen (framepos_t frame)
1244 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1246 /* if we're off the page, then scroll.
1249 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1250 center_screen_internal (frame, page);
1255 Editor::center_screen_internal (framepos_t frame, float page)
1260 frame -= (framepos_t) page;
1265 reset_x_origin (frame);
1270 Editor::update_title ()
1272 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1274 if (!own_window()) {
1279 bool dirty = _session->dirty();
1281 string session_name;
1283 if (_session->snap_name() != _session->name()) {
1284 session_name = _session->snap_name();
1286 session_name = _session->name();
1290 session_name = "*" + session_name;
1293 WindowTitle title(session_name);
1294 title += S_("Window|Editor");
1295 title += Glib::get_application_name();
1296 own_window()->set_title (title.get_string());
1298 /* ::session_going_away() will have taken care of it */
1303 Editor::set_session (Session *t)
1305 SessionHandlePtr::set_session (t);
1311 _playlist_selector->set_session (_session);
1312 nudge_clock->set_session (_session);
1313 _summary->set_session (_session);
1314 _group_tabs->set_session (_session);
1315 _route_groups->set_session (_session);
1316 _regions->set_session (_session);
1317 _snapshots->set_session (_session);
1318 _routes->set_session (_session);
1319 _locations->set_session (_session);
1320 _time_info_box->set_session (_session);
1322 if (rhythm_ferret) {
1323 rhythm_ferret->set_session (_session);
1326 if (analysis_window) {
1327 analysis_window->set_session (_session);
1331 sfbrowser->set_session (_session);
1334 compute_fixed_ruler_scale ();
1336 /* Make sure we have auto loop and auto punch ranges */
1338 Location* loc = _session->locations()->auto_loop_location();
1340 loc->set_name (_("Loop"));
1343 loc = _session->locations()->auto_punch_location();
1346 loc->set_name (_("Punch"));
1349 refresh_location_display ();
1351 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1352 the selected Marker; this needs the LocationMarker list to be available.
1354 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1355 set_state (*node, Stateful::loading_state_version);
1357 /* catch up with the playhead */
1359 _session->request_locate (playhead_cursor->current_frame ());
1360 _pending_initial_locate = true;
1364 /* These signals can all be emitted by a non-GUI thread. Therefore the
1365 handlers for them must not attempt to directly interact with the GUI,
1366 but use PBD::Signal<T>::connect() which accepts an event loop
1367 ("context") where the handler will be asked to run.
1370 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1371 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1372 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1373 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1374 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1375 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1376 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1377 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1378 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1379 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1380 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1381 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1382 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1383 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1384 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1386 playhead_cursor->show ();
1388 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1389 Config->map_parameters (pc);
1390 _session->config.map_parameters (pc);
1392 restore_ruler_visibility ();
1393 //tempo_map_changed (PropertyChange (0));
1394 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1396 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1397 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1400 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1401 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1404 switch (_snap_type) {
1405 case SnapToRegionStart:
1406 case SnapToRegionEnd:
1407 case SnapToRegionSync:
1408 case SnapToRegionBoundary:
1409 build_region_boundary_cache ();
1416 /* catch up on selection of stripables (other selection state is lost
1417 * when a session is closed
1422 _session->get_stripables (sl);
1423 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1424 if ((*s)->presentation_info().selected()) {
1425 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1427 tl.push_back (rtav);
1432 selection->set (tl);
1435 /* register for undo history */
1436 _session->register_with_memento_command_factory(id(), this);
1437 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1439 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1441 LuaInstance::instance()->set_session(_session);
1443 start_updating_meters ();
1447 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1449 if (a->get_name() == "RegionMenu") {
1450 /* When the main menu's region menu is opened, we setup the actions so that they look right
1451 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1452 so we resensitize all region actions when the entered regionview or the region selection
1453 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1454 happens after the region context menu is opened. So we set a flag here, too.
1458 sensitize_the_right_region_actions ();
1459 _last_region_menu_was_main = true;
1464 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1466 using namespace Menu_Helpers;
1468 void (Editor::*emf)(FadeShape);
1469 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1472 images = &_xfade_in_images;
1473 emf = &Editor::set_fade_in_shape;
1475 images = &_xfade_out_images;
1476 emf = &Editor::set_fade_out_shape;
1481 _("Linear (for highly correlated material)"),
1482 *(*images)[FadeLinear],
1483 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 _("Constant power"),
1492 *(*images)[FadeConstantPower],
1493 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *(*images)[FadeSymmetric],
1502 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 *(*images)[FadeSlow],
1512 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1515 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 *(*images)[FadeFast],
1521 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1524 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1527 /** Pop up a context menu for when the user clicks on a start crossfade */
1529 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1531 using namespace Menu_Helpers;
1532 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1537 MenuList& items (xfade_in_context_menu.items());
1540 if (arv->audio_region()->fade_in_active()) {
1541 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1543 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1546 items.push_back (SeparatorElem());
1547 fill_xfade_menu (items, true);
1549 xfade_in_context_menu.popup (button, time);
1552 /** Pop up a context menu for when the user clicks on an end crossfade */
1554 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1556 using namespace Menu_Helpers;
1557 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1562 MenuList& items (xfade_out_context_menu.items());
1565 if (arv->audio_region()->fade_out_active()) {
1566 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1568 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1571 items.push_back (SeparatorElem());
1572 fill_xfade_menu (items, false);
1574 xfade_out_context_menu.popup (button, time);
1578 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1580 using namespace Menu_Helpers;
1581 Menu* (Editor::*build_menu_function)();
1584 switch (item_type) {
1586 case RegionViewName:
1587 case RegionViewNameHighlight:
1588 case LeftFrameHandle:
1589 case RightFrameHandle:
1590 if (with_selection) {
1591 build_menu_function = &Editor::build_track_selection_context_menu;
1593 build_menu_function = &Editor::build_track_region_context_menu;
1598 if (with_selection) {
1599 build_menu_function = &Editor::build_track_selection_context_menu;
1601 build_menu_function = &Editor::build_track_context_menu;
1606 if (clicked_routeview->track()) {
1607 build_menu_function = &Editor::build_track_context_menu;
1609 build_menu_function = &Editor::build_track_bus_context_menu;
1614 /* probably shouldn't happen but if it does, we don't care */
1618 menu = (this->*build_menu_function)();
1619 menu->set_name ("ArdourContextMenu");
1621 /* now handle specific situations */
1623 switch (item_type) {
1625 case RegionViewName:
1626 case RegionViewNameHighlight:
1627 case LeftFrameHandle:
1628 case RightFrameHandle:
1629 if (!with_selection) {
1630 if (region_edit_menu_split_item) {
1631 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1632 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1634 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1637 if (region_edit_menu_split_multichannel_item) {
1638 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1639 region_edit_menu_split_multichannel_item->set_sensitive (true);
1641 region_edit_menu_split_multichannel_item->set_sensitive (false);
1654 /* probably shouldn't happen but if it does, we don't care */
1658 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1660 /* Bounce to disk */
1662 using namespace Menu_Helpers;
1663 MenuList& edit_items = menu->items();
1665 edit_items.push_back (SeparatorElem());
1667 switch (clicked_routeview->audio_track()->freeze_state()) {
1668 case AudioTrack::NoFreeze:
1669 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1672 case AudioTrack::Frozen:
1673 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1676 case AudioTrack::UnFrozen:
1677 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1683 if (item_type == StreamItem && clicked_routeview) {
1684 clicked_routeview->build_underlay_menu(menu);
1687 /* When the region menu is opened, we setup the actions so that they look right
1690 sensitize_the_right_region_actions ();
1691 _last_region_menu_was_main = false;
1693 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1694 menu->popup (button, time);
1698 Editor::build_track_context_menu ()
1700 using namespace Menu_Helpers;
1702 MenuList& edit_items = track_context_menu.items();
1705 add_dstream_context_items (edit_items);
1706 return &track_context_menu;
1710 Editor::build_track_bus_context_menu ()
1712 using namespace Menu_Helpers;
1714 MenuList& edit_items = track_context_menu.items();
1717 add_bus_context_items (edit_items);
1718 return &track_context_menu;
1722 Editor::build_track_region_context_menu ()
1724 using namespace Menu_Helpers;
1725 MenuList& edit_items = track_region_context_menu.items();
1728 /* we've just cleared the track region context menu, so the menu that these
1729 two items were on will have disappeared; stop them dangling.
1731 region_edit_menu_split_item = 0;
1732 region_edit_menu_split_multichannel_item = 0;
1734 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1737 boost::shared_ptr<Track> tr;
1738 boost::shared_ptr<Playlist> pl;
1740 if ((tr = rtv->track())) {
1741 add_region_context_items (edit_items, tr);
1745 add_dstream_context_items (edit_items);
1747 return &track_region_context_menu;
1751 Editor::loudness_analyze_region_selection ()
1756 Selection& s (PublicEditor::instance ().get_selection ());
1757 RegionSelection ars = s.regions;
1758 ARDOUR::AnalysisGraph ag (_session);
1759 framecnt_t total_work = 0;
1761 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1762 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1766 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1769 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1770 total_work += arv->region ()->length ();
1773 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1775 ag.set_total_frames (total_work);
1776 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1779 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1780 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1784 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1788 ag.analyze_region (ar);
1791 if (!ag.canceled ()) {
1792 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1798 Editor::loudness_analyze_range_selection ()
1803 Selection& s (PublicEditor::instance ().get_selection ());
1804 TimeSelection ts = s.time;
1805 ARDOUR::AnalysisGraph ag (_session);
1806 framecnt_t total_work = 0;
1808 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1809 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1813 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1817 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1818 total_work += j->length ();
1822 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1824 ag.set_total_frames (total_work);
1825 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1828 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1829 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1833 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1837 ag.analyze_range (rui->route (), pl, ts);
1840 if (!ag.canceled ()) {
1841 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1847 Editor::spectral_analyze_region_selection ()
1849 if (analysis_window == 0) {
1850 analysis_window = new AnalysisWindow();
1853 analysis_window->set_session(_session);
1855 analysis_window->show_all();
1858 analysis_window->set_regionmode();
1859 analysis_window->analyze();
1861 analysis_window->present();
1865 Editor::spectral_analyze_range_selection()
1867 if (analysis_window == 0) {
1868 analysis_window = new AnalysisWindow();
1871 analysis_window->set_session(_session);
1873 analysis_window->show_all();
1876 analysis_window->set_rangemode();
1877 analysis_window->analyze();
1879 analysis_window->present();
1883 Editor::build_track_selection_context_menu ()
1885 using namespace Menu_Helpers;
1886 MenuList& edit_items = track_selection_context_menu.items();
1887 edit_items.clear ();
1889 add_selection_context_items (edit_items);
1890 // edit_items.push_back (SeparatorElem());
1891 // add_dstream_context_items (edit_items);
1893 return &track_selection_context_menu;
1897 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1899 using namespace Menu_Helpers;
1901 /* OK, stick the region submenu at the top of the list, and then add
1905 RegionSelection rs = get_regions_from_selection_and_entered ();
1907 string::size_type pos = 0;
1908 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1910 /* we have to hack up the region name because "_" has a special
1911 meaning for menu titles.
1914 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1915 menu_item_name.replace (pos, 1, "__");
1919 if (_popup_region_menu_item == 0) {
1920 _popup_region_menu_item = new MenuItem (menu_item_name);
1921 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1922 _popup_region_menu_item->show ();
1924 _popup_region_menu_item->set_label (menu_item_name);
1927 /* No latering allowed in later is higher layering model */
1928 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1929 if (act && Config->get_layer_model() == LaterHigher) {
1930 act->set_sensitive (false);
1932 act->set_sensitive (true);
1935 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1937 edit_items.push_back (*_popup_region_menu_item);
1938 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1939 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1941 edit_items.push_back (SeparatorElem());
1944 /** Add context menu items relevant to selection ranges.
1945 * @param edit_items List to add the items to.
1948 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1950 using namespace Menu_Helpers;
1952 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1953 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1955 edit_items.push_back (SeparatorElem());
1956 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1958 edit_items.push_back (SeparatorElem());
1959 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1960 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1962 edit_items.push_back (SeparatorElem());
1964 edit_items.push_back (
1966 _("Move Range Start to Previous Region Boundary"),
1967 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1971 edit_items.push_back (
1973 _("Move Range Start to Next Region Boundary"),
1974 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1978 edit_items.push_back (
1980 _("Move Range End to Previous Region Boundary"),
1981 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1985 edit_items.push_back (
1987 _("Move Range End to Next Region Boundary"),
1988 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1992 edit_items.push_back (SeparatorElem());
1993 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1994 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1996 edit_items.push_back (SeparatorElem());
1997 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1999 edit_items.push_back (SeparatorElem());
2000 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2001 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2002 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2004 edit_items.push_back (SeparatorElem());
2005 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2007 edit_items.push_back (SeparatorElem());
2008 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2009 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2011 edit_items.push_back (SeparatorElem());
2012 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2013 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2014 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2015 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2016 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2017 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2018 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2024 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2026 using namespace Menu_Helpers;
2030 Menu *play_menu = manage (new Menu);
2031 MenuList& play_items = play_menu->items();
2032 play_menu->set_name ("ArdourContextMenu");
2034 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2035 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2036 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2037 play_items.push_back (SeparatorElem());
2038 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2040 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2044 Menu *select_menu = manage (new Menu);
2045 MenuList& select_items = select_menu->items();
2046 select_menu->set_name ("ArdourContextMenu");
2048 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2049 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2050 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2051 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2052 select_items.push_back (SeparatorElem());
2053 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2054 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2055 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2056 select_items.push_back (SeparatorElem());
2057 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2058 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2059 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2060 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2061 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2062 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2063 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2065 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2069 Menu *cutnpaste_menu = manage (new Menu);
2070 MenuList& cutnpaste_items = cutnpaste_menu->items();
2071 cutnpaste_menu->set_name ("ArdourContextMenu");
2073 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2074 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2075 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2077 cutnpaste_items.push_back (SeparatorElem());
2079 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2080 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2082 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2084 /* Adding new material */
2086 edit_items.push_back (SeparatorElem());
2087 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2088 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2092 Menu *nudge_menu = manage (new Menu());
2093 MenuList& nudge_items = nudge_menu->items();
2094 nudge_menu->set_name ("ArdourContextMenu");
2096 edit_items.push_back (SeparatorElem());
2097 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2098 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2099 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2100 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2102 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2106 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2108 using namespace Menu_Helpers;
2112 Menu *play_menu = manage (new Menu);
2113 MenuList& play_items = play_menu->items();
2114 play_menu->set_name ("ArdourContextMenu");
2116 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2117 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2118 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2122 Menu *select_menu = manage (new Menu);
2123 MenuList& select_items = select_menu->items();
2124 select_menu->set_name ("ArdourContextMenu");
2126 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2127 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2128 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2129 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2130 select_items.push_back (SeparatorElem());
2131 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2132 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2133 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2134 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2136 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2140 Menu *cutnpaste_menu = manage (new Menu);
2141 MenuList& cutnpaste_items = cutnpaste_menu->items();
2142 cutnpaste_menu->set_name ("ArdourContextMenu");
2144 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2145 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2146 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2148 Menu *nudge_menu = manage (new Menu());
2149 MenuList& nudge_items = nudge_menu->items();
2150 nudge_menu->set_name ("ArdourContextMenu");
2152 edit_items.push_back (SeparatorElem());
2153 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2154 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2155 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2156 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2158 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2162 Editor::snap_type() const
2168 Editor::snap_musical() const
2170 switch (_snap_type) {
2171 case SnapToBeatDiv128:
2172 case SnapToBeatDiv64:
2173 case SnapToBeatDiv32:
2174 case SnapToBeatDiv28:
2175 case SnapToBeatDiv24:
2176 case SnapToBeatDiv20:
2177 case SnapToBeatDiv16:
2178 case SnapToBeatDiv14:
2179 case SnapToBeatDiv12:
2180 case SnapToBeatDiv10:
2181 case SnapToBeatDiv8:
2182 case SnapToBeatDiv7:
2183 case SnapToBeatDiv6:
2184 case SnapToBeatDiv5:
2185 case SnapToBeatDiv4:
2186 case SnapToBeatDiv3:
2187 case SnapToBeatDiv2:
2199 Editor::snap_mode() const
2205 Editor::set_snap_to (SnapType st)
2207 unsigned int snap_ind = (unsigned int)st;
2209 if (internal_editing()) {
2210 internal_snap_type = st;
2212 pre_internal_snap_type = st;
2217 if (snap_ind > snap_type_strings.size() - 1) {
2219 _snap_type = (SnapType)snap_ind;
2222 string str = snap_type_strings[snap_ind];
2224 if (str != snap_type_selector.get_text()) {
2225 snap_type_selector.set_text (str);
2230 switch (_snap_type) {
2231 case SnapToBeatDiv128:
2232 case SnapToBeatDiv64:
2233 case SnapToBeatDiv32:
2234 case SnapToBeatDiv28:
2235 case SnapToBeatDiv24:
2236 case SnapToBeatDiv20:
2237 case SnapToBeatDiv16:
2238 case SnapToBeatDiv14:
2239 case SnapToBeatDiv12:
2240 case SnapToBeatDiv10:
2241 case SnapToBeatDiv8:
2242 case SnapToBeatDiv7:
2243 case SnapToBeatDiv6:
2244 case SnapToBeatDiv5:
2245 case SnapToBeatDiv4:
2246 case SnapToBeatDiv3:
2247 case SnapToBeatDiv2: {
2248 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2249 update_tempo_based_rulers ();
2253 case SnapToRegionStart:
2254 case SnapToRegionEnd:
2255 case SnapToRegionSync:
2256 case SnapToRegionBoundary:
2257 build_region_boundary_cache ();
2265 redisplay_tempo (false);
2267 SnapChanged (); /* EMIT SIGNAL */
2271 Editor::set_snap_mode (SnapMode mode)
2273 string str = snap_mode_strings[(int)mode];
2275 if (internal_editing()) {
2276 internal_snap_mode = mode;
2278 pre_internal_snap_mode = mode;
2283 if (str != snap_mode_selector.get_text ()) {
2284 snap_mode_selector.set_text (str);
2291 Editor::set_edit_point_preference (EditPoint ep, bool force)
2293 bool changed = (_edit_point != ep);
2296 if (Profile->get_mixbus())
2297 if (ep == EditAtSelectedMarker)
2298 ep = EditAtPlayhead;
2300 string str = edit_point_strings[(int)ep];
2301 if (str != edit_point_selector.get_text ()) {
2302 edit_point_selector.set_text (str);
2305 update_all_enter_cursors();
2307 if (!force && !changed) {
2311 const char* action=NULL;
2313 switch (_edit_point) {
2314 case EditAtPlayhead:
2315 action = "edit-at-playhead";
2317 case EditAtSelectedMarker:
2318 action = "edit-at-marker";
2321 action = "edit-at-mouse";
2325 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2327 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2331 bool in_track_canvas;
2333 if (!mouse_frame (foo, in_track_canvas)) {
2334 in_track_canvas = false;
2337 reset_canvas_action_sensitivity (in_track_canvas);
2343 Editor::set_state (const XMLNode& node, int version)
2345 XMLProperty const * prop;
2347 PBD::Unwinder<bool> nsi (no_save_instant, true);
2350 Tabbable::set_state (node, version);
2352 if (_session && (prop = node.property ("playhead"))) {
2354 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2356 playhead_cursor->set_position (pos);
2358 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2359 playhead_cursor->set_position (0);
2362 playhead_cursor->set_position (0);
2365 if ((prop = node.property ("mixer-width"))) {
2366 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2369 if ((prop = node.property ("zoom-focus"))) {
2370 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2372 zoom_focus_selection_done (zoom_focus);
2375 if ((prop = node.property ("zoom"))) {
2376 /* older versions of ardour used floating point samples_per_pixel */
2377 double f = PBD::atof (prop->value());
2378 reset_zoom (llrintf (f));
2380 reset_zoom (samples_per_pixel);
2383 if ((prop = node.property ("visible-track-count"))) {
2384 set_visible_track_count (PBD::atoi (prop->value()));
2387 if ((prop = node.property ("snap-to"))) {
2388 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2389 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2391 set_snap_to (_snap_type);
2394 if ((prop = node.property ("snap-mode"))) {
2395 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2396 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2397 * snap_mode_selection_done() will only mark an already active item as active
2398 * which does not trigger set_text().
2400 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2402 set_snap_mode (_snap_mode);
2405 if ((prop = node.property ("internal-snap-to"))) {
2406 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2409 if ((prop = node.property ("internal-snap-mode"))) {
2410 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2413 if ((prop = node.property ("pre-internal-snap-to"))) {
2414 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2417 if ((prop = node.property ("pre-internal-snap-mode"))) {
2418 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2421 if ((prop = node.property ("mouse-mode"))) {
2422 MouseMode m = str2mousemode(prop->value());
2423 set_mouse_mode (m, true);
2425 set_mouse_mode (MouseObject, true);
2428 if ((prop = node.property ("left-frame")) != 0) {
2430 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2434 reset_x_origin (pos);
2438 if ((prop = node.property ("y-origin")) != 0) {
2439 reset_y_origin (atof (prop->value ()));
2442 if ((prop = node.property ("join-object-range"))) {
2443 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2444 bool yn = string_is_affirmative (prop->value());
2446 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2447 tact->set_active (!yn);
2448 tact->set_active (yn);
2450 set_mouse_mode(mouse_mode, true);
2453 if ((prop = node.property ("edit-point"))) {
2454 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2456 set_edit_point_preference (_edit_point);
2459 if ((prop = node.property ("show-measures"))) {
2460 bool yn = string_is_affirmative (prop->value());
2461 _show_measures = yn;
2464 if ((prop = node.property ("follow-playhead"))) {
2465 bool yn = string_is_affirmative (prop->value());
2466 set_follow_playhead (yn);
2469 if ((prop = node.property ("stationary-playhead"))) {
2470 bool yn = string_is_affirmative (prop->value());
2471 set_stationary_playhead (yn);
2474 if ((prop = node.property ("region-list-sort-type"))) {
2475 RegionListSortType st;
2476 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2479 if ((prop = node.property ("show-editor-mixer"))) {
2481 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2484 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2485 bool yn = string_is_affirmative (prop->value());
2487 /* do it twice to force the change */
2489 tact->set_active (!yn);
2490 tact->set_active (yn);
2493 if ((prop = node.property ("show-editor-list"))) {
2495 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2498 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2499 bool yn = string_is_affirmative (prop->value());
2501 /* do it twice to force the change */
2503 tact->set_active (!yn);
2504 tact->set_active (yn);
2507 if ((prop = node.property (X_("editor-list-page")))) {
2508 _the_notebook.set_current_page (atoi (prop->value ()));
2511 if ((prop = node.property (X_("show-marker-lines")))) {
2512 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2514 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2515 bool yn = string_is_affirmative (prop->value ());
2517 tact->set_active (!yn);
2518 tact->set_active (yn);
2521 XMLNodeList children = node.children ();
2522 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2523 selection->set_state (**i, Stateful::current_state_version);
2524 _regions->set_state (**i);
2527 if ((prop = node.property ("maximised"))) {
2528 bool yn = string_is_affirmative (prop->value());
2529 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2531 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2532 bool fs = tact && tact->get_active();
2534 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2538 if ((prop = node.property ("nudge-clock-value"))) {
2540 sscanf (prop->value().c_str(), "%" PRId64, &f);
2541 nudge_clock->set (f);
2543 nudge_clock->set_mode (AudioClock::Timecode);
2544 nudge_clock->set (_session->frame_rate() * 5, true);
2549 * Not all properties may have been in XML, but
2550 * those that are linked to a private variable may need changing
2555 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2557 yn = _show_measures;
2558 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2559 /* do it twice to force the change */
2560 tact->set_active (!yn);
2561 tact->set_active (yn);
2564 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2565 yn = _follow_playhead;
2567 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2568 if (tact->get_active() != yn) {
2569 tact->set_active (yn);
2573 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2574 yn = _stationary_playhead;
2576 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2577 if (tact->get_active() != yn) {
2578 tact->set_active (yn);
2583 return LuaInstance::instance()->set_state(node);
2587 Editor::get_state ()
2589 XMLNode* node = new XMLNode (X_("Editor"));
2593 id().print (buf, sizeof (buf));
2594 node->add_property ("id", buf);
2596 node->add_child_nocopy (Tabbable::get_state());
2598 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2599 node->add_property("edit-horizontal-pane-pos", string(buf));
2600 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2601 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2602 node->add_property("edit-vertical-pane-pos", string(buf));
2604 maybe_add_mixer_strip_width (*node);
2606 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2608 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2609 node->add_property ("zoom", buf);
2610 node->add_property ("snap-to", enum_2_string (_snap_type));
2611 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2612 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2613 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2614 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2615 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2616 node->add_property ("edit-point", enum_2_string (_edit_point));
2617 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2618 node->add_property ("visible-track-count", buf);
2620 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2621 node->add_property ("playhead", buf);
2622 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2623 node->add_property ("left-frame", buf);
2624 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2625 node->add_property ("y-origin", buf);
2627 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2628 node->add_property ("maximised", _maximised ? "yes" : "no");
2629 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2630 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2631 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2632 node->add_property ("mouse-mode", enum2str(mouse_mode));
2633 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2635 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2637 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2638 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2641 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2643 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2644 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2647 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2648 node->add_property (X_("editor-list-page"), buf);
2650 if (button_bindings) {
2651 XMLNode* bb = new XMLNode (X_("Buttons"));
2652 button_bindings->save (*bb);
2653 node->add_child_nocopy (*bb);
2656 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2658 node->add_child_nocopy (selection->get_state ());
2659 node->add_child_nocopy (_regions->get_state ());
2661 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2662 node->add_property ("nudge-clock-value", buf);
2664 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2665 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2670 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2671 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2673 * @return pair: TimeAxisView that y is over, layer index.
2675 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2676 * in stacked or expanded region display mode, otherwise 0.
2678 std::pair<TimeAxisView *, double>
2679 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2681 if (!trackview_relative_offset) {
2682 y -= _trackview_group->canvas_origin().y;
2686 return std::make_pair ( (TimeAxisView *) 0, 0);
2689 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2691 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2698 return std::make_pair ( (TimeAxisView *) 0, 0);
2701 /** Snap a position to the grid, if appropriate, taking into account current
2702 * grid settings and also the state of any snap modifier keys that may be pressed.
2703 * @param start Position to snap.
2704 * @param event Event to get current key modifier information from, or 0.
2707 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2709 if (!_session || !event) {
2713 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2714 if (_snap_mode == SnapOff) {
2715 snap_to_internal (start, direction, for_mark);
2718 if (_snap_mode != SnapOff) {
2719 snap_to_internal (start, direction, for_mark);
2720 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2721 /* SnapOff, but we pressed the snap_delta modifier */
2722 snap_to_internal (start, direction, for_mark);
2728 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2730 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2734 snap_to_internal (start, direction, for_mark, ensure_snap);
2738 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2740 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2741 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2743 switch (_snap_type) {
2744 case SnapToTimecodeFrame:
2745 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2746 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2747 /* start is already on a whole timecode frame, do nothing */
2748 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2749 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2751 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2755 case SnapToTimecodeSeconds:
2756 if (_session->config.get_timecode_offset_negative()) {
2757 start += _session->config.get_timecode_offset ();
2759 start -= _session->config.get_timecode_offset ();
2761 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2762 (start % one_timecode_second == 0)) {
2763 /* start is already on a whole second, do nothing */
2764 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2765 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2767 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2770 if (_session->config.get_timecode_offset_negative()) {
2771 start -= _session->config.get_timecode_offset ();
2773 start += _session->config.get_timecode_offset ();
2777 case SnapToTimecodeMinutes:
2778 if (_session->config.get_timecode_offset_negative()) {
2779 start += _session->config.get_timecode_offset ();
2781 start -= _session->config.get_timecode_offset ();
2783 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2784 (start % one_timecode_minute == 0)) {
2785 /* start is already on a whole minute, do nothing */
2786 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2787 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2789 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2791 if (_session->config.get_timecode_offset_negative()) {
2792 start -= _session->config.get_timecode_offset ();
2794 start += _session->config.get_timecode_offset ();
2798 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2799 abort(); /*NOTREACHED*/
2804 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2806 const framepos_t one_second = _session->frame_rate();
2807 const framepos_t one_minute = _session->frame_rate() * 60;
2808 framepos_t presnap = start;
2812 switch (_snap_type) {
2813 case SnapToTimecodeFrame:
2814 case SnapToTimecodeSeconds:
2815 case SnapToTimecodeMinutes:
2816 return timecode_snap_to_internal (start, direction, for_mark);
2819 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2820 start % (one_second/75) == 0) {
2821 /* start is already on a whole CD frame, do nothing */
2822 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2823 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2825 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2830 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2831 start % one_second == 0) {
2832 /* start is already on a whole second, do nothing */
2833 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2834 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2836 start = (framepos_t) floor ((double) start / one_second) * one_second;
2841 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2842 start % one_minute == 0) {
2843 /* start is already on a whole minute, do nothing */
2844 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2845 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2847 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2852 start = _session->tempo_map().round_to_bar (start, direction);
2856 start = _session->tempo_map().round_to_beat (start, direction);
2859 case SnapToBeatDiv128:
2860 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2862 case SnapToBeatDiv64:
2863 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2865 case SnapToBeatDiv32:
2866 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2868 case SnapToBeatDiv28:
2869 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2871 case SnapToBeatDiv24:
2872 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2874 case SnapToBeatDiv20:
2875 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2877 case SnapToBeatDiv16:
2878 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2880 case SnapToBeatDiv14:
2881 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2883 case SnapToBeatDiv12:
2884 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2886 case SnapToBeatDiv10:
2887 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2889 case SnapToBeatDiv8:
2890 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2892 case SnapToBeatDiv7:
2893 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2895 case SnapToBeatDiv6:
2896 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2898 case SnapToBeatDiv5:
2899 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2901 case SnapToBeatDiv4:
2902 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2904 case SnapToBeatDiv3:
2905 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2907 case SnapToBeatDiv2:
2908 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2916 _session->locations()->marks_either_side (start, before, after);
2918 if (before == max_framepos && after == max_framepos) {
2919 /* No marks to snap to, so just don't snap */
2921 } else if (before == max_framepos) {
2923 } else if (after == max_framepos) {
2925 } else if (before != max_framepos && after != max_framepos) {
2926 /* have before and after */
2927 if ((start - before) < (after - start)) {
2936 case SnapToRegionStart:
2937 case SnapToRegionEnd:
2938 case SnapToRegionSync:
2939 case SnapToRegionBoundary:
2940 if (!region_boundary_cache.empty()) {
2942 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2943 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2945 if (direction > 0) {
2946 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2948 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2951 if (next != region_boundary_cache.begin ()) {
2956 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2957 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2959 if (start > (p + n) / 2) {
2968 switch (_snap_mode) {
2978 if (presnap > start) {
2979 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2983 } else if (presnap < start) {
2984 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2990 /* handled at entry */
2998 Editor::setup_toolbar ()
3000 HBox* mode_box = manage(new HBox);
3001 mode_box->set_border_width (2);
3002 mode_box->set_spacing(2);
3004 HBox* mouse_mode_box = manage (new HBox);
3005 HBox* mouse_mode_hbox = manage (new HBox);
3006 VBox* mouse_mode_vbox = manage (new VBox);
3007 Alignment* mouse_mode_align = manage (new Alignment);
3009 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3010 mouse_mode_size_group->add_widget (smart_mode_button);
3011 mouse_mode_size_group->add_widget (mouse_move_button);
3012 mouse_mode_size_group->add_widget (mouse_cut_button);
3013 mouse_mode_size_group->add_widget (mouse_select_button);
3014 mouse_mode_size_group->add_widget (mouse_timefx_button);
3015 mouse_mode_size_group->add_widget (mouse_audition_button);
3016 mouse_mode_size_group->add_widget (mouse_draw_button);
3017 mouse_mode_size_group->add_widget (mouse_content_button);
3019 mouse_mode_size_group->add_widget (zoom_in_button);
3020 mouse_mode_size_group->add_widget (zoom_out_button);
3021 mouse_mode_size_group->add_widget (zoom_preset_selector);
3022 mouse_mode_size_group->add_widget (zoom_out_full_button);
3023 mouse_mode_size_group->add_widget (zoom_focus_selector);
3025 mouse_mode_size_group->add_widget (tav_shrink_button);
3026 mouse_mode_size_group->add_widget (tav_expand_button);
3027 mouse_mode_size_group->add_widget (visible_tracks_selector);
3029 mouse_mode_size_group->add_widget (snap_type_selector);
3030 mouse_mode_size_group->add_widget (snap_mode_selector);
3032 mouse_mode_size_group->add_widget (edit_point_selector);
3033 mouse_mode_size_group->add_widget (edit_mode_selector);
3035 mouse_mode_size_group->add_widget (*nudge_clock);
3036 mouse_mode_size_group->add_widget (nudge_forward_button);
3037 mouse_mode_size_group->add_widget (nudge_backward_button);
3039 mouse_mode_hbox->set_spacing (2);
3041 if (!ARDOUR::Profile->get_trx()) {
3042 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3045 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3046 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3048 if (!ARDOUR::Profile->get_mixbus()) {
3049 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3052 if (!ARDOUR::Profile->get_trx()) {
3053 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3054 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3055 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3056 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3059 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3061 mouse_mode_align->add (*mouse_mode_vbox);
3062 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3064 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3066 edit_mode_selector.set_name ("mouse mode button");
3068 if (!ARDOUR::Profile->get_trx()) {
3069 mode_box->pack_start (edit_mode_selector, false, false);
3072 mode_box->pack_start (*mouse_mode_box, false, false);
3076 _zoom_box.set_spacing (2);
3077 _zoom_box.set_border_width (2);
3081 zoom_preset_selector.set_name ("zoom button");
3082 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3083 zoom_preset_selector.set_size_request (42, -1);
3085 zoom_in_button.set_name ("zoom button");
3086 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3087 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3088 zoom_in_button.set_related_action (act);
3090 zoom_out_button.set_name ("zoom button");
3091 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3092 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3093 zoom_out_button.set_related_action (act);
3095 zoom_out_full_button.set_name ("zoom button");
3096 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3097 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3098 zoom_out_full_button.set_related_action (act);
3100 zoom_focus_selector.set_name ("zoom button");
3102 if (ARDOUR::Profile->get_mixbus()) {
3103 _zoom_box.pack_start (zoom_preset_selector, false, false);
3104 } else if (ARDOUR::Profile->get_trx()) {
3105 mode_box->pack_start (zoom_out_button, false, false);
3106 mode_box->pack_start (zoom_in_button, false, false);
3108 _zoom_box.pack_start (zoom_out_button, false, false);
3109 _zoom_box.pack_start (zoom_in_button, false, false);
3110 _zoom_box.pack_start (zoom_out_full_button, false, false);
3111 _zoom_box.pack_start (zoom_focus_selector, false, false);
3114 /* Track zoom buttons */
3115 _track_box.set_spacing (2);
3116 _track_box.set_border_width (2);
3118 visible_tracks_selector.set_name ("zoom button");
3119 if (Profile->get_mixbus()) {
3120 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3121 visible_tracks_selector.set_size_request (42, -1);
3123 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3126 tav_expand_button.set_name ("zoom button");
3127 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3128 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3129 tav_expand_button.set_related_action (act);
3131 tav_shrink_button.set_name ("zoom button");
3132 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3133 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3134 tav_shrink_button.set_related_action (act);
3136 if (ARDOUR::Profile->get_mixbus()) {
3137 _track_box.pack_start (visible_tracks_selector);
3138 } else if (ARDOUR::Profile->get_trx()) {
3139 _track_box.pack_start (tav_shrink_button);
3140 _track_box.pack_start (tav_expand_button);
3142 _track_box.pack_start (visible_tracks_selector);
3143 _track_box.pack_start (tav_shrink_button);
3144 _track_box.pack_start (tav_expand_button);
3147 snap_box.set_spacing (2);
3148 snap_box.set_border_width (2);
3150 snap_type_selector.set_name ("mouse mode button");
3152 snap_mode_selector.set_name ("mouse mode button");
3154 edit_point_selector.set_name ("mouse mode button");
3156 snap_box.pack_start (snap_mode_selector, false, false);
3157 snap_box.pack_start (snap_type_selector, false, false);
3160 HBox *ep_box = manage (new HBox);
3161 ep_box->set_spacing (2);
3162 ep_box->set_border_width (2);
3164 ep_box->pack_start (edit_point_selector, false, false);
3168 HBox *nudge_box = manage (new HBox);
3169 nudge_box->set_spacing (2);
3170 nudge_box->set_border_width (2);
3172 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3173 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3175 nudge_box->pack_start (nudge_backward_button, false, false);
3176 nudge_box->pack_start (nudge_forward_button, false, false);
3177 nudge_box->pack_start (*nudge_clock, false, false);
3180 /* Pack everything in... */
3182 toolbar_hbox.set_spacing (2);
3183 toolbar_hbox.set_border_width (2);
3185 toolbar_hbox.pack_start (*mode_box, false, false);
3187 if (!ARDOUR::Profile->get_trx()) {
3189 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3191 toolbar_hbox.pack_start (_zoom_box, false, false);
3193 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3195 toolbar_hbox.pack_start (_track_box, false, false);
3197 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3199 toolbar_hbox.pack_start (snap_box, false, false);
3201 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3203 toolbar_hbox.pack_start (*ep_box, false, false);
3205 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3207 toolbar_hbox.pack_start (*nudge_box, false, false);
3210 toolbar_hbox.show_all ();
3214 Editor::build_edit_point_menu ()
3216 using namespace Menu_Helpers;
3218 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3219 if(!Profile->get_mixbus())
3220 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3221 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3223 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3227 Editor::build_edit_mode_menu ()
3229 using namespace Menu_Helpers;
3231 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3232 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3233 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3234 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3236 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3240 Editor::build_snap_mode_menu ()
3242 using namespace Menu_Helpers;
3244 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3245 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3246 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3248 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3252 Editor::build_snap_type_menu ()
3254 using namespace Menu_Helpers;
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3273 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3274 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3275 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3276 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3277 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3278 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3279 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3280 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3281 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3282 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3283 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3284 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3287 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3292 Editor::setup_tooltips ()
3294 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3295 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3296 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3297 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3298 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3299 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3300 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3301 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3302 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3303 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3304 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3305 set_tooltip (zoom_in_button, _("Zoom In"));
3306 set_tooltip (zoom_out_button, _("Zoom Out"));
3307 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3308 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3309 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3310 set_tooltip (tav_expand_button, _("Expand Tracks"));
3311 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3312 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3313 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3314 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3315 set_tooltip (edit_point_selector, _("Edit Point"));
3316 set_tooltip (edit_mode_selector, _("Edit Mode"));
3317 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3321 Editor::convert_drop_to_paths (
3322 vector<string>& paths,
3323 const RefPtr<Gdk::DragContext>& /*context*/,
3326 const SelectionData& data,
3330 if (_session == 0) {
3334 vector<string> uris = data.get_uris();
3338 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3339 are actually URI lists. So do it by hand.
3342 if (data.get_target() != "text/plain") {
3346 /* Parse the "uri-list" format that Nautilus provides,
3347 where each pathname is delimited by \r\n.
3349 THERE MAY BE NO NULL TERMINATING CHAR!!!
3352 string txt = data.get_text();
3356 p = (char *) malloc (txt.length() + 1);
3357 txt.copy (p, txt.length(), 0);
3358 p[txt.length()] = '\0';
3364 while (g_ascii_isspace (*p))
3368 while (*q && (*q != '\n') && (*q != '\r')) {
3375 while (q > p && g_ascii_isspace (*q))
3380 uris.push_back (string (p, q - p + 1));
3384 p = strchr (p, '\n');
3396 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3397 if ((*i).substr (0,7) == "file://") {
3398 paths.push_back (Glib::filename_from_uri (*i));
3406 Editor::new_tempo_section ()
3411 Editor::map_transport_state ()
3413 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3415 if (_session && _session->transport_stopped()) {
3416 have_pending_keyboard_selection = false;
3419 update_loop_range_view ();
3425 Editor::begin_selection_op_history ()
3427 selection_op_cmd_depth = 0;
3428 selection_op_history_it = 0;
3430 while(!selection_op_history.empty()) {
3431 delete selection_op_history.front();
3432 selection_op_history.pop_front();
3435 selection_undo_action->set_sensitive (false);
3436 selection_redo_action->set_sensitive (false);
3437 selection_op_history.push_front (&_selection_memento->get_state ());
3441 Editor::begin_reversible_selection_op (string name)
3444 //cerr << name << endl;
3445 /* begin/commit pairs can be nested */
3446 selection_op_cmd_depth++;
3451 Editor::commit_reversible_selection_op ()
3454 if (selection_op_cmd_depth == 1) {
3456 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3458 The user has undone some selection ops and then made a new one,
3459 making anything earlier in the list invalid.
3462 list<XMLNode *>::iterator it = selection_op_history.begin();
3463 list<XMLNode *>::iterator e_it = it;
3464 advance (e_it, selection_op_history_it);
3466 for ( ; it != e_it; ++it) {
3469 selection_op_history.erase (selection_op_history.begin(), e_it);
3472 selection_op_history.push_front (&_selection_memento->get_state ());
3473 selection_op_history_it = 0;
3475 selection_undo_action->set_sensitive (true);
3476 selection_redo_action->set_sensitive (false);
3479 if (selection_op_cmd_depth > 0) {
3480 selection_op_cmd_depth--;
3486 Editor::undo_selection_op ()
3489 selection_op_history_it++;
3491 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3492 if (n == selection_op_history_it) {
3493 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3494 selection_redo_action->set_sensitive (true);
3498 /* is there an earlier entry? */
3499 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3500 selection_undo_action->set_sensitive (false);
3506 Editor::redo_selection_op ()
3509 if (selection_op_history_it > 0) {
3510 selection_op_history_it--;
3513 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3514 if (n == selection_op_history_it) {
3515 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3516 selection_undo_action->set_sensitive (true);
3521 if (selection_op_history_it == 0) {
3522 selection_redo_action->set_sensitive (false);
3528 Editor::begin_reversible_command (string name)
3531 before.push_back (&_selection_memento->get_state ());
3532 _session->begin_reversible_command (name);
3537 Editor::begin_reversible_command (GQuark q)
3540 before.push_back (&_selection_memento->get_state ());
3541 _session->begin_reversible_command (q);
3546 Editor::abort_reversible_command ()
3549 while(!before.empty()) {
3550 delete before.front();
3553 _session->abort_reversible_command ();
3558 Editor::commit_reversible_command ()
3561 if (before.size() == 1) {
3562 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3563 redo_action->set_sensitive(false);
3564 undo_action->set_sensitive(true);
3565 begin_selection_op_history ();
3568 if (before.empty()) {
3569 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3574 _session->commit_reversible_command ();
3579 Editor::history_changed ()
3583 if (undo_action && _session) {
3584 if (_session->undo_depth() == 0) {
3585 label = S_("Command|Undo");
3587 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3589 undo_action->property_label() = label;
3592 if (redo_action && _session) {
3593 if (_session->redo_depth() == 0) {
3595 redo_action->set_sensitive (false);
3597 label = string_compose(_("Redo (%1)"), _session->next_redo());
3598 redo_action->set_sensitive (true);
3600 redo_action->property_label() = label;
3605 Editor::duplicate_range (bool with_dialog)
3609 RegionSelection rs = get_regions_from_selection_and_entered ();
3611 if ( selection->time.length() == 0 && rs.empty()) {
3617 ArdourDialog win (_("Duplicate"));
3618 Label label (_("Number of duplications:"));
3619 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3620 SpinButton spinner (adjustment, 0.0, 1);
3623 win.get_vbox()->set_spacing (12);
3624 win.get_vbox()->pack_start (hbox);
3625 hbox.set_border_width (6);
3626 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3628 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3629 place, visually. so do this by hand.
3632 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3633 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3634 spinner.grab_focus();
3640 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3641 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3642 win.set_default_response (RESPONSE_ACCEPT);
3644 spinner.grab_focus ();
3646 switch (win.run ()) {
3647 case RESPONSE_ACCEPT:
3653 times = adjustment.get_value();
3656 if ((current_mouse_mode() == Editing::MouseRange)) {
3657 if (selection->time.length()) {
3658 duplicate_selection (times);
3660 } else if (get_smart_mode()) {
3661 if (selection->time.length()) {
3662 duplicate_selection (times);
3664 duplicate_some_regions (rs, times);
3666 duplicate_some_regions (rs, times);
3671 Editor::set_edit_mode (EditMode m)
3673 Config->set_edit_mode (m);
3677 Editor::cycle_edit_mode ()
3679 switch (Config->get_edit_mode()) {
3681 Config->set_edit_mode (Ripple);
3685 Config->set_edit_mode (Lock);
3688 Config->set_edit_mode (Slide);
3694 Editor::edit_mode_selection_done ( EditMode m )
3696 Config->set_edit_mode ( m );
3700 Editor::snap_type_selection_done (SnapType snaptype)
3702 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3704 ract->set_active ();
3709 Editor::snap_mode_selection_done (SnapMode mode)
3711 RefPtr<RadioAction> ract = snap_mode_action (mode);
3714 ract->set_active (true);
3719 Editor::cycle_edit_point (bool with_marker)
3721 if(Profile->get_mixbus())
3722 with_marker = false;
3724 switch (_edit_point) {
3726 set_edit_point_preference (EditAtPlayhead);
3728 case EditAtPlayhead:
3730 set_edit_point_preference (EditAtSelectedMarker);
3732 set_edit_point_preference (EditAtMouse);
3735 case EditAtSelectedMarker:
3736 set_edit_point_preference (EditAtMouse);
3742 Editor::edit_point_selection_done (EditPoint ep)
3744 set_edit_point_preference ( ep );
3748 Editor::build_zoom_focus_menu ()
3750 using namespace Menu_Helpers;
3752 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3753 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3754 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3755 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3756 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3757 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3759 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3763 Editor::zoom_focus_selection_done ( ZoomFocus f )
3765 RefPtr<RadioAction> ract = zoom_focus_action (f);
3767 ract->set_active ();
3772 Editor::build_track_count_menu ()
3774 using namespace Menu_Helpers;
3776 if (!Profile->get_mixbus()) {
3777 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3791 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3792 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3793 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3794 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3795 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3796 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3797 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3798 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3799 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3800 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3802 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3803 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3804 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3805 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3806 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3807 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3808 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3809 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3810 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3811 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3812 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3817 Editor::set_zoom_preset (int64_t ms)
3820 temporal_zoom_session();
3824 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3825 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3829 Editor::set_visible_track_count (int32_t n)
3831 _visible_track_count = n;
3833 /* if the canvas hasn't really been allocated any size yet, just
3834 record the desired number of visible tracks and return. when canvas
3835 allocation happens, we will get called again and then we can do the
3839 if (_visible_canvas_height <= 1) {
3845 DisplaySuspender ds;
3847 if (_visible_track_count > 0) {
3848 h = trackviews_height() / _visible_track_count;
3849 std::ostringstream s;
3850 s << _visible_track_count;
3852 } else if (_visible_track_count == 0) {
3854 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3855 if ((*i)->marked_for_display()) {
3859 h = trackviews_height() / n;
3862 /* negative value means that the visible track count has
3863 been overridden by explicit track height changes.
3865 visible_tracks_selector.set_text (X_("*"));
3869 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3870 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3873 if (str != visible_tracks_selector.get_text()) {
3874 visible_tracks_selector.set_text (str);
3879 Editor::override_visible_track_count ()
3881 _visible_track_count = -1;
3882 visible_tracks_selector.set_text ( _("*") );
3886 Editor::edit_controls_button_release (GdkEventButton* ev)
3888 if (Keyboard::is_context_menu_event (ev)) {
3889 ARDOUR_UI::instance()->add_route ();
3890 } else if (ev->button == 1) {
3891 selection->clear_tracks ();
3898 Editor::mouse_select_button_release (GdkEventButton* ev)
3900 /* this handles just right-clicks */
3902 if (ev->button != 3) {
3910 Editor::set_zoom_focus (ZoomFocus f)
3912 string str = zoom_focus_strings[(int)f];
3914 if (str != zoom_focus_selector.get_text()) {
3915 zoom_focus_selector.set_text (str);
3918 if (zoom_focus != f) {
3925 Editor::cycle_zoom_focus ()
3927 switch (zoom_focus) {
3929 set_zoom_focus (ZoomFocusRight);
3931 case ZoomFocusRight:
3932 set_zoom_focus (ZoomFocusCenter);
3934 case ZoomFocusCenter:
3935 set_zoom_focus (ZoomFocusPlayhead);
3937 case ZoomFocusPlayhead:
3938 set_zoom_focus (ZoomFocusMouse);
3940 case ZoomFocusMouse:
3941 set_zoom_focus (ZoomFocusEdit);
3944 set_zoom_focus (ZoomFocusLeft);
3950 Editor::set_show_measures (bool yn)
3952 if (_show_measures != yn) {
3955 if ((_show_measures = yn) == true) {
3957 tempo_lines->show();
3960 std::vector<TempoMap::BBTPoint> grid;
3961 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3962 draw_measures (grid);
3970 Editor::toggle_follow_playhead ()
3972 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3974 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3975 set_follow_playhead (tact->get_active());
3979 /** @param yn true to follow playhead, otherwise false.
3980 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3983 Editor::set_follow_playhead (bool yn, bool catch_up)
3985 if (_follow_playhead != yn) {
3986 if ((_follow_playhead = yn) == true && catch_up) {
3988 reset_x_origin_to_follow_playhead ();
3995 Editor::toggle_stationary_playhead ()
3997 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3999 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4000 set_stationary_playhead (tact->get_active());
4005 Editor::set_stationary_playhead (bool yn)
4007 if (_stationary_playhead != yn) {
4008 if ((_stationary_playhead = yn) == true) {
4010 // FIXME need a 3.0 equivalent of this 2.X call
4011 // update_current_screen ();
4018 Editor::playlist_selector () const
4020 return *_playlist_selector;
4024 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4026 if (paste_count == 0) {
4027 /* don't bother calculating an offset that will be zero anyway */
4031 /* calculate basic unsnapped multi-paste offset */
4032 framecnt_t offset = paste_count * duration;
4034 /* snap offset so pos + offset is aligned to the grid */
4035 framepos_t offset_pos = pos + offset;
4036 snap_to(offset_pos, RoundUpMaybe);
4037 offset = offset_pos - pos;
4043 Editor::get_grid_beat_divisions(framepos_t position)
4045 switch (_snap_type) {
4046 case SnapToBeatDiv128: return 128;
4047 case SnapToBeatDiv64: return 64;
4048 case SnapToBeatDiv32: return 32;
4049 case SnapToBeatDiv28: return 28;
4050 case SnapToBeatDiv24: return 24;
4051 case SnapToBeatDiv20: return 20;
4052 case SnapToBeatDiv16: return 16;
4053 case SnapToBeatDiv14: return 14;
4054 case SnapToBeatDiv12: return 12;
4055 case SnapToBeatDiv10: return 10;
4056 case SnapToBeatDiv8: return 8;
4057 case SnapToBeatDiv7: return 7;
4058 case SnapToBeatDiv6: return 6;
4059 case SnapToBeatDiv5: return 5;
4060 case SnapToBeatDiv4: return 4;
4061 case SnapToBeatDiv3: return 3;
4062 case SnapToBeatDiv2: return 2;
4068 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4069 if the grid is non-musical, returns 0.
4070 if the grid is snapped to bars, returns -1.
4071 @param event_state the current keyboard modifier mask.
4074 Editor::get_grid_music_divisions (uint32_t event_state)
4076 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4080 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4084 switch (_snap_type) {
4085 case SnapToBeatDiv128: return 128;
4086 case SnapToBeatDiv64: return 64;
4087 case SnapToBeatDiv32: return 32;
4088 case SnapToBeatDiv28: return 28;
4089 case SnapToBeatDiv24: return 24;
4090 case SnapToBeatDiv20: return 20;
4091 case SnapToBeatDiv16: return 16;
4092 case SnapToBeatDiv14: return 14;
4093 case SnapToBeatDiv12: return 12;
4094 case SnapToBeatDiv10: return 10;
4095 case SnapToBeatDiv8: return 8;
4096 case SnapToBeatDiv7: return 7;
4097 case SnapToBeatDiv6: return 6;
4098 case SnapToBeatDiv5: return 5;
4099 case SnapToBeatDiv4: return 4;
4100 case SnapToBeatDiv3: return 3;
4101 case SnapToBeatDiv2: return 2;
4102 case SnapToBeat: return 1;
4103 case SnapToBar : return -1;
4110 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4114 const unsigned divisions = get_grid_beat_divisions(position);
4116 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4119 switch (_snap_type) {
4121 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4124 const Meter& m = _session->tempo_map().meter_at_frame (position);
4125 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4133 return Evoral::Beats();
4137 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4141 ret = nudge_clock->current_duration (pos);
4142 next = ret + 1; /* XXXX fix me */
4148 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4150 ArdourDialog dialog (_("Playlist Deletion"));
4151 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4152 "If it is kept, its audio files will not be cleaned.\n"
4153 "If it is deleted, audio files used by it alone will be cleaned."),
4156 dialog.set_position (WIN_POS_CENTER);
4157 dialog.get_vbox()->pack_start (label);
4161 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4162 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4163 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4164 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4165 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4167 // by default gtk uses the left most button
4168 keep->grab_focus ();
4170 switch (dialog.run ()) {
4172 /* keep this and all remaining ones */
4177 /* delete this and all others */
4181 case RESPONSE_ACCEPT:
4182 /* delete the playlist */
4186 case RESPONSE_REJECT:
4187 /* keep the playlist */
4199 Editor::audio_region_selection_covers (framepos_t where)
4201 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4202 if ((*a)->region()->covers (where)) {
4211 Editor::prepare_for_cleanup ()
4213 cut_buffer->clear_regions ();
4214 cut_buffer->clear_playlists ();
4216 selection->clear_regions ();
4217 selection->clear_playlists ();
4219 _regions->suspend_redisplay ();
4223 Editor::finish_cleanup ()
4225 _regions->resume_redisplay ();
4229 Editor::transport_loop_location()
4232 return _session->locations()->auto_loop_location();
4239 Editor::transport_punch_location()
4242 return _session->locations()->auto_punch_location();
4249 Editor::control_layout_scroll (GdkEventScroll* ev)
4251 /* Just forward to the normal canvas scroll method. The coordinate
4252 systems are different but since the canvas is always larger than the
4253 track headers, and aligned with the trackview area, this will work.
4255 In the not too distant future this layout is going away anyway and
4256 headers will be on the canvas.
4258 return canvas_scroll_event (ev, false);
4262 Editor::session_state_saved (string)
4265 _snapshots->redisplay ();
4269 Editor::maximise_editing_space ()
4275 Gtk::Window* toplevel = current_toplevel();
4278 toplevel->fullscreen ();
4284 Editor::restore_editing_space ()
4290 Gtk::Window* toplevel = current_toplevel();
4293 toplevel->unfullscreen();
4299 * Make new playlists for a given track and also any others that belong
4300 * to the same active route group with the `select' property.
4305 Editor::new_playlists (TimeAxisView* v)
4307 begin_reversible_command (_("new playlists"));
4308 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4309 _session->playlists->get (playlists);
4310 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4311 commit_reversible_command ();
4315 * Use a copy of the current playlist for a given track and also any others that belong
4316 * to the same active route group with the `select' property.
4321 Editor::copy_playlists (TimeAxisView* v)
4323 begin_reversible_command (_("copy playlists"));
4324 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4325 _session->playlists->get (playlists);
4326 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4327 commit_reversible_command ();
4330 /** Clear the current playlist for a given track and also any others that belong
4331 * to the same active route group with the `select' property.
4336 Editor::clear_playlists (TimeAxisView* v)
4338 begin_reversible_command (_("clear playlists"));
4339 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4340 _session->playlists->get (playlists);
4341 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4342 commit_reversible_command ();
4346 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4348 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4352 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4354 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4358 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4360 atv.clear_playlist ();
4364 Editor::get_y_origin () const
4366 return vertical_adjustment.get_value ();
4369 /** Queue up a change to the viewport x origin.
4370 * @param frame New x origin.
4373 Editor::reset_x_origin (framepos_t frame)
4375 pending_visual_change.add (VisualChange::TimeOrigin);
4376 pending_visual_change.time_origin = frame;
4377 ensure_visual_change_idle_handler ();
4381 Editor::reset_y_origin (double y)
4383 pending_visual_change.add (VisualChange::YOrigin);
4384 pending_visual_change.y_origin = y;
4385 ensure_visual_change_idle_handler ();
4389 Editor::reset_zoom (framecnt_t spp)
4391 if (spp == samples_per_pixel) {
4395 pending_visual_change.add (VisualChange::ZoomLevel);
4396 pending_visual_change.samples_per_pixel = spp;
4397 ensure_visual_change_idle_handler ();
4401 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4403 reset_x_origin (frame);
4406 if (!no_save_visual) {
4407 undo_visual_stack.push_back (current_visual_state(false));
4411 Editor::VisualState::VisualState (bool with_tracks)
4412 : gui_state (with_tracks ? new GUIObjectState : 0)
4416 Editor::VisualState::~VisualState ()
4421 Editor::VisualState*
4422 Editor::current_visual_state (bool with_tracks)
4424 VisualState* vs = new VisualState (with_tracks);
4425 vs->y_position = vertical_adjustment.get_value();
4426 vs->samples_per_pixel = samples_per_pixel;
4427 vs->leftmost_frame = leftmost_frame;
4428 vs->zoom_focus = zoom_focus;
4431 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4438 Editor::undo_visual_state ()
4440 if (undo_visual_stack.empty()) {
4444 VisualState* vs = undo_visual_stack.back();
4445 undo_visual_stack.pop_back();
4448 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4451 use_visual_state (*vs);
4456 Editor::redo_visual_state ()
4458 if (redo_visual_stack.empty()) {
4462 VisualState* vs = redo_visual_stack.back();
4463 redo_visual_stack.pop_back();
4465 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4466 // why do we check here?
4467 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4470 use_visual_state (*vs);
4475 Editor::swap_visual_state ()
4477 if (undo_visual_stack.empty()) {
4478 redo_visual_state ();
4480 undo_visual_state ();
4485 Editor::use_visual_state (VisualState& vs)
4487 PBD::Unwinder<bool> nsv (no_save_visual, true);
4488 DisplaySuspender ds;
4490 vertical_adjustment.set_value (vs.y_position);
4492 set_zoom_focus (vs.zoom_focus);
4493 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4496 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4498 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4499 (*i)->clear_property_cache();
4500 (*i)->reset_visual_state ();
4504 _routes->update_visibility ();
4507 /** This is the core function that controls the zoom level of the canvas. It is called
4508 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4509 * @param spp new number of samples per pixel
4512 Editor::set_samples_per_pixel (framecnt_t spp)
4518 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4519 const framecnt_t lots_of_pixels = 4000;
4521 /* if the zoom level is greater than what you'd get trying to display 3
4522 * days of audio on a really big screen, then it's too big.
4525 if (spp * lots_of_pixels > three_days) {
4529 samples_per_pixel = spp;
4532 tempo_lines->tempo_map_changed();
4535 bool const showing_time_selection = selection->time.length() > 0;
4537 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4538 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4539 (*i)->reshow_selection (selection->time);
4543 ZoomChanged (); /* EMIT_SIGNAL */
4545 ArdourCanvas::GtkCanvasViewport* c;
4547 c = get_track_canvas();
4549 c->canvas()->zoomed ();
4552 if (playhead_cursor) {
4553 playhead_cursor->set_position (playhead_cursor->current_frame ());
4556 refresh_location_display();
4557 _summary->set_overlays_dirty ();
4559 update_marker_labels ();
4565 Editor::playhead_cursor_sample () const
4567 return playhead_cursor->current_frame();
4571 Editor::queue_visual_videotimeline_update ()
4574 * pending_visual_change.add (VisualChange::VideoTimeline);
4575 * or maybe even more specific: which videotimeline-image
4576 * currently it calls update_video_timeline() to update
4577 * _all outdated_ images on the video-timeline.
4578 * see 'exposeimg()' in video_image_frame.cc
4580 ensure_visual_change_idle_handler ();
4584 Editor::ensure_visual_change_idle_handler ()
4586 if (pending_visual_change.idle_handler_id < 0) {
4587 // see comment in add_to_idle_resize above.
4588 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4589 pending_visual_change.being_handled = false;
4594 Editor::_idle_visual_changer (void* arg)
4596 return static_cast<Editor*>(arg)->idle_visual_changer ();
4600 Editor::idle_visual_changer ()
4602 /* set_horizontal_position() below (and maybe other calls) call
4603 gtk_main_iteration(), so it's possible that a signal will be handled
4604 half-way through this method. If this signal wants an
4605 idle_visual_changer we must schedule another one after this one, so
4606 mark the idle_handler_id as -1 here to allow that. Also make a note
4607 that we are doing the visual change, so that changes in response to
4608 super-rapid-screen-update can be dropped if we are still processing
4612 pending_visual_change.idle_handler_id = -1;
4613 pending_visual_change.being_handled = true;
4615 VisualChange vc = pending_visual_change;
4617 pending_visual_change.pending = (VisualChange::Type) 0;
4619 visual_changer (vc);
4621 pending_visual_change.being_handled = false;
4623 return 0; /* this is always a one-shot call */
4627 Editor::visual_changer (const VisualChange& vc)
4629 double const last_time_origin = horizontal_position ();
4631 if (vc.pending & VisualChange::ZoomLevel) {
4632 set_samples_per_pixel (vc.samples_per_pixel);
4634 compute_fixed_ruler_scale ();
4636 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4637 update_tempo_based_rulers ();
4639 update_video_timeline();
4642 if (vc.pending & VisualChange::TimeOrigin) {
4643 set_horizontal_position (vc.time_origin / samples_per_pixel);
4646 if (vc.pending & VisualChange::YOrigin) {
4647 vertical_adjustment.set_value (vc.y_origin);
4650 if (last_time_origin == horizontal_position ()) {
4651 /* changed signal not emitted */
4652 update_fixed_rulers ();
4653 redisplay_tempo (true);
4656 if (!(vc.pending & VisualChange::ZoomLevel)) {
4657 update_video_timeline();
4660 _summary->set_overlays_dirty ();
4663 struct EditorOrderTimeAxisSorter {
4664 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4665 return a->order () < b->order ();
4670 Editor::sort_track_selection (TrackViewList& sel)
4672 EditorOrderTimeAxisSorter cmp;
4677 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4680 framepos_t where = 0;
4681 EditPoint ep = _edit_point;
4683 if (Profile->get_mixbus()) {
4684 if (ep == EditAtSelectedMarker) {
4685 ep = EditAtPlayhead;
4689 if (from_outside_canvas && (ep == EditAtMouse)) {
4690 ep = EditAtPlayhead;
4691 } else if (from_context_menu && (ep == EditAtMouse)) {
4692 return canvas_event_sample (&context_click_event, 0, 0);
4695 if (entered_marker) {
4696 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4697 return entered_marker->position();
4700 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4701 ep = EditAtSelectedMarker;
4704 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4705 ep = EditAtPlayhead;
4709 case EditAtPlayhead:
4710 if (_dragging_playhead) {
4711 where = *_control_scroll_target;
4713 where = _session->audible_frame();
4715 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4718 case EditAtSelectedMarker:
4719 if (!selection->markers.empty()) {
4721 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4724 where = loc->start();
4728 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4736 if (!mouse_frame (where, ignored)) {
4737 /* XXX not right but what can we do ? */
4741 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4749 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4751 if (!_session) return;
4753 begin_reversible_command (cmd);
4757 if ((tll = transport_loop_location()) == 0) {
4758 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4759 XMLNode &before = _session->locations()->get_state();
4760 _session->locations()->add (loc, true);
4761 _session->set_auto_loop_location (loc);
4762 XMLNode &after = _session->locations()->get_state();
4763 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4765 XMLNode &before = tll->get_state();
4766 tll->set_hidden (false, this);
4767 tll->set (start, end);
4768 XMLNode &after = tll->get_state();
4769 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4772 commit_reversible_command ();
4776 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4778 if (!_session) return;
4780 begin_reversible_command (cmd);
4784 if ((tpl = transport_punch_location()) == 0) {
4785 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4786 XMLNode &before = _session->locations()->get_state();
4787 _session->locations()->add (loc, true);
4788 _session->set_auto_punch_location (loc);
4789 XMLNode &after = _session->locations()->get_state();
4790 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4792 XMLNode &before = tpl->get_state();
4793 tpl->set_hidden (false, this);
4794 tpl->set (start, end);
4795 XMLNode &after = tpl->get_state();
4796 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4799 commit_reversible_command ();
4802 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4803 * @param rs List to which found regions are added.
4804 * @param where Time to look at.
4805 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4808 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4810 const TrackViewList* tracks;
4813 tracks = &track_views;
4818 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4820 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4823 boost::shared_ptr<Track> tr;
4824 boost::shared_ptr<Playlist> pl;
4826 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4828 boost::shared_ptr<RegionList> regions = pl->regions_at (
4829 (framepos_t) floor ( (double) where * tr->speed()));
4831 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4832 RegionView* rv = rtv->view()->find_view (*i);
4843 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4845 const TrackViewList* tracks;
4848 tracks = &track_views;
4853 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4854 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4856 boost::shared_ptr<Track> tr;
4857 boost::shared_ptr<Playlist> pl;
4859 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4861 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4862 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4864 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4866 RegionView* rv = rtv->view()->find_view (*i);
4877 /** Get regions using the following method:
4879 * Make a region list using:
4880 * (a) any selected regions
4881 * (b) the intersection of any selected tracks and the edit point(*)
4882 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4884 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4886 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4890 Editor::get_regions_from_selection_and_edit_point ()
4892 RegionSelection regions;
4894 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4895 regions.add (entered_regionview);
4897 regions = selection->regions;
4900 if ( regions.empty() ) {
4901 TrackViewList tracks = selection->tracks;
4903 if (!tracks.empty()) {
4904 /* no region selected or entered, but some selected tracks:
4905 * act on all regions on the selected tracks at the edit point
4907 framepos_t const where = get_preferred_edit_position ();
4908 get_regions_at(regions, where, tracks);
4915 /** Get regions using the following method:
4917 * Make a region list using:
4918 * (a) any selected regions
4919 * (b) the intersection of any selected tracks and the edit point(*)
4920 * (c) if neither exists, then whatever region is under the mouse
4922 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4924 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4927 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4929 RegionSelection regions;
4931 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4932 regions.add (entered_regionview);
4934 regions = selection->regions;
4937 if ( regions.empty() ) {
4938 TrackViewList tracks = selection->tracks;
4940 if (!tracks.empty()) {
4941 /* no region selected or entered, but some selected tracks:
4942 * act on all regions on the selected tracks at the edit point
4944 get_regions_at(regions, pos, tracks);
4951 /** Start with regions that are selected, or the entered regionview if none are selected.
4952 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4953 * of the regions that we started with.
4957 Editor::get_regions_from_selection_and_entered () const
4959 RegionSelection regions = selection->regions;
4961 if (regions.empty() && entered_regionview) {
4962 regions.add (entered_regionview);
4969 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4971 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4972 RouteTimeAxisView* rtav;
4974 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4975 boost::shared_ptr<Playlist> pl;
4976 std::vector<boost::shared_ptr<Region> > results;
4977 boost::shared_ptr<Track> tr;
4979 if ((tr = rtav->track()) == 0) {
4984 if ((pl = (tr->playlist())) != 0) {
4985 boost::shared_ptr<Region> r = pl->region_by_id (id);
4987 RegionView* rv = rtav->view()->find_view (r);
4989 regions.push_back (rv);
4998 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5001 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5002 MidiTimeAxisView* mtav;
5004 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5006 mtav->get_per_region_note_selection (selection);
5013 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5015 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5017 RouteTimeAxisView* tatv;
5019 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5021 boost::shared_ptr<Playlist> pl;
5022 vector<boost::shared_ptr<Region> > results;
5024 boost::shared_ptr<Track> tr;
5026 if ((tr = tatv->track()) == 0) {
5031 if ((pl = (tr->playlist())) != 0) {
5032 if (src_comparison) {
5033 pl->get_source_equivalent_regions (region, results);
5035 pl->get_region_list_equivalent_regions (region, results);
5039 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5040 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5041 regions.push_back (marv);
5050 Editor::show_rhythm_ferret ()
5052 if (rhythm_ferret == 0) {
5053 rhythm_ferret = new RhythmFerret(*this);
5056 rhythm_ferret->set_session (_session);
5057 rhythm_ferret->show ();
5058 rhythm_ferret->present ();
5062 Editor::first_idle ()
5064 MessageDialog* dialog = 0;
5066 if (track_views.size() > 1) {
5067 Timers::TimerSuspender t;
5068 dialog = new MessageDialog (
5069 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5073 ARDOUR_UI::instance()->flush_pending (60);
5076 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5080 // first idle adds route children (automation tracks), so we need to redisplay here
5081 _routes->redisplay ();
5085 if (_session->undo_depth() == 0) {
5086 undo_action->set_sensitive(false);
5088 redo_action->set_sensitive(false);
5089 begin_selection_op_history ();
5095 Editor::_idle_resize (gpointer arg)
5097 return ((Editor*)arg)->idle_resize ();
5101 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5103 if (resize_idle_id < 0) {
5104 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5105 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5106 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5108 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5109 _pending_resize_amount = 0;
5112 /* make a note of the smallest resulting height, so that we can clamp the
5113 lower limit at TimeAxisView::hSmall */
5115 int32_t min_resulting = INT32_MAX;
5117 _pending_resize_amount += h;
5118 _pending_resize_view = view;
5120 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5122 if (selection->tracks.contains (_pending_resize_view)) {
5123 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5124 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5128 if (min_resulting < 0) {
5133 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5134 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5138 /** Handle pending resizing of tracks */
5140 Editor::idle_resize ()
5142 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5144 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5145 selection->tracks.contains (_pending_resize_view)) {
5147 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5148 if (*i != _pending_resize_view) {
5149 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5154 _pending_resize_amount = 0;
5155 _group_tabs->set_dirty ();
5156 resize_idle_id = -1;
5164 ENSURE_GUI_THREAD (*this, &Editor::located);
5167 playhead_cursor->set_position (_session->audible_frame ());
5168 if (_follow_playhead && !_pending_initial_locate) {
5169 reset_x_origin_to_follow_playhead ();
5173 _pending_locate_request = false;
5174 _pending_initial_locate = false;
5178 Editor::region_view_added (RegionView * rv)
5180 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5181 if (rv->region ()->id () == (*pr)) {
5182 selection->add (rv);
5183 selection->regions.pending.erase (pr);
5188 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5190 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5191 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5192 if (rv->region()->id () == (*rnote).first) {
5193 mrv->select_notes ((*rnote).second);
5194 selection->pending_midi_note_selection.erase(rnote);
5200 _summary->set_background_dirty ();
5204 Editor::region_view_removed ()
5206 _summary->set_background_dirty ();
5210 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5212 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5213 if ((*j)->stripable() == s) {
5223 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5227 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5228 TimeAxisView* tv = axis_view_from_stripable (*i);
5238 Editor::suspend_route_redisplay ()
5241 _routes->suspend_redisplay();
5246 Editor::resume_route_redisplay ()
5249 _routes->redisplay(); // queue redisplay
5250 _routes->resume_redisplay();
5255 Editor::add_vcas (VCAList& vlist)
5259 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5260 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5263 add_stripables (sl);
5267 Editor::add_routes (RouteList& rlist)
5271 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5275 add_stripables (sl);
5279 Editor::add_stripables (StripableList& sl)
5281 list<TimeAxisView*> new_views;
5282 boost::shared_ptr<VCA> v;
5283 boost::shared_ptr<Route> r;
5284 TrackViewList new_selection;
5285 bool from_scratch = (track_views.size() == 0);
5287 sl.sort (StripablePresentationInfoSorter());
5289 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5291 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5293 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5295 new_views.push_back (vtv);
5297 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5299 if (r->is_auditioner() || r->is_monitor()) {
5303 RouteTimeAxisView* rtv;
5304 DataType dt = r->input()->default_type();
5306 if (dt == ARDOUR::DataType::AUDIO) {
5307 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5309 } else if (dt == ARDOUR::DataType::MIDI) {
5310 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5313 throw unknown_type();
5316 new_views.push_back (rtv);
5317 track_views.push_back (rtv);
5318 new_selection.push_back (rtv);
5320 rtv->effective_gain_display ();
5322 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5323 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5327 if (new_views.size() > 0) {
5328 _routes->time_axis_views_added (new_views);
5329 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5332 /* note: !new_selection.empty() means that we got some routes rather
5336 if (!from_scratch && !new_selection.empty()) {
5337 selection->tracks.clear();
5338 selection->add (new_selection);
5339 begin_selection_op_history();
5342 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5343 show_editor_mixer (true);
5346 editor_list_button.set_sensitive (true);
5350 Editor::timeaxisview_deleted (TimeAxisView *tv)
5352 if (tv == entered_track) {
5356 if (_session && _session->deletion_in_progress()) {
5357 /* the situation is under control */
5361 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5363 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5365 _routes->route_removed (tv);
5367 TimeAxisView::Children c = tv->get_child_list ();
5368 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5369 if (entered_track == i->get()) {
5374 /* remove it from the list of track views */
5376 TrackViewList::iterator i;
5378 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5379 i = track_views.erase (i);
5382 /* update whatever the current mixer strip is displaying, if revelant */
5384 boost::shared_ptr<Route> route;
5387 route = rtav->route ();
5390 if (current_mixer_strip && current_mixer_strip->route() == route) {
5392 TimeAxisView* next_tv;
5394 if (track_views.empty()) {
5396 } else if (i == track_views.end()) {
5397 next_tv = track_views.front();
5404 set_selected_mixer_strip (*next_tv);
5406 /* make the editor mixer strip go away setting the
5407 * button to inactive (which also unticks the menu option)
5410 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5416 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5418 if (apply_to_selection) {
5419 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5421 TrackSelection::iterator j = i;
5424 hide_track_in_display (*i, false);
5429 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5431 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5432 // this will hide the mixer strip
5433 set_selected_mixer_strip (*tv);
5436 _routes->hide_track_in_display (*tv);
5441 Editor::sync_track_view_list_and_routes ()
5443 track_views = TrackViewList (_routes->views ());
5445 _summary->set_background_dirty();
5446 _group_tabs->set_dirty ();
5448 return false; // do not call again (until needed)
5452 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5454 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5459 /** Find a RouteTimeAxisView by the ID of its route */
5461 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5463 RouteTimeAxisView* v;
5465 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5466 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5467 if(v->route()->id() == id) {
5477 Editor::fit_route_group (RouteGroup *g)
5479 TrackViewList ts = axis_views_from_routes (g->route_list ());
5484 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5486 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5489 _session->cancel_audition ();
5493 if (_session->is_auditioning()) {
5494 _session->cancel_audition ();
5495 if (r == last_audition_region) {
5500 _session->audition_region (r);
5501 last_audition_region = r;
5506 Editor::hide_a_region (boost::shared_ptr<Region> r)
5508 r->set_hidden (true);
5512 Editor::show_a_region (boost::shared_ptr<Region> r)
5514 r->set_hidden (false);
5518 Editor::audition_region_from_region_list ()
5520 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5524 Editor::hide_region_from_region_list ()
5526 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5530 Editor::show_region_in_region_list ()
5532 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5536 Editor::step_edit_status_change (bool yn)
5539 start_step_editing ();
5541 stop_step_editing ();
5546 Editor::start_step_editing ()
5548 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5552 Editor::stop_step_editing ()
5554 step_edit_connection.disconnect ();
5558 Editor::check_step_edit ()
5560 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5561 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5563 mtv->check_step_edit ();
5567 return true; // do it again, till we stop
5571 Editor::scroll_press (Direction dir)
5573 ++_scroll_callbacks;
5575 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5576 /* delay the first auto-repeat */
5582 scroll_backward (1);
5590 scroll_up_one_track ();
5594 scroll_down_one_track ();
5598 /* do hacky auto-repeat */
5599 if (!_scroll_connection.connected ()) {
5601 _scroll_connection = Glib::signal_timeout().connect (
5602 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5605 _scroll_callbacks = 0;
5612 Editor::scroll_release ()
5614 _scroll_connection.disconnect ();
5617 /** Queue a change for the Editor viewport x origin to follow the playhead */
5619 Editor::reset_x_origin_to_follow_playhead ()
5621 framepos_t const frame = playhead_cursor->current_frame ();
5623 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5625 if (_session->transport_speed() < 0) {
5627 if (frame > (current_page_samples() / 2)) {
5628 center_screen (frame-(current_page_samples()/2));
5630 center_screen (current_page_samples()/2);
5637 if (frame < leftmost_frame) {
5639 if (_session->transport_rolling()) {
5640 /* rolling; end up with the playhead at the right of the page */
5641 l = frame - current_page_samples ();
5643 /* not rolling: end up with the playhead 1/4 of the way along the page */
5644 l = frame - current_page_samples() / 4;
5648 if (_session->transport_rolling()) {
5649 /* rolling: end up with the playhead on the left of the page */
5652 /* not rolling: end up with the playhead 3/4 of the way along the page */
5653 l = frame - 3 * current_page_samples() / 4;
5661 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5667 Editor::super_rapid_screen_update ()
5669 if (!_session || !_session->engine().running()) {
5673 /* METERING / MIXER STRIPS */
5675 /* update track meters, if required */
5676 if (contents().is_mapped() && meters_running) {
5677 RouteTimeAxisView* rtv;
5678 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5679 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5680 rtv->fast_update ();
5685 /* and any current mixer strip */
5686 if (current_mixer_strip) {
5687 current_mixer_strip->fast_update ();
5690 /* PLAYHEAD AND VIEWPORT */
5692 framepos_t const frame = _session->audible_frame();
5694 /* There are a few reasons why we might not update the playhead / viewport stuff:
5696 * 1. we don't update things when there's a pending locate request, otherwise
5697 * when the editor requests a locate there is a chance that this method
5698 * will move the playhead before the locate request is processed, causing
5700 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5701 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5704 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5706 last_update_frame = frame;
5708 if (!_dragging_playhead) {
5709 playhead_cursor->set_position (frame);
5712 if (!_stationary_playhead) {
5714 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5715 /* We only do this if we aren't already
5716 handling a visual change (ie if
5717 pending_visual_change.being_handled is
5718 false) so that these requests don't stack
5719 up there are too many of them to handle in
5722 reset_x_origin_to_follow_playhead ();
5727 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5728 framepos_t const frame = playhead_cursor->current_frame ();
5729 double target = ((double)frame - (double)current_page_samples()/2.0);
5730 if (target <= 0.0) {
5733 // compare to EditorCursor::set_position()
5734 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5735 double const new_pos = sample_to_pixel_unrounded (target);
5736 if (rint (new_pos) != rint (old_pos)) {
5737 reset_x_origin (pixel_to_sample (floor (new_pos)));
5748 Editor::session_going_away ()
5750 _have_idled = false;
5752 _session_connections.drop_connections ();
5754 super_rapid_screen_update_connection.disconnect ();
5756 selection->clear ();
5757 cut_buffer->clear ();
5759 clicked_regionview = 0;
5760 clicked_axisview = 0;
5761 clicked_routeview = 0;
5762 entered_regionview = 0;
5764 last_update_frame = 0;
5767 playhead_cursor->hide ();
5769 /* rip everything out of the list displays */
5773 _route_groups->clear ();
5775 /* do this first so that deleting a track doesn't reset cms to null
5776 and thus cause a leak.
5779 if (current_mixer_strip) {
5780 if (current_mixer_strip->get_parent() != 0) {
5781 global_hpacker.remove (*current_mixer_strip);
5783 delete current_mixer_strip;
5784 current_mixer_strip = 0;
5787 /* delete all trackviews */
5789 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5792 track_views.clear ();
5794 nudge_clock->set_session (0);
5796 editor_list_button.set_active(false);
5797 editor_list_button.set_sensitive(false);
5799 /* clear tempo/meter rulers */
5800 remove_metric_marks ();
5802 clear_marker_display ();
5804 stop_step_editing ();
5808 /* get rid of any existing editor mixer strip */
5810 WindowTitle title(Glib::get_application_name());
5811 title += _("Editor");
5813 own_window()->set_title (title.get_string());
5816 SessionHandlePtr::session_going_away ();
5820 Editor::trigger_script (int i)
5822 LuaInstance::instance()-> call_action (i);
5826 Editor::set_script_action_name (int i, const std::string& n)
5828 string const a = string_compose (X_("script-action-%1"), i + 1);
5829 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5832 act->set_label (string_compose (_("Unset #%1"), i + 1));
5833 act->set_tooltip (_("no action bound"));
5834 act->set_sensitive (false);
5837 act->set_tooltip (n);
5838 act->set_sensitive (true);
5840 KeyEditor::UpdateBindings ();
5844 Editor::show_editor_list (bool yn)
5847 _the_notebook.show ();
5849 _the_notebook.hide ();
5854 Editor::change_region_layering_order (bool from_context_menu)
5856 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5858 if (!clicked_routeview) {
5859 if (layering_order_editor) {
5860 layering_order_editor->hide ();
5865 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5871 boost::shared_ptr<Playlist> pl = track->playlist();
5877 if (layering_order_editor == 0) {
5878 layering_order_editor = new RegionLayeringOrderEditor (*this);
5881 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5882 layering_order_editor->maybe_present ();
5886 Editor::update_region_layering_order_editor ()
5888 if (layering_order_editor && layering_order_editor->is_visible ()) {
5889 change_region_layering_order (true);
5894 Editor::setup_fade_images ()
5896 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5897 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5898 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5899 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5900 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5902 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5903 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5904 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5905 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5906 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5908 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5909 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5910 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5911 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5912 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5914 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5915 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5916 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5917 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5918 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5922 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5924 Editor::action_menu_item (std::string const & name)
5926 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5929 return *manage (a->create_menu_item ());
5933 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5935 EventBox* b = manage (new EventBox);
5936 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5937 Label* l = manage (new Label (name));
5941 _the_notebook.append_page (widget, *b);
5945 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5947 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5948 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5951 if (ev->type == GDK_2BUTTON_PRESS) {
5953 /* double-click on a notebook tab shrinks or expands the notebook */
5955 if (_notebook_shrunk) {
5956 if (pre_notebook_shrink_pane_width) {
5957 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5959 _notebook_shrunk = false;
5961 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5963 /* this expands the LHS of the edit pane to cover the notebook
5964 PAGE but leaves the tabs visible.
5966 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5967 _notebook_shrunk = true;
5975 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5977 using namespace Menu_Helpers;
5979 MenuList& items = _control_point_context_menu.items ();
5982 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5983 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5984 if (!can_remove_control_point (item)) {
5985 items.back().set_sensitive (false);
5988 _control_point_context_menu.popup (event->button.button, event->button.time);
5992 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5994 using namespace Menu_Helpers;
5996 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6001 /* We need to get the selection here and pass it to the operations, since
6002 popping up the menu will cause a region leave event which clears
6003 entered_regionview. */
6005 MidiRegionView& mrv = note->region_view();
6006 const RegionSelection rs = get_regions_from_selection_and_entered ();
6007 const uint32_t sel_size = mrv.selection_size ();
6009 MenuList& items = _note_context_menu.items();
6013 items.push_back(MenuElem(_("Delete"),
6014 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6017 items.push_back(MenuElem(_("Edit..."),
6018 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6019 if (sel_size != 1) {
6020 items.back().set_sensitive (false);
6023 items.push_back(MenuElem(_("Transpose..."),
6024 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6027 items.push_back(MenuElem(_("Legatize"),
6028 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6030 items.back().set_sensitive (false);
6033 items.push_back(MenuElem(_("Quantize..."),
6034 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6036 items.push_back(MenuElem(_("Remove Overlap"),
6037 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6039 items.back().set_sensitive (false);
6042 items.push_back(MenuElem(_("Transform..."),
6043 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6045 _note_context_menu.popup (event->button.button, event->button.time);
6049 Editor::zoom_vertical_modifier_released()
6051 _stepping_axis_view = 0;
6055 Editor::ui_parameter_changed (string parameter)
6057 if (parameter == "icon-set") {
6058 while (!_cursor_stack.empty()) {
6059 _cursor_stack.pop_back();
6061 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6062 _cursor_stack.push_back(_cursors->grabber);
6063 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6064 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6066 } else if (parameter == "draggable-playhead") {
6067 if (_verbose_cursor) {
6068 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6074 Editor::use_own_window (bool and_fill_it)
6076 bool new_window = !own_window();
6078 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6080 if (win && new_window) {
6081 win->set_name ("EditorWindow");
6083 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6085 // win->signal_realize().connect (*this, &Editor::on_realize);
6086 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6087 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6088 win->set_data ("ardour-bindings", bindings);
6093 DisplaySuspender ds;
6094 contents().show_all ();
6096 /* XXX: this is a bit unfortunate; it would probably
6097 be nicer if we could just call show () above rather
6098 than needing the show_all ()
6101 /* re-hide stuff if necessary */
6102 editor_list_button_toggled ();
6103 parameter_changed ("show-summary");
6104 parameter_changed ("show-group-tabs");
6105 parameter_changed ("show-zoom-tools");
6107 /* now reset all audio_time_axis heights, because widgets might need
6113 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6114 tv = (static_cast<TimeAxisView*>(*i));
6115 tv->reset_height ();
6118 if (current_mixer_strip) {
6119 current_mixer_strip->hide_things ();
6120 current_mixer_strip->parameter_changed ("mixer-element-visibility");