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 , cd_marker_bar_drag_rect (0)
397 , range_bar_drag_rect (0)
398 , transport_bar_drag_rect (0)
399 , transport_bar_range_rect (0)
400 , transport_bar_preroll_rect (0)
401 , transport_bar_postroll_rect (0)
402 , transport_loop_range_rect (0)
403 , transport_punch_range_rect (0)
404 , transport_punchin_line (0)
405 , transport_punchout_line (0)
406 , transport_preroll_rect (0)
407 , transport_postroll_rect (0)
409 , rubberband_rect (0)
415 , autoscroll_horizontal_allowed (false)
416 , autoscroll_vertical_allowed (false)
418 , autoscroll_widget (0)
419 , show_gain_after_trim (false)
420 , selection_op_cmd_depth (0)
421 , selection_op_history_it (0)
422 , no_save_instant (false)
424 , current_mixer_strip (0)
425 , show_editor_mixer_when_tracks_arrive (false)
426 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
427 , current_stepping_trackview (0)
428 , last_track_height_step_timestamp (0)
430 , entered_regionview (0)
431 , clear_entered_track (false)
432 , _edit_point (EditAtMouse)
433 , meters_running (false)
435 , _have_idled (false)
436 , resize_idle_id (-1)
437 , _pending_resize_amount (0)
438 , _pending_resize_view (0)
439 , _pending_locate_request (false)
440 , _pending_initial_locate (false)
444 , layering_order_editor (0)
445 , _last_cut_copy_source_track (0)
446 , _region_selection_change_updates_region_list (true)
448 , _following_mixer_selection (false)
449 , _control_point_toggled_on_press (false)
450 , _stepping_axis_view (0)
451 , quantize_dialog (0)
452 , _main_menu_disabler (0)
453 , myactions (X_("editor"))
455 /* we are a singleton */
457 PublicEditor::_instance = this;
461 last_event_time.tv_sec = 0;
462 last_event_time.tv_usec = 0;
464 selection_op_history.clear();
467 snap_type_strings = I18N (_snap_type_strings);
468 snap_mode_strings = I18N (_snap_mode_strings);
469 zoom_focus_strings = I18N (_zoom_focus_strings);
470 edit_mode_strings = I18N (_edit_mode_strings);
471 edit_point_strings = I18N (_edit_point_strings);
472 #ifdef USE_RUBBERBAND
473 rb_opt_strings = I18N (_rb_opt_strings);
477 build_edit_mode_menu();
478 build_zoom_focus_menu();
479 build_track_count_menu();
480 build_snap_mode_menu();
481 build_snap_type_menu();
482 build_edit_point_menu();
484 location_marker_color = UIConfiguration::instance().color ("location marker");
485 location_range_color = UIConfiguration::instance().color ("location range");
486 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
487 location_loop_color = UIConfiguration::instance().color ("location loop");
488 location_punch_color = UIConfiguration::instance().color ("location punch");
490 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
492 TimeAxisView::setup_sizes ();
493 ArdourMarker::setup_sizes (timebar_height);
494 TempoCurve::setup_sizes (timebar_height);
496 bbt_label.set_name ("EditorRulerLabel");
497 bbt_label.set_size_request (-1, (int)timebar_height);
498 bbt_label.set_alignment (1.0, 0.5);
499 bbt_label.set_padding (5,0);
501 bbt_label.set_no_show_all();
502 minsec_label.set_name ("EditorRulerLabel");
503 minsec_label.set_size_request (-1, (int)timebar_height);
504 minsec_label.set_alignment (1.0, 0.5);
505 minsec_label.set_padding (5,0);
506 minsec_label.hide ();
507 minsec_label.set_no_show_all();
508 timecode_label.set_name ("EditorRulerLabel");
509 timecode_label.set_size_request (-1, (int)timebar_height);
510 timecode_label.set_alignment (1.0, 0.5);
511 timecode_label.set_padding (5,0);
512 timecode_label.hide ();
513 timecode_label.set_no_show_all();
514 samples_label.set_name ("EditorRulerLabel");
515 samples_label.set_size_request (-1, (int)timebar_height);
516 samples_label.set_alignment (1.0, 0.5);
517 samples_label.set_padding (5,0);
518 samples_label.hide ();
519 samples_label.set_no_show_all();
521 tempo_label.set_name ("EditorRulerLabel");
522 tempo_label.set_size_request (-1, (int)timebar_height);
523 tempo_label.set_alignment (1.0, 0.5);
524 tempo_label.set_padding (5,0);
526 tempo_label.set_no_show_all();
528 meter_label.set_name ("EditorRulerLabel");
529 meter_label.set_size_request (-1, (int)timebar_height);
530 meter_label.set_alignment (1.0, 0.5);
531 meter_label.set_padding (5,0);
533 meter_label.set_no_show_all();
535 if (Profile->get_trx()) {
536 mark_label.set_text (_("Markers"));
538 mark_label.set_name ("EditorRulerLabel");
539 mark_label.set_size_request (-1, (int)timebar_height);
540 mark_label.set_alignment (1.0, 0.5);
541 mark_label.set_padding (5,0);
543 mark_label.set_no_show_all();
545 cd_mark_label.set_name ("EditorRulerLabel");
546 cd_mark_label.set_size_request (-1, (int)timebar_height);
547 cd_mark_label.set_alignment (1.0, 0.5);
548 cd_mark_label.set_padding (5,0);
549 cd_mark_label.hide();
550 cd_mark_label.set_no_show_all();
552 videotl_bar_height = 4;
553 videotl_label.set_name ("EditorRulerLabel");
554 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
555 videotl_label.set_alignment (1.0, 0.5);
556 videotl_label.set_padding (5,0);
557 videotl_label.hide();
558 videotl_label.set_no_show_all();
560 range_mark_label.set_name ("EditorRulerLabel");
561 range_mark_label.set_size_request (-1, (int)timebar_height);
562 range_mark_label.set_alignment (1.0, 0.5);
563 range_mark_label.set_padding (5,0);
564 range_mark_label.hide();
565 range_mark_label.set_no_show_all();
567 transport_mark_label.set_name ("EditorRulerLabel");
568 transport_mark_label.set_size_request (-1, (int)timebar_height);
569 transport_mark_label.set_alignment (1.0, 0.5);
570 transport_mark_label.set_padding (5,0);
571 transport_mark_label.hide();
572 transport_mark_label.set_no_show_all();
574 initialize_canvas ();
576 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
578 _summary = new EditorSummary (this);
580 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
581 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
583 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
585 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
586 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
588 edit_controls_vbox.set_spacing (0);
589 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
590 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
592 HBox* h = manage (new HBox);
593 _group_tabs = new EditorGroupTabs (this);
594 if (!ARDOUR::Profile->get_trx()) {
595 h->pack_start (*_group_tabs, PACK_SHRINK);
597 h->pack_start (edit_controls_vbox);
598 controls_layout.add (*h);
600 controls_layout.set_name ("EditControlsBase");
601 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
602 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
603 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
605 _cursors = new MouseCursors;
606 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
607 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
609 /* Push default cursor to ever-present bottom of cursor stack. */
610 push_canvas_cursor(_cursors->grabber);
612 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
614 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
615 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
616 pad_line_1->set_outline_color (0xFF0000FF);
622 edit_packer.set_col_spacings (0);
623 edit_packer.set_row_spacings (0);
624 edit_packer.set_homogeneous (false);
625 edit_packer.set_border_width (0);
626 edit_packer.set_name ("EditorWindow");
628 time_bars_event_box.add (time_bars_vbox);
629 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
630 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
632 /* labels for the time bars */
633 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
635 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
637 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
639 bottom_hbox.set_border_width (2);
640 bottom_hbox.set_spacing (3);
642 _route_groups = new EditorRouteGroups (this);
643 _routes = new EditorRoutes (this);
644 _regions = new EditorRegions (this);
645 _snapshots = new EditorSnapshots (this);
646 _locations = new EditorLocations (this);
647 _time_info_box = new TimeInfoBox (true);
649 /* these are static location signals */
651 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
655 add_notebook_page (_("Regions"), _regions->widget ());
656 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
657 add_notebook_page (_("Snapshots"), _snapshots->widget ());
658 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
659 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
661 _the_notebook.set_show_tabs (true);
662 _the_notebook.set_scrollable (true);
663 _the_notebook.popup_disable ();
664 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
665 _the_notebook.show_all ();
667 _notebook_shrunk = false;
670 /* Pick up some settings we need to cache, early */
672 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
675 if (settings && (prop = settings->property ("notebook-shrunk"))) {
676 _notebook_shrunk = string_is_affirmative (prop->value ());
679 editor_summary_pane.set_check_divider_position (true);
680 editor_summary_pane.add (edit_packer);
682 Button* summary_arrows_left_left = manage (new Button);
683 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
684 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
685 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
687 Button* summary_arrows_left_right = manage (new Button);
688 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
689 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
690 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
692 VBox* summary_arrows_left = manage (new VBox);
693 summary_arrows_left->pack_start (*summary_arrows_left_left);
694 summary_arrows_left->pack_start (*summary_arrows_left_right);
696 Button* summary_arrows_right_up = manage (new Button);
697 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
698 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
699 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
701 Button* summary_arrows_right_down = manage (new Button);
702 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
703 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
704 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
706 VBox* summary_arrows_right = manage (new VBox);
707 summary_arrows_right->pack_start (*summary_arrows_right_up);
708 summary_arrows_right->pack_start (*summary_arrows_right_down);
710 Frame* summary_frame = manage (new Frame);
711 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
713 summary_frame->add (*_summary);
714 summary_frame->show ();
716 _summary_hbox.pack_start (*summary_arrows_left, false, false);
717 _summary_hbox.pack_start (*summary_frame, true, true);
718 _summary_hbox.pack_start (*summary_arrows_right, false, false);
720 if (!ARDOUR::Profile->get_trx()) {
721 editor_summary_pane.add (_summary_hbox);
724 edit_pane.set_check_divider_position (true);
725 edit_pane.add (editor_summary_pane);
726 if (!ARDOUR::Profile->get_trx()) {
727 VBox* editor_list_vbox = manage (new VBox);
728 editor_list_vbox->pack_start (*_time_info_box, false, false, 0);
729 editor_list_vbox->pack_start (_the_notebook);
730 edit_pane.add (*editor_list_vbox);
731 edit_pane.set_child_minsize (*editor_list_vbox, 30); /* rough guess at width of notebook tabs */
734 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
735 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
742 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
743 /* initial allocation is 90% to canvas, 10% to notebook */
744 edit_pane.set_divider (0, 0.90);
746 edit_pane.set_divider (0, fract);
749 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
750 /* initial allocation is 90% to canvas, 10% to summary */
751 editor_summary_pane.set_divider (0, 0.90);
754 editor_summary_pane.set_divider (0, fract);
758 global_vpacker.set_spacing (2);
759 global_vpacker.set_border_width (0);
761 global_vpacker.pack_start (toolbar_hbox, false, false);
762 global_vpacker.pack_start (edit_pane, true, true);
763 global_hpacker.pack_start (global_vpacker, true, true);
765 /* need to show the "contents" widget so that notebook will show if tab is switched to
768 global_hpacker.show ();
770 /* register actions now so that set_state() can find them and set toggles/checks etc */
777 _playlist_selector = new PlaylistSelector();
778 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
780 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
784 nudge_forward_button.set_name ("nudge button");
785 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
787 nudge_backward_button.set_name ("nudge button");
788 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
790 fade_context_menu.set_name ("ArdourContextMenu");
792 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
794 /* allow external control surfaces/protocols to do various things */
796 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
797 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
798 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
799 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
800 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
801 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
802 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
803 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
804 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
805 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
806 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
807 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
808 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
809 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
811 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
812 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
813 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
814 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
815 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
817 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
821 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
823 /* problematic: has to return a value and thus cannot be x-thread */
825 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
827 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
828 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
830 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
832 _ignore_region_action = false;
833 _last_region_menu_was_main = false;
834 _popup_region_menu_item = 0;
836 _show_marker_lines = false;
838 /* Button bindings */
840 button_bindings = new Bindings ("editor-mouse");
842 XMLNode* node = button_settings();
844 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
845 button_bindings->load_operation (**i);
851 /* grab current parameter state */
852 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
853 UIConfiguration::instance().map_parameters (pc);
855 setup_fade_images ();
857 LuaInstance::instance(); // instantiate
858 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
865 delete button_bindings;
867 delete _route_groups;
868 delete _track_canvas_viewport;
871 delete _verbose_cursor;
872 delete quantize_dialog;
878 delete _playlist_selector;
879 delete _time_info_box;
881 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
887 Editor::button_settings () const
889 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
890 XMLNode* node = find_named_node (*settings, X_("Buttons"));
893 node = new XMLNode (X_("Buttons"));
900 Editor::get_smart_mode () const
902 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
906 Editor::catch_vanishing_regionview (RegionView *rv)
908 /* note: the selection will take care of the vanishing
909 audioregionview by itself.
912 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
916 if (clicked_regionview == rv) {
917 clicked_regionview = 0;
920 if (entered_regionview == rv) {
921 set_entered_regionview (0);
924 if (!_all_region_actions_sensitized) {
925 sensitize_all_region_actions (true);
930 Editor::set_entered_regionview (RegionView* rv)
932 if (rv == entered_regionview) {
936 if (entered_regionview) {
937 entered_regionview->exited ();
940 entered_regionview = rv;
942 if (entered_regionview != 0) {
943 entered_regionview->entered ();
946 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
947 /* This RegionView entry might have changed what region actions
948 are allowed, so sensitize them all in case a key is pressed.
950 sensitize_all_region_actions (true);
955 Editor::set_entered_track (TimeAxisView* tav)
958 entered_track->exited ();
964 entered_track->entered ();
969 Editor::instant_save ()
971 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
976 _session->add_instant_xml(get_state());
978 Config->add_instant_xml(get_state());
983 Editor::control_vertical_zoom_in_all ()
985 tav_zoom_smooth (false, true);
989 Editor::control_vertical_zoom_out_all ()
991 tav_zoom_smooth (true, true);
995 Editor::control_vertical_zoom_in_selected ()
997 tav_zoom_smooth (false, false);
1001 Editor::control_vertical_zoom_out_selected ()
1003 tav_zoom_smooth (true, false);
1007 Editor::control_view (uint32_t view)
1009 goto_visual_state (view);
1013 Editor::control_unselect ()
1015 selection->clear_tracks ();
1019 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1021 TimeAxisView* tav = axis_view_from_stripable (s);
1025 case Selection::Add:
1026 selection->add (tav);
1028 case Selection::Toggle:
1029 selection->toggle (tav);
1031 case Selection::Extend:
1033 case Selection::Set:
1034 selection->set (tav);
1038 selection->clear_tracks ();
1043 Editor::control_step_tracks_up ()
1045 scroll_tracks_up_line ();
1049 Editor::control_step_tracks_down ()
1051 scroll_tracks_down_line ();
1055 Editor::control_scroll (float fraction)
1057 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1063 double step = fraction * current_page_samples();
1066 _control_scroll_target is an optional<T>
1068 it acts like a pointer to an framepos_t, with
1069 a operator conversion to boolean to check
1070 that it has a value could possibly use
1071 playhead_cursor->current_frame to store the
1072 value and a boolean in the class to know
1073 when it's out of date
1076 if (!_control_scroll_target) {
1077 _control_scroll_target = _session->transport_frame();
1078 _dragging_playhead = true;
1081 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1082 *_control_scroll_target = 0;
1083 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1084 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1086 *_control_scroll_target += (framepos_t) trunc (step);
1089 /* move visuals, we'll catch up with it later */
1091 playhead_cursor->set_position (*_control_scroll_target);
1092 UpdateAllTransportClocks (*_control_scroll_target);
1094 if (*_control_scroll_target > (current_page_samples() / 2)) {
1095 /* try to center PH in window */
1096 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1102 Now we do a timeout to actually bring the session to the right place
1103 according to the playhead. This is to avoid reading disk buffers on every
1104 call to control_scroll, which is driven by ScrollTimeline and therefore
1105 probably by a control surface wheel which can generate lots of events.
1107 /* cancel the existing timeout */
1109 control_scroll_connection.disconnect ();
1111 /* add the next timeout */
1113 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1117 Editor::deferred_control_scroll (framepos_t /*target*/)
1119 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1120 // reset for next stream
1121 _control_scroll_target = boost::none;
1122 _dragging_playhead = false;
1127 Editor::access_action (std::string action_group, std::string action_item)
1133 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1136 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1144 Editor::on_realize ()
1148 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1149 start_lock_event_timing ();
1154 Editor::start_lock_event_timing ()
1156 /* check if we should lock the GUI every 30 seconds */
1158 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1162 Editor::generic_event_handler (GdkEvent* ev)
1165 case GDK_BUTTON_PRESS:
1166 case GDK_BUTTON_RELEASE:
1167 case GDK_MOTION_NOTIFY:
1169 case GDK_KEY_RELEASE:
1170 if (contents().is_mapped()) {
1171 gettimeofday (&last_event_time, 0);
1175 case GDK_LEAVE_NOTIFY:
1176 switch (ev->crossing.detail) {
1177 case GDK_NOTIFY_UNKNOWN:
1178 case GDK_NOTIFY_INFERIOR:
1179 case GDK_NOTIFY_ANCESTOR:
1181 case GDK_NOTIFY_VIRTUAL:
1182 case GDK_NOTIFY_NONLINEAR:
1183 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1184 /* leaving window, so reset focus, thus ending any and
1185 all text entry operations.
1187 ARDOUR_UI::instance()->reset_focus (&contents());
1200 Editor::lock_timeout_callback ()
1202 struct timeval now, delta;
1204 gettimeofday (&now, 0);
1206 timersub (&now, &last_event_time, &delta);
1208 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1210 /* don't call again. Returning false will effectively
1211 disconnect us from the timer callback.
1213 unlock() will call start_lock_event_timing() to get things
1223 Editor::map_position_change (framepos_t frame)
1225 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1227 if (_session == 0) {
1231 if (_follow_playhead) {
1232 center_screen (frame);
1235 playhead_cursor->set_position (frame);
1239 Editor::center_screen (framepos_t frame)
1241 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1243 /* if we're off the page, then scroll.
1246 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1247 center_screen_internal (frame, page);
1252 Editor::center_screen_internal (framepos_t frame, float page)
1257 frame -= (framepos_t) page;
1262 reset_x_origin (frame);
1267 Editor::update_title ()
1269 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1271 if (!own_window()) {
1276 bool dirty = _session->dirty();
1278 string session_name;
1280 if (_session->snap_name() != _session->name()) {
1281 session_name = _session->snap_name();
1283 session_name = _session->name();
1287 session_name = "*" + session_name;
1290 WindowTitle title(session_name);
1291 title += S_("Window|Editor");
1292 title += Glib::get_application_name();
1293 own_window()->set_title (title.get_string());
1295 /* ::session_going_away() will have taken care of it */
1300 Editor::set_session (Session *t)
1302 SessionHandlePtr::set_session (t);
1308 _playlist_selector->set_session (_session);
1309 nudge_clock->set_session (_session);
1310 _summary->set_session (_session);
1311 _group_tabs->set_session (_session);
1312 _route_groups->set_session (_session);
1313 _regions->set_session (_session);
1314 _snapshots->set_session (_session);
1315 _routes->set_session (_session);
1316 _locations->set_session (_session);
1317 _time_info_box->set_session (_session);
1319 if (rhythm_ferret) {
1320 rhythm_ferret->set_session (_session);
1323 if (analysis_window) {
1324 analysis_window->set_session (_session);
1328 sfbrowser->set_session (_session);
1331 compute_fixed_ruler_scale ();
1333 /* Make sure we have auto loop and auto punch ranges */
1335 Location* loc = _session->locations()->auto_loop_location();
1337 loc->set_name (_("Loop"));
1340 loc = _session->locations()->auto_punch_location();
1343 loc->set_name (_("Punch"));
1346 refresh_location_display ();
1348 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1349 the selected Marker; this needs the LocationMarker list to be available.
1351 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1352 set_state (*node, Stateful::loading_state_version);
1354 /* catch up with the playhead */
1356 _session->request_locate (playhead_cursor->current_frame ());
1357 _pending_initial_locate = true;
1361 /* These signals can all be emitted by a non-GUI thread. Therefore the
1362 handlers for them must not attempt to directly interact with the GUI,
1363 but use PBD::Signal<T>::connect() which accepts an event loop
1364 ("context") where the handler will be asked to run.
1367 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1368 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1369 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1370 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1371 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1372 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1373 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1374 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1375 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1376 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1377 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1378 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1379 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1380 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1381 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1383 playhead_cursor->show ();
1385 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1386 Config->map_parameters (pc);
1387 _session->config.map_parameters (pc);
1389 restore_ruler_visibility ();
1390 //tempo_map_changed (PropertyChange (0));
1391 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1393 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1394 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1397 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1398 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1401 switch (_snap_type) {
1402 case SnapToRegionStart:
1403 case SnapToRegionEnd:
1404 case SnapToRegionSync:
1405 case SnapToRegionBoundary:
1406 build_region_boundary_cache ();
1413 /* catch up on selection of stripables (other selection state is lost
1414 * when a session is closed
1419 _session->get_stripables (sl);
1420 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1421 if ((*s)->presentation_info().selected()) {
1422 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1424 tl.push_back (rtav);
1429 selection->set (tl);
1432 /* register for undo history */
1433 _session->register_with_memento_command_factory(id(), this);
1434 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1436 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1438 LuaInstance::instance()->set_session(_session);
1440 start_updating_meters ();
1444 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1446 if (a->get_name() == "RegionMenu") {
1447 /* When the main menu's region menu is opened, we setup the actions so that they look right
1448 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1449 so we resensitize all region actions when the entered regionview or the region selection
1450 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1451 happens after the region context menu is opened. So we set a flag here, too.
1455 sensitize_the_right_region_actions ();
1456 _last_region_menu_was_main = true;
1461 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1463 using namespace Menu_Helpers;
1465 void (Editor::*emf)(FadeShape);
1466 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1469 images = &_xfade_in_images;
1470 emf = &Editor::set_fade_in_shape;
1472 images = &_xfade_out_images;
1473 emf = &Editor::set_fade_out_shape;
1478 _("Linear (for highly correlated material)"),
1479 *(*images)[FadeLinear],
1480 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1484 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488 _("Constant power"),
1489 *(*images)[FadeConstantPower],
1490 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1493 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1498 *(*images)[FadeSymmetric],
1499 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1503 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1508 *(*images)[FadeSlow],
1509 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1512 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1517 *(*images)[FadeFast],
1518 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1521 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1524 /** Pop up a context menu for when the user clicks on a start crossfade */
1526 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1528 using namespace Menu_Helpers;
1529 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1534 MenuList& items (xfade_in_context_menu.items());
1537 if (arv->audio_region()->fade_in_active()) {
1538 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1540 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1543 items.push_back (SeparatorElem());
1544 fill_xfade_menu (items, true);
1546 xfade_in_context_menu.popup (button, time);
1549 /** Pop up a context menu for when the user clicks on an end crossfade */
1551 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1553 using namespace Menu_Helpers;
1554 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1559 MenuList& items (xfade_out_context_menu.items());
1562 if (arv->audio_region()->fade_out_active()) {
1563 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1565 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1568 items.push_back (SeparatorElem());
1569 fill_xfade_menu (items, false);
1571 xfade_out_context_menu.popup (button, time);
1575 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1577 using namespace Menu_Helpers;
1578 Menu* (Editor::*build_menu_function)();
1581 switch (item_type) {
1583 case RegionViewName:
1584 case RegionViewNameHighlight:
1585 case LeftFrameHandle:
1586 case RightFrameHandle:
1587 if (with_selection) {
1588 build_menu_function = &Editor::build_track_selection_context_menu;
1590 build_menu_function = &Editor::build_track_region_context_menu;
1595 if (with_selection) {
1596 build_menu_function = &Editor::build_track_selection_context_menu;
1598 build_menu_function = &Editor::build_track_context_menu;
1603 if (clicked_routeview->track()) {
1604 build_menu_function = &Editor::build_track_context_menu;
1606 build_menu_function = &Editor::build_track_bus_context_menu;
1611 /* probably shouldn't happen but if it does, we don't care */
1615 menu = (this->*build_menu_function)();
1616 menu->set_name ("ArdourContextMenu");
1618 /* now handle specific situations */
1620 switch (item_type) {
1622 case RegionViewName:
1623 case RegionViewNameHighlight:
1624 case LeftFrameHandle:
1625 case RightFrameHandle:
1626 if (!with_selection) {
1627 if (region_edit_menu_split_item) {
1628 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1629 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1631 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1634 if (region_edit_menu_split_multichannel_item) {
1635 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1636 region_edit_menu_split_multichannel_item->set_sensitive (true);
1638 region_edit_menu_split_multichannel_item->set_sensitive (false);
1651 /* probably shouldn't happen but if it does, we don't care */
1655 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1657 /* Bounce to disk */
1659 using namespace Menu_Helpers;
1660 MenuList& edit_items = menu->items();
1662 edit_items.push_back (SeparatorElem());
1664 switch (clicked_routeview->audio_track()->freeze_state()) {
1665 case AudioTrack::NoFreeze:
1666 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1669 case AudioTrack::Frozen:
1670 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1673 case AudioTrack::UnFrozen:
1674 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1680 if (item_type == StreamItem && clicked_routeview) {
1681 clicked_routeview->build_underlay_menu(menu);
1684 /* When the region menu is opened, we setup the actions so that they look right
1687 sensitize_the_right_region_actions ();
1688 _last_region_menu_was_main = false;
1690 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1691 menu->popup (button, time);
1695 Editor::build_track_context_menu ()
1697 using namespace Menu_Helpers;
1699 MenuList& edit_items = track_context_menu.items();
1702 add_dstream_context_items (edit_items);
1703 return &track_context_menu;
1707 Editor::build_track_bus_context_menu ()
1709 using namespace Menu_Helpers;
1711 MenuList& edit_items = track_context_menu.items();
1714 add_bus_context_items (edit_items);
1715 return &track_context_menu;
1719 Editor::build_track_region_context_menu ()
1721 using namespace Menu_Helpers;
1722 MenuList& edit_items = track_region_context_menu.items();
1725 /* we've just cleared the track region context menu, so the menu that these
1726 two items were on will have disappeared; stop them dangling.
1728 region_edit_menu_split_item = 0;
1729 region_edit_menu_split_multichannel_item = 0;
1731 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1734 boost::shared_ptr<Track> tr;
1735 boost::shared_ptr<Playlist> pl;
1737 if ((tr = rtv->track())) {
1738 add_region_context_items (edit_items, tr);
1742 add_dstream_context_items (edit_items);
1744 return &track_region_context_menu;
1748 Editor::loudness_analyze_region_selection ()
1753 Selection& s (PublicEditor::instance ().get_selection ());
1754 RegionSelection ars = s.regions;
1755 ARDOUR::AnalysisGraph ag (_session);
1756 framecnt_t total_work = 0;
1758 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1759 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1763 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1766 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1767 total_work += arv->region ()->length ();
1770 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1772 ag.set_total_frames (total_work);
1773 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1776 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1777 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1781 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1785 ag.analyze_region (ar);
1788 if (!ag.canceled ()) {
1789 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1795 Editor::loudness_analyze_range_selection ()
1800 Selection& s (PublicEditor::instance ().get_selection ());
1801 TimeSelection ts = s.time;
1802 ARDOUR::AnalysisGraph ag (_session);
1803 framecnt_t total_work = 0;
1805 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1806 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1810 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1814 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1815 total_work += j->length ();
1819 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1821 ag.set_total_frames (total_work);
1822 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1825 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1826 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1830 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1834 ag.analyze_range (rui->route (), pl, ts);
1837 if (!ag.canceled ()) {
1838 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1844 Editor::spectral_analyze_region_selection ()
1846 if (analysis_window == 0) {
1847 analysis_window = new AnalysisWindow();
1850 analysis_window->set_session(_session);
1852 analysis_window->show_all();
1855 analysis_window->set_regionmode();
1856 analysis_window->analyze();
1858 analysis_window->present();
1862 Editor::spectral_analyze_range_selection()
1864 if (analysis_window == 0) {
1865 analysis_window = new AnalysisWindow();
1868 analysis_window->set_session(_session);
1870 analysis_window->show_all();
1873 analysis_window->set_rangemode();
1874 analysis_window->analyze();
1876 analysis_window->present();
1880 Editor::build_track_selection_context_menu ()
1882 using namespace Menu_Helpers;
1883 MenuList& edit_items = track_selection_context_menu.items();
1884 edit_items.clear ();
1886 add_selection_context_items (edit_items);
1887 // edit_items.push_back (SeparatorElem());
1888 // add_dstream_context_items (edit_items);
1890 return &track_selection_context_menu;
1894 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1896 using namespace Menu_Helpers;
1898 /* OK, stick the region submenu at the top of the list, and then add
1902 RegionSelection rs = get_regions_from_selection_and_entered ();
1904 string::size_type pos = 0;
1905 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1907 /* we have to hack up the region name because "_" has a special
1908 meaning for menu titles.
1911 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1912 menu_item_name.replace (pos, 1, "__");
1916 if (_popup_region_menu_item == 0) {
1917 _popup_region_menu_item = new MenuItem (menu_item_name);
1918 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1919 _popup_region_menu_item->show ();
1921 _popup_region_menu_item->set_label (menu_item_name);
1924 /* No latering allowed in later is higher layering model */
1925 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1926 if (act && Config->get_layer_model() == LaterHigher) {
1927 act->set_sensitive (false);
1929 act->set_sensitive (true);
1932 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1934 edit_items.push_back (*_popup_region_menu_item);
1935 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1936 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1938 edit_items.push_back (SeparatorElem());
1941 /** Add context menu items relevant to selection ranges.
1942 * @param edit_items List to add the items to.
1945 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1947 using namespace Menu_Helpers;
1949 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1950 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1952 edit_items.push_back (SeparatorElem());
1953 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1955 edit_items.push_back (SeparatorElem());
1956 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1957 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1959 edit_items.push_back (SeparatorElem());
1961 edit_items.push_back (
1963 _("Move Range Start to Previous Region Boundary"),
1964 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1968 edit_items.push_back (
1970 _("Move Range Start to Next Region Boundary"),
1971 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1975 edit_items.push_back (
1977 _("Move Range End to Previous Region Boundary"),
1978 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1982 edit_items.push_back (
1984 _("Move Range End to Next Region Boundary"),
1985 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1989 edit_items.push_back (SeparatorElem());
1990 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1991 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1993 edit_items.push_back (SeparatorElem());
1994 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1996 edit_items.push_back (SeparatorElem());
1997 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1998 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1999 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2001 edit_items.push_back (SeparatorElem());
2002 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2004 edit_items.push_back (SeparatorElem());
2005 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2006 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2008 edit_items.push_back (SeparatorElem());
2009 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2010 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2011 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2012 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2013 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2014 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2015 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2021 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2023 using namespace Menu_Helpers;
2027 Menu *play_menu = manage (new Menu);
2028 MenuList& play_items = play_menu->items();
2029 play_menu->set_name ("ArdourContextMenu");
2031 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2032 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2033 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2034 play_items.push_back (SeparatorElem());
2035 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2037 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2041 Menu *select_menu = manage (new Menu);
2042 MenuList& select_items = select_menu->items();
2043 select_menu->set_name ("ArdourContextMenu");
2045 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2046 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2047 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2048 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2049 select_items.push_back (SeparatorElem());
2050 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2051 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2052 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2053 select_items.push_back (SeparatorElem());
2054 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2055 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2056 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2057 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2058 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2059 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2060 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2062 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2066 Menu *cutnpaste_menu = manage (new Menu);
2067 MenuList& cutnpaste_items = cutnpaste_menu->items();
2068 cutnpaste_menu->set_name ("ArdourContextMenu");
2070 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2071 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2072 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2074 cutnpaste_items.push_back (SeparatorElem());
2076 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2077 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2079 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2081 /* Adding new material */
2083 edit_items.push_back (SeparatorElem());
2084 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2085 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2089 Menu *nudge_menu = manage (new Menu());
2090 MenuList& nudge_items = nudge_menu->items();
2091 nudge_menu->set_name ("ArdourContextMenu");
2093 edit_items.push_back (SeparatorElem());
2094 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2095 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2096 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2097 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2099 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2103 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2105 using namespace Menu_Helpers;
2109 Menu *play_menu = manage (new Menu);
2110 MenuList& play_items = play_menu->items();
2111 play_menu->set_name ("ArdourContextMenu");
2113 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2114 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2115 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2119 Menu *select_menu = manage (new Menu);
2120 MenuList& select_items = select_menu->items();
2121 select_menu->set_name ("ArdourContextMenu");
2123 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2124 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2125 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2126 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2127 select_items.push_back (SeparatorElem());
2128 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2129 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2130 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2131 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2133 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2137 Menu *cutnpaste_menu = manage (new Menu);
2138 MenuList& cutnpaste_items = cutnpaste_menu->items();
2139 cutnpaste_menu->set_name ("ArdourContextMenu");
2141 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2142 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2143 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2145 Menu *nudge_menu = manage (new Menu());
2146 MenuList& nudge_items = nudge_menu->items();
2147 nudge_menu->set_name ("ArdourContextMenu");
2149 edit_items.push_back (SeparatorElem());
2150 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2151 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2152 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2153 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2155 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2159 Editor::snap_type() const
2165 Editor::snap_musical() const
2167 switch (_snap_type) {
2168 case SnapToBeatDiv128:
2169 case SnapToBeatDiv64:
2170 case SnapToBeatDiv32:
2171 case SnapToBeatDiv28:
2172 case SnapToBeatDiv24:
2173 case SnapToBeatDiv20:
2174 case SnapToBeatDiv16:
2175 case SnapToBeatDiv14:
2176 case SnapToBeatDiv12:
2177 case SnapToBeatDiv10:
2178 case SnapToBeatDiv8:
2179 case SnapToBeatDiv7:
2180 case SnapToBeatDiv6:
2181 case SnapToBeatDiv5:
2182 case SnapToBeatDiv4:
2183 case SnapToBeatDiv3:
2184 case SnapToBeatDiv2:
2196 Editor::snap_mode() const
2202 Editor::set_snap_to (SnapType st)
2204 unsigned int snap_ind = (unsigned int)st;
2206 if (internal_editing()) {
2207 internal_snap_type = st;
2209 pre_internal_snap_type = st;
2214 if (snap_ind > snap_type_strings.size() - 1) {
2216 _snap_type = (SnapType)snap_ind;
2219 string str = snap_type_strings[snap_ind];
2221 if (str != snap_type_selector.get_text()) {
2222 snap_type_selector.set_text (str);
2227 switch (_snap_type) {
2228 case SnapToBeatDiv128:
2229 case SnapToBeatDiv64:
2230 case SnapToBeatDiv32:
2231 case SnapToBeatDiv28:
2232 case SnapToBeatDiv24:
2233 case SnapToBeatDiv20:
2234 case SnapToBeatDiv16:
2235 case SnapToBeatDiv14:
2236 case SnapToBeatDiv12:
2237 case SnapToBeatDiv10:
2238 case SnapToBeatDiv8:
2239 case SnapToBeatDiv7:
2240 case SnapToBeatDiv6:
2241 case SnapToBeatDiv5:
2242 case SnapToBeatDiv4:
2243 case SnapToBeatDiv3:
2244 case SnapToBeatDiv2: {
2245 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2246 update_tempo_based_rulers ();
2250 case SnapToRegionStart:
2251 case SnapToRegionEnd:
2252 case SnapToRegionSync:
2253 case SnapToRegionBoundary:
2254 build_region_boundary_cache ();
2262 redisplay_tempo (false);
2264 SnapChanged (); /* EMIT SIGNAL */
2268 Editor::set_snap_mode (SnapMode mode)
2270 string str = snap_mode_strings[(int)mode];
2272 if (internal_editing()) {
2273 internal_snap_mode = mode;
2275 pre_internal_snap_mode = mode;
2280 if (str != snap_mode_selector.get_text ()) {
2281 snap_mode_selector.set_text (str);
2288 Editor::set_edit_point_preference (EditPoint ep, bool force)
2290 bool changed = (_edit_point != ep);
2293 if (Profile->get_mixbus())
2294 if (ep == EditAtSelectedMarker)
2295 ep = EditAtPlayhead;
2297 string str = edit_point_strings[(int)ep];
2298 if (str != edit_point_selector.get_text ()) {
2299 edit_point_selector.set_text (str);
2302 update_all_enter_cursors();
2304 if (!force && !changed) {
2308 const char* action=NULL;
2310 switch (_edit_point) {
2311 case EditAtPlayhead:
2312 action = "edit-at-playhead";
2314 case EditAtSelectedMarker:
2315 action = "edit-at-marker";
2318 action = "edit-at-mouse";
2322 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2324 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2328 bool in_track_canvas;
2330 if (!mouse_frame (foo, in_track_canvas)) {
2331 in_track_canvas = false;
2334 reset_canvas_action_sensitivity (in_track_canvas);
2340 Editor::set_state (const XMLNode& node, int version)
2342 XMLProperty const * prop;
2344 PBD::Unwinder<bool> nsi (no_save_instant, true);
2347 Tabbable::set_state (node, version);
2349 if (_session && (prop = node.property ("playhead"))) {
2351 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2353 playhead_cursor->set_position (pos);
2355 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2356 playhead_cursor->set_position (0);
2359 playhead_cursor->set_position (0);
2362 if ((prop = node.property ("mixer-width"))) {
2363 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2366 if ((prop = node.property ("zoom-focus"))) {
2367 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2369 zoom_focus_selection_done (zoom_focus);
2372 if ((prop = node.property ("zoom"))) {
2373 /* older versions of ardour used floating point samples_per_pixel */
2374 double f = PBD::atof (prop->value());
2375 reset_zoom (llrintf (f));
2377 reset_zoom (samples_per_pixel);
2380 if ((prop = node.property ("visible-track-count"))) {
2381 set_visible_track_count (PBD::atoi (prop->value()));
2384 if ((prop = node.property ("snap-to"))) {
2385 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2386 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2388 set_snap_to (_snap_type);
2391 if ((prop = node.property ("snap-mode"))) {
2392 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2393 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2394 * snap_mode_selection_done() will only mark an already active item as active
2395 * which does not trigger set_text().
2397 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2399 set_snap_mode (_snap_mode);
2402 if ((prop = node.property ("internal-snap-to"))) {
2403 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2406 if ((prop = node.property ("internal-snap-mode"))) {
2407 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2410 if ((prop = node.property ("pre-internal-snap-to"))) {
2411 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2414 if ((prop = node.property ("pre-internal-snap-mode"))) {
2415 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2418 if ((prop = node.property ("mouse-mode"))) {
2419 MouseMode m = str2mousemode(prop->value());
2420 set_mouse_mode (m, true);
2422 set_mouse_mode (MouseObject, true);
2425 if ((prop = node.property ("left-frame")) != 0) {
2427 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2431 reset_x_origin (pos);
2435 if ((prop = node.property ("y-origin")) != 0) {
2436 reset_y_origin (atof (prop->value ()));
2439 if ((prop = node.property ("join-object-range"))) {
2440 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2441 bool yn = string_is_affirmative (prop->value());
2443 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2444 tact->set_active (!yn);
2445 tact->set_active (yn);
2447 set_mouse_mode(mouse_mode, true);
2450 if ((prop = node.property ("edit-point"))) {
2451 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2453 set_edit_point_preference (_edit_point);
2456 if ((prop = node.property ("show-measures"))) {
2457 bool yn = string_is_affirmative (prop->value());
2458 _show_measures = yn;
2461 if ((prop = node.property ("follow-playhead"))) {
2462 bool yn = string_is_affirmative (prop->value());
2463 set_follow_playhead (yn);
2466 if ((prop = node.property ("stationary-playhead"))) {
2467 bool yn = string_is_affirmative (prop->value());
2468 set_stationary_playhead (yn);
2471 if ((prop = node.property ("region-list-sort-type"))) {
2472 RegionListSortType st;
2473 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2476 if ((prop = node.property ("show-editor-mixer"))) {
2478 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2481 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2482 bool yn = string_is_affirmative (prop->value());
2484 /* do it twice to force the change */
2486 tact->set_active (!yn);
2487 tact->set_active (yn);
2490 if ((prop = node.property ("show-editor-list"))) {
2492 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2495 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2496 bool yn = string_is_affirmative (prop->value());
2498 /* do it twice to force the change */
2500 tact->set_active (!yn);
2501 tact->set_active (yn);
2504 if ((prop = node.property (X_("editor-list-page")))) {
2505 _the_notebook.set_current_page (atoi (prop->value ()));
2508 if ((prop = node.property (X_("show-marker-lines")))) {
2509 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2511 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2512 bool yn = string_is_affirmative (prop->value ());
2514 tact->set_active (!yn);
2515 tact->set_active (yn);
2518 XMLNodeList children = node.children ();
2519 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2520 selection->set_state (**i, Stateful::current_state_version);
2521 _regions->set_state (**i);
2524 if ((prop = node.property ("maximised"))) {
2525 bool yn = string_is_affirmative (prop->value());
2526 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2528 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2529 bool fs = tact && tact->get_active();
2531 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2535 if ((prop = node.property ("nudge-clock-value"))) {
2537 sscanf (prop->value().c_str(), "%" PRId64, &f);
2538 nudge_clock->set (f);
2540 nudge_clock->set_mode (AudioClock::Timecode);
2541 nudge_clock->set (_session->frame_rate() * 5, true);
2546 * Not all properties may have been in XML, but
2547 * those that are linked to a private variable may need changing
2552 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2554 yn = _show_measures;
2555 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2556 /* do it twice to force the change */
2557 tact->set_active (!yn);
2558 tact->set_active (yn);
2561 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2562 yn = _follow_playhead;
2564 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2565 if (tact->get_active() != yn) {
2566 tact->set_active (yn);
2570 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2571 yn = _stationary_playhead;
2573 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2574 if (tact->get_active() != yn) {
2575 tact->set_active (yn);
2580 return LuaInstance::instance()->set_state(node);
2584 Editor::get_state ()
2586 XMLNode* node = new XMLNode (X_("Editor"));
2590 id().print (buf, sizeof (buf));
2591 node->add_property ("id", buf);
2593 node->add_child_nocopy (Tabbable::get_state());
2595 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2596 node->add_property("edit-horizontal-pane-pos", string(buf));
2597 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2598 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2599 node->add_property("edit-vertical-pane-pos", string(buf));
2601 maybe_add_mixer_strip_width (*node);
2603 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2605 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2606 node->add_property ("zoom", buf);
2607 node->add_property ("snap-to", enum_2_string (_snap_type));
2608 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2609 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2610 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2611 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2612 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2613 node->add_property ("edit-point", enum_2_string (_edit_point));
2614 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2615 node->add_property ("visible-track-count", buf);
2617 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2618 node->add_property ("playhead", buf);
2619 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2620 node->add_property ("left-frame", buf);
2621 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2622 node->add_property ("y-origin", buf);
2624 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2625 node->add_property ("maximised", _maximised ? "yes" : "no");
2626 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2627 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2628 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2629 node->add_property ("mouse-mode", enum2str(mouse_mode));
2630 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2632 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2634 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2635 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2638 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2640 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2641 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2644 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2645 node->add_property (X_("editor-list-page"), buf);
2647 if (button_bindings) {
2648 XMLNode* bb = new XMLNode (X_("Buttons"));
2649 button_bindings->save (*bb);
2650 node->add_child_nocopy (*bb);
2653 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2655 node->add_child_nocopy (selection->get_state ());
2656 node->add_child_nocopy (_regions->get_state ());
2658 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2659 node->add_property ("nudge-clock-value", buf);
2661 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2662 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2667 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2668 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2670 * @return pair: TimeAxisView that y is over, layer index.
2672 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2673 * in stacked or expanded region display mode, otherwise 0.
2675 std::pair<TimeAxisView *, double>
2676 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2678 if (!trackview_relative_offset) {
2679 y -= _trackview_group->canvas_origin().y;
2683 return std::make_pair ( (TimeAxisView *) 0, 0);
2686 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2688 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2695 return std::make_pair ( (TimeAxisView *) 0, 0);
2698 /** Snap a position to the grid, if appropriate, taking into account current
2699 * grid settings and also the state of any snap modifier keys that may be pressed.
2700 * @param start Position to snap.
2701 * @param event Event to get current key modifier information from, or 0.
2704 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2706 if (!_session || !event) {
2710 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2711 if (_snap_mode == SnapOff) {
2712 snap_to_internal (start, direction, for_mark);
2715 if (_snap_mode != SnapOff) {
2716 snap_to_internal (start, direction, for_mark);
2717 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2718 /* SnapOff, but we pressed the snap_delta modifier */
2719 snap_to_internal (start, direction, for_mark);
2725 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2727 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2731 snap_to_internal (start, direction, for_mark, ensure_snap);
2735 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2737 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2738 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2740 switch (_snap_type) {
2741 case SnapToTimecodeFrame:
2742 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2743 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2744 /* start is already on a whole timecode frame, do nothing */
2745 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2746 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2748 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2752 case SnapToTimecodeSeconds:
2753 if (_session->config.get_timecode_offset_negative()) {
2754 start += _session->config.get_timecode_offset ();
2756 start -= _session->config.get_timecode_offset ();
2758 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2759 (start % one_timecode_second == 0)) {
2760 /* start is already on a whole second, do nothing */
2761 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2762 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2764 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2767 if (_session->config.get_timecode_offset_negative()) {
2768 start -= _session->config.get_timecode_offset ();
2770 start += _session->config.get_timecode_offset ();
2774 case SnapToTimecodeMinutes:
2775 if (_session->config.get_timecode_offset_negative()) {
2776 start += _session->config.get_timecode_offset ();
2778 start -= _session->config.get_timecode_offset ();
2780 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2781 (start % one_timecode_minute == 0)) {
2782 /* start is already on a whole minute, do nothing */
2783 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2784 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2786 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2788 if (_session->config.get_timecode_offset_negative()) {
2789 start -= _session->config.get_timecode_offset ();
2791 start += _session->config.get_timecode_offset ();
2795 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2796 abort(); /*NOTREACHED*/
2801 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2803 const framepos_t one_second = _session->frame_rate();
2804 const framepos_t one_minute = _session->frame_rate() * 60;
2805 framepos_t presnap = start;
2809 switch (_snap_type) {
2810 case SnapToTimecodeFrame:
2811 case SnapToTimecodeSeconds:
2812 case SnapToTimecodeMinutes:
2813 return timecode_snap_to_internal (start, direction, for_mark);
2816 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2817 start % (one_second/75) == 0) {
2818 /* start is already on a whole CD frame, do nothing */
2819 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2820 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2822 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2827 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2828 start % one_second == 0) {
2829 /* start is already on a whole second, do nothing */
2830 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2831 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2833 start = (framepos_t) floor ((double) start / one_second) * one_second;
2838 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2839 start % one_minute == 0) {
2840 /* start is already on a whole minute, do nothing */
2841 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2842 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2844 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2849 start = _session->tempo_map().round_to_bar (start, direction);
2853 start = _session->tempo_map().round_to_beat (start, direction);
2856 case SnapToBeatDiv128:
2857 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2859 case SnapToBeatDiv64:
2860 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2862 case SnapToBeatDiv32:
2863 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2865 case SnapToBeatDiv28:
2866 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2868 case SnapToBeatDiv24:
2869 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2871 case SnapToBeatDiv20:
2872 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2874 case SnapToBeatDiv16:
2875 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2877 case SnapToBeatDiv14:
2878 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2880 case SnapToBeatDiv12:
2881 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2883 case SnapToBeatDiv10:
2884 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2886 case SnapToBeatDiv8:
2887 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2889 case SnapToBeatDiv7:
2890 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2892 case SnapToBeatDiv6:
2893 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2895 case SnapToBeatDiv5:
2896 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2898 case SnapToBeatDiv4:
2899 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2901 case SnapToBeatDiv3:
2902 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2904 case SnapToBeatDiv2:
2905 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2913 _session->locations()->marks_either_side (start, before, after);
2915 if (before == max_framepos && after == max_framepos) {
2916 /* No marks to snap to, so just don't snap */
2918 } else if (before == max_framepos) {
2920 } else if (after == max_framepos) {
2922 } else if (before != max_framepos && after != max_framepos) {
2923 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2925 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2927 else if (direction == 0 ) {
2928 if ((start - before) < (after - start)) {
2938 case SnapToRegionStart:
2939 case SnapToRegionEnd:
2940 case SnapToRegionSync:
2941 case SnapToRegionBoundary:
2942 if (!region_boundary_cache.empty()) {
2944 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2945 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2947 if (direction > 0) {
2948 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2950 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2953 if (next != region_boundary_cache.begin ()) {
2958 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2959 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2961 if (start > (p + n) / 2) {
2970 switch (_snap_mode) {
2980 if (presnap > start) {
2981 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2985 } else if (presnap < start) {
2986 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2992 /* handled at entry */
3000 Editor::setup_toolbar ()
3002 HBox* mode_box = manage(new HBox);
3003 mode_box->set_border_width (2);
3004 mode_box->set_spacing(2);
3006 HBox* mouse_mode_box = manage (new HBox);
3007 HBox* mouse_mode_hbox = manage (new HBox);
3008 VBox* mouse_mode_vbox = manage (new VBox);
3009 Alignment* mouse_mode_align = manage (new Alignment);
3011 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3012 mouse_mode_size_group->add_widget (smart_mode_button);
3013 mouse_mode_size_group->add_widget (mouse_move_button);
3014 mouse_mode_size_group->add_widget (mouse_cut_button);
3015 mouse_mode_size_group->add_widget (mouse_select_button);
3016 mouse_mode_size_group->add_widget (mouse_timefx_button);
3017 mouse_mode_size_group->add_widget (mouse_audition_button);
3018 mouse_mode_size_group->add_widget (mouse_draw_button);
3019 mouse_mode_size_group->add_widget (mouse_content_button);
3021 mouse_mode_size_group->add_widget (zoom_in_button);
3022 mouse_mode_size_group->add_widget (zoom_out_button);
3023 mouse_mode_size_group->add_widget (zoom_preset_selector);
3024 mouse_mode_size_group->add_widget (zoom_out_full_button);
3025 mouse_mode_size_group->add_widget (zoom_focus_selector);
3027 mouse_mode_size_group->add_widget (tav_shrink_button);
3028 mouse_mode_size_group->add_widget (tav_expand_button);
3029 mouse_mode_size_group->add_widget (visible_tracks_selector);
3031 mouse_mode_size_group->add_widget (snap_type_selector);
3032 mouse_mode_size_group->add_widget (snap_mode_selector);
3034 mouse_mode_size_group->add_widget (edit_point_selector);
3035 mouse_mode_size_group->add_widget (edit_mode_selector);
3037 mouse_mode_size_group->add_widget (*nudge_clock);
3038 mouse_mode_size_group->add_widget (nudge_forward_button);
3039 mouse_mode_size_group->add_widget (nudge_backward_button);
3041 mouse_mode_hbox->set_spacing (2);
3043 if (!ARDOUR::Profile->get_trx()) {
3044 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3047 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3048 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3050 if (!ARDOUR::Profile->get_mixbus()) {
3051 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3054 if (!ARDOUR::Profile->get_trx()) {
3055 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3056 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3057 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3058 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3061 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3063 mouse_mode_align->add (*mouse_mode_vbox);
3064 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3066 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3068 edit_mode_selector.set_name ("mouse mode button");
3070 if (!ARDOUR::Profile->get_trx()) {
3071 mode_box->pack_start (edit_mode_selector, false, false);
3074 mode_box->pack_start (*mouse_mode_box, false, false);
3078 _zoom_box.set_spacing (2);
3079 _zoom_box.set_border_width (2);
3083 zoom_preset_selector.set_name ("zoom button");
3084 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3085 zoom_preset_selector.set_size_request (42, -1);
3087 zoom_in_button.set_name ("zoom button");
3088 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3089 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3090 zoom_in_button.set_related_action (act);
3092 zoom_out_button.set_name ("zoom button");
3093 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3094 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3095 zoom_out_button.set_related_action (act);
3097 zoom_out_full_button.set_name ("zoom button");
3098 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3099 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3100 zoom_out_full_button.set_related_action (act);
3102 zoom_focus_selector.set_name ("zoom button");
3104 if (ARDOUR::Profile->get_mixbus()) {
3105 _zoom_box.pack_start (zoom_preset_selector, false, false);
3106 } else if (ARDOUR::Profile->get_trx()) {
3107 mode_box->pack_start (zoom_out_button, false, false);
3108 mode_box->pack_start (zoom_in_button, false, false);
3110 _zoom_box.pack_start (zoom_out_button, false, false);
3111 _zoom_box.pack_start (zoom_in_button, false, false);
3112 _zoom_box.pack_start (zoom_out_full_button, false, false);
3113 _zoom_box.pack_start (zoom_focus_selector, false, false);
3116 /* Track zoom buttons */
3117 _track_box.set_spacing (2);
3118 _track_box.set_border_width (2);
3120 visible_tracks_selector.set_name ("zoom button");
3121 if (Profile->get_mixbus()) {
3122 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3123 visible_tracks_selector.set_size_request (42, -1);
3125 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3128 tav_expand_button.set_name ("zoom button");
3129 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3130 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3131 tav_expand_button.set_related_action (act);
3133 tav_shrink_button.set_name ("zoom button");
3134 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3135 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3136 tav_shrink_button.set_related_action (act);
3138 if (ARDOUR::Profile->get_mixbus()) {
3139 _track_box.pack_start (visible_tracks_selector);
3140 } else if (ARDOUR::Profile->get_trx()) {
3141 _track_box.pack_start (tav_shrink_button);
3142 _track_box.pack_start (tav_expand_button);
3144 _track_box.pack_start (visible_tracks_selector);
3145 _track_box.pack_start (tav_shrink_button);
3146 _track_box.pack_start (tav_expand_button);
3149 snap_box.set_spacing (2);
3150 snap_box.set_border_width (2);
3152 snap_type_selector.set_name ("mouse mode button");
3154 snap_mode_selector.set_name ("mouse mode button");
3156 edit_point_selector.set_name ("mouse mode button");
3158 snap_box.pack_start (snap_mode_selector, false, false);
3159 snap_box.pack_start (snap_type_selector, false, false);
3162 HBox *ep_box = manage (new HBox);
3163 ep_box->set_spacing (2);
3164 ep_box->set_border_width (2);
3166 ep_box->pack_start (edit_point_selector, false, false);
3170 HBox *nudge_box = manage (new HBox);
3171 nudge_box->set_spacing (2);
3172 nudge_box->set_border_width (2);
3174 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3175 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3177 nudge_box->pack_start (nudge_backward_button, false, false);
3178 nudge_box->pack_start (nudge_forward_button, false, false);
3179 nudge_box->pack_start (*nudge_clock, false, false);
3182 /* Pack everything in... */
3184 toolbar_hbox.set_spacing (2);
3185 toolbar_hbox.set_border_width (2);
3187 toolbar_hbox.pack_start (*mode_box, false, false);
3189 if (!ARDOUR::Profile->get_trx()) {
3191 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3193 toolbar_hbox.pack_start (_zoom_box, false, false);
3195 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3197 toolbar_hbox.pack_start (_track_box, false, false);
3199 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3201 toolbar_hbox.pack_start (snap_box, false, false);
3203 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3205 toolbar_hbox.pack_start (*ep_box, false, false);
3207 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3209 toolbar_hbox.pack_start (*nudge_box, false, false);
3212 toolbar_hbox.show_all ();
3216 Editor::build_edit_point_menu ()
3218 using namespace Menu_Helpers;
3220 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3221 if(!Profile->get_mixbus())
3222 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3223 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3225 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3229 Editor::build_edit_mode_menu ()
3231 using namespace Menu_Helpers;
3233 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3234 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3235 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3236 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3238 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3242 Editor::build_snap_mode_menu ()
3244 using namespace Menu_Helpers;
3246 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3247 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3248 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3250 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3254 Editor::build_snap_type_menu ()
3256 using namespace Menu_Helpers;
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3273 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3274 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3275 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3276 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3277 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3278 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3279 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3280 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3281 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3282 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3283 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3284 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3287 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3289 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3294 Editor::setup_tooltips ()
3296 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3297 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3298 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3299 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3300 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3301 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3302 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3303 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3304 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3305 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3306 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3307 set_tooltip (zoom_in_button, _("Zoom In"));
3308 set_tooltip (zoom_out_button, _("Zoom Out"));
3309 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3310 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3311 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3312 set_tooltip (tav_expand_button, _("Expand Tracks"));
3313 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3314 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3315 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3316 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3317 set_tooltip (edit_point_selector, _("Edit Point"));
3318 set_tooltip (edit_mode_selector, _("Edit Mode"));
3319 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3323 Editor::convert_drop_to_paths (
3324 vector<string>& paths,
3325 const RefPtr<Gdk::DragContext>& /*context*/,
3328 const SelectionData& data,
3332 if (_session == 0) {
3336 vector<string> uris = data.get_uris();
3340 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3341 are actually URI lists. So do it by hand.
3344 if (data.get_target() != "text/plain") {
3348 /* Parse the "uri-list" format that Nautilus provides,
3349 where each pathname is delimited by \r\n.
3351 THERE MAY BE NO NULL TERMINATING CHAR!!!
3354 string txt = data.get_text();
3358 p = (char *) malloc (txt.length() + 1);
3359 txt.copy (p, txt.length(), 0);
3360 p[txt.length()] = '\0';
3366 while (g_ascii_isspace (*p))
3370 while (*q && (*q != '\n') && (*q != '\r')) {
3377 while (q > p && g_ascii_isspace (*q))
3382 uris.push_back (string (p, q - p + 1));
3386 p = strchr (p, '\n');
3398 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3399 if ((*i).substr (0,7) == "file://") {
3400 paths.push_back (Glib::filename_from_uri (*i));
3408 Editor::new_tempo_section ()
3413 Editor::map_transport_state ()
3415 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3417 if (_session && _session->transport_stopped()) {
3418 have_pending_keyboard_selection = false;
3421 update_loop_range_view ();
3427 Editor::begin_selection_op_history ()
3429 selection_op_cmd_depth = 0;
3430 selection_op_history_it = 0;
3432 while(!selection_op_history.empty()) {
3433 delete selection_op_history.front();
3434 selection_op_history.pop_front();
3437 selection_undo_action->set_sensitive (false);
3438 selection_redo_action->set_sensitive (false);
3439 selection_op_history.push_front (&_selection_memento->get_state ());
3443 Editor::begin_reversible_selection_op (string name)
3446 //cerr << name << endl;
3447 /* begin/commit pairs can be nested */
3448 selection_op_cmd_depth++;
3453 Editor::commit_reversible_selection_op ()
3456 if (selection_op_cmd_depth == 1) {
3458 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3460 The user has undone some selection ops and then made a new one,
3461 making anything earlier in the list invalid.
3464 list<XMLNode *>::iterator it = selection_op_history.begin();
3465 list<XMLNode *>::iterator e_it = it;
3466 advance (e_it, selection_op_history_it);
3468 for ( ; it != e_it; ++it) {
3471 selection_op_history.erase (selection_op_history.begin(), e_it);
3474 selection_op_history.push_front (&_selection_memento->get_state ());
3475 selection_op_history_it = 0;
3477 selection_undo_action->set_sensitive (true);
3478 selection_redo_action->set_sensitive (false);
3481 if (selection_op_cmd_depth > 0) {
3482 selection_op_cmd_depth--;
3488 Editor::undo_selection_op ()
3491 selection_op_history_it++;
3493 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3494 if (n == selection_op_history_it) {
3495 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3496 selection_redo_action->set_sensitive (true);
3500 /* is there an earlier entry? */
3501 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3502 selection_undo_action->set_sensitive (false);
3508 Editor::redo_selection_op ()
3511 if (selection_op_history_it > 0) {
3512 selection_op_history_it--;
3515 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3516 if (n == selection_op_history_it) {
3517 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3518 selection_undo_action->set_sensitive (true);
3523 if (selection_op_history_it == 0) {
3524 selection_redo_action->set_sensitive (false);
3530 Editor::begin_reversible_command (string name)
3533 before.push_back (&_selection_memento->get_state ());
3534 _session->begin_reversible_command (name);
3539 Editor::begin_reversible_command (GQuark q)
3542 before.push_back (&_selection_memento->get_state ());
3543 _session->begin_reversible_command (q);
3548 Editor::abort_reversible_command ()
3551 while(!before.empty()) {
3552 delete before.front();
3555 _session->abort_reversible_command ();
3560 Editor::commit_reversible_command ()
3563 if (before.size() == 1) {
3564 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3565 redo_action->set_sensitive(false);
3566 undo_action->set_sensitive(true);
3567 begin_selection_op_history ();
3570 if (before.empty()) {
3571 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3576 _session->commit_reversible_command ();
3581 Editor::history_changed ()
3585 if (undo_action && _session) {
3586 if (_session->undo_depth() == 0) {
3587 label = S_("Command|Undo");
3589 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3591 undo_action->property_label() = label;
3594 if (redo_action && _session) {
3595 if (_session->redo_depth() == 0) {
3597 redo_action->set_sensitive (false);
3599 label = string_compose(_("Redo (%1)"), _session->next_redo());
3600 redo_action->set_sensitive (true);
3602 redo_action->property_label() = label;
3607 Editor::duplicate_range (bool with_dialog)
3611 RegionSelection rs = get_regions_from_selection_and_entered ();
3613 if ( selection->time.length() == 0 && rs.empty()) {
3619 ArdourDialog win (_("Duplicate"));
3620 Label label (_("Number of duplications:"));
3621 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3622 SpinButton spinner (adjustment, 0.0, 1);
3625 win.get_vbox()->set_spacing (12);
3626 win.get_vbox()->pack_start (hbox);
3627 hbox.set_border_width (6);
3628 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3630 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3631 place, visually. so do this by hand.
3634 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3635 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3636 spinner.grab_focus();
3642 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3643 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3644 win.set_default_response (RESPONSE_ACCEPT);
3646 spinner.grab_focus ();
3648 switch (win.run ()) {
3649 case RESPONSE_ACCEPT:
3655 times = adjustment.get_value();
3658 if ((current_mouse_mode() == Editing::MouseRange)) {
3659 if (selection->time.length()) {
3660 duplicate_selection (times);
3662 } else if (get_smart_mode()) {
3663 if (selection->time.length()) {
3664 duplicate_selection (times);
3666 duplicate_some_regions (rs, times);
3668 duplicate_some_regions (rs, times);
3673 Editor::set_edit_mode (EditMode m)
3675 Config->set_edit_mode (m);
3679 Editor::cycle_edit_mode ()
3681 switch (Config->get_edit_mode()) {
3683 Config->set_edit_mode (Ripple);
3687 Config->set_edit_mode (Lock);
3690 Config->set_edit_mode (Slide);
3696 Editor::edit_mode_selection_done ( EditMode m )
3698 Config->set_edit_mode ( m );
3702 Editor::snap_type_selection_done (SnapType snaptype)
3704 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3706 ract->set_active ();
3711 Editor::snap_mode_selection_done (SnapMode mode)
3713 RefPtr<RadioAction> ract = snap_mode_action (mode);
3716 ract->set_active (true);
3721 Editor::cycle_edit_point (bool with_marker)
3723 if(Profile->get_mixbus())
3724 with_marker = false;
3726 switch (_edit_point) {
3728 set_edit_point_preference (EditAtPlayhead);
3730 case EditAtPlayhead:
3732 set_edit_point_preference (EditAtSelectedMarker);
3734 set_edit_point_preference (EditAtMouse);
3737 case EditAtSelectedMarker:
3738 set_edit_point_preference (EditAtMouse);
3744 Editor::edit_point_selection_done (EditPoint ep)
3746 set_edit_point_preference ( ep );
3750 Editor::build_zoom_focus_menu ()
3752 using namespace Menu_Helpers;
3754 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3755 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3756 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3757 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3758 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3759 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3761 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3765 Editor::zoom_focus_selection_done ( ZoomFocus f )
3767 RefPtr<RadioAction> ract = zoom_focus_action (f);
3769 ract->set_active ();
3774 Editor::build_track_count_menu ()
3776 using namespace Menu_Helpers;
3778 if (!Profile->get_mixbus()) {
3779 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3790 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3791 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3793 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3794 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3795 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3796 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3797 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3798 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3799 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3800 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3801 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3802 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3804 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3805 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3806 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3807 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3808 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3809 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3810 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3811 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3812 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3813 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3814 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3819 Editor::set_zoom_preset (int64_t ms)
3822 temporal_zoom_session();
3826 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3827 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3831 Editor::set_visible_track_count (int32_t n)
3833 _visible_track_count = n;
3835 /* if the canvas hasn't really been allocated any size yet, just
3836 record the desired number of visible tracks and return. when canvas
3837 allocation happens, we will get called again and then we can do the
3841 if (_visible_canvas_height <= 1) {
3847 DisplaySuspender ds;
3849 if (_visible_track_count > 0) {
3850 h = trackviews_height() / _visible_track_count;
3851 std::ostringstream s;
3852 s << _visible_track_count;
3854 } else if (_visible_track_count == 0) {
3856 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3857 if ((*i)->marked_for_display()) {
3861 h = trackviews_height() / n;
3864 /* negative value means that the visible track count has
3865 been overridden by explicit track height changes.
3867 visible_tracks_selector.set_text (X_("*"));
3871 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3872 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3875 if (str != visible_tracks_selector.get_text()) {
3876 visible_tracks_selector.set_text (str);
3881 Editor::override_visible_track_count ()
3883 _visible_track_count = -1;
3884 visible_tracks_selector.set_text ( _("*") );
3888 Editor::edit_controls_button_release (GdkEventButton* ev)
3890 if (Keyboard::is_context_menu_event (ev)) {
3891 ARDOUR_UI::instance()->add_route ();
3892 } else if (ev->button == 1) {
3893 selection->clear_tracks ();
3900 Editor::mouse_select_button_release (GdkEventButton* ev)
3902 /* this handles just right-clicks */
3904 if (ev->button != 3) {
3912 Editor::set_zoom_focus (ZoomFocus f)
3914 string str = zoom_focus_strings[(int)f];
3916 if (str != zoom_focus_selector.get_text()) {
3917 zoom_focus_selector.set_text (str);
3920 if (zoom_focus != f) {
3927 Editor::cycle_zoom_focus ()
3929 switch (zoom_focus) {
3931 set_zoom_focus (ZoomFocusRight);
3933 case ZoomFocusRight:
3934 set_zoom_focus (ZoomFocusCenter);
3936 case ZoomFocusCenter:
3937 set_zoom_focus (ZoomFocusPlayhead);
3939 case ZoomFocusPlayhead:
3940 set_zoom_focus (ZoomFocusMouse);
3942 case ZoomFocusMouse:
3943 set_zoom_focus (ZoomFocusEdit);
3946 set_zoom_focus (ZoomFocusLeft);
3952 Editor::set_show_measures (bool yn)
3954 if (_show_measures != yn) {
3957 if ((_show_measures = yn) == true) {
3959 tempo_lines->show();
3962 std::vector<TempoMap::BBTPoint> grid;
3963 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3964 draw_measures (grid);
3972 Editor::toggle_follow_playhead ()
3974 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3976 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3977 set_follow_playhead (tact->get_active());
3981 /** @param yn true to follow playhead, otherwise false.
3982 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3985 Editor::set_follow_playhead (bool yn, bool catch_up)
3987 if (_follow_playhead != yn) {
3988 if ((_follow_playhead = yn) == true && catch_up) {
3990 reset_x_origin_to_follow_playhead ();
3997 Editor::toggle_stationary_playhead ()
3999 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4001 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4002 set_stationary_playhead (tact->get_active());
4007 Editor::set_stationary_playhead (bool yn)
4009 if (_stationary_playhead != yn) {
4010 if ((_stationary_playhead = yn) == true) {
4012 // FIXME need a 3.0 equivalent of this 2.X call
4013 // update_current_screen ();
4020 Editor::playlist_selector () const
4022 return *_playlist_selector;
4026 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4028 if (paste_count == 0) {
4029 /* don't bother calculating an offset that will be zero anyway */
4033 /* calculate basic unsnapped multi-paste offset */
4034 framecnt_t offset = paste_count * duration;
4036 /* snap offset so pos + offset is aligned to the grid */
4037 framepos_t offset_pos = pos + offset;
4038 snap_to(offset_pos, RoundUpMaybe);
4039 offset = offset_pos - pos;
4045 Editor::get_grid_beat_divisions(framepos_t position)
4047 switch (_snap_type) {
4048 case SnapToBeatDiv128: return 128;
4049 case SnapToBeatDiv64: return 64;
4050 case SnapToBeatDiv32: return 32;
4051 case SnapToBeatDiv28: return 28;
4052 case SnapToBeatDiv24: return 24;
4053 case SnapToBeatDiv20: return 20;
4054 case SnapToBeatDiv16: return 16;
4055 case SnapToBeatDiv14: return 14;
4056 case SnapToBeatDiv12: return 12;
4057 case SnapToBeatDiv10: return 10;
4058 case SnapToBeatDiv8: return 8;
4059 case SnapToBeatDiv7: return 7;
4060 case SnapToBeatDiv6: return 6;
4061 case SnapToBeatDiv5: return 5;
4062 case SnapToBeatDiv4: return 4;
4063 case SnapToBeatDiv3: return 3;
4064 case SnapToBeatDiv2: return 2;
4070 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4071 if the grid is non-musical, returns 0.
4072 if the grid is snapped to bars, returns -1.
4073 @param event_state the current keyboard modifier mask.
4076 Editor::get_grid_music_divisions (uint32_t event_state)
4078 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4082 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4086 switch (_snap_type) {
4087 case SnapToBeatDiv128: return 128;
4088 case SnapToBeatDiv64: return 64;
4089 case SnapToBeatDiv32: return 32;
4090 case SnapToBeatDiv28: return 28;
4091 case SnapToBeatDiv24: return 24;
4092 case SnapToBeatDiv20: return 20;
4093 case SnapToBeatDiv16: return 16;
4094 case SnapToBeatDiv14: return 14;
4095 case SnapToBeatDiv12: return 12;
4096 case SnapToBeatDiv10: return 10;
4097 case SnapToBeatDiv8: return 8;
4098 case SnapToBeatDiv7: return 7;
4099 case SnapToBeatDiv6: return 6;
4100 case SnapToBeatDiv5: return 5;
4101 case SnapToBeatDiv4: return 4;
4102 case SnapToBeatDiv3: return 3;
4103 case SnapToBeatDiv2: return 2;
4104 case SnapToBeat: return 1;
4105 case SnapToBar : return -1;
4112 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4116 const unsigned divisions = get_grid_beat_divisions(position);
4118 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4121 switch (_snap_type) {
4123 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4126 const Meter& m = _session->tempo_map().meter_at_frame (position);
4127 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4135 return Evoral::Beats();
4139 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4143 ret = nudge_clock->current_duration (pos);
4144 next = ret + 1; /* XXXX fix me */
4150 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4152 ArdourDialog dialog (_("Playlist Deletion"));
4153 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4154 "If it is kept, its audio files will not be cleaned.\n"
4155 "If it is deleted, audio files used by it alone will be cleaned."),
4158 dialog.set_position (WIN_POS_CENTER);
4159 dialog.get_vbox()->pack_start (label);
4163 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4164 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4165 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4166 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4167 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4169 // by default gtk uses the left most button
4170 keep->grab_focus ();
4172 switch (dialog.run ()) {
4174 /* keep this and all remaining ones */
4179 /* delete this and all others */
4183 case RESPONSE_ACCEPT:
4184 /* delete the playlist */
4188 case RESPONSE_REJECT:
4189 /* keep the playlist */
4201 Editor::audio_region_selection_covers (framepos_t where)
4203 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4204 if ((*a)->region()->covers (where)) {
4213 Editor::prepare_for_cleanup ()
4215 cut_buffer->clear_regions ();
4216 cut_buffer->clear_playlists ();
4218 selection->clear_regions ();
4219 selection->clear_playlists ();
4221 _regions->suspend_redisplay ();
4225 Editor::finish_cleanup ()
4227 _regions->resume_redisplay ();
4231 Editor::transport_loop_location()
4234 return _session->locations()->auto_loop_location();
4241 Editor::transport_punch_location()
4244 return _session->locations()->auto_punch_location();
4251 Editor::control_layout_scroll (GdkEventScroll* ev)
4253 /* Just forward to the normal canvas scroll method. The coordinate
4254 systems are different but since the canvas is always larger than the
4255 track headers, and aligned with the trackview area, this will work.
4257 In the not too distant future this layout is going away anyway and
4258 headers will be on the canvas.
4260 return canvas_scroll_event (ev, false);
4264 Editor::session_state_saved (string)
4267 _snapshots->redisplay ();
4271 Editor::maximise_editing_space ()
4277 Gtk::Window* toplevel = current_toplevel();
4280 toplevel->fullscreen ();
4286 Editor::restore_editing_space ()
4292 Gtk::Window* toplevel = current_toplevel();
4295 toplevel->unfullscreen();
4301 * Make new playlists for a given track and also any others that belong
4302 * to the same active route group with the `select' property.
4307 Editor::new_playlists (TimeAxisView* v)
4309 begin_reversible_command (_("new playlists"));
4310 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4311 _session->playlists->get (playlists);
4312 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4313 commit_reversible_command ();
4317 * Use a copy of the current playlist for a given track and also any others that belong
4318 * to the same active route group with the `select' property.
4323 Editor::copy_playlists (TimeAxisView* v)
4325 begin_reversible_command (_("copy playlists"));
4326 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4327 _session->playlists->get (playlists);
4328 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4329 commit_reversible_command ();
4332 /** Clear the current playlist for a given track and also any others that belong
4333 * to the same active route group with the `select' property.
4338 Editor::clear_playlists (TimeAxisView* v)
4340 begin_reversible_command (_("clear playlists"));
4341 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4342 _session->playlists->get (playlists);
4343 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4344 commit_reversible_command ();
4348 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4350 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4354 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4356 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4360 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4362 atv.clear_playlist ();
4366 Editor::get_y_origin () const
4368 return vertical_adjustment.get_value ();
4371 /** Queue up a change to the viewport x origin.
4372 * @param frame New x origin.
4375 Editor::reset_x_origin (framepos_t frame)
4377 pending_visual_change.add (VisualChange::TimeOrigin);
4378 pending_visual_change.time_origin = frame;
4379 ensure_visual_change_idle_handler ();
4383 Editor::reset_y_origin (double y)
4385 pending_visual_change.add (VisualChange::YOrigin);
4386 pending_visual_change.y_origin = y;
4387 ensure_visual_change_idle_handler ();
4391 Editor::reset_zoom (framecnt_t spp)
4393 if (spp == samples_per_pixel) {
4397 pending_visual_change.add (VisualChange::ZoomLevel);
4398 pending_visual_change.samples_per_pixel = spp;
4399 ensure_visual_change_idle_handler ();
4403 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4405 reset_x_origin (frame);
4408 if (!no_save_visual) {
4409 undo_visual_stack.push_back (current_visual_state(false));
4413 Editor::VisualState::VisualState (bool with_tracks)
4414 : gui_state (with_tracks ? new GUIObjectState : 0)
4418 Editor::VisualState::~VisualState ()
4423 Editor::VisualState*
4424 Editor::current_visual_state (bool with_tracks)
4426 VisualState* vs = new VisualState (with_tracks);
4427 vs->y_position = vertical_adjustment.get_value();
4428 vs->samples_per_pixel = samples_per_pixel;
4429 vs->leftmost_frame = leftmost_frame;
4430 vs->zoom_focus = zoom_focus;
4433 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4440 Editor::undo_visual_state ()
4442 if (undo_visual_stack.empty()) {
4446 VisualState* vs = undo_visual_stack.back();
4447 undo_visual_stack.pop_back();
4450 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4453 use_visual_state (*vs);
4458 Editor::redo_visual_state ()
4460 if (redo_visual_stack.empty()) {
4464 VisualState* vs = redo_visual_stack.back();
4465 redo_visual_stack.pop_back();
4467 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4468 // why do we check here?
4469 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4472 use_visual_state (*vs);
4477 Editor::swap_visual_state ()
4479 if (undo_visual_stack.empty()) {
4480 redo_visual_state ();
4482 undo_visual_state ();
4487 Editor::use_visual_state (VisualState& vs)
4489 PBD::Unwinder<bool> nsv (no_save_visual, true);
4490 DisplaySuspender ds;
4492 vertical_adjustment.set_value (vs.y_position);
4494 set_zoom_focus (vs.zoom_focus);
4495 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4498 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4500 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4501 (*i)->clear_property_cache();
4502 (*i)->reset_visual_state ();
4506 _routes->update_visibility ();
4509 /** This is the core function that controls the zoom level of the canvas. It is called
4510 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4511 * @param spp new number of samples per pixel
4514 Editor::set_samples_per_pixel (framecnt_t spp)
4520 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4521 const framecnt_t lots_of_pixels = 4000;
4523 /* if the zoom level is greater than what you'd get trying to display 3
4524 * days of audio on a really big screen, then it's too big.
4527 if (spp * lots_of_pixels > three_days) {
4531 samples_per_pixel = spp;
4534 tempo_lines->tempo_map_changed();
4537 bool const showing_time_selection = selection->time.length() > 0;
4539 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4540 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4541 (*i)->reshow_selection (selection->time);
4545 ZoomChanged (); /* EMIT_SIGNAL */
4547 ArdourCanvas::GtkCanvasViewport* c;
4549 c = get_track_canvas();
4551 c->canvas()->zoomed ();
4554 if (playhead_cursor) {
4555 playhead_cursor->set_position (playhead_cursor->current_frame ());
4558 refresh_location_display();
4559 _summary->set_overlays_dirty ();
4561 update_marker_labels ();
4567 Editor::playhead_cursor_sample () const
4569 return playhead_cursor->current_frame();
4573 Editor::queue_visual_videotimeline_update ()
4576 * pending_visual_change.add (VisualChange::VideoTimeline);
4577 * or maybe even more specific: which videotimeline-image
4578 * currently it calls update_video_timeline() to update
4579 * _all outdated_ images on the video-timeline.
4580 * see 'exposeimg()' in video_image_frame.cc
4582 ensure_visual_change_idle_handler ();
4586 Editor::ensure_visual_change_idle_handler ()
4588 if (pending_visual_change.idle_handler_id < 0) {
4589 // see comment in add_to_idle_resize above.
4590 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4591 pending_visual_change.being_handled = false;
4596 Editor::_idle_visual_changer (void* arg)
4598 return static_cast<Editor*>(arg)->idle_visual_changer ();
4602 Editor::idle_visual_changer ()
4604 /* set_horizontal_position() below (and maybe other calls) call
4605 gtk_main_iteration(), so it's possible that a signal will be handled
4606 half-way through this method. If this signal wants an
4607 idle_visual_changer we must schedule another one after this one, so
4608 mark the idle_handler_id as -1 here to allow that. Also make a note
4609 that we are doing the visual change, so that changes in response to
4610 super-rapid-screen-update can be dropped if we are still processing
4614 pending_visual_change.idle_handler_id = -1;
4615 pending_visual_change.being_handled = true;
4617 VisualChange vc = pending_visual_change;
4619 pending_visual_change.pending = (VisualChange::Type) 0;
4621 visual_changer (vc);
4623 pending_visual_change.being_handled = false;
4625 return 0; /* this is always a one-shot call */
4629 Editor::visual_changer (const VisualChange& vc)
4631 double const last_time_origin = horizontal_position ();
4633 if (vc.pending & VisualChange::ZoomLevel) {
4634 set_samples_per_pixel (vc.samples_per_pixel);
4636 compute_fixed_ruler_scale ();
4638 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4639 update_tempo_based_rulers ();
4641 update_video_timeline();
4644 if (vc.pending & VisualChange::TimeOrigin) {
4645 set_horizontal_position (vc.time_origin / samples_per_pixel);
4648 if (vc.pending & VisualChange::YOrigin) {
4649 vertical_adjustment.set_value (vc.y_origin);
4652 if (last_time_origin == horizontal_position ()) {
4653 /* changed signal not emitted */
4654 update_fixed_rulers ();
4655 redisplay_tempo (true);
4658 if (!(vc.pending & VisualChange::ZoomLevel)) {
4659 update_video_timeline();
4662 _summary->set_overlays_dirty ();
4665 struct EditorOrderTimeAxisSorter {
4666 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4667 return a->order () < b->order ();
4672 Editor::sort_track_selection (TrackViewList& sel)
4674 EditorOrderTimeAxisSorter cmp;
4679 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4682 framepos_t where = 0;
4683 EditPoint ep = _edit_point;
4685 if (Profile->get_mixbus()) {
4686 if (ep == EditAtSelectedMarker) {
4687 ep = EditAtPlayhead;
4691 if (from_outside_canvas && (ep == EditAtMouse)) {
4692 ep = EditAtPlayhead;
4693 } else if (from_context_menu && (ep == EditAtMouse)) {
4694 return canvas_event_sample (&context_click_event, 0, 0);
4697 if (entered_marker) {
4698 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4699 return entered_marker->position();
4702 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4703 ep = EditAtSelectedMarker;
4706 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4707 ep = EditAtPlayhead;
4711 case EditAtPlayhead:
4712 if (_dragging_playhead) {
4713 where = *_control_scroll_target;
4715 where = _session->audible_frame();
4717 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4720 case EditAtSelectedMarker:
4721 if (!selection->markers.empty()) {
4723 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4726 where = loc->start();
4730 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4738 if (!mouse_frame (where, ignored)) {
4739 /* XXX not right but what can we do ? */
4743 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4751 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4753 if (!_session) return;
4755 begin_reversible_command (cmd);
4759 if ((tll = transport_loop_location()) == 0) {
4760 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4761 XMLNode &before = _session->locations()->get_state();
4762 _session->locations()->add (loc, true);
4763 _session->set_auto_loop_location (loc);
4764 XMLNode &after = _session->locations()->get_state();
4765 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4767 XMLNode &before = tll->get_state();
4768 tll->set_hidden (false, this);
4769 tll->set (start, end);
4770 XMLNode &after = tll->get_state();
4771 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4774 commit_reversible_command ();
4778 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4780 if (!_session) return;
4782 begin_reversible_command (cmd);
4786 if ((tpl = transport_punch_location()) == 0) {
4787 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4788 XMLNode &before = _session->locations()->get_state();
4789 _session->locations()->add (loc, true);
4790 _session->set_auto_punch_location (loc);
4791 XMLNode &after = _session->locations()->get_state();
4792 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4794 XMLNode &before = tpl->get_state();
4795 tpl->set_hidden (false, this);
4796 tpl->set (start, end);
4797 XMLNode &after = tpl->get_state();
4798 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4801 commit_reversible_command ();
4804 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4805 * @param rs List to which found regions are added.
4806 * @param where Time to look at.
4807 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4810 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4812 const TrackViewList* tracks;
4815 tracks = &track_views;
4820 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4822 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4825 boost::shared_ptr<Track> tr;
4826 boost::shared_ptr<Playlist> pl;
4828 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4830 boost::shared_ptr<RegionList> regions = pl->regions_at (
4831 (framepos_t) floor ( (double) where * tr->speed()));
4833 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4834 RegionView* rv = rtv->view()->find_view (*i);
4845 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4847 const TrackViewList* tracks;
4850 tracks = &track_views;
4855 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4856 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4858 boost::shared_ptr<Track> tr;
4859 boost::shared_ptr<Playlist> pl;
4861 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4863 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4864 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4866 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4868 RegionView* rv = rtv->view()->find_view (*i);
4879 /** Get regions using the following method:
4881 * Make a region list using:
4882 * (a) any selected regions
4883 * (b) the intersection of any selected tracks and the edit point(*)
4884 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4886 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4888 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4892 Editor::get_regions_from_selection_and_edit_point ()
4894 RegionSelection regions;
4896 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4897 regions.add (entered_regionview);
4899 regions = selection->regions;
4902 if ( regions.empty() ) {
4903 TrackViewList tracks = selection->tracks;
4905 if (!tracks.empty()) {
4906 /* no region selected or entered, but some selected tracks:
4907 * act on all regions on the selected tracks at the edit point
4909 framepos_t const where = get_preferred_edit_position ();
4910 get_regions_at(regions, where, tracks);
4917 /** Get regions using the following method:
4919 * Make a region list using:
4920 * (a) any selected regions
4921 * (b) the intersection of any selected tracks and the edit point(*)
4922 * (c) if neither exists, then whatever region is under the mouse
4924 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4926 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4929 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4931 RegionSelection regions;
4933 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4934 regions.add (entered_regionview);
4936 regions = selection->regions;
4939 if ( regions.empty() ) {
4940 TrackViewList tracks = selection->tracks;
4942 if (!tracks.empty()) {
4943 /* no region selected or entered, but some selected tracks:
4944 * act on all regions on the selected tracks at the edit point
4946 get_regions_at(regions, pos, tracks);
4953 /** Start with regions that are selected, or the entered regionview if none are selected.
4954 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4955 * of the regions that we started with.
4959 Editor::get_regions_from_selection_and_entered () const
4961 RegionSelection regions = selection->regions;
4963 if (regions.empty() && entered_regionview) {
4964 regions.add (entered_regionview);
4971 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4973 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4974 RouteTimeAxisView* rtav;
4976 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4977 boost::shared_ptr<Playlist> pl;
4978 std::vector<boost::shared_ptr<Region> > results;
4979 boost::shared_ptr<Track> tr;
4981 if ((tr = rtav->track()) == 0) {
4986 if ((pl = (tr->playlist())) != 0) {
4987 boost::shared_ptr<Region> r = pl->region_by_id (id);
4989 RegionView* rv = rtav->view()->find_view (r);
4991 regions.push_back (rv);
5000 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5003 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5004 MidiTimeAxisView* mtav;
5006 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5008 mtav->get_per_region_note_selection (selection);
5015 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5017 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5019 RouteTimeAxisView* tatv;
5021 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5023 boost::shared_ptr<Playlist> pl;
5024 vector<boost::shared_ptr<Region> > results;
5026 boost::shared_ptr<Track> tr;
5028 if ((tr = tatv->track()) == 0) {
5033 if ((pl = (tr->playlist())) != 0) {
5034 if (src_comparison) {
5035 pl->get_source_equivalent_regions (region, results);
5037 pl->get_region_list_equivalent_regions (region, results);
5041 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5042 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5043 regions.push_back (marv);
5052 Editor::show_rhythm_ferret ()
5054 if (rhythm_ferret == 0) {
5055 rhythm_ferret = new RhythmFerret(*this);
5058 rhythm_ferret->set_session (_session);
5059 rhythm_ferret->show ();
5060 rhythm_ferret->present ();
5064 Editor::first_idle ()
5066 MessageDialog* dialog = 0;
5068 if (track_views.size() > 1) {
5069 Timers::TimerSuspender t;
5070 dialog = new MessageDialog (
5071 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5075 ARDOUR_UI::instance()->flush_pending (60);
5078 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5082 // first idle adds route children (automation tracks), so we need to redisplay here
5083 _routes->redisplay ();
5087 if (_session->undo_depth() == 0) {
5088 undo_action->set_sensitive(false);
5090 redo_action->set_sensitive(false);
5091 begin_selection_op_history ();
5097 Editor::_idle_resize (gpointer arg)
5099 return ((Editor*)arg)->idle_resize ();
5103 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5105 if (resize_idle_id < 0) {
5106 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5107 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5108 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5110 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5111 _pending_resize_amount = 0;
5114 /* make a note of the smallest resulting height, so that we can clamp the
5115 lower limit at TimeAxisView::hSmall */
5117 int32_t min_resulting = INT32_MAX;
5119 _pending_resize_amount += h;
5120 _pending_resize_view = view;
5122 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5124 if (selection->tracks.contains (_pending_resize_view)) {
5125 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5126 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5130 if (min_resulting < 0) {
5135 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5136 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5140 /** Handle pending resizing of tracks */
5142 Editor::idle_resize ()
5144 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5146 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5147 selection->tracks.contains (_pending_resize_view)) {
5149 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5150 if (*i != _pending_resize_view) {
5151 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5156 _pending_resize_amount = 0;
5157 _group_tabs->set_dirty ();
5158 resize_idle_id = -1;
5166 ENSURE_GUI_THREAD (*this, &Editor::located);
5169 playhead_cursor->set_position (_session->audible_frame ());
5170 if (_follow_playhead && !_pending_initial_locate) {
5171 reset_x_origin_to_follow_playhead ();
5175 _pending_locate_request = false;
5176 _pending_initial_locate = false;
5180 Editor::region_view_added (RegionView * rv)
5182 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5183 if (rv->region ()->id () == (*pr)) {
5184 selection->add (rv);
5185 selection->regions.pending.erase (pr);
5190 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5192 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5193 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5194 if (rv->region()->id () == (*rnote).first) {
5195 mrv->select_notes ((*rnote).second);
5196 selection->pending_midi_note_selection.erase(rnote);
5202 _summary->set_background_dirty ();
5206 Editor::region_view_removed ()
5208 _summary->set_background_dirty ();
5212 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5214 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5215 if ((*j)->stripable() == s) {
5225 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5229 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5230 TimeAxisView* tv = axis_view_from_stripable (*i);
5240 Editor::suspend_route_redisplay ()
5243 _routes->suspend_redisplay();
5248 Editor::resume_route_redisplay ()
5251 _routes->redisplay(); // queue redisplay
5252 _routes->resume_redisplay();
5257 Editor::add_vcas (VCAList& vlist)
5261 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5262 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5265 add_stripables (sl);
5269 Editor::add_routes (RouteList& rlist)
5273 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5277 add_stripables (sl);
5281 Editor::add_stripables (StripableList& sl)
5283 list<TimeAxisView*> new_views;
5284 boost::shared_ptr<VCA> v;
5285 boost::shared_ptr<Route> r;
5286 TrackViewList new_selection;
5287 bool from_scratch = (track_views.size() == 0);
5289 sl.sort (StripablePresentationInfoSorter());
5291 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5293 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5295 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5297 new_views.push_back (vtv);
5299 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5301 if (r->is_auditioner() || r->is_monitor()) {
5305 RouteTimeAxisView* rtv;
5306 DataType dt = r->input()->default_type();
5308 if (dt == ARDOUR::DataType::AUDIO) {
5309 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5311 } else if (dt == ARDOUR::DataType::MIDI) {
5312 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5315 throw unknown_type();
5318 new_views.push_back (rtv);
5319 track_views.push_back (rtv);
5320 new_selection.push_back (rtv);
5322 rtv->effective_gain_display ();
5324 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5325 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5329 if (new_views.size() > 0) {
5330 _routes->time_axis_views_added (new_views);
5331 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5334 /* note: !new_selection.empty() means that we got some routes rather
5338 if (!from_scratch && !new_selection.empty()) {
5339 selection->tracks.clear();
5340 selection->add (new_selection);
5341 begin_selection_op_history();
5344 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5345 show_editor_mixer (true);
5348 editor_list_button.set_sensitive (true);
5352 Editor::timeaxisview_deleted (TimeAxisView *tv)
5354 if (tv == entered_track) {
5358 if (_session && _session->deletion_in_progress()) {
5359 /* the situation is under control */
5363 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5365 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5367 _routes->route_removed (tv);
5369 TimeAxisView::Children c = tv->get_child_list ();
5370 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5371 if (entered_track == i->get()) {
5376 /* remove it from the list of track views */
5378 TrackViewList::iterator i;
5380 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5381 i = track_views.erase (i);
5384 /* update whatever the current mixer strip is displaying, if revelant */
5386 boost::shared_ptr<Route> route;
5389 route = rtav->route ();
5392 if (current_mixer_strip && current_mixer_strip->route() == route) {
5394 TimeAxisView* next_tv;
5396 if (track_views.empty()) {
5398 } else if (i == track_views.end()) {
5399 next_tv = track_views.front();
5406 set_selected_mixer_strip (*next_tv);
5408 /* make the editor mixer strip go away setting the
5409 * button to inactive (which also unticks the menu option)
5412 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5418 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5420 if (apply_to_selection) {
5421 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5423 TrackSelection::iterator j = i;
5426 hide_track_in_display (*i, false);
5431 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5433 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5434 // this will hide the mixer strip
5435 set_selected_mixer_strip (*tv);
5438 _routes->hide_track_in_display (*tv);
5443 Editor::sync_track_view_list_and_routes ()
5445 track_views = TrackViewList (_routes->views ());
5447 _summary->set_background_dirty();
5448 _group_tabs->set_dirty ();
5450 return false; // do not call again (until needed)
5454 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5456 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5461 /** Find a RouteTimeAxisView by the ID of its route */
5463 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5465 RouteTimeAxisView* v;
5467 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5468 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5469 if(v->route()->id() == id) {
5479 Editor::fit_route_group (RouteGroup *g)
5481 TrackViewList ts = axis_views_from_routes (g->route_list ());
5486 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5488 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5491 _session->cancel_audition ();
5495 if (_session->is_auditioning()) {
5496 _session->cancel_audition ();
5497 if (r == last_audition_region) {
5502 _session->audition_region (r);
5503 last_audition_region = r;
5508 Editor::hide_a_region (boost::shared_ptr<Region> r)
5510 r->set_hidden (true);
5514 Editor::show_a_region (boost::shared_ptr<Region> r)
5516 r->set_hidden (false);
5520 Editor::audition_region_from_region_list ()
5522 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5526 Editor::hide_region_from_region_list ()
5528 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5532 Editor::show_region_in_region_list ()
5534 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5538 Editor::step_edit_status_change (bool yn)
5541 start_step_editing ();
5543 stop_step_editing ();
5548 Editor::start_step_editing ()
5550 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5554 Editor::stop_step_editing ()
5556 step_edit_connection.disconnect ();
5560 Editor::check_step_edit ()
5562 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5563 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5565 mtv->check_step_edit ();
5569 return true; // do it again, till we stop
5573 Editor::scroll_press (Direction dir)
5575 ++_scroll_callbacks;
5577 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5578 /* delay the first auto-repeat */
5584 scroll_backward (1);
5592 scroll_up_one_track ();
5596 scroll_down_one_track ();
5600 /* do hacky auto-repeat */
5601 if (!_scroll_connection.connected ()) {
5603 _scroll_connection = Glib::signal_timeout().connect (
5604 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5607 _scroll_callbacks = 0;
5614 Editor::scroll_release ()
5616 _scroll_connection.disconnect ();
5619 /** Queue a change for the Editor viewport x origin to follow the playhead */
5621 Editor::reset_x_origin_to_follow_playhead ()
5623 framepos_t const frame = playhead_cursor->current_frame ();
5625 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5627 if (_session->transport_speed() < 0) {
5629 if (frame > (current_page_samples() / 2)) {
5630 center_screen (frame-(current_page_samples()/2));
5632 center_screen (current_page_samples()/2);
5639 if (frame < leftmost_frame) {
5641 if (_session->transport_rolling()) {
5642 /* rolling; end up with the playhead at the right of the page */
5643 l = frame - current_page_samples ();
5645 /* not rolling: end up with the playhead 1/4 of the way along the page */
5646 l = frame - current_page_samples() / 4;
5650 if (_session->transport_rolling()) {
5651 /* rolling: end up with the playhead on the left of the page */
5654 /* not rolling: end up with the playhead 3/4 of the way along the page */
5655 l = frame - 3 * current_page_samples() / 4;
5663 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5669 Editor::super_rapid_screen_update ()
5671 if (!_session || !_session->engine().running()) {
5675 /* METERING / MIXER STRIPS */
5677 /* update track meters, if required */
5678 if (contents().is_mapped() && meters_running) {
5679 RouteTimeAxisView* rtv;
5680 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5681 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5682 rtv->fast_update ();
5687 /* and any current mixer strip */
5688 if (current_mixer_strip) {
5689 current_mixer_strip->fast_update ();
5692 /* PLAYHEAD AND VIEWPORT */
5694 framepos_t const frame = _session->audible_frame();
5696 /* There are a few reasons why we might not update the playhead / viewport stuff:
5698 * 1. we don't update things when there's a pending locate request, otherwise
5699 * when the editor requests a locate there is a chance that this method
5700 * will move the playhead before the locate request is processed, causing
5702 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5703 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5706 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5708 last_update_frame = frame;
5710 if (!_dragging_playhead) {
5711 playhead_cursor->set_position (frame);
5714 if (!_stationary_playhead) {
5716 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5717 /* We only do this if we aren't already
5718 handling a visual change (ie if
5719 pending_visual_change.being_handled is
5720 false) so that these requests don't stack
5721 up there are too many of them to handle in
5724 reset_x_origin_to_follow_playhead ();
5729 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5730 framepos_t const frame = playhead_cursor->current_frame ();
5731 double target = ((double)frame - (double)current_page_samples()/2.0);
5732 if (target <= 0.0) {
5735 // compare to EditorCursor::set_position()
5736 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5737 double const new_pos = sample_to_pixel_unrounded (target);
5738 if (rint (new_pos) != rint (old_pos)) {
5739 reset_x_origin (pixel_to_sample (floor (new_pos)));
5750 Editor::session_going_away ()
5752 _have_idled = false;
5754 _session_connections.drop_connections ();
5756 super_rapid_screen_update_connection.disconnect ();
5758 selection->clear ();
5759 cut_buffer->clear ();
5761 clicked_regionview = 0;
5762 clicked_axisview = 0;
5763 clicked_routeview = 0;
5764 entered_regionview = 0;
5766 last_update_frame = 0;
5769 playhead_cursor->hide ();
5771 /* rip everything out of the list displays */
5775 _route_groups->clear ();
5777 /* do this first so that deleting a track doesn't reset cms to null
5778 and thus cause a leak.
5781 if (current_mixer_strip) {
5782 if (current_mixer_strip->get_parent() != 0) {
5783 global_hpacker.remove (*current_mixer_strip);
5785 delete current_mixer_strip;
5786 current_mixer_strip = 0;
5789 /* delete all trackviews */
5791 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5794 track_views.clear ();
5796 nudge_clock->set_session (0);
5798 editor_list_button.set_active(false);
5799 editor_list_button.set_sensitive(false);
5801 /* clear tempo/meter rulers */
5802 remove_metric_marks ();
5804 clear_marker_display ();
5806 stop_step_editing ();
5810 /* get rid of any existing editor mixer strip */
5812 WindowTitle title(Glib::get_application_name());
5813 title += _("Editor");
5815 own_window()->set_title (title.get_string());
5818 SessionHandlePtr::session_going_away ();
5822 Editor::trigger_script (int i)
5824 LuaInstance::instance()-> call_action (i);
5828 Editor::set_script_action_name (int i, const std::string& n)
5830 string const a = string_compose (X_("script-action-%1"), i + 1);
5831 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5834 act->set_label (string_compose (_("Unset #%1"), i + 1));
5835 act->set_tooltip (_("no action bound"));
5836 act->set_sensitive (false);
5839 act->set_tooltip (n);
5840 act->set_sensitive (true);
5842 KeyEditor::UpdateBindings ();
5846 Editor::show_editor_list (bool yn)
5849 _the_notebook.show ();
5851 _the_notebook.hide ();
5856 Editor::change_region_layering_order (bool from_context_menu)
5858 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5860 if (!clicked_routeview) {
5861 if (layering_order_editor) {
5862 layering_order_editor->hide ();
5867 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5873 boost::shared_ptr<Playlist> pl = track->playlist();
5879 if (layering_order_editor == 0) {
5880 layering_order_editor = new RegionLayeringOrderEditor (*this);
5883 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5884 layering_order_editor->maybe_present ();
5888 Editor::update_region_layering_order_editor ()
5890 if (layering_order_editor && layering_order_editor->is_visible ()) {
5891 change_region_layering_order (true);
5896 Editor::setup_fade_images ()
5898 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5899 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5900 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5901 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5902 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5904 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5905 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5906 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5907 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5908 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5910 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5911 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5912 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5913 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5914 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5916 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5917 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5918 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5919 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5920 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5924 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5926 Editor::action_menu_item (std::string const & name)
5928 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5931 return *manage (a->create_menu_item ());
5935 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5937 EventBox* b = manage (new EventBox);
5938 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5939 Label* l = manage (new Label (name));
5943 _the_notebook.append_page (widget, *b);
5947 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5949 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5950 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5953 if (ev->type == GDK_2BUTTON_PRESS) {
5955 /* double-click on a notebook tab shrinks or expands the notebook */
5957 if (_notebook_shrunk) {
5958 if (pre_notebook_shrink_pane_width) {
5959 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5961 _notebook_shrunk = false;
5963 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5965 /* this expands the LHS of the edit pane to cover the notebook
5966 PAGE but leaves the tabs visible.
5968 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5969 _notebook_shrunk = true;
5977 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5979 using namespace Menu_Helpers;
5981 MenuList& items = _control_point_context_menu.items ();
5984 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5985 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5986 if (!can_remove_control_point (item)) {
5987 items.back().set_sensitive (false);
5990 _control_point_context_menu.popup (event->button.button, event->button.time);
5994 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5996 using namespace Menu_Helpers;
5998 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6003 /* We need to get the selection here and pass it to the operations, since
6004 popping up the menu will cause a region leave event which clears
6005 entered_regionview. */
6007 MidiRegionView& mrv = note->region_view();
6008 const RegionSelection rs = get_regions_from_selection_and_entered ();
6009 const uint32_t sel_size = mrv.selection_size ();
6011 MenuList& items = _note_context_menu.items();
6015 items.push_back(MenuElem(_("Delete"),
6016 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6019 items.push_back(MenuElem(_("Edit..."),
6020 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6021 if (sel_size != 1) {
6022 items.back().set_sensitive (false);
6025 items.push_back(MenuElem(_("Transpose..."),
6026 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6029 items.push_back(MenuElem(_("Legatize"),
6030 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6032 items.back().set_sensitive (false);
6035 items.push_back(MenuElem(_("Quantize..."),
6036 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6038 items.push_back(MenuElem(_("Remove Overlap"),
6039 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6041 items.back().set_sensitive (false);
6044 items.push_back(MenuElem(_("Transform..."),
6045 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6047 _note_context_menu.popup (event->button.button, event->button.time);
6051 Editor::zoom_vertical_modifier_released()
6053 _stepping_axis_view = 0;
6057 Editor::ui_parameter_changed (string parameter)
6059 if (parameter == "icon-set") {
6060 while (!_cursor_stack.empty()) {
6061 _cursor_stack.pop_back();
6063 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6064 _cursor_stack.push_back(_cursors->grabber);
6065 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6066 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6068 } else if (parameter == "draggable-playhead") {
6069 if (_verbose_cursor) {
6070 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6076 Editor::use_own_window (bool and_fill_it)
6078 bool new_window = !own_window();
6080 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6082 if (win && new_window) {
6083 win->set_name ("EditorWindow");
6085 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6087 // win->signal_realize().connect (*this, &Editor::on_realize);
6088 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6089 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6090 win->set_data ("ardour-bindings", bindings);
6095 DisplaySuspender ds;
6096 contents().show_all ();
6098 /* XXX: this is a bit unfortunate; it would probably
6099 be nicer if we could just call show () above rather
6100 than needing the show_all ()
6103 /* re-hide stuff if necessary */
6104 editor_list_button_toggled ();
6105 parameter_changed ("show-summary");
6106 parameter_changed ("show-group-tabs");
6107 parameter_changed ("show-zoom-tools");
6109 /* now reset all audio_time_axis heights, because widgets might need
6115 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6116 tv = (static_cast<TimeAxisView*>(*i));
6117 tv->reset_height ();
6120 if (current_mixer_strip) {
6121 current_mixer_strip->hide_things ();
6122 current_mixer_strip->parameter_changed ("mixer-element-visibility");