2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route_group.h"
76 #include "ardour/session_playlists.h"
77 #include "ardour/tempo.h"
78 #include "ardour/utils.h"
80 #include "canvas/debug.h"
81 #include "canvas/text.h"
83 #include "control_protocol/control_protocol.h"
86 #include "analysis_window.h"
87 #include "audio_clock.h"
88 #include "audio_region_view.h"
89 #include "audio_streamview.h"
90 #include "audio_time_axis.h"
91 #include "automation_time_axis.h"
92 #include "bundle_manager.h"
93 #include "crossfade_edit.h"
97 #include "editor_cursors.h"
98 #include "editor_drag.h"
99 #include "editor_group_tabs.h"
100 #include "editor_locations.h"
101 #include "editor_regions.h"
102 #include "editor_route_groups.h"
103 #include "editor_routes.h"
104 #include "editor_snapshots.h"
105 #include "editor_summary.h"
106 #include "export_report.h"
107 #include "global_port_matrix.h"
108 #include "gui_object.h"
109 #include "gui_thread.h"
110 #include "keyboard.h"
111 #include "keyeditor.h"
112 #include "luainstance.h"
114 #include "midi_region_view.h"
115 #include "midi_time_axis.h"
116 #include "mixer_strip.h"
117 #include "mixer_ui.h"
118 #include "mouse_cursors.h"
119 #include "note_base.h"
120 #include "playlist_selector.h"
121 #include "public_editor.h"
122 #include "quantize_dialog.h"
123 #include "region_layering_order_editor.h"
124 #include "rgb_macros.h"
125 #include "rhythm_ferret.h"
126 #include "selection.h"
127 #include "simple_progress_dialog.h"
129 #include "tempo_lines.h"
130 #include "time_axis_view.h"
132 #include "tooltips.h"
133 #include "ui_config.h"
135 #include "verbose_cursor.h"
140 using namespace ARDOUR;
141 using namespace ARDOUR_UI_UTILS;
144 using namespace Glib;
145 using namespace Gtkmm2ext;
146 using namespace Editing;
148 using PBD::internationalize;
150 using Gtkmm2ext::Keyboard;
152 double Editor::timebar_height = 15.0;
154 static const gchar *_snap_type_strings[] = {
188 static const gchar *_snap_mode_strings[] = {
195 static const gchar *_edit_point_strings[] = {
202 static const gchar *_edit_mode_strings[] = {
210 static const gchar *_zoom_focus_strings[] = {
220 #ifdef USE_RUBBERBAND
221 static const gchar *_rb_opt_strings[] = {
224 N_("Balanced multitimbral mixture"),
225 N_("Unpitched percussion with stable notes"),
226 N_("Crisp monophonic instrumental"),
227 N_("Unpitched solo percussion"),
228 N_("Resample without preserving pitch"),
233 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
236 pane_size_watcher (Paned* pane)
238 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
242 Quartz: impossible to access
244 so stop that by preventing it from ever getting too narrow. 35
245 pixels is basically a rough guess at the tab width.
250 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
252 gint pos = pane->get_position ();
254 if (pos > max_width_of_lhs) {
255 pane->set_position (max_width_of_lhs);
260 : PublicEditor (global_hpacker)
261 , editor_mixer_strip_width (Wide)
262 , constructed (false)
263 , _playlist_selector (0)
264 , no_save_visual (false)
266 , samples_per_pixel (2048)
267 , zoom_focus (ZoomFocusPlayhead)
268 , mouse_mode (MouseObject)
269 , pre_internal_snap_type (SnapToBeat)
270 , pre_internal_snap_mode (SnapOff)
271 , internal_snap_type (SnapToBeat)
272 , internal_snap_mode (SnapOff)
273 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
274 , _notebook_shrunk (false)
275 , location_marker_color (0)
276 , location_range_color (0)
277 , location_loop_color (0)
278 , location_punch_color (0)
279 , location_cd_marker_color (0)
281 , _show_marker_lines (false)
282 , clicked_axisview (0)
283 , clicked_routeview (0)
284 , clicked_regionview (0)
285 , clicked_selection (0)
286 , clicked_control_point (0)
287 , button_release_can_deselect (true)
288 , _mouse_changed_selection (false)
289 , region_edit_menu_split_item (0)
290 , region_edit_menu_split_multichannel_item (0)
291 , track_region_edit_playlist_menu (0)
292 , track_edit_playlist_submenu (0)
293 , track_selection_edit_playlist_submenu (0)
294 , _popup_region_menu_item (0)
296 , _track_canvas_viewport (0)
297 , within_track_canvas (false)
298 , _verbose_cursor (0)
302 , range_marker_group (0)
303 , transport_marker_group (0)
304 , cd_marker_group (0)
305 , _time_markers_group (0)
306 , hv_scroll_group (0)
308 , cursor_scroll_group (0)
309 , no_scroll_group (0)
310 , _trackview_group (0)
311 , _drag_motion_group (0)
312 , _canvas_drop_zone (0)
313 , no_ruler_shown_update (false)
314 , ruler_grabbed_widget (0)
316 , minsec_mark_interval (0)
317 , minsec_mark_modulo (0)
319 , timecode_mark_modulo (0)
320 , timecode_nmarks (0)
321 , _samples_ruler_interval (0)
324 , bbt_bar_helper_on (0)
325 , bbt_accent_modulo (0)
330 , visible_timebars (0)
331 , editor_ruler_menu (0)
335 , range_marker_bar (0)
336 , transport_marker_bar (0)
338 , minsec_label (_("Mins:Secs"))
339 , bbt_label (_("Bars:Beats"))
340 , timecode_label (_("Timecode"))
341 , samples_label (_("Samples"))
342 , tempo_label (_("Tempo"))
343 , meter_label (_("Meter"))
344 , mark_label (_("Location Markers"))
345 , range_mark_label (_("Range Markers"))
346 , transport_mark_label (_("Loop/Punch Ranges"))
347 , cd_mark_label (_("CD Markers"))
348 , videotl_label (_("Video Timeline"))
350 , playhead_cursor (0)
351 , edit_packer (4, 4, true)
352 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
353 , horizontal_adjustment (0.0, 0.0, 1e16)
354 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
355 , controls_layout (unused_adjustment, vertical_adjustment)
356 , _scroll_callbacks (0)
357 , _visible_canvas_width (0)
358 , _visible_canvas_height (0)
359 , _full_canvas_height (0)
360 , edit_controls_left_menu (0)
361 , edit_controls_right_menu (0)
362 , last_update_frame (0)
363 , cut_buffer_start (0)
364 , cut_buffer_length (0)
365 , button_bindings (0)
369 , current_interthread_info (0)
370 , analysis_window (0)
371 , select_new_marker (false)
373 , scrubbing_direction (0)
374 , scrub_reversals (0)
375 , scrub_reverse_distance (0)
376 , have_pending_keyboard_selection (false)
377 , pending_keyboard_selection_start (0)
378 , _snap_type (SnapToBeat)
379 , _snap_mode (SnapOff)
380 , snap_threshold (5.0)
381 , ignore_gui_changes (false)
382 , _drags (new DragManager (this))
384 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
385 , _dragging_playhead (false)
386 , _dragging_edit_point (false)
387 , _show_measures (true)
388 , _follow_playhead (true)
389 , _stationary_playhead (false)
392 , global_rect_group (0)
393 , time_line_group (0)
394 , tempo_or_meter_marker_menu (0)
396 , range_marker_menu (0)
397 , transport_marker_menu (0)
398 , new_transport_marker_menu (0)
400 , marker_menu_item (0)
401 , bbt_beat_subdivision (4)
402 , _visible_track_count (-1)
403 , toolbar_selection_clock_table (2,3)
404 , automation_mode_button (_("mode"))
405 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
406 , selection (new Selection (this))
407 , cut_buffer (new Selection (this))
408 , _selection_memento (new SelectionMemento())
409 , _all_region_actions_sensitized (false)
410 , _ignore_region_action (false)
411 , _last_region_menu_was_main (false)
412 , _ignore_follow_edits (false)
413 , cd_marker_bar_drag_rect (0)
414 , range_bar_drag_rect (0)
415 , transport_bar_drag_rect (0)
416 , transport_bar_range_rect (0)
417 , transport_bar_preroll_rect (0)
418 , transport_bar_postroll_rect (0)
419 , transport_loop_range_rect (0)
420 , transport_punch_range_rect (0)
421 , transport_punchin_line (0)
422 , transport_punchout_line (0)
423 , transport_preroll_rect (0)
424 , transport_postroll_rect (0)
426 , rubberband_rect (0)
432 , autoscroll_horizontal_allowed (false)
433 , autoscroll_vertical_allowed (false)
435 , autoscroll_widget (0)
436 , show_gain_after_trim (false)
437 , selection_op_cmd_depth (0)
438 , selection_op_history_it (0)
439 , no_save_instant (false)
441 , current_mixer_strip (0)
442 , show_editor_mixer_when_tracks_arrive (false)
443 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
444 , current_stepping_trackview (0)
445 , last_track_height_step_timestamp (0)
447 , entered_regionview (0)
448 , clear_entered_track (false)
449 , _edit_point (EditAtMouse)
450 , meters_running (false)
452 , _have_idled (false)
453 , resize_idle_id (-1)
454 , _pending_resize_amount (0)
455 , _pending_resize_view (0)
456 , _pending_locate_request (false)
457 , _pending_initial_locate (false)
461 , layering_order_editor (0)
462 , _last_cut_copy_source_track (0)
463 , _region_selection_change_updates_region_list (true)
465 , _following_mixer_selection (false)
466 , _control_point_toggled_on_press (false)
467 , _stepping_axis_view (0)
468 , quantize_dialog (0)
469 , _main_menu_disabler (0)
470 , myactions (X_("editor"))
472 /* we are a singleton */
474 PublicEditor::_instance = this;
478 last_event_time.tv_sec = 0;
479 last_event_time.tv_usec = 0;
481 selection_op_history.clear();
484 snap_type_strings = I18N (_snap_type_strings);
485 snap_mode_strings = I18N (_snap_mode_strings);
486 zoom_focus_strings = I18N (_zoom_focus_strings);
487 edit_mode_strings = I18N (_edit_mode_strings);
488 edit_point_strings = I18N (_edit_point_strings);
489 #ifdef USE_RUBBERBAND
490 rb_opt_strings = I18N (_rb_opt_strings);
494 build_edit_mode_menu();
495 build_zoom_focus_menu();
496 build_track_count_menu();
497 build_snap_mode_menu();
498 build_snap_type_menu();
499 build_edit_point_menu();
501 location_marker_color = UIConfiguration::instance().color ("location marker");
502 location_range_color = UIConfiguration::instance().color ("location range");
503 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
504 location_loop_color = UIConfiguration::instance().color ("location loop");
505 location_punch_color = UIConfiguration::instance().color ("location punch");
507 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
509 TimeAxisView::setup_sizes ();
510 ArdourMarker::setup_sizes (timebar_height);
512 bbt_label.set_name ("EditorRulerLabel");
513 bbt_label.set_size_request (-1, (int)timebar_height);
514 bbt_label.set_alignment (1.0, 0.5);
515 bbt_label.set_padding (5,0);
517 bbt_label.set_no_show_all();
518 minsec_label.set_name ("EditorRulerLabel");
519 minsec_label.set_size_request (-1, (int)timebar_height);
520 minsec_label.set_alignment (1.0, 0.5);
521 minsec_label.set_padding (5,0);
522 minsec_label.hide ();
523 minsec_label.set_no_show_all();
524 timecode_label.set_name ("EditorRulerLabel");
525 timecode_label.set_size_request (-1, (int)timebar_height);
526 timecode_label.set_alignment (1.0, 0.5);
527 timecode_label.set_padding (5,0);
528 timecode_label.hide ();
529 timecode_label.set_no_show_all();
530 samples_label.set_name ("EditorRulerLabel");
531 samples_label.set_size_request (-1, (int)timebar_height);
532 samples_label.set_alignment (1.0, 0.5);
533 samples_label.set_padding (5,0);
534 samples_label.hide ();
535 samples_label.set_no_show_all();
537 tempo_label.set_name ("EditorRulerLabel");
538 tempo_label.set_size_request (-1, (int)timebar_height);
539 tempo_label.set_alignment (1.0, 0.5);
540 tempo_label.set_padding (5,0);
542 tempo_label.set_no_show_all();
544 meter_label.set_name ("EditorRulerLabel");
545 meter_label.set_size_request (-1, (int)timebar_height);
546 meter_label.set_alignment (1.0, 0.5);
547 meter_label.set_padding (5,0);
549 meter_label.set_no_show_all();
551 if (Profile->get_trx()) {
552 mark_label.set_text (_("Markers"));
554 mark_label.set_name ("EditorRulerLabel");
555 mark_label.set_size_request (-1, (int)timebar_height);
556 mark_label.set_alignment (1.0, 0.5);
557 mark_label.set_padding (5,0);
559 mark_label.set_no_show_all();
561 cd_mark_label.set_name ("EditorRulerLabel");
562 cd_mark_label.set_size_request (-1, (int)timebar_height);
563 cd_mark_label.set_alignment (1.0, 0.5);
564 cd_mark_label.set_padding (5,0);
565 cd_mark_label.hide();
566 cd_mark_label.set_no_show_all();
568 videotl_bar_height = 4;
569 videotl_label.set_name ("EditorRulerLabel");
570 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
571 videotl_label.set_alignment (1.0, 0.5);
572 videotl_label.set_padding (5,0);
573 videotl_label.hide();
574 videotl_label.set_no_show_all();
576 range_mark_label.set_name ("EditorRulerLabel");
577 range_mark_label.set_size_request (-1, (int)timebar_height);
578 range_mark_label.set_alignment (1.0, 0.5);
579 range_mark_label.set_padding (5,0);
580 range_mark_label.hide();
581 range_mark_label.set_no_show_all();
583 transport_mark_label.set_name ("EditorRulerLabel");
584 transport_mark_label.set_size_request (-1, (int)timebar_height);
585 transport_mark_label.set_alignment (1.0, 0.5);
586 transport_mark_label.set_padding (5,0);
587 transport_mark_label.hide();
588 transport_mark_label.set_no_show_all();
590 initialize_canvas ();
592 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
594 _summary = new EditorSummary (this);
596 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
597 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
599 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
601 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
602 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
604 edit_controls_vbox.set_spacing (0);
605 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
606 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
608 HBox* h = manage (new HBox);
609 _group_tabs = new EditorGroupTabs (this);
610 if (!ARDOUR::Profile->get_trx()) {
611 h->pack_start (*_group_tabs, PACK_SHRINK);
613 h->pack_start (edit_controls_vbox);
614 controls_layout.add (*h);
616 controls_layout.set_name ("EditControlsBase");
617 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
618 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
619 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
621 _cursors = new MouseCursors;
622 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
623 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
625 /* Push default cursor to ever-present bottom of cursor stack. */
626 push_canvas_cursor(_cursors->grabber);
628 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
630 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
631 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
632 pad_line_1->set_outline_color (0xFF0000FF);
638 edit_packer.set_col_spacings (0);
639 edit_packer.set_row_spacings (0);
640 edit_packer.set_homogeneous (false);
641 edit_packer.set_border_width (0);
642 edit_packer.set_name ("EditorWindow");
644 time_bars_event_box.add (time_bars_vbox);
645 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
646 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
648 /* labels for the time bars */
649 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
651 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
653 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
655 bottom_hbox.set_border_width (2);
656 bottom_hbox.set_spacing (3);
658 _route_groups = new EditorRouteGroups (this);
659 _routes = new EditorRoutes (this);
660 _regions = new EditorRegions (this);
661 _snapshots = new EditorSnapshots (this);
662 _locations = new EditorLocations (this);
664 /* these are static location signals */
666 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
667 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
668 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
670 add_notebook_page (_("Regions"), _regions->widget ());
671 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
672 add_notebook_page (_("Snapshots"), _snapshots->widget ());
673 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
674 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
676 _the_notebook.set_show_tabs (true);
677 _the_notebook.set_scrollable (true);
678 _the_notebook.popup_disable ();
679 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
680 _the_notebook.show_all ();
682 _notebook_shrunk = false;
684 editor_summary_pane.pack1(edit_packer);
686 Button* summary_arrows_left_left = manage (new Button);
687 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
688 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
689 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 Button* summary_arrows_left_right = manage (new Button);
692 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
693 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
694 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
696 VBox* summary_arrows_left = manage (new VBox);
697 summary_arrows_left->pack_start (*summary_arrows_left_left);
698 summary_arrows_left->pack_start (*summary_arrows_left_right);
700 Button* summary_arrows_right_up = manage (new Button);
701 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
702 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
703 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 Button* summary_arrows_right_down = manage (new Button);
706 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
707 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
708 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
710 VBox* summary_arrows_right = manage (new VBox);
711 summary_arrows_right->pack_start (*summary_arrows_right_up);
712 summary_arrows_right->pack_start (*summary_arrows_right_down);
714 Frame* summary_frame = manage (new Frame);
715 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
717 summary_frame->add (*_summary);
718 summary_frame->show ();
720 _summary_hbox.pack_start (*summary_arrows_left, false, false);
721 _summary_hbox.pack_start (*summary_frame, true, true);
722 _summary_hbox.pack_start (*summary_arrows_right, false, false);
724 if (!ARDOUR::Profile->get_trx()) {
725 editor_summary_pane.pack2 (_summary_hbox);
728 edit_pane.pack1 (editor_summary_pane, true, true);
729 if (!ARDOUR::Profile->get_trx()) {
730 edit_pane.pack2 (_the_notebook, false, true);
733 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
735 /* XXX: editor_summary_pane might need similar to the edit_pane */
737 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
739 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
740 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
742 top_hbox.pack_start (toolbar_frame);
744 HBox *hbox = manage (new HBox);
745 hbox->pack_start (edit_pane, true, true);
747 global_vpacker.pack_start (top_hbox, false, false);
748 global_vpacker.pack_start (*hbox, true, true);
749 global_hpacker.pack_start (global_vpacker, true, true);
751 /* need to show the "contents" widget so that notebook will show if tab is switched to
754 global_hpacker.show ();
756 /* register actions now so that set_state() can find them and set toggles/checks etc */
763 _playlist_selector = new PlaylistSelector();
764 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
766 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
770 nudge_forward_button.set_name ("nudge button");
771 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
773 nudge_backward_button.set_name ("nudge button");
774 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
776 fade_context_menu.set_name ("ArdourContextMenu");
778 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
780 /* allow external control surfaces/protocols to do various things */
782 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
783 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
784 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
785 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
786 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
787 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
788 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
789 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
790 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
791 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
792 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
793 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
794 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
795 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
797 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
798 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
799 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
800 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
801 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
803 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
805 /* problematic: has to return a value and thus cannot be x-thread */
807 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
809 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
810 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
812 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
814 _ignore_region_action = false;
815 _last_region_menu_was_main = false;
816 _popup_region_menu_item = 0;
818 _ignore_follow_edits = false;
820 _show_marker_lines = false;
822 /* Button bindings */
824 button_bindings = new Bindings ("editor-mouse");
826 XMLNode* node = button_settings();
828 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
829 button_bindings->load_operation (**i);
835 /* grab current parameter state */
836 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
837 UIConfiguration::instance().map_parameters (pc);
839 setup_fade_images ();
841 LuaInstance::instance(); // instantiate
842 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
849 delete button_bindings;
851 delete _route_groups;
852 delete _track_canvas_viewport;
855 delete quantize_dialog;
861 delete _playlist_selector;
863 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
869 Editor::button_settings () const
871 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
872 XMLNode* node = find_named_node (*settings, X_("Buttons"));
875 node = new XMLNode (X_("Buttons"));
882 Editor::get_smart_mode () const
884 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
888 Editor::catch_vanishing_regionview (RegionView *rv)
890 /* note: the selection will take care of the vanishing
891 audioregionview by itself.
894 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
898 if (clicked_regionview == rv) {
899 clicked_regionview = 0;
902 if (entered_regionview == rv) {
903 set_entered_regionview (0);
906 if (!_all_region_actions_sensitized) {
907 sensitize_all_region_actions (true);
912 Editor::set_entered_regionview (RegionView* rv)
914 if (rv == entered_regionview) {
918 if (entered_regionview) {
919 entered_regionview->exited ();
922 entered_regionview = rv;
924 if (entered_regionview != 0) {
925 entered_regionview->entered ();
928 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
929 /* This RegionView entry might have changed what region actions
930 are allowed, so sensitize them all in case a key is pressed.
932 sensitize_all_region_actions (true);
937 Editor::set_entered_track (TimeAxisView* tav)
940 entered_track->exited ();
946 entered_track->entered ();
951 Editor::instant_save ()
953 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
958 _session->add_instant_xml(get_state());
960 Config->add_instant_xml(get_state());
965 Editor::control_vertical_zoom_in_all ()
967 tav_zoom_smooth (false, true);
971 Editor::control_vertical_zoom_out_all ()
973 tav_zoom_smooth (true, true);
977 Editor::control_vertical_zoom_in_selected ()
979 tav_zoom_smooth (false, false);
983 Editor::control_vertical_zoom_out_selected ()
985 tav_zoom_smooth (true, false);
989 Editor::control_view (uint32_t view)
991 goto_visual_state (view);
995 Editor::control_unselect ()
997 selection->clear_tracks ();
1001 Editor::control_select (uint32_t rid, Selection::Operation op)
1003 /* handles the (static) signal from the ControlProtocol class that
1004 * requests setting the selected track to a given RID
1011 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1017 TimeAxisView* tav = axis_view_from_route (r);
1021 case Selection::Add:
1022 selection->add (tav);
1024 case Selection::Toggle:
1025 selection->toggle (tav);
1027 case Selection::Extend:
1029 case Selection::Set:
1030 selection->set (tav);
1034 selection->clear_tracks ();
1039 Editor::control_step_tracks_up ()
1041 scroll_tracks_up_line ();
1045 Editor::control_step_tracks_down ()
1047 scroll_tracks_down_line ();
1051 Editor::control_scroll (float fraction)
1053 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1059 double step = fraction * current_page_samples();
1062 _control_scroll_target is an optional<T>
1064 it acts like a pointer to an framepos_t, with
1065 a operator conversion to boolean to check
1066 that it has a value could possibly use
1067 playhead_cursor->current_frame to store the
1068 value and a boolean in the class to know
1069 when it's out of date
1072 if (!_control_scroll_target) {
1073 _control_scroll_target = _session->transport_frame();
1074 _dragging_playhead = true;
1077 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1078 *_control_scroll_target = 0;
1079 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1080 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1082 *_control_scroll_target += (framepos_t) trunc (step);
1085 /* move visuals, we'll catch up with it later */
1087 playhead_cursor->set_position (*_control_scroll_target);
1088 UpdateAllTransportClocks (*_control_scroll_target);
1090 if (*_control_scroll_target > (current_page_samples() / 2)) {
1091 /* try to center PH in window */
1092 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1098 Now we do a timeout to actually bring the session to the right place
1099 according to the playhead. This is to avoid reading disk buffers on every
1100 call to control_scroll, which is driven by ScrollTimeline and therefore
1101 probably by a control surface wheel which can generate lots of events.
1103 /* cancel the existing timeout */
1105 control_scroll_connection.disconnect ();
1107 /* add the next timeout */
1109 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1113 Editor::deferred_control_scroll (framepos_t /*target*/)
1115 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1116 // reset for next stream
1117 _control_scroll_target = boost::none;
1118 _dragging_playhead = false;
1123 Editor::access_action (std::string action_group, std::string action_item)
1129 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1132 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1140 Editor::on_realize ()
1144 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1145 start_lock_event_timing ();
1150 Editor::start_lock_event_timing ()
1152 /* check if we should lock the GUI every 30 seconds */
1154 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1158 Editor::generic_event_handler (GdkEvent* ev)
1161 case GDK_BUTTON_PRESS:
1162 case GDK_BUTTON_RELEASE:
1163 case GDK_MOTION_NOTIFY:
1165 case GDK_KEY_RELEASE:
1166 if (contents().is_mapped()) {
1167 gettimeofday (&last_event_time, 0);
1171 case GDK_LEAVE_NOTIFY:
1172 switch (ev->crossing.detail) {
1173 case GDK_NOTIFY_UNKNOWN:
1174 case GDK_NOTIFY_INFERIOR:
1175 case GDK_NOTIFY_ANCESTOR:
1177 case GDK_NOTIFY_VIRTUAL:
1178 case GDK_NOTIFY_NONLINEAR:
1179 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1180 /* leaving window, so reset focus, thus ending any and
1181 all text entry operations.
1183 reset_focus (&contents());
1196 Editor::lock_timeout_callback ()
1198 struct timeval now, delta;
1200 gettimeofday (&now, 0);
1202 timersub (&now, &last_event_time, &delta);
1204 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1206 /* don't call again. Returning false will effectively
1207 disconnect us from the timer callback.
1209 unlock() will call start_lock_event_timing() to get things
1219 Editor::map_position_change (framepos_t frame)
1221 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1223 if (_session == 0) {
1227 if (_follow_playhead) {
1228 center_screen (frame);
1231 playhead_cursor->set_position (frame);
1235 Editor::center_screen (framepos_t frame)
1237 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1239 /* if we're off the page, then scroll.
1242 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1243 center_screen_internal (frame, page);
1248 Editor::center_screen_internal (framepos_t frame, float page)
1253 frame -= (framepos_t) page;
1258 reset_x_origin (frame);
1263 Editor::update_title ()
1265 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1267 if (!own_window()) {
1272 bool dirty = _session->dirty();
1274 string session_name;
1276 if (_session->snap_name() != _session->name()) {
1277 session_name = _session->snap_name();
1279 session_name = _session->name();
1283 session_name = "*" + session_name;
1286 WindowTitle title(session_name);
1287 title += S_("Window|Editor");
1288 title += Glib::get_application_name();
1289 own_window()->set_title (title.get_string());
1291 /* ::session_going_away() will have taken care of it */
1296 Editor::set_session (Session *t)
1298 SessionHandlePtr::set_session (t);
1304 _playlist_selector->set_session (_session);
1305 nudge_clock->set_session (_session);
1306 _summary->set_session (_session);
1307 _group_tabs->set_session (_session);
1308 _route_groups->set_session (_session);
1309 _regions->set_session (_session);
1310 _snapshots->set_session (_session);
1311 _routes->set_session (_session);
1312 _locations->set_session (_session);
1314 if (rhythm_ferret) {
1315 rhythm_ferret->set_session (_session);
1318 if (analysis_window) {
1319 analysis_window->set_session (_session);
1323 sfbrowser->set_session (_session);
1326 compute_fixed_ruler_scale ();
1328 /* Make sure we have auto loop and auto punch ranges */
1330 Location* loc = _session->locations()->auto_loop_location();
1332 loc->set_name (_("Loop"));
1335 loc = _session->locations()->auto_punch_location();
1338 loc->set_name (_("Punch"));
1341 refresh_location_display ();
1343 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1344 the selected Marker; this needs the LocationMarker list to be available.
1346 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1347 set_state (*node, Stateful::loading_state_version);
1349 /* catch up with the playhead */
1351 _session->request_locate (playhead_cursor->current_frame ());
1352 _pending_initial_locate = true;
1356 /* These signals can all be emitted by a non-GUI thread. Therefore the
1357 handlers for them must not attempt to directly interact with the GUI,
1358 but use PBD::Signal<T>::connect() which accepts an event loop
1359 ("context") where the handler will be asked to run.
1362 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1363 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1364 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1365 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1366 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1367 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1368 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1369 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1370 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1371 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1372 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1373 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1374 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1375 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1377 playhead_cursor->show ();
1379 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1380 Config->map_parameters (pc);
1381 _session->config.map_parameters (pc);
1383 restore_ruler_visibility ();
1384 //tempo_map_changed (PropertyChange (0));
1385 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1387 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1388 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1391 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1392 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1395 switch (_snap_type) {
1396 case SnapToRegionStart:
1397 case SnapToRegionEnd:
1398 case SnapToRegionSync:
1399 case SnapToRegionBoundary:
1400 build_region_boundary_cache ();
1407 /* register for undo history */
1408 _session->register_with_memento_command_factory(id(), this);
1409 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1411 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1413 LuaInstance::instance()->set_session(_session);
1415 start_updating_meters ();
1419 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1421 if (a->get_name() == "RegionMenu") {
1422 /* When the main menu's region menu is opened, we setup the actions so that they look right
1423 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1424 so we resensitize all region actions when the entered regionview or the region selection
1425 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1426 happens after the region context menu is opened. So we set a flag here, too.
1430 sensitize_the_right_region_actions ();
1431 _last_region_menu_was_main = true;
1436 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1438 using namespace Menu_Helpers;
1440 void (Editor::*emf)(FadeShape);
1441 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1444 images = &_xfade_in_images;
1445 emf = &Editor::set_fade_in_shape;
1447 images = &_xfade_out_images;
1448 emf = &Editor::set_fade_out_shape;
1453 _("Linear (for highly correlated material)"),
1454 *(*images)[FadeLinear],
1455 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1459 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1463 _("Constant power"),
1464 *(*images)[FadeConstantPower],
1465 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1468 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1473 *(*images)[FadeSymmetric],
1474 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1478 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1483 *(*images)[FadeSlow],
1484 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1492 *(*images)[FadeFast],
1493 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 /** Pop up a context menu for when the user clicks on a start crossfade */
1501 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1503 using namespace Menu_Helpers;
1504 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1509 MenuList& items (xfade_in_context_menu.items());
1512 if (arv->audio_region()->fade_in_active()) {
1513 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1515 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1518 items.push_back (SeparatorElem());
1519 fill_xfade_menu (items, true);
1521 xfade_in_context_menu.popup (button, time);
1524 /** Pop up a context menu for when the user clicks on an end crossfade */
1526 Editor::popup_xfade_out_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_out_context_menu.items());
1537 if (arv->audio_region()->fade_out_active()) {
1538 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1540 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1543 items.push_back (SeparatorElem());
1544 fill_xfade_menu (items, false);
1546 xfade_out_context_menu.popup (button, time);
1550 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1552 using namespace Menu_Helpers;
1553 Menu* (Editor::*build_menu_function)();
1556 switch (item_type) {
1558 case RegionViewName:
1559 case RegionViewNameHighlight:
1560 case LeftFrameHandle:
1561 case RightFrameHandle:
1562 if (with_selection) {
1563 build_menu_function = &Editor::build_track_selection_context_menu;
1565 build_menu_function = &Editor::build_track_region_context_menu;
1570 if (with_selection) {
1571 build_menu_function = &Editor::build_track_selection_context_menu;
1573 build_menu_function = &Editor::build_track_context_menu;
1578 if (clicked_routeview->track()) {
1579 build_menu_function = &Editor::build_track_context_menu;
1581 build_menu_function = &Editor::build_track_bus_context_menu;
1586 /* probably shouldn't happen but if it does, we don't care */
1590 menu = (this->*build_menu_function)();
1591 menu->set_name ("ArdourContextMenu");
1593 /* now handle specific situations */
1595 switch (item_type) {
1597 case RegionViewName:
1598 case RegionViewNameHighlight:
1599 case LeftFrameHandle:
1600 case RightFrameHandle:
1601 if (!with_selection) {
1602 if (region_edit_menu_split_item) {
1603 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1604 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1606 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1609 if (region_edit_menu_split_multichannel_item) {
1610 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1611 region_edit_menu_split_multichannel_item->set_sensitive (true);
1613 region_edit_menu_split_multichannel_item->set_sensitive (false);
1626 /* probably shouldn't happen but if it does, we don't care */
1630 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1632 /* Bounce to disk */
1634 using namespace Menu_Helpers;
1635 MenuList& edit_items = menu->items();
1637 edit_items.push_back (SeparatorElem());
1639 switch (clicked_routeview->audio_track()->freeze_state()) {
1640 case AudioTrack::NoFreeze:
1641 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1644 case AudioTrack::Frozen:
1645 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1648 case AudioTrack::UnFrozen:
1649 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1655 if (item_type == StreamItem && clicked_routeview) {
1656 clicked_routeview->build_underlay_menu(menu);
1659 /* When the region menu is opened, we setup the actions so that they look right
1662 sensitize_the_right_region_actions ();
1663 _last_region_menu_was_main = false;
1665 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1666 menu->popup (button, time);
1670 Editor::build_track_context_menu ()
1672 using namespace Menu_Helpers;
1674 MenuList& edit_items = track_context_menu.items();
1677 add_dstream_context_items (edit_items);
1678 return &track_context_menu;
1682 Editor::build_track_bus_context_menu ()
1684 using namespace Menu_Helpers;
1686 MenuList& edit_items = track_context_menu.items();
1689 add_bus_context_items (edit_items);
1690 return &track_context_menu;
1694 Editor::build_track_region_context_menu ()
1696 using namespace Menu_Helpers;
1697 MenuList& edit_items = track_region_context_menu.items();
1700 /* we've just cleared the track region context menu, so the menu that these
1701 two items were on will have disappeared; stop them dangling.
1703 region_edit_menu_split_item = 0;
1704 region_edit_menu_split_multichannel_item = 0;
1706 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1709 boost::shared_ptr<Track> tr;
1710 boost::shared_ptr<Playlist> pl;
1712 if ((tr = rtv->track())) {
1713 add_region_context_items (edit_items, tr);
1717 add_dstream_context_items (edit_items);
1719 return &track_region_context_menu;
1723 Editor::loudness_analyze_region_selection ()
1728 Selection& s (PublicEditor::instance ().get_selection ());
1729 RegionSelection ars = s.regions;
1730 ARDOUR::AnalysisGraph ag (_session);
1731 framecnt_t total_work = 0;
1733 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1734 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1738 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1741 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1742 total_work += arv->region ()->length ();
1745 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1747 ag.set_total_frames (total_work);
1748 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1751 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1752 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1756 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1760 ag.analyze_region (ar);
1763 if (!ag.canceled ()) {
1764 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1770 Editor::loudness_analyze_range_selection ()
1775 Selection& s (PublicEditor::instance ().get_selection ());
1776 TimeSelection ts = s.time;
1777 ARDOUR::AnalysisGraph ag (_session);
1778 framecnt_t total_work = 0;
1780 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1781 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1785 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1789 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1790 total_work += j->length ();
1794 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1796 ag.set_total_frames (total_work);
1797 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1800 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1801 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1805 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1809 ag.analyze_range (rui->route (), pl, ts);
1812 if (!ag.canceled ()) {
1813 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1819 Editor::spectral_analyze_region_selection ()
1821 if (analysis_window == 0) {
1822 analysis_window = new AnalysisWindow();
1825 analysis_window->set_session(_session);
1827 analysis_window->show_all();
1830 analysis_window->set_regionmode();
1831 analysis_window->analyze();
1833 analysis_window->present();
1837 Editor::spectral_analyze_range_selection()
1839 if (analysis_window == 0) {
1840 analysis_window = new AnalysisWindow();
1843 analysis_window->set_session(_session);
1845 analysis_window->show_all();
1848 analysis_window->set_rangemode();
1849 analysis_window->analyze();
1851 analysis_window->present();
1855 Editor::build_track_selection_context_menu ()
1857 using namespace Menu_Helpers;
1858 MenuList& edit_items = track_selection_context_menu.items();
1859 edit_items.clear ();
1861 add_selection_context_items (edit_items);
1862 // edit_items.push_back (SeparatorElem());
1863 // add_dstream_context_items (edit_items);
1865 return &track_selection_context_menu;
1869 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1871 using namespace Menu_Helpers;
1873 /* OK, stick the region submenu at the top of the list, and then add
1877 RegionSelection rs = get_regions_from_selection_and_entered ();
1879 string::size_type pos = 0;
1880 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1882 /* we have to hack up the region name because "_" has a special
1883 meaning for menu titles.
1886 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1887 menu_item_name.replace (pos, 1, "__");
1891 if (_popup_region_menu_item == 0) {
1892 _popup_region_menu_item = new MenuItem (menu_item_name);
1893 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1894 _popup_region_menu_item->show ();
1896 _popup_region_menu_item->set_label (menu_item_name);
1899 /* No latering allowed in later is higher layering model */
1900 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1901 if (act && Config->get_layer_model() == LaterHigher) {
1902 act->set_sensitive (false);
1904 act->set_sensitive (true);
1907 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1909 edit_items.push_back (*_popup_region_menu_item);
1910 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1911 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1913 edit_items.push_back (SeparatorElem());
1916 /** Add context menu items relevant to selection ranges.
1917 * @param edit_items List to add the items to.
1920 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1922 using namespace Menu_Helpers;
1924 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1925 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1927 edit_items.push_back (SeparatorElem());
1928 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1930 edit_items.push_back (SeparatorElem());
1931 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1932 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1934 edit_items.push_back (SeparatorElem());
1936 edit_items.push_back (
1938 _("Move Range Start to Previous Region Boundary"),
1939 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1943 edit_items.push_back (
1945 _("Move Range Start to Next Region Boundary"),
1946 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1950 edit_items.push_back (
1952 _("Move Range End to Previous Region Boundary"),
1953 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1957 edit_items.push_back (
1959 _("Move Range End to Next Region Boundary"),
1960 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1964 edit_items.push_back (SeparatorElem());
1965 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1966 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1971 edit_items.push_back (SeparatorElem());
1972 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1973 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1974 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1976 edit_items.push_back (SeparatorElem());
1977 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1979 edit_items.push_back (SeparatorElem());
1980 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1981 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1983 edit_items.push_back (SeparatorElem());
1984 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1985 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1986 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1987 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1988 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1989 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1990 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1996 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1998 using namespace Menu_Helpers;
2002 Menu *play_menu = manage (new Menu);
2003 MenuList& play_items = play_menu->items();
2004 play_menu->set_name ("ArdourContextMenu");
2006 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2007 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2008 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2009 play_items.push_back (SeparatorElem());
2010 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2012 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2016 Menu *select_menu = manage (new Menu);
2017 MenuList& select_items = select_menu->items();
2018 select_menu->set_name ("ArdourContextMenu");
2020 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2021 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2022 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2023 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2024 select_items.push_back (SeparatorElem());
2025 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2026 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2027 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2028 select_items.push_back (SeparatorElem());
2029 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2030 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2031 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2032 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2033 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2034 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2035 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2037 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2041 Menu *cutnpaste_menu = manage (new Menu);
2042 MenuList& cutnpaste_items = cutnpaste_menu->items();
2043 cutnpaste_menu->set_name ("ArdourContextMenu");
2045 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2046 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2047 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2049 cutnpaste_items.push_back (SeparatorElem());
2051 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2052 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2054 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2056 /* Adding new material */
2058 edit_items.push_back (SeparatorElem());
2059 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2060 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2064 Menu *nudge_menu = manage (new Menu());
2065 MenuList& nudge_items = nudge_menu->items();
2066 nudge_menu->set_name ("ArdourContextMenu");
2068 edit_items.push_back (SeparatorElem());
2069 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2070 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2071 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2072 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2074 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2078 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2080 using namespace Menu_Helpers;
2084 Menu *play_menu = manage (new Menu);
2085 MenuList& play_items = play_menu->items();
2086 play_menu->set_name ("ArdourContextMenu");
2088 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2089 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2090 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2094 Menu *select_menu = manage (new Menu);
2095 MenuList& select_items = select_menu->items();
2096 select_menu->set_name ("ArdourContextMenu");
2098 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2099 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2100 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2101 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2102 select_items.push_back (SeparatorElem());
2103 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2104 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2105 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2106 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2108 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2112 Menu *cutnpaste_menu = manage (new Menu);
2113 MenuList& cutnpaste_items = cutnpaste_menu->items();
2114 cutnpaste_menu->set_name ("ArdourContextMenu");
2116 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2117 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2118 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2120 Menu *nudge_menu = manage (new Menu());
2121 MenuList& nudge_items = nudge_menu->items();
2122 nudge_menu->set_name ("ArdourContextMenu");
2124 edit_items.push_back (SeparatorElem());
2125 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2126 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2127 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2128 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2130 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2134 Editor::snap_type() const
2140 Editor::snap_musical() const
2142 switch (_snap_type) {
2143 case SnapToBeatDiv128:
2144 case SnapToBeatDiv64:
2145 case SnapToBeatDiv32:
2146 case SnapToBeatDiv28:
2147 case SnapToBeatDiv24:
2148 case SnapToBeatDiv20:
2149 case SnapToBeatDiv16:
2150 case SnapToBeatDiv14:
2151 case SnapToBeatDiv12:
2152 case SnapToBeatDiv10:
2153 case SnapToBeatDiv8:
2154 case SnapToBeatDiv7:
2155 case SnapToBeatDiv6:
2156 case SnapToBeatDiv5:
2157 case SnapToBeatDiv4:
2158 case SnapToBeatDiv3:
2159 case SnapToBeatDiv2:
2171 Editor::snap_mode() const
2177 Editor::set_snap_to (SnapType st)
2179 unsigned int snap_ind = (unsigned int)st;
2181 if (internal_editing()) {
2182 internal_snap_type = st;
2184 pre_internal_snap_type = st;
2189 if (snap_ind > snap_type_strings.size() - 1) {
2191 _snap_type = (SnapType)snap_ind;
2194 string str = snap_type_strings[snap_ind];
2196 if (str != snap_type_selector.get_text()) {
2197 snap_type_selector.set_text (str);
2202 switch (_snap_type) {
2203 case SnapToBeatDiv128:
2204 case SnapToBeatDiv64:
2205 case SnapToBeatDiv32:
2206 case SnapToBeatDiv28:
2207 case SnapToBeatDiv24:
2208 case SnapToBeatDiv20:
2209 case SnapToBeatDiv16:
2210 case SnapToBeatDiv14:
2211 case SnapToBeatDiv12:
2212 case SnapToBeatDiv10:
2213 case SnapToBeatDiv8:
2214 case SnapToBeatDiv7:
2215 case SnapToBeatDiv6:
2216 case SnapToBeatDiv5:
2217 case SnapToBeatDiv4:
2218 case SnapToBeatDiv3:
2219 case SnapToBeatDiv2: {
2220 std::vector<TempoMap::BBTPoint> grid;
2221 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2222 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2223 update_tempo_based_rulers (grid);
2227 case SnapToRegionStart:
2228 case SnapToRegionEnd:
2229 case SnapToRegionSync:
2230 case SnapToRegionBoundary:
2231 build_region_boundary_cache ();
2239 redisplay_tempo (false);
2241 SnapChanged (); /* EMIT SIGNAL */
2245 Editor::set_snap_mode (SnapMode mode)
2247 string str = snap_mode_strings[(int)mode];
2249 if (internal_editing()) {
2250 internal_snap_mode = mode;
2252 pre_internal_snap_mode = mode;
2257 if (str != snap_mode_selector.get_text ()) {
2258 snap_mode_selector.set_text (str);
2265 Editor::set_edit_point_preference (EditPoint ep, bool force)
2267 bool changed = (_edit_point != ep);
2270 if (Profile->get_mixbus())
2271 if (ep == EditAtSelectedMarker)
2272 ep = EditAtPlayhead;
2274 string str = edit_point_strings[(int)ep];
2275 if (str != edit_point_selector.get_text ()) {
2276 edit_point_selector.set_text (str);
2279 update_all_enter_cursors();
2281 if (!force && !changed) {
2285 const char* action=NULL;
2287 switch (_edit_point) {
2288 case EditAtPlayhead:
2289 action = "edit-at-playhead";
2291 case EditAtSelectedMarker:
2292 action = "edit-at-marker";
2295 action = "edit-at-mouse";
2299 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2301 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2305 bool in_track_canvas;
2307 if (!mouse_frame (foo, in_track_canvas)) {
2308 in_track_canvas = false;
2311 reset_canvas_action_sensitivity (in_track_canvas);
2317 Editor::set_state (const XMLNode& node, int version)
2319 XMLProperty const * prop;
2321 PBD::Unwinder<bool> nsi (no_save_instant, true);
2323 Tabbable::set_state (node, version);
2325 if (_session && (prop = node.property ("playhead"))) {
2327 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2329 playhead_cursor->set_position (pos);
2331 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2332 playhead_cursor->set_position (0);
2335 playhead_cursor->set_position (0);
2338 if ((prop = node.property ("mixer-width"))) {
2339 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2342 if ((prop = node.property ("zoom-focus"))) {
2343 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2346 if ((prop = node.property ("zoom"))) {
2347 /* older versions of ardour used floating point samples_per_pixel */
2348 double f = PBD::atof (prop->value());
2349 reset_zoom (llrintf (f));
2351 reset_zoom (samples_per_pixel);
2354 if ((prop = node.property ("visible-track-count"))) {
2355 set_visible_track_count (PBD::atoi (prop->value()));
2358 if ((prop = node.property ("snap-to"))) {
2359 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2360 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2363 if ((prop = node.property ("snap-mode"))) {
2364 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2365 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2366 * snap_mode_selection_done() will only mark an already active item as active
2367 * which does not trigger set_text().
2369 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2372 if ((prop = node.property ("internal-snap-to"))) {
2373 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2376 if ((prop = node.property ("internal-snap-mode"))) {
2377 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2380 if ((prop = node.property ("pre-internal-snap-to"))) {
2381 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2384 if ((prop = node.property ("pre-internal-snap-mode"))) {
2385 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2388 if ((prop = node.property ("mouse-mode"))) {
2389 MouseMode m = str2mousemode(prop->value());
2390 set_mouse_mode (m, true);
2392 set_mouse_mode (MouseObject, true);
2395 if ((prop = node.property ("left-frame")) != 0) {
2397 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2401 reset_x_origin (pos);
2405 if ((prop = node.property ("y-origin")) != 0) {
2406 reset_y_origin (atof (prop->value ()));
2409 if ((prop = node.property ("join-object-range"))) {
2410 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2411 bool yn = string_is_affirmative (prop->value());
2413 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2414 tact->set_active (!yn);
2415 tact->set_active (yn);
2417 set_mouse_mode(mouse_mode, true);
2420 if ((prop = node.property ("edit-point"))) {
2421 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2424 if ((prop = node.property ("show-measures"))) {
2425 bool yn = string_is_affirmative (prop->value());
2426 _show_measures = yn;
2429 if ((prop = node.property ("follow-playhead"))) {
2430 bool yn = string_is_affirmative (prop->value());
2431 set_follow_playhead (yn);
2434 if ((prop = node.property ("stationary-playhead"))) {
2435 bool yn = string_is_affirmative (prop->value());
2436 set_stationary_playhead (yn);
2439 if ((prop = node.property ("region-list-sort-type"))) {
2440 RegionListSortType st;
2441 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2444 if ((prop = node.property ("show-editor-mixer"))) {
2446 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2449 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2450 bool yn = string_is_affirmative (prop->value());
2452 /* do it twice to force the change */
2454 tact->set_active (!yn);
2455 tact->set_active (yn);
2458 if ((prop = node.property ("show-editor-list"))) {
2460 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2463 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2464 bool yn = string_is_affirmative (prop->value());
2466 /* do it twice to force the change */
2468 tact->set_active (!yn);
2469 tact->set_active (yn);
2472 if ((prop = node.property (X_("editor-list-page")))) {
2473 _the_notebook.set_current_page (atoi (prop->value ()));
2476 if ((prop = node.property (X_("show-marker-lines")))) {
2477 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2479 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2480 bool yn = string_is_affirmative (prop->value ());
2482 tact->set_active (!yn);
2483 tact->set_active (yn);
2486 XMLNodeList children = node.children ();
2487 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2488 selection->set_state (**i, Stateful::current_state_version);
2489 _regions->set_state (**i);
2492 if ((prop = node.property ("maximised"))) {
2493 bool yn = string_is_affirmative (prop->value());
2494 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2496 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 bool fs = tact && tact->get_active();
2499 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2503 if ((prop = node.property ("nudge-clock-value"))) {
2505 sscanf (prop->value().c_str(), "%" PRId64, &f);
2506 nudge_clock->set (f);
2508 nudge_clock->set_mode (AudioClock::Timecode);
2509 nudge_clock->set (_session->frame_rate() * 5, true);
2514 * Not all properties may have been in XML, but
2515 * those that are linked to a private variable may need changing
2520 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2522 yn = _show_measures;
2523 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2524 /* do it twice to force the change */
2525 tact->set_active (!yn);
2526 tact->set_active (yn);
2529 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2530 yn = _follow_playhead;
2532 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2533 if (tact->get_active() != yn) {
2534 tact->set_active (yn);
2538 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2539 yn = _stationary_playhead;
2541 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2542 if (tact->get_active() != yn) {
2543 tact->set_active (yn);
2548 return LuaInstance::instance()->set_state(node);
2552 Editor::get_state ()
2554 XMLNode* node = new XMLNode (X_("Editor"));
2557 id().print (buf, sizeof (buf));
2558 node->add_property ("id", buf);
2560 node->add_child_nocopy (Tabbable::get_state());
2562 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2563 node->add_property("edit-horizontal-pane-pos", string(buf));
2564 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2565 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2566 node->add_property("edit-vertical-pane-pos", string(buf));
2568 maybe_add_mixer_strip_width (*node);
2570 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2572 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2573 node->add_property ("zoom", buf);
2574 node->add_property ("snap-to", enum_2_string (_snap_type));
2575 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2576 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2577 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2578 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2579 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2580 node->add_property ("edit-point", enum_2_string (_edit_point));
2581 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2582 node->add_property ("visible-track-count", buf);
2584 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2585 node->add_property ("playhead", buf);
2586 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2587 node->add_property ("left-frame", buf);
2588 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2589 node->add_property ("y-origin", buf);
2591 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2592 node->add_property ("maximised", _maximised ? "yes" : "no");
2593 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2594 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2595 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2596 node->add_property ("mouse-mode", enum2str(mouse_mode));
2597 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2599 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2601 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2602 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2605 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2607 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2608 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2611 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2612 node->add_property (X_("editor-list-page"), buf);
2614 if (button_bindings) {
2615 XMLNode* bb = new XMLNode (X_("Buttons"));
2616 button_bindings->save (*bb);
2617 node->add_child_nocopy (*bb);
2620 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2622 node->add_child_nocopy (selection->get_state ());
2623 node->add_child_nocopy (_regions->get_state ());
2625 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2626 node->add_property ("nudge-clock-value", buf);
2628 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2629 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2634 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2635 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2637 * @return pair: TimeAxisView that y is over, layer index.
2639 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2640 * in stacked or expanded region display mode, otherwise 0.
2642 std::pair<TimeAxisView *, double>
2643 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2645 if (!trackview_relative_offset) {
2646 y -= _trackview_group->canvas_origin().y;
2650 return std::make_pair ( (TimeAxisView *) 0, 0);
2653 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2655 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2662 return std::make_pair ( (TimeAxisView *) 0, 0);
2665 /** Snap a position to the grid, if appropriate, taking into account current
2666 * grid settings and also the state of any snap modifier keys that may be pressed.
2667 * @param start Position to snap.
2668 * @param event Event to get current key modifier information from, or 0.
2671 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2673 if (!_session || !event) {
2677 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2678 if (_snap_mode == SnapOff) {
2679 snap_to_internal (start, direction, for_mark);
2682 if (_snap_mode != SnapOff) {
2683 snap_to_internal (start, direction, for_mark);
2684 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2685 /* SnapOff, but we pressed the snap_delta modifier */
2686 snap_to_internal (start, direction, for_mark);
2692 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2694 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2698 snap_to_internal (start, direction, for_mark, ensure_snap);
2702 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2704 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2705 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2707 switch (_snap_type) {
2708 case SnapToTimecodeFrame:
2709 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2710 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2711 /* start is already on a whole timecode frame, do nothing */
2712 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2713 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2715 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2719 case SnapToTimecodeSeconds:
2720 if (_session->config.get_timecode_offset_negative()) {
2721 start += _session->config.get_timecode_offset ();
2723 start -= _session->config.get_timecode_offset ();
2725 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2726 (start % one_timecode_second == 0)) {
2727 /* start is already on a whole second, do nothing */
2728 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2729 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2731 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2734 if (_session->config.get_timecode_offset_negative()) {
2735 start -= _session->config.get_timecode_offset ();
2737 start += _session->config.get_timecode_offset ();
2741 case SnapToTimecodeMinutes:
2742 if (_session->config.get_timecode_offset_negative()) {
2743 start += _session->config.get_timecode_offset ();
2745 start -= _session->config.get_timecode_offset ();
2747 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2748 (start % one_timecode_minute == 0)) {
2749 /* start is already on a whole minute, do nothing */
2750 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2751 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2753 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2755 if (_session->config.get_timecode_offset_negative()) {
2756 start -= _session->config.get_timecode_offset ();
2758 start += _session->config.get_timecode_offset ();
2762 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2763 abort(); /*NOTREACHED*/
2768 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2770 const framepos_t one_second = _session->frame_rate();
2771 const framepos_t one_minute = _session->frame_rate() * 60;
2772 framepos_t presnap = start;
2776 switch (_snap_type) {
2777 case SnapToTimecodeFrame:
2778 case SnapToTimecodeSeconds:
2779 case SnapToTimecodeMinutes:
2780 return timecode_snap_to_internal (start, direction, for_mark);
2783 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2784 start % (one_second/75) == 0) {
2785 /* start is already on a whole CD frame, do nothing */
2786 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2787 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2789 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2794 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2795 start % one_second == 0) {
2796 /* start is already on a whole second, do nothing */
2797 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2798 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2800 start = (framepos_t) floor ((double) start / one_second) * one_second;
2805 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2806 start % one_minute == 0) {
2807 /* start is already on a whole minute, do nothing */
2808 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2809 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2811 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2816 start = _session->tempo_map().round_to_bar (start, direction);
2820 start = _session->tempo_map().round_to_beat (start, direction);
2823 case SnapToBeatDiv128:
2824 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2826 case SnapToBeatDiv64:
2827 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2829 case SnapToBeatDiv32:
2830 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2832 case SnapToBeatDiv28:
2833 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2835 case SnapToBeatDiv24:
2836 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2838 case SnapToBeatDiv20:
2839 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2841 case SnapToBeatDiv16:
2842 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2844 case SnapToBeatDiv14:
2845 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2847 case SnapToBeatDiv12:
2848 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2850 case SnapToBeatDiv10:
2851 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2853 case SnapToBeatDiv8:
2854 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2856 case SnapToBeatDiv7:
2857 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2859 case SnapToBeatDiv6:
2860 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2862 case SnapToBeatDiv5:
2863 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2865 case SnapToBeatDiv4:
2866 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2868 case SnapToBeatDiv3:
2869 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2871 case SnapToBeatDiv2:
2872 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2880 _session->locations()->marks_either_side (start, before, after);
2882 if (before == max_framepos && after == max_framepos) {
2883 /* No marks to snap to, so just don't snap */
2885 } else if (before == max_framepos) {
2887 } else if (after == max_framepos) {
2889 } else if (before != max_framepos && after != max_framepos) {
2890 /* have before and after */
2891 if ((start - before) < (after - start)) {
2900 case SnapToRegionStart:
2901 case SnapToRegionEnd:
2902 case SnapToRegionSync:
2903 case SnapToRegionBoundary:
2904 if (!region_boundary_cache.empty()) {
2906 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2907 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2909 if (direction > 0) {
2910 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2912 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2915 if (next != region_boundary_cache.begin ()) {
2920 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2921 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2923 if (start > (p + n) / 2) {
2932 switch (_snap_mode) {
2942 if (presnap > start) {
2943 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2947 } else if (presnap < start) {
2948 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2954 /* handled at entry */
2962 Editor::setup_toolbar ()
2964 HBox* mode_box = manage(new HBox);
2965 mode_box->set_border_width (2);
2966 mode_box->set_spacing(2);
2968 HBox* mouse_mode_box = manage (new HBox);
2969 HBox* mouse_mode_hbox = manage (new HBox);
2970 VBox* mouse_mode_vbox = manage (new VBox);
2971 Alignment* mouse_mode_align = manage (new Alignment);
2973 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2974 mouse_mode_size_group->add_widget (smart_mode_button);
2975 mouse_mode_size_group->add_widget (mouse_move_button);
2976 mouse_mode_size_group->add_widget (mouse_cut_button);
2977 mouse_mode_size_group->add_widget (mouse_select_button);
2978 mouse_mode_size_group->add_widget (mouse_timefx_button);
2979 mouse_mode_size_group->add_widget (mouse_audition_button);
2980 mouse_mode_size_group->add_widget (mouse_draw_button);
2981 mouse_mode_size_group->add_widget (mouse_content_button);
2983 mouse_mode_size_group->add_widget (zoom_in_button);
2984 mouse_mode_size_group->add_widget (zoom_out_button);
2985 mouse_mode_size_group->add_widget (zoom_preset_selector);
2986 mouse_mode_size_group->add_widget (zoom_out_full_button);
2987 mouse_mode_size_group->add_widget (zoom_focus_selector);
2989 mouse_mode_size_group->add_widget (tav_shrink_button);
2990 mouse_mode_size_group->add_widget (tav_expand_button);
2991 mouse_mode_size_group->add_widget (visible_tracks_selector);
2993 mouse_mode_size_group->add_widget (snap_type_selector);
2994 mouse_mode_size_group->add_widget (snap_mode_selector);
2996 mouse_mode_size_group->add_widget (edit_point_selector);
2997 mouse_mode_size_group->add_widget (edit_mode_selector);
2999 mouse_mode_size_group->add_widget (*nudge_clock);
3000 mouse_mode_size_group->add_widget (nudge_forward_button);
3001 mouse_mode_size_group->add_widget (nudge_backward_button);
3003 mouse_mode_hbox->set_spacing (2);
3005 if (!ARDOUR::Profile->get_trx()) {
3006 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3009 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3010 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3012 if (!ARDOUR::Profile->get_mixbus()) {
3013 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3016 if (!ARDOUR::Profile->get_trx()) {
3017 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3018 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3019 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3020 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3023 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3025 mouse_mode_align->add (*mouse_mode_vbox);
3026 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3028 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3030 edit_mode_selector.set_name ("mouse mode button");
3032 if (!ARDOUR::Profile->get_trx()) {
3033 mode_box->pack_start (edit_mode_selector, false, false);
3036 mode_box->pack_start (*mouse_mode_box, false, false);
3040 _zoom_box.set_spacing (2);
3041 _zoom_box.set_border_width (2);
3045 zoom_preset_selector.set_name ("zoom button");
3046 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3047 zoom_preset_selector.set_size_request (42, -1);
3049 zoom_in_button.set_name ("zoom button");
3050 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3051 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3052 zoom_in_button.set_related_action (act);
3054 zoom_out_button.set_name ("zoom button");
3055 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3056 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3057 zoom_out_button.set_related_action (act);
3059 zoom_out_full_button.set_name ("zoom button");
3060 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3061 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3062 zoom_out_full_button.set_related_action (act);
3064 zoom_focus_selector.set_name ("zoom button");
3066 if (ARDOUR::Profile->get_mixbus()) {
3067 _zoom_box.pack_start (zoom_preset_selector, false, false);
3068 } else if (ARDOUR::Profile->get_trx()) {
3069 mode_box->pack_start (zoom_out_button, false, false);
3070 mode_box->pack_start (zoom_in_button, false, false);
3072 _zoom_box.pack_start (zoom_out_button, false, false);
3073 _zoom_box.pack_start (zoom_in_button, false, false);
3074 _zoom_box.pack_start (zoom_out_full_button, false, false);
3075 _zoom_box.pack_start (zoom_focus_selector, false, false);
3078 /* Track zoom buttons */
3079 visible_tracks_selector.set_name ("zoom button");
3080 if (Profile->get_mixbus()) {
3081 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3082 visible_tracks_selector.set_size_request (42, -1);
3084 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3087 tav_expand_button.set_name ("zoom button");
3088 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3089 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3090 tav_expand_button.set_related_action (act);
3092 tav_shrink_button.set_name ("zoom button");
3093 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3094 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3095 tav_shrink_button.set_related_action (act);
3097 if (ARDOUR::Profile->get_mixbus()) {
3098 _zoom_box.pack_start (visible_tracks_selector);
3099 } else if (ARDOUR::Profile->get_trx()) {
3100 _zoom_box.pack_start (tav_shrink_button);
3101 _zoom_box.pack_start (tav_expand_button);
3103 _zoom_box.pack_start (visible_tracks_selector);
3104 _zoom_box.pack_start (tav_shrink_button);
3105 _zoom_box.pack_start (tav_expand_button);
3108 snap_box.set_spacing (2);
3109 snap_box.set_border_width (2);
3111 snap_type_selector.set_name ("mouse mode button");
3113 snap_mode_selector.set_name ("mouse mode button");
3115 edit_point_selector.set_name ("mouse mode button");
3117 snap_box.pack_start (snap_mode_selector, false, false);
3118 snap_box.pack_start (snap_type_selector, false, false);
3119 snap_box.pack_start (edit_point_selector, false, false);
3123 HBox *nudge_box = manage (new HBox);
3124 nudge_box->set_spacing (2);
3125 nudge_box->set_border_width (2);
3127 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3128 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3130 nudge_box->pack_start (nudge_backward_button, false, false);
3131 nudge_box->pack_start (nudge_forward_button, false, false);
3132 nudge_box->pack_start (*nudge_clock, false, false);
3135 /* Pack everything in... */
3137 HBox* hbox = manage (new HBox);
3138 hbox->set_spacing(2);
3140 toolbar_hbox.set_spacing (2);
3141 toolbar_hbox.set_border_width (1);
3143 toolbar_hbox.pack_start (*mode_box, false, false);
3144 if (!ARDOUR::Profile->get_trx()) {
3145 toolbar_hbox.pack_start (_zoom_box, false, false);
3146 toolbar_hbox.pack_start (*hbox, false, false);
3149 if (!ARDOUR::Profile->get_trx()) {
3150 hbox->pack_start (snap_box, false, false);
3151 hbox->pack_start (*nudge_box, false, false);
3156 toolbar_base.set_name ("ToolBarBase");
3157 toolbar_base.add (toolbar_hbox);
3159 _toolbar_viewport.add (toolbar_base);
3160 /* stick to the required height but allow width to vary if there's not enough room */
3161 _toolbar_viewport.set_size_request (1, -1);
3163 toolbar_frame.set_shadow_type (SHADOW_OUT);
3164 toolbar_frame.set_name ("BaseFrame");
3165 toolbar_frame.add (_toolbar_viewport);
3169 Editor::build_edit_point_menu ()
3171 using namespace Menu_Helpers;
3173 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3174 if(!Profile->get_mixbus())
3175 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3176 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3178 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3182 Editor::build_edit_mode_menu ()
3184 using namespace Menu_Helpers;
3186 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3187 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3188 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3189 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3191 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3195 Editor::build_snap_mode_menu ()
3197 using namespace Menu_Helpers;
3199 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3200 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3201 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3203 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3207 Editor::build_snap_type_menu ()
3209 using namespace Menu_Helpers;
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3242 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3247 Editor::setup_tooltips ()
3249 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3250 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3251 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3252 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3253 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3254 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3255 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3256 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3257 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3258 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3259 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3260 set_tooltip (zoom_in_button, _("Zoom In"));
3261 set_tooltip (zoom_out_button, _("Zoom Out"));
3262 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3263 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3264 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3265 set_tooltip (tav_expand_button, _("Expand Tracks"));
3266 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3267 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3268 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3269 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3270 set_tooltip (edit_point_selector, _("Edit Point"));
3271 set_tooltip (edit_mode_selector, _("Edit Mode"));
3272 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3276 Editor::convert_drop_to_paths (
3277 vector<string>& paths,
3278 const RefPtr<Gdk::DragContext>& /*context*/,
3281 const SelectionData& data,
3285 if (_session == 0) {
3289 vector<string> uris = data.get_uris();
3293 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3294 are actually URI lists. So do it by hand.
3297 if (data.get_target() != "text/plain") {
3301 /* Parse the "uri-list" format that Nautilus provides,
3302 where each pathname is delimited by \r\n.
3304 THERE MAY BE NO NULL TERMINATING CHAR!!!
3307 string txt = data.get_text();
3311 p = (char *) malloc (txt.length() + 1);
3312 txt.copy (p, txt.length(), 0);
3313 p[txt.length()] = '\0';
3319 while (g_ascii_isspace (*p))
3323 while (*q && (*q != '\n') && (*q != '\r')) {
3330 while (q > p && g_ascii_isspace (*q))
3335 uris.push_back (string (p, q - p + 1));
3339 p = strchr (p, '\n');
3351 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3352 if ((*i).substr (0,7) == "file://") {
3353 paths.push_back (Glib::filename_from_uri (*i));
3361 Editor::new_tempo_section ()
3366 Editor::map_transport_state ()
3368 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3370 if (_session && _session->transport_stopped()) {
3371 have_pending_keyboard_selection = false;
3374 update_loop_range_view ();
3380 Editor::begin_selection_op_history ()
3382 selection_op_cmd_depth = 0;
3383 selection_op_history_it = 0;
3385 while(!selection_op_history.empty()) {
3386 delete selection_op_history.front();
3387 selection_op_history.pop_front();
3390 selection_undo_action->set_sensitive (false);
3391 selection_redo_action->set_sensitive (false);
3392 selection_op_history.push_front (&_selection_memento->get_state ());
3396 Editor::begin_reversible_selection_op (string name)
3399 //cerr << name << endl;
3400 /* begin/commit pairs can be nested */
3401 selection_op_cmd_depth++;
3406 Editor::commit_reversible_selection_op ()
3409 if (selection_op_cmd_depth == 1) {
3411 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3413 The user has undone some selection ops and then made a new one,
3414 making anything earlier in the list invalid.
3417 list<XMLNode *>::iterator it = selection_op_history.begin();
3418 list<XMLNode *>::iterator e_it = it;
3419 advance (e_it, selection_op_history_it);
3421 for ( ; it != e_it; ++it) {
3424 selection_op_history.erase (selection_op_history.begin(), e_it);
3427 selection_op_history.push_front (&_selection_memento->get_state ());
3428 selection_op_history_it = 0;
3430 selection_undo_action->set_sensitive (true);
3431 selection_redo_action->set_sensitive (false);
3434 if (selection_op_cmd_depth > 0) {
3435 selection_op_cmd_depth--;
3441 Editor::undo_selection_op ()
3444 selection_op_history_it++;
3446 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3447 if (n == selection_op_history_it) {
3448 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3449 selection_redo_action->set_sensitive (true);
3453 /* is there an earlier entry? */
3454 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3455 selection_undo_action->set_sensitive (false);
3461 Editor::redo_selection_op ()
3464 if (selection_op_history_it > 0) {
3465 selection_op_history_it--;
3468 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3469 if (n == selection_op_history_it) {
3470 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3471 selection_undo_action->set_sensitive (true);
3476 if (selection_op_history_it == 0) {
3477 selection_redo_action->set_sensitive (false);
3483 Editor::begin_reversible_command (string name)
3486 before.push_back (&_selection_memento->get_state ());
3487 _session->begin_reversible_command (name);
3492 Editor::begin_reversible_command (GQuark q)
3495 before.push_back (&_selection_memento->get_state ());
3496 _session->begin_reversible_command (q);
3501 Editor::abort_reversible_command ()
3504 while(!before.empty()) {
3505 delete before.front();
3508 _session->abort_reversible_command ();
3513 Editor::commit_reversible_command ()
3516 if (before.size() == 1) {
3517 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3518 redo_action->set_sensitive(false);
3519 undo_action->set_sensitive(true);
3520 begin_selection_op_history ();
3523 if (before.empty()) {
3524 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3529 _session->commit_reversible_command ();
3534 Editor::history_changed ()
3538 if (undo_action && _session) {
3539 if (_session->undo_depth() == 0) {
3540 label = S_("Command|Undo");
3542 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3544 undo_action->property_label() = label;
3547 if (redo_action && _session) {
3548 if (_session->redo_depth() == 0) {
3550 redo_action->set_sensitive (false);
3552 label = string_compose(_("Redo (%1)"), _session->next_redo());
3553 redo_action->set_sensitive (true);
3555 redo_action->property_label() = label;
3560 Editor::duplicate_range (bool with_dialog)
3564 RegionSelection rs = get_regions_from_selection_and_entered ();
3566 if ( selection->time.length() == 0 && rs.empty()) {
3572 ArdourDialog win (_("Duplicate"));
3573 Label label (_("Number of duplications:"));
3574 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3575 SpinButton spinner (adjustment, 0.0, 1);
3578 win.get_vbox()->set_spacing (12);
3579 win.get_vbox()->pack_start (hbox);
3580 hbox.set_border_width (6);
3581 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3583 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3584 place, visually. so do this by hand.
3587 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3588 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3589 spinner.grab_focus();
3595 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3596 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3597 win.set_default_response (RESPONSE_ACCEPT);
3599 spinner.grab_focus ();
3601 switch (win.run ()) {
3602 case RESPONSE_ACCEPT:
3608 times = adjustment.get_value();
3611 if ((current_mouse_mode() == Editing::MouseRange)) {
3612 if (selection->time.length()) {
3613 duplicate_selection (times);
3615 } else if (get_smart_mode()) {
3616 if (selection->time.length()) {
3617 duplicate_selection (times);
3619 duplicate_some_regions (rs, times);
3621 duplicate_some_regions (rs, times);
3626 Editor::set_edit_mode (EditMode m)
3628 Config->set_edit_mode (m);
3632 Editor::cycle_edit_mode ()
3634 switch (Config->get_edit_mode()) {
3636 Config->set_edit_mode (Ripple);
3640 Config->set_edit_mode (Lock);
3643 Config->set_edit_mode (Slide);
3649 Editor::edit_mode_selection_done ( EditMode m )
3651 Config->set_edit_mode ( m );
3655 Editor::snap_type_selection_done (SnapType snaptype)
3657 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3659 ract->set_active ();
3664 Editor::snap_mode_selection_done (SnapMode mode)
3666 RefPtr<RadioAction> ract = snap_mode_action (mode);
3669 ract->set_active (true);
3674 Editor::cycle_edit_point (bool with_marker)
3676 if(Profile->get_mixbus())
3677 with_marker = false;
3679 switch (_edit_point) {
3681 set_edit_point_preference (EditAtPlayhead);
3683 case EditAtPlayhead:
3685 set_edit_point_preference (EditAtSelectedMarker);
3687 set_edit_point_preference (EditAtMouse);
3690 case EditAtSelectedMarker:
3691 set_edit_point_preference (EditAtMouse);
3697 Editor::edit_point_selection_done (EditPoint ep)
3699 set_edit_point_preference ( ep );
3703 Editor::build_zoom_focus_menu ()
3705 using namespace Menu_Helpers;
3707 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3708 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3709 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3710 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3711 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3712 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3714 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3718 Editor::zoom_focus_selection_done ( ZoomFocus f )
3720 RefPtr<RadioAction> ract = zoom_focus_action (f);
3722 ract->set_active ();
3727 Editor::build_track_count_menu ()
3729 using namespace Menu_Helpers;
3731 if (!Profile->get_mixbus()) {
3732 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3740 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3744 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3746 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3747 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3748 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3749 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3750 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3751 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3752 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3753 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3754 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3755 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3757 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3758 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3759 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3760 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3761 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3762 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3763 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3764 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3765 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3766 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3767 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3772 Editor::set_zoom_preset (int64_t ms)
3775 temporal_zoom_session();
3779 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3780 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3784 Editor::set_visible_track_count (int32_t n)
3786 _visible_track_count = n;
3788 /* if the canvas hasn't really been allocated any size yet, just
3789 record the desired number of visible tracks and return. when canvas
3790 allocation happens, we will get called again and then we can do the
3794 if (_visible_canvas_height <= 1) {
3800 DisplaySuspender ds;
3802 if (_visible_track_count > 0) {
3803 h = trackviews_height() / _visible_track_count;
3804 std::ostringstream s;
3805 s << _visible_track_count;
3807 } else if (_visible_track_count == 0) {
3809 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3810 if ((*i)->marked_for_display()) {
3814 h = trackviews_height() / n;
3817 /* negative value means that the visible track count has
3818 been overridden by explicit track height changes.
3820 visible_tracks_selector.set_text (X_("*"));
3824 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3825 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3828 if (str != visible_tracks_selector.get_text()) {
3829 visible_tracks_selector.set_text (str);
3834 Editor::override_visible_track_count ()
3836 _visible_track_count = -1;
3837 visible_tracks_selector.set_text ( _("*") );
3841 Editor::edit_controls_button_release (GdkEventButton* ev)
3843 if (Keyboard::is_context_menu_event (ev)) {
3844 ARDOUR_UI::instance()->add_route ();
3845 } else if (ev->button == 1) {
3846 selection->clear_tracks ();
3853 Editor::mouse_select_button_release (GdkEventButton* ev)
3855 /* this handles just right-clicks */
3857 if (ev->button != 3) {
3865 Editor::set_zoom_focus (ZoomFocus f)
3867 string str = zoom_focus_strings[(int)f];
3869 if (str != zoom_focus_selector.get_text()) {
3870 zoom_focus_selector.set_text (str);
3873 if (zoom_focus != f) {
3880 Editor::cycle_zoom_focus ()
3882 switch (zoom_focus) {
3884 set_zoom_focus (ZoomFocusRight);
3886 case ZoomFocusRight:
3887 set_zoom_focus (ZoomFocusCenter);
3889 case ZoomFocusCenter:
3890 set_zoom_focus (ZoomFocusPlayhead);
3892 case ZoomFocusPlayhead:
3893 set_zoom_focus (ZoomFocusMouse);
3895 case ZoomFocusMouse:
3896 set_zoom_focus (ZoomFocusEdit);
3899 set_zoom_focus (ZoomFocusLeft);
3905 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3907 /* recover or initialize pane positions. do this here rather than earlier because
3908 we don't want the positions to change the child allocations, which they seem to do.
3912 XMLProperty const * prop;
3914 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3923 XMLNode* geometry = find_named_node (*node, "geometry");
3925 if (which == static_cast<Paned*> (&edit_pane)) {
3927 if (done & Horizontal) {
3931 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3932 _notebook_shrunk = string_is_affirmative (prop->value ());
3935 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3936 /* initial allocation is 90% to canvas, 10% to notebook */
3937 pos = (int) floor (alloc.get_width() * 0.90f);
3938 snprintf (buf, sizeof(buf), "%d", pos);
3940 pos = atoi (prop->value());
3943 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3944 edit_pane.set_position (pos);
3947 done = (Pane) (done | Horizontal);
3949 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3951 if (done & Vertical) {
3955 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3956 /* initial allocation is 90% to canvas, 10% to summary */
3957 pos = (int) floor (alloc.get_height() * 0.90f);
3958 snprintf (buf, sizeof(buf), "%d", pos);
3961 pos = atoi (prop->value());
3964 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3965 editor_summary_pane.set_position (pos);
3968 done = (Pane) (done | Vertical);
3973 Editor::set_show_measures (bool yn)
3975 if (_show_measures != yn) {
3978 if ((_show_measures = yn) == true) {
3980 tempo_lines->show();
3983 std::vector<TempoMap::BBTPoint> grid;
3984 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3985 draw_measures (grid);
3993 Editor::toggle_follow_playhead ()
3995 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3997 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3998 set_follow_playhead (tact->get_active());
4002 /** @param yn true to follow playhead, otherwise false.
4003 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4006 Editor::set_follow_playhead (bool yn, bool catch_up)
4008 if (_follow_playhead != yn) {
4009 if ((_follow_playhead = yn) == true && catch_up) {
4011 reset_x_origin_to_follow_playhead ();
4018 Editor::toggle_stationary_playhead ()
4020 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4022 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4023 set_stationary_playhead (tact->get_active());
4028 Editor::set_stationary_playhead (bool yn)
4030 if (_stationary_playhead != yn) {
4031 if ((_stationary_playhead = yn) == true) {
4033 // FIXME need a 3.0 equivalent of this 2.X call
4034 // update_current_screen ();
4041 Editor::playlist_selector () const
4043 return *_playlist_selector;
4047 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4049 if (paste_count == 0) {
4050 /* don't bother calculating an offset that will be zero anyway */
4054 /* calculate basic unsnapped multi-paste offset */
4055 framecnt_t offset = paste_count * duration;
4057 /* snap offset so pos + offset is aligned to the grid */
4058 framepos_t offset_pos = pos + offset;
4059 snap_to(offset_pos, RoundUpMaybe);
4060 offset = offset_pos - pos;
4066 Editor::get_grid_beat_divisions(framepos_t position)
4068 switch (_snap_type) {
4069 case SnapToBeatDiv128: return 128;
4070 case SnapToBeatDiv64: return 64;
4071 case SnapToBeatDiv32: return 32;
4072 case SnapToBeatDiv28: return 28;
4073 case SnapToBeatDiv24: return 24;
4074 case SnapToBeatDiv20: return 20;
4075 case SnapToBeatDiv16: return 16;
4076 case SnapToBeatDiv14: return 14;
4077 case SnapToBeatDiv12: return 12;
4078 case SnapToBeatDiv10: return 10;
4079 case SnapToBeatDiv8: return 8;
4080 case SnapToBeatDiv7: return 7;
4081 case SnapToBeatDiv6: return 6;
4082 case SnapToBeatDiv5: return 5;
4083 case SnapToBeatDiv4: return 4;
4084 case SnapToBeatDiv3: return 3;
4085 case SnapToBeatDiv2: return 2;
4092 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4096 const unsigned divisions = get_grid_beat_divisions(position);
4098 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4101 switch (_snap_type) {
4103 return Evoral::Beats(1.0);
4106 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4114 return Evoral::Beats();
4118 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4122 ret = nudge_clock->current_duration (pos);
4123 next = ret + 1; /* XXXX fix me */
4129 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4131 ArdourDialog dialog (_("Playlist Deletion"));
4132 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4133 "If it is kept, its audio files will not be cleaned.\n"
4134 "If it is deleted, audio files used by it alone will be cleaned."),
4137 dialog.set_position (WIN_POS_CENTER);
4138 dialog.get_vbox()->pack_start (label);
4142 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4143 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4144 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4145 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4146 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4148 // by default gtk uses the left most button
4149 keep->grab_focus ();
4151 switch (dialog.run ()) {
4153 /* keep this and all remaining ones */
4158 /* delete this and all others */
4162 case RESPONSE_ACCEPT:
4163 /* delete the playlist */
4167 case RESPONSE_REJECT:
4168 /* keep the playlist */
4180 Editor::audio_region_selection_covers (framepos_t where)
4182 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4183 if ((*a)->region()->covers (where)) {
4192 Editor::prepare_for_cleanup ()
4194 cut_buffer->clear_regions ();
4195 cut_buffer->clear_playlists ();
4197 selection->clear_regions ();
4198 selection->clear_playlists ();
4200 _regions->suspend_redisplay ();
4204 Editor::finish_cleanup ()
4206 _regions->resume_redisplay ();
4210 Editor::transport_loop_location()
4213 return _session->locations()->auto_loop_location();
4220 Editor::transport_punch_location()
4223 return _session->locations()->auto_punch_location();
4230 Editor::control_layout_scroll (GdkEventScroll* ev)
4232 /* Just forward to the normal canvas scroll method. The coordinate
4233 systems are different but since the canvas is always larger than the
4234 track headers, and aligned with the trackview area, this will work.
4236 In the not too distant future this layout is going away anyway and
4237 headers will be on the canvas.
4239 return canvas_scroll_event (ev, false);
4243 Editor::session_state_saved (string)
4246 _snapshots->redisplay ();
4250 Editor::maximise_editing_space ()
4256 Gtk::Window* toplevel = current_toplevel();
4259 toplevel->fullscreen ();
4265 Editor::restore_editing_space ()
4271 Gtk::Window* toplevel = current_toplevel();
4274 toplevel->unfullscreen();
4280 * Make new playlists for a given track and also any others that belong
4281 * to the same active route group with the `select' property.
4286 Editor::new_playlists (TimeAxisView* v)
4288 begin_reversible_command (_("new playlists"));
4289 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4290 _session->playlists->get (playlists);
4291 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4292 commit_reversible_command ();
4296 * Use a copy of the current playlist for a given track and also any others that belong
4297 * to the same active route group with the `select' property.
4302 Editor::copy_playlists (TimeAxisView* v)
4304 begin_reversible_command (_("copy playlists"));
4305 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4306 _session->playlists->get (playlists);
4307 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4308 commit_reversible_command ();
4311 /** Clear the current playlist for a given track and also any others that belong
4312 * to the same active route group with the `select' property.
4317 Editor::clear_playlists (TimeAxisView* v)
4319 begin_reversible_command (_("clear playlists"));
4320 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4321 _session->playlists->get (playlists);
4322 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4323 commit_reversible_command ();
4327 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4329 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4333 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4335 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4339 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4341 atv.clear_playlist ();
4345 Editor::get_y_origin () const
4347 return vertical_adjustment.get_value ();
4350 /** Queue up a change to the viewport x origin.
4351 * @param frame New x origin.
4354 Editor::reset_x_origin (framepos_t frame)
4356 pending_visual_change.add (VisualChange::TimeOrigin);
4357 pending_visual_change.time_origin = frame;
4358 ensure_visual_change_idle_handler ();
4362 Editor::reset_y_origin (double y)
4364 pending_visual_change.add (VisualChange::YOrigin);
4365 pending_visual_change.y_origin = y;
4366 ensure_visual_change_idle_handler ();
4370 Editor::reset_zoom (framecnt_t spp)
4372 if (spp == samples_per_pixel) {
4376 pending_visual_change.add (VisualChange::ZoomLevel);
4377 pending_visual_change.samples_per_pixel = spp;
4378 ensure_visual_change_idle_handler ();
4382 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4384 reset_x_origin (frame);
4387 if (!no_save_visual) {
4388 undo_visual_stack.push_back (current_visual_state(false));
4392 Editor::VisualState::VisualState (bool with_tracks)
4393 : gui_state (with_tracks ? new GUIObjectState : 0)
4397 Editor::VisualState::~VisualState ()
4402 Editor::VisualState*
4403 Editor::current_visual_state (bool with_tracks)
4405 VisualState* vs = new VisualState (with_tracks);
4406 vs->y_position = vertical_adjustment.get_value();
4407 vs->samples_per_pixel = samples_per_pixel;
4408 vs->leftmost_frame = leftmost_frame;
4409 vs->zoom_focus = zoom_focus;
4412 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4419 Editor::undo_visual_state ()
4421 if (undo_visual_stack.empty()) {
4425 VisualState* vs = undo_visual_stack.back();
4426 undo_visual_stack.pop_back();
4429 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4432 use_visual_state (*vs);
4437 Editor::redo_visual_state ()
4439 if (redo_visual_stack.empty()) {
4443 VisualState* vs = redo_visual_stack.back();
4444 redo_visual_stack.pop_back();
4446 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4447 // why do we check here?
4448 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4451 use_visual_state (*vs);
4456 Editor::swap_visual_state ()
4458 if (undo_visual_stack.empty()) {
4459 redo_visual_state ();
4461 undo_visual_state ();
4466 Editor::use_visual_state (VisualState& vs)
4468 PBD::Unwinder<bool> nsv (no_save_visual, true);
4469 DisplaySuspender ds;
4471 vertical_adjustment.set_value (vs.y_position);
4473 set_zoom_focus (vs.zoom_focus);
4474 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4477 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4479 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4480 (*i)->clear_property_cache();
4481 (*i)->reset_visual_state ();
4485 _routes->update_visibility ();
4488 /** This is the core function that controls the zoom level of the canvas. It is called
4489 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4490 * @param spp new number of samples per pixel
4493 Editor::set_samples_per_pixel (framecnt_t spp)
4499 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4500 const framecnt_t lots_of_pixels = 4000;
4502 /* if the zoom level is greater than what you'd get trying to display 3
4503 * days of audio on a really big screen, then it's too big.
4506 if (spp * lots_of_pixels > three_days) {
4510 samples_per_pixel = spp;
4513 tempo_lines->tempo_map_changed();
4516 bool const showing_time_selection = selection->time.length() > 0;
4518 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4519 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4520 (*i)->reshow_selection (selection->time);
4524 ZoomChanged (); /* EMIT_SIGNAL */
4526 ArdourCanvas::GtkCanvasViewport* c;
4528 c = get_track_canvas();
4530 c->canvas()->zoomed ();
4533 if (playhead_cursor) {
4534 playhead_cursor->set_position (playhead_cursor->current_frame ());
4537 refresh_location_display();
4538 _summary->set_overlays_dirty ();
4540 update_marker_labels ();
4546 Editor::queue_visual_videotimeline_update ()
4549 * pending_visual_change.add (VisualChange::VideoTimeline);
4550 * or maybe even more specific: which videotimeline-image
4551 * currently it calls update_video_timeline() to update
4552 * _all outdated_ images on the video-timeline.
4553 * see 'exposeimg()' in video_image_frame.cc
4555 ensure_visual_change_idle_handler ();
4559 Editor::ensure_visual_change_idle_handler ()
4561 if (pending_visual_change.idle_handler_id < 0) {
4562 // see comment in add_to_idle_resize above.
4563 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4564 pending_visual_change.being_handled = false;
4569 Editor::_idle_visual_changer (void* arg)
4571 return static_cast<Editor*>(arg)->idle_visual_changer ();
4575 Editor::idle_visual_changer ()
4577 /* set_horizontal_position() below (and maybe other calls) call
4578 gtk_main_iteration(), so it's possible that a signal will be handled
4579 half-way through this method. If this signal wants an
4580 idle_visual_changer we must schedule another one after this one, so
4581 mark the idle_handler_id as -1 here to allow that. Also make a note
4582 that we are doing the visual change, so that changes in response to
4583 super-rapid-screen-update can be dropped if we are still processing
4587 pending_visual_change.idle_handler_id = -1;
4588 pending_visual_change.being_handled = true;
4590 VisualChange vc = pending_visual_change;
4592 pending_visual_change.pending = (VisualChange::Type) 0;
4594 visual_changer (vc);
4596 pending_visual_change.being_handled = false;
4598 return 0; /* this is always a one-shot call */
4602 Editor::visual_changer (const VisualChange& vc)
4604 double const last_time_origin = horizontal_position ();
4606 if (vc.pending & VisualChange::ZoomLevel) {
4607 set_samples_per_pixel (vc.samples_per_pixel);
4609 compute_fixed_ruler_scale ();
4611 std::vector<TempoMap::BBTPoint> grid;
4612 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4613 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4614 update_tempo_based_rulers (grid);
4616 update_video_timeline();
4619 if (vc.pending & VisualChange::TimeOrigin) {
4620 set_horizontal_position (vc.time_origin / samples_per_pixel);
4623 if (vc.pending & VisualChange::YOrigin) {
4624 vertical_adjustment.set_value (vc.y_origin);
4627 if (last_time_origin == horizontal_position ()) {
4628 /* changed signal not emitted */
4629 update_fixed_rulers ();
4630 redisplay_tempo (true);
4633 if (!(vc.pending & VisualChange::ZoomLevel)) {
4634 update_video_timeline();
4637 _summary->set_overlays_dirty ();
4640 struct EditorOrderTimeAxisSorter {
4641 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4642 return a->order () < b->order ();
4647 Editor::sort_track_selection (TrackViewList& sel)
4649 EditorOrderTimeAxisSorter cmp;
4654 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4657 framepos_t where = 0;
4658 EditPoint ep = _edit_point;
4660 if (Profile->get_mixbus())
4661 if (ep == EditAtSelectedMarker)
4662 ep = EditAtPlayhead;
4664 if (from_outside_canvas && (ep == EditAtMouse)) {
4665 ep = EditAtPlayhead;
4666 } else if (from_context_menu && (ep == EditAtMouse)) {
4667 return canvas_event_sample (&context_click_event, 0, 0);
4670 if (entered_marker) {
4671 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4672 return entered_marker->position();
4675 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4676 ep = EditAtSelectedMarker;
4679 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4680 ep = EditAtPlayhead;
4684 case EditAtPlayhead:
4685 if (_dragging_playhead) {
4686 where = *_control_scroll_target;
4688 where = _session->audible_frame();
4690 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4693 case EditAtSelectedMarker:
4694 if (!selection->markers.empty()) {
4696 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4699 where = loc->start();
4703 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4711 if (!mouse_frame (where, ignored)) {
4712 /* XXX not right but what can we do ? */
4716 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4724 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4726 if (!_session) return;
4728 begin_reversible_command (cmd);
4732 if ((tll = transport_loop_location()) == 0) {
4733 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4734 XMLNode &before = _session->locations()->get_state();
4735 _session->locations()->add (loc, true);
4736 _session->set_auto_loop_location (loc);
4737 XMLNode &after = _session->locations()->get_state();
4738 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4740 XMLNode &before = tll->get_state();
4741 tll->set_hidden (false, this);
4742 tll->set (start, end);
4743 XMLNode &after = tll->get_state();
4744 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4747 commit_reversible_command ();
4751 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4753 if (!_session) return;
4755 begin_reversible_command (cmd);
4759 if ((tpl = transport_punch_location()) == 0) {
4760 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4761 XMLNode &before = _session->locations()->get_state();
4762 _session->locations()->add (loc, true);
4763 _session->set_auto_punch_location (loc);
4764 XMLNode &after = _session->locations()->get_state();
4765 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4767 XMLNode &before = tpl->get_state();
4768 tpl->set_hidden (false, this);
4769 tpl->set (start, end);
4770 XMLNode &after = tpl->get_state();
4771 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4774 commit_reversible_command ();
4777 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4778 * @param rs List to which found regions are added.
4779 * @param where Time to look at.
4780 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4783 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4785 const TrackViewList* tracks;
4788 tracks = &track_views;
4793 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4795 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4798 boost::shared_ptr<Track> tr;
4799 boost::shared_ptr<Playlist> pl;
4801 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4803 boost::shared_ptr<RegionList> regions = pl->regions_at (
4804 (framepos_t) floor ( (double) where * tr->speed()));
4806 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4807 RegionView* rv = rtv->view()->find_view (*i);
4818 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4820 const TrackViewList* tracks;
4823 tracks = &track_views;
4828 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4829 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4831 boost::shared_ptr<Track> tr;
4832 boost::shared_ptr<Playlist> pl;
4834 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4836 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4837 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4839 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4841 RegionView* rv = rtv->view()->find_view (*i);
4852 /** Get regions using the following method:
4854 * Make a region list using:
4855 * (a) any selected regions
4856 * (b) the intersection of any selected tracks and the edit point(*)
4857 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4859 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4861 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4865 Editor::get_regions_from_selection_and_edit_point ()
4867 RegionSelection regions;
4869 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4870 regions.add (entered_regionview);
4872 regions = selection->regions;
4875 if ( regions.empty() ) {
4876 TrackViewList tracks = selection->tracks;
4878 if (!tracks.empty()) {
4879 /* no region selected or entered, but some selected tracks:
4880 * act on all regions on the selected tracks at the edit point
4882 framepos_t const where = get_preferred_edit_position ();
4883 get_regions_at(regions, where, tracks);
4890 /** Get regions using the following method:
4892 * Make a region list using:
4893 * (a) any selected regions
4894 * (b) the intersection of any selected tracks and the edit point(*)
4895 * (c) if neither exists, then whatever region is under the mouse
4897 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4899 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4902 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4904 RegionSelection regions;
4906 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4907 regions.add (entered_regionview);
4909 regions = selection->regions;
4912 if ( regions.empty() ) {
4913 TrackViewList tracks = selection->tracks;
4915 if (!tracks.empty()) {
4916 /* no region selected or entered, but some selected tracks:
4917 * act on all regions on the selected tracks at the edit point
4919 get_regions_at(regions, pos, tracks);
4926 /** Start with regions that are selected, or the entered regionview if none are selected.
4927 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4928 * of the regions that we started with.
4932 Editor::get_regions_from_selection_and_entered () const
4934 RegionSelection regions = selection->regions;
4936 if (regions.empty() && entered_regionview) {
4937 regions.add (entered_regionview);
4944 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4946 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4947 RouteTimeAxisView* rtav;
4949 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4950 boost::shared_ptr<Playlist> pl;
4951 std::vector<boost::shared_ptr<Region> > results;
4952 boost::shared_ptr<Track> tr;
4954 if ((tr = rtav->track()) == 0) {
4959 if ((pl = (tr->playlist())) != 0) {
4960 boost::shared_ptr<Region> r = pl->region_by_id (id);
4962 RegionView* rv = rtav->view()->find_view (r);
4964 regions.push_back (rv);
4973 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4976 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4977 MidiTimeAxisView* mtav;
4979 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4981 mtav->get_per_region_note_selection (selection);
4988 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4990 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4992 RouteTimeAxisView* tatv;
4994 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4996 boost::shared_ptr<Playlist> pl;
4997 vector<boost::shared_ptr<Region> > results;
4999 boost::shared_ptr<Track> tr;
5001 if ((tr = tatv->track()) == 0) {
5006 if ((pl = (tr->playlist())) != 0) {
5007 if (src_comparison) {
5008 pl->get_source_equivalent_regions (region, results);
5010 pl->get_region_list_equivalent_regions (region, results);
5014 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5015 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5016 regions.push_back (marv);
5025 Editor::show_rhythm_ferret ()
5027 if (rhythm_ferret == 0) {
5028 rhythm_ferret = new RhythmFerret(*this);
5031 rhythm_ferret->set_session (_session);
5032 rhythm_ferret->show ();
5033 rhythm_ferret->present ();
5037 Editor::first_idle ()
5039 MessageDialog* dialog = 0;
5041 if (track_views.size() > 1) {
5042 Timers::TimerSuspender t;
5043 dialog = new MessageDialog (
5044 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5048 ARDOUR_UI::instance()->flush_pending ();
5051 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5055 // first idle adds route children (automation tracks), so we need to redisplay here
5056 _routes->redisplay ();
5060 if (_session->undo_depth() == 0) {
5061 undo_action->set_sensitive(false);
5063 redo_action->set_sensitive(false);
5064 begin_selection_op_history ();
5070 Editor::_idle_resize (gpointer arg)
5072 return ((Editor*)arg)->idle_resize ();
5076 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5078 if (resize_idle_id < 0) {
5079 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5080 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5081 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5083 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5084 _pending_resize_amount = 0;
5087 /* make a note of the smallest resulting height, so that we can clamp the
5088 lower limit at TimeAxisView::hSmall */
5090 int32_t min_resulting = INT32_MAX;
5092 _pending_resize_amount += h;
5093 _pending_resize_view = view;
5095 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5097 if (selection->tracks.contains (_pending_resize_view)) {
5098 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5099 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5103 if (min_resulting < 0) {
5108 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5109 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5113 /** Handle pending resizing of tracks */
5115 Editor::idle_resize ()
5117 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5119 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5120 selection->tracks.contains (_pending_resize_view)) {
5122 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5123 if (*i != _pending_resize_view) {
5124 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5129 _pending_resize_amount = 0;
5130 _group_tabs->set_dirty ();
5131 resize_idle_id = -1;
5139 ENSURE_GUI_THREAD (*this, &Editor::located);
5142 playhead_cursor->set_position (_session->audible_frame ());
5143 if (_follow_playhead && !_pending_initial_locate) {
5144 reset_x_origin_to_follow_playhead ();
5148 _pending_locate_request = false;
5149 _pending_initial_locate = false;
5153 Editor::region_view_added (RegionView * rv)
5155 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5156 if (rv->region ()->id () == (*pr)) {
5157 selection->add (rv);
5158 selection->regions.pending.erase (pr);
5163 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5165 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5166 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5167 if (rv->region()->id () == (*rnote).first) {
5168 mrv->select_notes ((*rnote).second);
5169 selection->pending_midi_note_selection.erase(rnote);
5175 _summary->set_background_dirty ();
5179 Editor::region_view_removed ()
5181 _summary->set_background_dirty ();
5185 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5187 TrackViewList::const_iterator j = track_views.begin ();
5188 while (j != track_views.end()) {
5189 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5190 if (rtv && rtv->route() == r) {
5201 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5205 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5206 TimeAxisView* tv = axis_view_from_route (*i);
5216 Editor::suspend_route_redisplay ()
5219 _routes->suspend_redisplay();
5224 Editor::resume_route_redisplay ()
5227 _routes->redisplay(); // queue redisplay
5228 _routes->resume_redisplay();
5233 Editor::add_routes (RouteList& routes)
5235 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5237 RouteTimeAxisView *rtv;
5238 list<RouteTimeAxisView*> new_views;
5239 TrackViewList new_selection;
5240 bool from_scratch = (track_views.size() == 0);
5242 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5243 boost::shared_ptr<Route> route = (*x);
5245 if (route->is_auditioner() || route->is_monitor()) {
5249 DataType dt = route->input()->default_type();
5251 if (dt == ARDOUR::DataType::AUDIO) {
5252 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5253 rtv->set_route (route);
5254 } else if (dt == ARDOUR::DataType::MIDI) {
5255 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5256 rtv->set_route (route);
5258 throw unknown_type();
5261 new_views.push_back (rtv);
5262 track_views.push_back (rtv);
5263 new_selection.push_back (rtv);
5265 rtv->effective_gain_display ();
5267 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5268 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5271 if (new_views.size() > 0) {
5272 _routes->routes_added (new_views);
5273 _summary->routes_added (new_views);
5276 if (!from_scratch) {
5277 selection->tracks.clear();
5278 selection->add (new_selection);
5279 begin_selection_op_history();
5282 if (show_editor_mixer_when_tracks_arrive) {
5283 show_editor_mixer (true);
5286 editor_list_button.set_sensitive (true);
5290 Editor::timeaxisview_deleted (TimeAxisView *tv)
5292 if (tv == entered_track) {
5296 if (_session && _session->deletion_in_progress()) {
5297 /* the situation is under control */
5301 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5303 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5305 _routes->route_removed (tv);
5307 TimeAxisView::Children c = tv->get_child_list ();
5308 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5309 if (entered_track == i->get()) {
5314 /* remove it from the list of track views */
5316 TrackViewList::iterator i;
5318 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5319 i = track_views.erase (i);
5322 /* update whatever the current mixer strip is displaying, if revelant */
5324 boost::shared_ptr<Route> route;
5327 route = rtav->route ();
5330 if (current_mixer_strip && current_mixer_strip->route() == route) {
5332 TimeAxisView* next_tv;
5334 if (track_views.empty()) {
5336 } else if (i == track_views.end()) {
5337 next_tv = track_views.front();
5344 set_selected_mixer_strip (*next_tv);
5346 /* make the editor mixer strip go away setting the
5347 * button to inactive (which also unticks the menu option)
5350 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5356 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5358 if (apply_to_selection) {
5359 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5361 TrackSelection::iterator j = i;
5364 hide_track_in_display (*i, false);
5369 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5371 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5372 // this will hide the mixer strip
5373 set_selected_mixer_strip (*tv);
5376 _routes->hide_track_in_display (*tv);
5381 Editor::sync_track_view_list_and_routes ()
5383 track_views = TrackViewList (_routes->views ());
5385 _summary->set_background_dirty();
5386 _group_tabs->set_dirty ();
5388 return false; // do not call again (until needed)
5392 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5394 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5399 /** Find a RouteTimeAxisView by the ID of its route */
5401 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5403 RouteTimeAxisView* v;
5405 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5406 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5407 if(v->route()->id() == id) {
5417 Editor::fit_route_group (RouteGroup *g)
5419 TrackViewList ts = axis_views_from_routes (g->route_list ());
5424 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5426 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5429 _session->cancel_audition ();
5433 if (_session->is_auditioning()) {
5434 _session->cancel_audition ();
5435 if (r == last_audition_region) {
5440 _session->audition_region (r);
5441 last_audition_region = r;
5446 Editor::hide_a_region (boost::shared_ptr<Region> r)
5448 r->set_hidden (true);
5452 Editor::show_a_region (boost::shared_ptr<Region> r)
5454 r->set_hidden (false);
5458 Editor::audition_region_from_region_list ()
5460 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5464 Editor::hide_region_from_region_list ()
5466 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5470 Editor::show_region_in_region_list ()
5472 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5476 Editor::step_edit_status_change (bool yn)
5479 start_step_editing ();
5481 stop_step_editing ();
5486 Editor::start_step_editing ()
5488 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5492 Editor::stop_step_editing ()
5494 step_edit_connection.disconnect ();
5498 Editor::check_step_edit ()
5500 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5501 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5503 mtv->check_step_edit ();
5507 return true; // do it again, till we stop
5511 Editor::scroll_press (Direction dir)
5513 ++_scroll_callbacks;
5515 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5516 /* delay the first auto-repeat */
5522 scroll_backward (1);
5530 scroll_up_one_track ();
5534 scroll_down_one_track ();
5538 /* do hacky auto-repeat */
5539 if (!_scroll_connection.connected ()) {
5541 _scroll_connection = Glib::signal_timeout().connect (
5542 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5545 _scroll_callbacks = 0;
5552 Editor::scroll_release ()
5554 _scroll_connection.disconnect ();
5557 /** Queue a change for the Editor viewport x origin to follow the playhead */
5559 Editor::reset_x_origin_to_follow_playhead ()
5561 framepos_t const frame = playhead_cursor->current_frame ();
5563 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5565 if (_session->transport_speed() < 0) {
5567 if (frame > (current_page_samples() / 2)) {
5568 center_screen (frame-(current_page_samples()/2));
5570 center_screen (current_page_samples()/2);
5577 if (frame < leftmost_frame) {
5579 if (_session->transport_rolling()) {
5580 /* rolling; end up with the playhead at the right of the page */
5581 l = frame - current_page_samples ();
5583 /* not rolling: end up with the playhead 1/4 of the way along the page */
5584 l = frame - current_page_samples() / 4;
5588 if (_session->transport_rolling()) {
5589 /* rolling: end up with the playhead on the left of the page */
5592 /* not rolling: end up with the playhead 3/4 of the way along the page */
5593 l = frame - 3 * current_page_samples() / 4;
5601 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5607 Editor::super_rapid_screen_update ()
5609 if (!_session || !_session->engine().running()) {
5613 /* METERING / MIXER STRIPS */
5615 /* update track meters, if required */
5616 if (contents().is_mapped() && meters_running) {
5617 RouteTimeAxisView* rtv;
5618 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5619 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5620 rtv->fast_update ();
5625 /* and any current mixer strip */
5626 if (current_mixer_strip) {
5627 current_mixer_strip->fast_update ();
5630 /* PLAYHEAD AND VIEWPORT */
5632 framepos_t const frame = _session->audible_frame();
5634 /* There are a few reasons why we might not update the playhead / viewport stuff:
5636 * 1. we don't update things when there's a pending locate request, otherwise
5637 * when the editor requests a locate there is a chance that this method
5638 * will move the playhead before the locate request is processed, causing
5640 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5641 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5644 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5646 last_update_frame = frame;
5648 if (!_dragging_playhead) {
5649 playhead_cursor->set_position (frame);
5652 if (!_stationary_playhead) {
5654 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5655 /* We only do this if we aren't already
5656 handling a visual change (ie if
5657 pending_visual_change.being_handled is
5658 false) so that these requests don't stack
5659 up there are too many of them to handle in
5662 reset_x_origin_to_follow_playhead ();
5667 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5668 framepos_t const frame = playhead_cursor->current_frame ();
5669 double target = ((double)frame - (double)current_page_samples()/2.0);
5670 if (target <= 0.0) {
5673 // compare to EditorCursor::set_position()
5674 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5675 double const new_pos = sample_to_pixel_unrounded (target);
5676 if (rint (new_pos) != rint (old_pos)) {
5677 reset_x_origin (pixel_to_sample (floor (new_pos)));
5688 Editor::session_going_away ()
5690 _have_idled = false;
5692 _session_connections.drop_connections ();
5694 super_rapid_screen_update_connection.disconnect ();
5696 selection->clear ();
5697 cut_buffer->clear ();
5699 clicked_regionview = 0;
5700 clicked_axisview = 0;
5701 clicked_routeview = 0;
5702 entered_regionview = 0;
5704 last_update_frame = 0;
5707 playhead_cursor->hide ();
5709 /* rip everything out of the list displays */
5713 _route_groups->clear ();
5715 /* do this first so that deleting a track doesn't reset cms to null
5716 and thus cause a leak.
5719 if (current_mixer_strip) {
5720 if (current_mixer_strip->get_parent() != 0) {
5721 global_hpacker.remove (*current_mixer_strip);
5723 delete current_mixer_strip;
5724 current_mixer_strip = 0;
5727 /* delete all trackviews */
5729 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5732 track_views.clear ();
5734 nudge_clock->set_session (0);
5736 editor_list_button.set_active(false);
5737 editor_list_button.set_sensitive(false);
5739 /* clear tempo/meter rulers */
5740 remove_metric_marks ();
5742 clear_marker_display ();
5744 stop_step_editing ();
5748 /* get rid of any existing editor mixer strip */
5750 WindowTitle title(Glib::get_application_name());
5751 title += _("Editor");
5753 own_window()->set_title (title.get_string());
5756 SessionHandlePtr::session_going_away ();
5760 Editor::trigger_script (int i)
5762 LuaInstance::instance()-> call_action (i);
5766 Editor::set_script_action_name (int i, const std::string& n)
5768 string const a = string_compose (X_("script-action-%1"), i + 1);
5769 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5772 act->set_label (string_compose (_("Unset #%1"), i + 1));
5773 act->set_tooltip (_("no action bound"));
5774 act->set_sensitive (false);
5777 act->set_tooltip (n);
5778 act->set_sensitive (true);
5780 KeyEditor::UpdateBindings ();
5784 Editor::show_editor_list (bool yn)
5787 _the_notebook.show ();
5789 _the_notebook.hide ();
5794 Editor::change_region_layering_order (bool from_context_menu)
5796 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5798 if (!clicked_routeview) {
5799 if (layering_order_editor) {
5800 layering_order_editor->hide ();
5805 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5811 boost::shared_ptr<Playlist> pl = track->playlist();
5817 if (layering_order_editor == 0) {
5818 layering_order_editor = new RegionLayeringOrderEditor (*this);
5821 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5822 layering_order_editor->maybe_present ();
5826 Editor::update_region_layering_order_editor ()
5828 if (layering_order_editor && layering_order_editor->is_visible ()) {
5829 change_region_layering_order (true);
5834 Editor::setup_fade_images ()
5836 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5837 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5838 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5839 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5840 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5842 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5843 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5844 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5845 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5846 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5848 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5849 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5850 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5851 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5852 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5854 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5855 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5856 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5857 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5858 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5862 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5864 Editor::action_menu_item (std::string const & name)
5866 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5869 return *manage (a->create_menu_item ());
5873 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5875 EventBox* b = manage (new EventBox);
5876 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5877 Label* l = manage (new Label (name));
5881 _the_notebook.append_page (widget, *b);
5885 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5887 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5888 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5891 if (ev->type == GDK_2BUTTON_PRESS) {
5893 /* double-click on a notebook tab shrinks or expands the notebook */
5895 if (_notebook_shrunk) {
5896 if (pre_notebook_shrink_pane_width) {
5897 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5899 _notebook_shrunk = false;
5901 pre_notebook_shrink_pane_width = edit_pane.get_position();
5903 /* this expands the LHS of the edit pane to cover the notebook
5904 PAGE but leaves the tabs visible.
5906 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5907 _notebook_shrunk = true;
5915 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5917 using namespace Menu_Helpers;
5919 MenuList& items = _control_point_context_menu.items ();
5922 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5923 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5924 if (!can_remove_control_point (item)) {
5925 items.back().set_sensitive (false);
5928 _control_point_context_menu.popup (event->button.button, event->button.time);
5932 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5934 using namespace Menu_Helpers;
5936 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5941 /* We need to get the selection here and pass it to the operations, since
5942 popping up the menu will cause a region leave event which clears
5943 entered_regionview. */
5945 MidiRegionView& mrv = note->region_view();
5946 const RegionSelection rs = get_regions_from_selection_and_entered ();
5947 const uint32_t sel_size = mrv.selection_size ();
5949 MenuList& items = _note_context_menu.items();
5953 items.push_back(MenuElem(_("Delete"),
5954 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5957 items.push_back(MenuElem(_("Edit..."),
5958 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5959 if (sel_size != 1) {
5960 items.back().set_sensitive (false);
5963 items.push_back(MenuElem(_("Transpose..."),
5964 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5967 items.push_back(MenuElem(_("Legatize"),
5968 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5970 items.back().set_sensitive (false);
5973 items.push_back(MenuElem(_("Quantize..."),
5974 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5976 items.push_back(MenuElem(_("Remove Overlap"),
5977 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5979 items.back().set_sensitive (false);
5982 items.push_back(MenuElem(_("Transform..."),
5983 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5985 _note_context_menu.popup (event->button.button, event->button.time);
5989 Editor::zoom_vertical_modifier_released()
5991 _stepping_axis_view = 0;
5995 Editor::ui_parameter_changed (string parameter)
5997 if (parameter == "icon-set") {
5998 while (!_cursor_stack.empty()) {
5999 _cursor_stack.pop_back();
6001 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6002 _cursor_stack.push_back(_cursors->grabber);
6003 } else if (parameter == "draggable-playhead") {
6004 if (_verbose_cursor) {
6005 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6011 Editor::use_own_window (bool and_fill_it)
6013 bool new_window = !own_window();
6015 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6017 if (win && new_window) {
6018 win->set_name ("EditorWindow");
6020 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6022 // win->signal_realize().connect (*this, &Editor::on_realize);
6023 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6024 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6025 win->set_data ("ardour-bindings", bindings);
6030 DisplaySuspender ds;
6031 contents().show_all ();
6033 /* XXX: this is a bit unfortunate; it would probably
6034 be nicer if we could just call show () above rather
6035 than needing the show_all ()
6038 /* re-hide stuff if necessary */
6039 editor_list_button_toggled ();
6040 parameter_changed ("show-summary");
6041 parameter_changed ("show-group-tabs");
6042 parameter_changed ("show-zoom-tools");
6044 /* now reset all audio_time_axis heights, because widgets might need
6050 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6051 tv = (static_cast<TimeAxisView*>(*i));
6052 tv->reset_height ();
6055 if (current_mixer_strip) {
6056 current_mixer_strip->hide_things ();
6057 current_mixer_strip->parameter_changed ("mixer-element-visibility");