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:
2166 Editor::snap_mode() const
2172 Editor::set_snap_to (SnapType st)
2174 unsigned int snap_ind = (unsigned int)st;
2176 if (internal_editing()) {
2177 internal_snap_type = st;
2179 pre_internal_snap_type = st;
2184 if (snap_ind > snap_type_strings.size() - 1) {
2186 _snap_type = (SnapType)snap_ind;
2189 string str = snap_type_strings[snap_ind];
2191 if (str != snap_type_selector.get_text()) {
2192 snap_type_selector.set_text (str);
2197 switch (_snap_type) {
2198 case SnapToBeatDiv128:
2199 case SnapToBeatDiv64:
2200 case SnapToBeatDiv32:
2201 case SnapToBeatDiv28:
2202 case SnapToBeatDiv24:
2203 case SnapToBeatDiv20:
2204 case SnapToBeatDiv16:
2205 case SnapToBeatDiv14:
2206 case SnapToBeatDiv12:
2207 case SnapToBeatDiv10:
2208 case SnapToBeatDiv8:
2209 case SnapToBeatDiv7:
2210 case SnapToBeatDiv6:
2211 case SnapToBeatDiv5:
2212 case SnapToBeatDiv4:
2213 case SnapToBeatDiv3:
2214 case SnapToBeatDiv2: {
2215 std::vector<TempoMap::BBTPoint> grid;
2216 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2217 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2218 update_tempo_based_rulers (grid);
2222 case SnapToRegionStart:
2223 case SnapToRegionEnd:
2224 case SnapToRegionSync:
2225 case SnapToRegionBoundary:
2226 build_region_boundary_cache ();
2234 redisplay_tempo (false);
2236 SnapChanged (); /* EMIT SIGNAL */
2240 Editor::set_snap_mode (SnapMode mode)
2242 string str = snap_mode_strings[(int)mode];
2244 if (internal_editing()) {
2245 internal_snap_mode = mode;
2247 pre_internal_snap_mode = mode;
2252 if (str != snap_mode_selector.get_text ()) {
2253 snap_mode_selector.set_text (str);
2260 Editor::set_edit_point_preference (EditPoint ep, bool force)
2262 bool changed = (_edit_point != ep);
2265 if (Profile->get_mixbus())
2266 if (ep == EditAtSelectedMarker)
2267 ep = EditAtPlayhead;
2269 string str = edit_point_strings[(int)ep];
2270 if (str != edit_point_selector.get_text ()) {
2271 edit_point_selector.set_text (str);
2274 update_all_enter_cursors();
2276 if (!force && !changed) {
2280 const char* action=NULL;
2282 switch (_edit_point) {
2283 case EditAtPlayhead:
2284 action = "edit-at-playhead";
2286 case EditAtSelectedMarker:
2287 action = "edit-at-marker";
2290 action = "edit-at-mouse";
2294 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2296 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2300 bool in_track_canvas;
2302 if (!mouse_frame (foo, in_track_canvas)) {
2303 in_track_canvas = false;
2306 reset_canvas_action_sensitivity (in_track_canvas);
2312 Editor::set_state (const XMLNode& node, int version)
2314 XMLProperty const * prop;
2316 PBD::Unwinder<bool> nsi (no_save_instant, true);
2318 Tabbable::set_state (node, version);
2320 if (_session && (prop = node.property ("playhead"))) {
2322 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2324 playhead_cursor->set_position (pos);
2326 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2327 playhead_cursor->set_position (0);
2330 playhead_cursor->set_position (0);
2333 if ((prop = node.property ("mixer-width"))) {
2334 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2337 if ((prop = node.property ("zoom-focus"))) {
2338 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2341 if ((prop = node.property ("zoom"))) {
2342 /* older versions of ardour used floating point samples_per_pixel */
2343 double f = PBD::atof (prop->value());
2344 reset_zoom (llrintf (f));
2346 reset_zoom (samples_per_pixel);
2349 if ((prop = node.property ("visible-track-count"))) {
2350 set_visible_track_count (PBD::atoi (prop->value()));
2353 if ((prop = node.property ("snap-to"))) {
2354 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2355 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2358 if ((prop = node.property ("snap-mode"))) {
2359 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2360 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2361 * snap_mode_selection_done() will only mark an already active item as active
2362 * which does not trigger set_text().
2364 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2367 if ((prop = node.property ("internal-snap-to"))) {
2368 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2371 if ((prop = node.property ("internal-snap-mode"))) {
2372 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2375 if ((prop = node.property ("pre-internal-snap-to"))) {
2376 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2379 if ((prop = node.property ("pre-internal-snap-mode"))) {
2380 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2383 if ((prop = node.property ("mouse-mode"))) {
2384 MouseMode m = str2mousemode(prop->value());
2385 set_mouse_mode (m, true);
2387 set_mouse_mode (MouseObject, true);
2390 if ((prop = node.property ("left-frame")) != 0) {
2392 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2396 reset_x_origin (pos);
2400 if ((prop = node.property ("y-origin")) != 0) {
2401 reset_y_origin (atof (prop->value ()));
2404 if ((prop = node.property ("join-object-range"))) {
2405 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2406 bool yn = string_is_affirmative (prop->value());
2408 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2409 tact->set_active (!yn);
2410 tact->set_active (yn);
2412 set_mouse_mode(mouse_mode, true);
2415 if ((prop = node.property ("edit-point"))) {
2416 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2419 if ((prop = node.property ("show-measures"))) {
2420 bool yn = string_is_affirmative (prop->value());
2421 _show_measures = yn;
2424 if ((prop = node.property ("follow-playhead"))) {
2425 bool yn = string_is_affirmative (prop->value());
2426 set_follow_playhead (yn);
2429 if ((prop = node.property ("stationary-playhead"))) {
2430 bool yn = string_is_affirmative (prop->value());
2431 set_stationary_playhead (yn);
2434 if ((prop = node.property ("region-list-sort-type"))) {
2435 RegionListSortType st;
2436 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2439 if ((prop = node.property ("show-editor-mixer"))) {
2441 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2444 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2445 bool yn = string_is_affirmative (prop->value());
2447 /* do it twice to force the change */
2449 tact->set_active (!yn);
2450 tact->set_active (yn);
2453 if ((prop = node.property ("show-editor-list"))) {
2455 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2458 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2459 bool yn = string_is_affirmative (prop->value());
2461 /* do it twice to force the change */
2463 tact->set_active (!yn);
2464 tact->set_active (yn);
2467 if ((prop = node.property (X_("editor-list-page")))) {
2468 _the_notebook.set_current_page (atoi (prop->value ()));
2471 if ((prop = node.property (X_("show-marker-lines")))) {
2472 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2474 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2475 bool yn = string_is_affirmative (prop->value ());
2477 tact->set_active (!yn);
2478 tact->set_active (yn);
2481 XMLNodeList children = node.children ();
2482 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2483 selection->set_state (**i, Stateful::current_state_version);
2484 _regions->set_state (**i);
2487 if ((prop = node.property ("maximised"))) {
2488 bool yn = string_is_affirmative (prop->value());
2489 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2491 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2492 bool fs = tact && tact->get_active();
2494 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2498 if ((prop = node.property ("nudge-clock-value"))) {
2500 sscanf (prop->value().c_str(), "%" PRId64, &f);
2501 nudge_clock->set (f);
2503 nudge_clock->set_mode (AudioClock::Timecode);
2504 nudge_clock->set (_session->frame_rate() * 5, true);
2509 * Not all properties may have been in XML, but
2510 * those that are linked to a private variable may need changing
2515 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2517 yn = _show_measures;
2518 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2519 /* do it twice to force the change */
2520 tact->set_active (!yn);
2521 tact->set_active (yn);
2524 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2525 yn = _follow_playhead;
2527 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2528 if (tact->get_active() != yn) {
2529 tact->set_active (yn);
2533 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2534 yn = _stationary_playhead;
2536 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2537 if (tact->get_active() != yn) {
2538 tact->set_active (yn);
2543 return LuaInstance::instance()->set_state(node);
2547 Editor::get_state ()
2549 XMLNode* node = new XMLNode (X_("Editor"));
2552 id().print (buf, sizeof (buf));
2553 node->add_property ("id", buf);
2555 node->add_child_nocopy (Tabbable::get_state());
2557 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2558 node->add_property("edit-horizontal-pane-pos", string(buf));
2559 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2560 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2561 node->add_property("edit-vertical-pane-pos", string(buf));
2563 maybe_add_mixer_strip_width (*node);
2565 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2567 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2568 node->add_property ("zoom", buf);
2569 node->add_property ("snap-to", enum_2_string (_snap_type));
2570 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2571 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2572 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2573 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2574 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2575 node->add_property ("edit-point", enum_2_string (_edit_point));
2576 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2577 node->add_property ("visible-track-count", buf);
2579 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2580 node->add_property ("playhead", buf);
2581 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2582 node->add_property ("left-frame", buf);
2583 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2584 node->add_property ("y-origin", buf);
2586 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2587 node->add_property ("maximised", _maximised ? "yes" : "no");
2588 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2589 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2590 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2591 node->add_property ("mouse-mode", enum2str(mouse_mode));
2592 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2594 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2596 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2597 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2600 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2602 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2603 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2606 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2607 node->add_property (X_("editor-list-page"), buf);
2609 if (button_bindings) {
2610 XMLNode* bb = new XMLNode (X_("Buttons"));
2611 button_bindings->save (*bb);
2612 node->add_child_nocopy (*bb);
2615 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2617 node->add_child_nocopy (selection->get_state ());
2618 node->add_child_nocopy (_regions->get_state ());
2620 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2621 node->add_property ("nudge-clock-value", buf);
2623 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2624 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2629 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2630 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2632 * @return pair: TimeAxisView that y is over, layer index.
2634 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2635 * in stacked or expanded region display mode, otherwise 0.
2637 std::pair<TimeAxisView *, double>
2638 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2640 if (!trackview_relative_offset) {
2641 y -= _trackview_group->canvas_origin().y;
2645 return std::make_pair ( (TimeAxisView *) 0, 0);
2648 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2650 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2657 return std::make_pair ( (TimeAxisView *) 0, 0);
2660 /** Snap a position to the grid, if appropriate, taking into account current
2661 * grid settings and also the state of any snap modifier keys that may be pressed.
2662 * @param start Position to snap.
2663 * @param event Event to get current key modifier information from, or 0.
2666 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2668 if (!_session || !event) {
2672 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2673 if (_snap_mode == SnapOff) {
2674 snap_to_internal (start, direction, for_mark);
2677 if (_snap_mode != SnapOff) {
2678 snap_to_internal (start, direction, for_mark);
2679 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2680 /* SnapOff, but we pressed the snap_delta modifier */
2681 snap_to_internal (start, direction, for_mark);
2687 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2689 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2693 snap_to_internal (start, direction, for_mark, ensure_snap);
2697 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2699 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2700 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2702 switch (_snap_type) {
2703 case SnapToTimecodeFrame:
2704 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2705 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2706 /* start is already on a whole timecode frame, do nothing */
2707 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2708 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2710 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2714 case SnapToTimecodeSeconds:
2715 if (_session->config.get_timecode_offset_negative()) {
2716 start += _session->config.get_timecode_offset ();
2718 start -= _session->config.get_timecode_offset ();
2720 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2721 (start % one_timecode_second == 0)) {
2722 /* start is already on a whole second, do nothing */
2723 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2724 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2726 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2729 if (_session->config.get_timecode_offset_negative()) {
2730 start -= _session->config.get_timecode_offset ();
2732 start += _session->config.get_timecode_offset ();
2736 case SnapToTimecodeMinutes:
2737 if (_session->config.get_timecode_offset_negative()) {
2738 start += _session->config.get_timecode_offset ();
2740 start -= _session->config.get_timecode_offset ();
2742 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2743 (start % one_timecode_minute == 0)) {
2744 /* start is already on a whole minute, do nothing */
2745 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2746 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2748 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2750 if (_session->config.get_timecode_offset_negative()) {
2751 start -= _session->config.get_timecode_offset ();
2753 start += _session->config.get_timecode_offset ();
2757 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2758 abort(); /*NOTREACHED*/
2763 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2765 const framepos_t one_second = _session->frame_rate();
2766 const framepos_t one_minute = _session->frame_rate() * 60;
2767 framepos_t presnap = start;
2771 switch (_snap_type) {
2772 case SnapToTimecodeFrame:
2773 case SnapToTimecodeSeconds:
2774 case SnapToTimecodeMinutes:
2775 return timecode_snap_to_internal (start, direction, for_mark);
2778 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2779 start % (one_second/75) == 0) {
2780 /* start is already on a whole CD frame, do nothing */
2781 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2782 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2784 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2789 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2790 start % one_second == 0) {
2791 /* start is already on a whole second, do nothing */
2792 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2793 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2795 start = (framepos_t) floor ((double) start / one_second) * one_second;
2800 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2801 start % one_minute == 0) {
2802 /* start is already on a whole minute, do nothing */
2803 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2804 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2806 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2811 start = _session->tempo_map().round_to_bar (start, direction);
2815 start = _session->tempo_map().round_to_beat (start, direction);
2818 case SnapToBeatDiv128:
2819 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2821 case SnapToBeatDiv64:
2822 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2824 case SnapToBeatDiv32:
2825 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2827 case SnapToBeatDiv28:
2828 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2830 case SnapToBeatDiv24:
2831 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2833 case SnapToBeatDiv20:
2834 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2836 case SnapToBeatDiv16:
2837 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2839 case SnapToBeatDiv14:
2840 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2842 case SnapToBeatDiv12:
2843 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2845 case SnapToBeatDiv10:
2846 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2848 case SnapToBeatDiv8:
2849 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2851 case SnapToBeatDiv7:
2852 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2854 case SnapToBeatDiv6:
2855 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2857 case SnapToBeatDiv5:
2858 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2860 case SnapToBeatDiv4:
2861 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2863 case SnapToBeatDiv3:
2864 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2866 case SnapToBeatDiv2:
2867 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2875 _session->locations()->marks_either_side (start, before, after);
2877 if (before == max_framepos && after == max_framepos) {
2878 /* No marks to snap to, so just don't snap */
2880 } else if (before == max_framepos) {
2882 } else if (after == max_framepos) {
2884 } else if (before != max_framepos && after != max_framepos) {
2885 /* have before and after */
2886 if ((start - before) < (after - start)) {
2895 case SnapToRegionStart:
2896 case SnapToRegionEnd:
2897 case SnapToRegionSync:
2898 case SnapToRegionBoundary:
2899 if (!region_boundary_cache.empty()) {
2901 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2902 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2904 if (direction > 0) {
2905 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2907 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2910 if (next != region_boundary_cache.begin ()) {
2915 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2916 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2918 if (start > (p + n) / 2) {
2927 switch (_snap_mode) {
2937 if (presnap > start) {
2938 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2942 } else if (presnap < start) {
2943 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2949 /* handled at entry */
2957 Editor::setup_toolbar ()
2959 HBox* mode_box = manage(new HBox);
2960 mode_box->set_border_width (2);
2961 mode_box->set_spacing(2);
2963 HBox* mouse_mode_box = manage (new HBox);
2964 HBox* mouse_mode_hbox = manage (new HBox);
2965 VBox* mouse_mode_vbox = manage (new VBox);
2966 Alignment* mouse_mode_align = manage (new Alignment);
2968 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2969 mouse_mode_size_group->add_widget (smart_mode_button);
2970 mouse_mode_size_group->add_widget (mouse_move_button);
2971 mouse_mode_size_group->add_widget (mouse_cut_button);
2972 mouse_mode_size_group->add_widget (mouse_select_button);
2973 mouse_mode_size_group->add_widget (mouse_timefx_button);
2974 mouse_mode_size_group->add_widget (mouse_audition_button);
2975 mouse_mode_size_group->add_widget (mouse_draw_button);
2976 mouse_mode_size_group->add_widget (mouse_content_button);
2978 mouse_mode_size_group->add_widget (zoom_in_button);
2979 mouse_mode_size_group->add_widget (zoom_out_button);
2980 mouse_mode_size_group->add_widget (zoom_preset_selector);
2981 mouse_mode_size_group->add_widget (zoom_out_full_button);
2982 mouse_mode_size_group->add_widget (zoom_focus_selector);
2984 mouse_mode_size_group->add_widget (tav_shrink_button);
2985 mouse_mode_size_group->add_widget (tav_expand_button);
2986 mouse_mode_size_group->add_widget (visible_tracks_selector);
2988 mouse_mode_size_group->add_widget (snap_type_selector);
2989 mouse_mode_size_group->add_widget (snap_mode_selector);
2991 mouse_mode_size_group->add_widget (edit_point_selector);
2992 mouse_mode_size_group->add_widget (edit_mode_selector);
2994 mouse_mode_size_group->add_widget (*nudge_clock);
2995 mouse_mode_size_group->add_widget (nudge_forward_button);
2996 mouse_mode_size_group->add_widget (nudge_backward_button);
2998 mouse_mode_hbox->set_spacing (2);
3000 if (!ARDOUR::Profile->get_trx()) {
3001 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3004 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3005 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3007 if (!ARDOUR::Profile->get_mixbus()) {
3008 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3011 if (!ARDOUR::Profile->get_trx()) {
3012 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3013 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3014 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3015 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3018 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3020 mouse_mode_align->add (*mouse_mode_vbox);
3021 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3023 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3025 edit_mode_selector.set_name ("mouse mode button");
3027 if (!ARDOUR::Profile->get_trx()) {
3028 mode_box->pack_start (edit_mode_selector, false, false);
3031 mode_box->pack_start (*mouse_mode_box, false, false);
3035 _zoom_box.set_spacing (2);
3036 _zoom_box.set_border_width (2);
3040 zoom_preset_selector.set_name ("zoom button");
3041 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3042 zoom_preset_selector.set_size_request (42, -1);
3044 zoom_in_button.set_name ("zoom button");
3045 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3046 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3047 zoom_in_button.set_related_action (act);
3049 zoom_out_button.set_name ("zoom button");
3050 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3051 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3052 zoom_out_button.set_related_action (act);
3054 zoom_out_full_button.set_name ("zoom button");
3055 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3056 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3057 zoom_out_full_button.set_related_action (act);
3059 zoom_focus_selector.set_name ("zoom button");
3061 if (ARDOUR::Profile->get_mixbus()) {
3062 _zoom_box.pack_start (zoom_preset_selector, false, false);
3063 } else if (ARDOUR::Profile->get_trx()) {
3064 mode_box->pack_start (zoom_out_button, false, false);
3065 mode_box->pack_start (zoom_in_button, false, false);
3067 _zoom_box.pack_start (zoom_out_button, false, false);
3068 _zoom_box.pack_start (zoom_in_button, false, false);
3069 _zoom_box.pack_start (zoom_out_full_button, false, false);
3070 _zoom_box.pack_start (zoom_focus_selector, false, false);
3073 /* Track zoom buttons */
3074 visible_tracks_selector.set_name ("zoom button");
3075 if (Profile->get_mixbus()) {
3076 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3077 visible_tracks_selector.set_size_request (42, -1);
3079 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3082 tav_expand_button.set_name ("zoom button");
3083 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3084 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3085 tav_expand_button.set_related_action (act);
3087 tav_shrink_button.set_name ("zoom button");
3088 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3089 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3090 tav_shrink_button.set_related_action (act);
3092 if (ARDOUR::Profile->get_mixbus()) {
3093 _zoom_box.pack_start (visible_tracks_selector);
3094 } else if (ARDOUR::Profile->get_trx()) {
3095 _zoom_box.pack_start (tav_shrink_button);
3096 _zoom_box.pack_start (tav_expand_button);
3098 _zoom_box.pack_start (visible_tracks_selector);
3099 _zoom_box.pack_start (tav_shrink_button);
3100 _zoom_box.pack_start (tav_expand_button);
3103 snap_box.set_spacing (2);
3104 snap_box.set_border_width (2);
3106 snap_type_selector.set_name ("mouse mode button");
3108 snap_mode_selector.set_name ("mouse mode button");
3110 edit_point_selector.set_name ("mouse mode button");
3112 snap_box.pack_start (snap_mode_selector, false, false);
3113 snap_box.pack_start (snap_type_selector, false, false);
3114 snap_box.pack_start (edit_point_selector, false, false);
3118 HBox *nudge_box = manage (new HBox);
3119 nudge_box->set_spacing (2);
3120 nudge_box->set_border_width (2);
3122 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3123 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3125 nudge_box->pack_start (nudge_backward_button, false, false);
3126 nudge_box->pack_start (nudge_forward_button, false, false);
3127 nudge_box->pack_start (*nudge_clock, false, false);
3130 /* Pack everything in... */
3132 HBox* hbox = manage (new HBox);
3133 hbox->set_spacing(2);
3135 toolbar_hbox.set_spacing (2);
3136 toolbar_hbox.set_border_width (1);
3138 toolbar_hbox.pack_start (*mode_box, false, false);
3139 if (!ARDOUR::Profile->get_trx()) {
3140 toolbar_hbox.pack_start (_zoom_box, false, false);
3141 toolbar_hbox.pack_start (*hbox, false, false);
3144 if (!ARDOUR::Profile->get_trx()) {
3145 hbox->pack_start (snap_box, false, false);
3146 hbox->pack_start (*nudge_box, false, false);
3151 toolbar_base.set_name ("ToolBarBase");
3152 toolbar_base.add (toolbar_hbox);
3154 _toolbar_viewport.add (toolbar_base);
3155 /* stick to the required height but allow width to vary if there's not enough room */
3156 _toolbar_viewport.set_size_request (1, -1);
3158 toolbar_frame.set_shadow_type (SHADOW_OUT);
3159 toolbar_frame.set_name ("BaseFrame");
3160 toolbar_frame.add (_toolbar_viewport);
3164 Editor::build_edit_point_menu ()
3166 using namespace Menu_Helpers;
3168 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3169 if(!Profile->get_mixbus())
3170 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3171 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3173 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3177 Editor::build_edit_mode_menu ()
3179 using namespace Menu_Helpers;
3181 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3182 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3183 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3184 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3186 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3190 Editor::build_snap_mode_menu ()
3192 using namespace Menu_Helpers;
3194 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3195 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3196 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3198 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3202 Editor::build_snap_type_menu ()
3204 using namespace Menu_Helpers;
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3237 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3242 Editor::setup_tooltips ()
3244 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3245 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3246 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3247 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3248 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3249 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3250 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3251 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3252 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3253 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3254 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3255 set_tooltip (zoom_in_button, _("Zoom In"));
3256 set_tooltip (zoom_out_button, _("Zoom Out"));
3257 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3258 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3259 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3260 set_tooltip (tav_expand_button, _("Expand Tracks"));
3261 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3262 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3263 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3264 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3265 set_tooltip (edit_point_selector, _("Edit Point"));
3266 set_tooltip (edit_mode_selector, _("Edit Mode"));
3267 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3271 Editor::convert_drop_to_paths (
3272 vector<string>& paths,
3273 const RefPtr<Gdk::DragContext>& /*context*/,
3276 const SelectionData& data,
3280 if (_session == 0) {
3284 vector<string> uris = data.get_uris();
3288 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3289 are actually URI lists. So do it by hand.
3292 if (data.get_target() != "text/plain") {
3296 /* Parse the "uri-list" format that Nautilus provides,
3297 where each pathname is delimited by \r\n.
3299 THERE MAY BE NO NULL TERMINATING CHAR!!!
3302 string txt = data.get_text();
3306 p = (char *) malloc (txt.length() + 1);
3307 txt.copy (p, txt.length(), 0);
3308 p[txt.length()] = '\0';
3314 while (g_ascii_isspace (*p))
3318 while (*q && (*q != '\n') && (*q != '\r')) {
3325 while (q > p && g_ascii_isspace (*q))
3330 uris.push_back (string (p, q - p + 1));
3334 p = strchr (p, '\n');
3346 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3347 if ((*i).substr (0,7) == "file://") {
3348 paths.push_back (Glib::filename_from_uri (*i));
3356 Editor::new_tempo_section ()
3361 Editor::map_transport_state ()
3363 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3365 if (_session && _session->transport_stopped()) {
3366 have_pending_keyboard_selection = false;
3369 update_loop_range_view ();
3375 Editor::begin_selection_op_history ()
3377 selection_op_cmd_depth = 0;
3378 selection_op_history_it = 0;
3380 while(!selection_op_history.empty()) {
3381 delete selection_op_history.front();
3382 selection_op_history.pop_front();
3385 selection_undo_action->set_sensitive (false);
3386 selection_redo_action->set_sensitive (false);
3387 selection_op_history.push_front (&_selection_memento->get_state ());
3391 Editor::begin_reversible_selection_op (string name)
3394 //cerr << name << endl;
3395 /* begin/commit pairs can be nested */
3396 selection_op_cmd_depth++;
3401 Editor::commit_reversible_selection_op ()
3404 if (selection_op_cmd_depth == 1) {
3406 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3408 The user has undone some selection ops and then made a new one,
3409 making anything earlier in the list invalid.
3412 list<XMLNode *>::iterator it = selection_op_history.begin();
3413 list<XMLNode *>::iterator e_it = it;
3414 advance (e_it, selection_op_history_it);
3416 for ( ; it != e_it; ++it) {
3419 selection_op_history.erase (selection_op_history.begin(), e_it);
3422 selection_op_history.push_front (&_selection_memento->get_state ());
3423 selection_op_history_it = 0;
3425 selection_undo_action->set_sensitive (true);
3426 selection_redo_action->set_sensitive (false);
3429 if (selection_op_cmd_depth > 0) {
3430 selection_op_cmd_depth--;
3436 Editor::undo_selection_op ()
3439 selection_op_history_it++;
3441 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3442 if (n == selection_op_history_it) {
3443 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3444 selection_redo_action->set_sensitive (true);
3448 /* is there an earlier entry? */
3449 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3450 selection_undo_action->set_sensitive (false);
3456 Editor::redo_selection_op ()
3459 if (selection_op_history_it > 0) {
3460 selection_op_history_it--;
3463 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3464 if (n == selection_op_history_it) {
3465 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3466 selection_undo_action->set_sensitive (true);
3471 if (selection_op_history_it == 0) {
3472 selection_redo_action->set_sensitive (false);
3478 Editor::begin_reversible_command (string name)
3481 before.push_back (&_selection_memento->get_state ());
3482 _session->begin_reversible_command (name);
3487 Editor::begin_reversible_command (GQuark q)
3490 before.push_back (&_selection_memento->get_state ());
3491 _session->begin_reversible_command (q);
3496 Editor::abort_reversible_command ()
3499 while(!before.empty()) {
3500 delete before.front();
3503 _session->abort_reversible_command ();
3508 Editor::commit_reversible_command ()
3511 if (before.size() == 1) {
3512 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3513 redo_action->set_sensitive(false);
3514 undo_action->set_sensitive(true);
3515 begin_selection_op_history ();
3518 if (before.empty()) {
3519 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3524 _session->commit_reversible_command ();
3529 Editor::history_changed ()
3533 if (undo_action && _session) {
3534 if (_session->undo_depth() == 0) {
3535 label = S_("Command|Undo");
3537 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3539 undo_action->property_label() = label;
3542 if (redo_action && _session) {
3543 if (_session->redo_depth() == 0) {
3545 redo_action->set_sensitive (false);
3547 label = string_compose(_("Redo (%1)"), _session->next_redo());
3548 redo_action->set_sensitive (true);
3550 redo_action->property_label() = label;
3555 Editor::duplicate_range (bool with_dialog)
3559 RegionSelection rs = get_regions_from_selection_and_entered ();
3561 if ( selection->time.length() == 0 && rs.empty()) {
3567 ArdourDialog win (_("Duplicate"));
3568 Label label (_("Number of duplications:"));
3569 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3570 SpinButton spinner (adjustment, 0.0, 1);
3573 win.get_vbox()->set_spacing (12);
3574 win.get_vbox()->pack_start (hbox);
3575 hbox.set_border_width (6);
3576 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3578 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3579 place, visually. so do this by hand.
3582 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3583 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3584 spinner.grab_focus();
3590 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3591 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3592 win.set_default_response (RESPONSE_ACCEPT);
3594 spinner.grab_focus ();
3596 switch (win.run ()) {
3597 case RESPONSE_ACCEPT:
3603 times = adjustment.get_value();
3606 if ((current_mouse_mode() == Editing::MouseRange)) {
3607 if (selection->time.length()) {
3608 duplicate_selection (times);
3610 } else if (get_smart_mode()) {
3611 if (selection->time.length()) {
3612 duplicate_selection (times);
3614 duplicate_some_regions (rs, times);
3616 duplicate_some_regions (rs, times);
3621 Editor::set_edit_mode (EditMode m)
3623 Config->set_edit_mode (m);
3627 Editor::cycle_edit_mode ()
3629 switch (Config->get_edit_mode()) {
3631 Config->set_edit_mode (Ripple);
3635 Config->set_edit_mode (Lock);
3638 Config->set_edit_mode (Slide);
3644 Editor::edit_mode_selection_done ( EditMode m )
3646 Config->set_edit_mode ( m );
3650 Editor::snap_type_selection_done (SnapType snaptype)
3652 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3654 ract->set_active ();
3659 Editor::snap_mode_selection_done (SnapMode mode)
3661 RefPtr<RadioAction> ract = snap_mode_action (mode);
3664 ract->set_active (true);
3669 Editor::cycle_edit_point (bool with_marker)
3671 if(Profile->get_mixbus())
3672 with_marker = false;
3674 switch (_edit_point) {
3676 set_edit_point_preference (EditAtPlayhead);
3678 case EditAtPlayhead:
3680 set_edit_point_preference (EditAtSelectedMarker);
3682 set_edit_point_preference (EditAtMouse);
3685 case EditAtSelectedMarker:
3686 set_edit_point_preference (EditAtMouse);
3692 Editor::edit_point_selection_done (EditPoint ep)
3694 set_edit_point_preference ( ep );
3698 Editor::build_zoom_focus_menu ()
3700 using namespace Menu_Helpers;
3702 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3703 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3704 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3705 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3706 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3707 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3709 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3713 Editor::zoom_focus_selection_done ( ZoomFocus f )
3715 RefPtr<RadioAction> ract = zoom_focus_action (f);
3717 ract->set_active ();
3722 Editor::build_track_count_menu ()
3724 using namespace Menu_Helpers;
3726 if (!Profile->get_mixbus()) {
3727 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3732 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3744 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3745 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3746 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3747 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3748 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3749 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3750 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3752 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3753 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3754 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3755 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3756 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3757 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3758 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3759 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3760 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3761 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3762 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3767 Editor::set_zoom_preset (int64_t ms)
3770 temporal_zoom_session();
3774 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3775 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3779 Editor::set_visible_track_count (int32_t n)
3781 _visible_track_count = n;
3783 /* if the canvas hasn't really been allocated any size yet, just
3784 record the desired number of visible tracks and return. when canvas
3785 allocation happens, we will get called again and then we can do the
3789 if (_visible_canvas_height <= 1) {
3795 DisplaySuspender ds;
3797 if (_visible_track_count > 0) {
3798 h = trackviews_height() / _visible_track_count;
3799 std::ostringstream s;
3800 s << _visible_track_count;
3802 } else if (_visible_track_count == 0) {
3804 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3805 if ((*i)->marked_for_display()) {
3809 h = trackviews_height() / n;
3812 /* negative value means that the visible track count has
3813 been overridden by explicit track height changes.
3815 visible_tracks_selector.set_text (X_("*"));
3819 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3820 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3823 if (str != visible_tracks_selector.get_text()) {
3824 visible_tracks_selector.set_text (str);
3829 Editor::override_visible_track_count ()
3831 _visible_track_count = -1;
3832 visible_tracks_selector.set_text ( _("*") );
3836 Editor::edit_controls_button_release (GdkEventButton* ev)
3838 if (Keyboard::is_context_menu_event (ev)) {
3839 ARDOUR_UI::instance()->add_route ();
3840 } else if (ev->button == 1) {
3841 selection->clear_tracks ();
3848 Editor::mouse_select_button_release (GdkEventButton* ev)
3850 /* this handles just right-clicks */
3852 if (ev->button != 3) {
3860 Editor::set_zoom_focus (ZoomFocus f)
3862 string str = zoom_focus_strings[(int)f];
3864 if (str != zoom_focus_selector.get_text()) {
3865 zoom_focus_selector.set_text (str);
3868 if (zoom_focus != f) {
3875 Editor::cycle_zoom_focus ()
3877 switch (zoom_focus) {
3879 set_zoom_focus (ZoomFocusRight);
3881 case ZoomFocusRight:
3882 set_zoom_focus (ZoomFocusCenter);
3884 case ZoomFocusCenter:
3885 set_zoom_focus (ZoomFocusPlayhead);
3887 case ZoomFocusPlayhead:
3888 set_zoom_focus (ZoomFocusMouse);
3890 case ZoomFocusMouse:
3891 set_zoom_focus (ZoomFocusEdit);
3894 set_zoom_focus (ZoomFocusLeft);
3900 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3902 /* recover or initialize pane positions. do this here rather than earlier because
3903 we don't want the positions to change the child allocations, which they seem to do.
3907 XMLProperty const * prop;
3909 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3918 XMLNode* geometry = find_named_node (*node, "geometry");
3920 if (which == static_cast<Paned*> (&edit_pane)) {
3922 if (done & Horizontal) {
3926 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3927 _notebook_shrunk = string_is_affirmative (prop->value ());
3930 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3931 /* initial allocation is 90% to canvas, 10% to notebook */
3932 pos = (int) floor (alloc.get_width() * 0.90f);
3933 snprintf (buf, sizeof(buf), "%d", pos);
3935 pos = atoi (prop->value());
3938 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3939 edit_pane.set_position (pos);
3942 done = (Pane) (done | Horizontal);
3944 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3946 if (done & Vertical) {
3950 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3951 /* initial allocation is 90% to canvas, 10% to summary */
3952 pos = (int) floor (alloc.get_height() * 0.90f);
3953 snprintf (buf, sizeof(buf), "%d", pos);
3956 pos = atoi (prop->value());
3959 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3960 editor_summary_pane.set_position (pos);
3963 done = (Pane) (done | Vertical);
3968 Editor::set_show_measures (bool yn)
3970 if (_show_measures != yn) {
3973 if ((_show_measures = yn) == true) {
3975 tempo_lines->show();
3978 std::vector<TempoMap::BBTPoint> grid;
3979 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3980 draw_measures (grid);
3988 Editor::toggle_follow_playhead ()
3990 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3992 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3993 set_follow_playhead (tact->get_active());
3997 /** @param yn true to follow playhead, otherwise false.
3998 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4001 Editor::set_follow_playhead (bool yn, bool catch_up)
4003 if (_follow_playhead != yn) {
4004 if ((_follow_playhead = yn) == true && catch_up) {
4006 reset_x_origin_to_follow_playhead ();
4013 Editor::toggle_stationary_playhead ()
4015 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4017 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4018 set_stationary_playhead (tact->get_active());
4023 Editor::set_stationary_playhead (bool yn)
4025 if (_stationary_playhead != yn) {
4026 if ((_stationary_playhead = yn) == true) {
4028 // FIXME need a 3.0 equivalent of this 2.X call
4029 // update_current_screen ();
4036 Editor::playlist_selector () const
4038 return *_playlist_selector;
4042 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4044 if (paste_count == 0) {
4045 /* don't bother calculating an offset that will be zero anyway */
4049 /* calculate basic unsnapped multi-paste offset */
4050 framecnt_t offset = paste_count * duration;
4052 /* snap offset so pos + offset is aligned to the grid */
4053 framepos_t offset_pos = pos + offset;
4054 snap_to(offset_pos, RoundUpMaybe);
4055 offset = offset_pos - pos;
4061 Editor::get_grid_beat_divisions(framepos_t position)
4063 switch (_snap_type) {
4064 case SnapToBeatDiv128: return 128;
4065 case SnapToBeatDiv64: return 64;
4066 case SnapToBeatDiv32: return 32;
4067 case SnapToBeatDiv28: return 28;
4068 case SnapToBeatDiv24: return 24;
4069 case SnapToBeatDiv20: return 20;
4070 case SnapToBeatDiv16: return 16;
4071 case SnapToBeatDiv14: return 14;
4072 case SnapToBeatDiv12: return 12;
4073 case SnapToBeatDiv10: return 10;
4074 case SnapToBeatDiv8: return 8;
4075 case SnapToBeatDiv7: return 7;
4076 case SnapToBeatDiv6: return 6;
4077 case SnapToBeatDiv5: return 5;
4078 case SnapToBeatDiv4: return 4;
4079 case SnapToBeatDiv3: return 3;
4080 case SnapToBeatDiv2: return 2;
4087 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4091 const unsigned divisions = get_grid_beat_divisions(position);
4093 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4096 switch (_snap_type) {
4098 return Evoral::Beats(1.0);
4101 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4109 return Evoral::Beats();
4113 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4117 ret = nudge_clock->current_duration (pos);
4118 next = ret + 1; /* XXXX fix me */
4124 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4126 ArdourDialog dialog (_("Playlist Deletion"));
4127 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4128 "If it is kept, its audio files will not be cleaned.\n"
4129 "If it is deleted, audio files used by it alone will be cleaned."),
4132 dialog.set_position (WIN_POS_CENTER);
4133 dialog.get_vbox()->pack_start (label);
4137 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4138 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4139 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4140 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4141 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4143 // by default gtk uses the left most button
4144 keep->grab_focus ();
4146 switch (dialog.run ()) {
4148 /* keep this and all remaining ones */
4153 /* delete this and all others */
4157 case RESPONSE_ACCEPT:
4158 /* delete the playlist */
4162 case RESPONSE_REJECT:
4163 /* keep the playlist */
4175 Editor::audio_region_selection_covers (framepos_t where)
4177 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4178 if ((*a)->region()->covers (where)) {
4187 Editor::prepare_for_cleanup ()
4189 cut_buffer->clear_regions ();
4190 cut_buffer->clear_playlists ();
4192 selection->clear_regions ();
4193 selection->clear_playlists ();
4195 _regions->suspend_redisplay ();
4199 Editor::finish_cleanup ()
4201 _regions->resume_redisplay ();
4205 Editor::transport_loop_location()
4208 return _session->locations()->auto_loop_location();
4215 Editor::transport_punch_location()
4218 return _session->locations()->auto_punch_location();
4225 Editor::control_layout_scroll (GdkEventScroll* ev)
4227 /* Just forward to the normal canvas scroll method. The coordinate
4228 systems are different but since the canvas is always larger than the
4229 track headers, and aligned with the trackview area, this will work.
4231 In the not too distant future this layout is going away anyway and
4232 headers will be on the canvas.
4234 return canvas_scroll_event (ev, false);
4238 Editor::session_state_saved (string)
4241 _snapshots->redisplay ();
4245 Editor::maximise_editing_space ()
4251 Gtk::Window* toplevel = current_toplevel();
4254 toplevel->fullscreen ();
4260 Editor::restore_editing_space ()
4266 Gtk::Window* toplevel = current_toplevel();
4269 toplevel->unfullscreen();
4275 * Make new playlists for a given track and also any others that belong
4276 * to the same active route group with the `select' property.
4281 Editor::new_playlists (TimeAxisView* v)
4283 begin_reversible_command (_("new playlists"));
4284 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4285 _session->playlists->get (playlists);
4286 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4287 commit_reversible_command ();
4291 * Use a copy of the current playlist for a given track and also any others that belong
4292 * to the same active route group with the `select' property.
4297 Editor::copy_playlists (TimeAxisView* v)
4299 begin_reversible_command (_("copy playlists"));
4300 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4301 _session->playlists->get (playlists);
4302 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4303 commit_reversible_command ();
4306 /** Clear the current playlist for a given track and also any others that belong
4307 * to the same active route group with the `select' property.
4312 Editor::clear_playlists (TimeAxisView* v)
4314 begin_reversible_command (_("clear playlists"));
4315 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4316 _session->playlists->get (playlists);
4317 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4318 commit_reversible_command ();
4322 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4324 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4328 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4330 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4334 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4336 atv.clear_playlist ();
4340 Editor::get_y_origin () const
4342 return vertical_adjustment.get_value ();
4345 /** Queue up a change to the viewport x origin.
4346 * @param frame New x origin.
4349 Editor::reset_x_origin (framepos_t frame)
4351 pending_visual_change.add (VisualChange::TimeOrigin);
4352 pending_visual_change.time_origin = frame;
4353 ensure_visual_change_idle_handler ();
4357 Editor::reset_y_origin (double y)
4359 pending_visual_change.add (VisualChange::YOrigin);
4360 pending_visual_change.y_origin = y;
4361 ensure_visual_change_idle_handler ();
4365 Editor::reset_zoom (framecnt_t spp)
4367 if (spp == samples_per_pixel) {
4371 pending_visual_change.add (VisualChange::ZoomLevel);
4372 pending_visual_change.samples_per_pixel = spp;
4373 ensure_visual_change_idle_handler ();
4377 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4379 reset_x_origin (frame);
4382 if (!no_save_visual) {
4383 undo_visual_stack.push_back (current_visual_state(false));
4387 Editor::VisualState::VisualState (bool with_tracks)
4388 : gui_state (with_tracks ? new GUIObjectState : 0)
4392 Editor::VisualState::~VisualState ()
4397 Editor::VisualState*
4398 Editor::current_visual_state (bool with_tracks)
4400 VisualState* vs = new VisualState (with_tracks);
4401 vs->y_position = vertical_adjustment.get_value();
4402 vs->samples_per_pixel = samples_per_pixel;
4403 vs->leftmost_frame = leftmost_frame;
4404 vs->zoom_focus = zoom_focus;
4407 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4414 Editor::undo_visual_state ()
4416 if (undo_visual_stack.empty()) {
4420 VisualState* vs = undo_visual_stack.back();
4421 undo_visual_stack.pop_back();
4424 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4427 use_visual_state (*vs);
4432 Editor::redo_visual_state ()
4434 if (redo_visual_stack.empty()) {
4438 VisualState* vs = redo_visual_stack.back();
4439 redo_visual_stack.pop_back();
4441 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4442 // why do we check here?
4443 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4446 use_visual_state (*vs);
4451 Editor::swap_visual_state ()
4453 if (undo_visual_stack.empty()) {
4454 redo_visual_state ();
4456 undo_visual_state ();
4461 Editor::use_visual_state (VisualState& vs)
4463 PBD::Unwinder<bool> nsv (no_save_visual, true);
4464 DisplaySuspender ds;
4466 vertical_adjustment.set_value (vs.y_position);
4468 set_zoom_focus (vs.zoom_focus);
4469 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4472 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4474 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4475 (*i)->clear_property_cache();
4476 (*i)->reset_visual_state ();
4480 _routes->update_visibility ();
4483 /** This is the core function that controls the zoom level of the canvas. It is called
4484 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4485 * @param spp new number of samples per pixel
4488 Editor::set_samples_per_pixel (framecnt_t spp)
4494 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4495 const framecnt_t lots_of_pixels = 4000;
4497 /* if the zoom level is greater than what you'd get trying to display 3
4498 * days of audio on a really big screen, then it's too big.
4501 if (spp * lots_of_pixels > three_days) {
4505 samples_per_pixel = spp;
4508 tempo_lines->tempo_map_changed();
4511 bool const showing_time_selection = selection->time.length() > 0;
4513 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4514 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4515 (*i)->reshow_selection (selection->time);
4519 ZoomChanged (); /* EMIT_SIGNAL */
4521 ArdourCanvas::GtkCanvasViewport* c;
4523 c = get_track_canvas();
4525 c->canvas()->zoomed ();
4528 if (playhead_cursor) {
4529 playhead_cursor->set_position (playhead_cursor->current_frame ());
4532 refresh_location_display();
4533 _summary->set_overlays_dirty ();
4535 update_marker_labels ();
4541 Editor::queue_visual_videotimeline_update ()
4544 * pending_visual_change.add (VisualChange::VideoTimeline);
4545 * or maybe even more specific: which videotimeline-image
4546 * currently it calls update_video_timeline() to update
4547 * _all outdated_ images on the video-timeline.
4548 * see 'exposeimg()' in video_image_frame.cc
4550 ensure_visual_change_idle_handler ();
4554 Editor::ensure_visual_change_idle_handler ()
4556 if (pending_visual_change.idle_handler_id < 0) {
4557 // see comment in add_to_idle_resize above.
4558 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4559 pending_visual_change.being_handled = false;
4564 Editor::_idle_visual_changer (void* arg)
4566 return static_cast<Editor*>(arg)->idle_visual_changer ();
4570 Editor::idle_visual_changer ()
4572 /* set_horizontal_position() below (and maybe other calls) call
4573 gtk_main_iteration(), so it's possible that a signal will be handled
4574 half-way through this method. If this signal wants an
4575 idle_visual_changer we must schedule another one after this one, so
4576 mark the idle_handler_id as -1 here to allow that. Also make a note
4577 that we are doing the visual change, so that changes in response to
4578 super-rapid-screen-update can be dropped if we are still processing
4582 pending_visual_change.idle_handler_id = -1;
4583 pending_visual_change.being_handled = true;
4585 VisualChange vc = pending_visual_change;
4587 pending_visual_change.pending = (VisualChange::Type) 0;
4589 visual_changer (vc);
4591 pending_visual_change.being_handled = false;
4593 return 0; /* this is always a one-shot call */
4597 Editor::visual_changer (const VisualChange& vc)
4599 double const last_time_origin = horizontal_position ();
4601 if (vc.pending & VisualChange::ZoomLevel) {
4602 set_samples_per_pixel (vc.samples_per_pixel);
4604 compute_fixed_ruler_scale ();
4606 std::vector<TempoMap::BBTPoint> grid;
4607 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4608 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4609 update_tempo_based_rulers (grid);
4611 update_video_timeline();
4614 if (vc.pending & VisualChange::TimeOrigin) {
4615 set_horizontal_position (vc.time_origin / samples_per_pixel);
4618 if (vc.pending & VisualChange::YOrigin) {
4619 vertical_adjustment.set_value (vc.y_origin);
4622 if (last_time_origin == horizontal_position ()) {
4623 /* changed signal not emitted */
4624 update_fixed_rulers ();
4625 redisplay_tempo (true);
4628 if (!(vc.pending & VisualChange::ZoomLevel)) {
4629 update_video_timeline();
4632 _summary->set_overlays_dirty ();
4635 struct EditorOrderTimeAxisSorter {
4636 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4637 return a->order () < b->order ();
4642 Editor::sort_track_selection (TrackViewList& sel)
4644 EditorOrderTimeAxisSorter cmp;
4649 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4652 framepos_t where = 0;
4653 EditPoint ep = _edit_point;
4655 if (Profile->get_mixbus())
4656 if (ep == EditAtSelectedMarker)
4657 ep = EditAtPlayhead;
4659 if (from_outside_canvas && (ep == EditAtMouse)) {
4660 ep = EditAtPlayhead;
4661 } else if (from_context_menu && (ep == EditAtMouse)) {
4662 return canvas_event_sample (&context_click_event, 0, 0);
4665 if (entered_marker) {
4666 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4667 return entered_marker->position();
4670 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4671 ep = EditAtSelectedMarker;
4674 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4675 ep = EditAtPlayhead;
4679 case EditAtPlayhead:
4680 if (_dragging_playhead) {
4681 where = *_control_scroll_target;
4683 where = _session->audible_frame();
4685 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4688 case EditAtSelectedMarker:
4689 if (!selection->markers.empty()) {
4691 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4694 where = loc->start();
4698 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4706 if (!mouse_frame (where, ignored)) {
4707 /* XXX not right but what can we do ? */
4711 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4719 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4721 if (!_session) return;
4723 begin_reversible_command (cmd);
4727 if ((tll = transport_loop_location()) == 0) {
4728 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4729 XMLNode &before = _session->locations()->get_state();
4730 _session->locations()->add (loc, true);
4731 _session->set_auto_loop_location (loc);
4732 XMLNode &after = _session->locations()->get_state();
4733 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4735 XMLNode &before = tll->get_state();
4736 tll->set_hidden (false, this);
4737 tll->set (start, end);
4738 XMLNode &after = tll->get_state();
4739 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4742 commit_reversible_command ();
4746 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4748 if (!_session) return;
4750 begin_reversible_command (cmd);
4754 if ((tpl = transport_punch_location()) == 0) {
4755 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4756 XMLNode &before = _session->locations()->get_state();
4757 _session->locations()->add (loc, true);
4758 _session->set_auto_punch_location (loc);
4759 XMLNode &after = _session->locations()->get_state();
4760 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4762 XMLNode &before = tpl->get_state();
4763 tpl->set_hidden (false, this);
4764 tpl->set (start, end);
4765 XMLNode &after = tpl->get_state();
4766 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4769 commit_reversible_command ();
4772 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4773 * @param rs List to which found regions are added.
4774 * @param where Time to look at.
4775 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4778 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4780 const TrackViewList* tracks;
4783 tracks = &track_views;
4788 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4790 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4793 boost::shared_ptr<Track> tr;
4794 boost::shared_ptr<Playlist> pl;
4796 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4798 boost::shared_ptr<RegionList> regions = pl->regions_at (
4799 (framepos_t) floor ( (double) where * tr->speed()));
4801 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4802 RegionView* rv = rtv->view()->find_view (*i);
4813 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4815 const TrackViewList* tracks;
4818 tracks = &track_views;
4823 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4824 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4826 boost::shared_ptr<Track> tr;
4827 boost::shared_ptr<Playlist> pl;
4829 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4831 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4832 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4834 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4836 RegionView* rv = rtv->view()->find_view (*i);
4847 /** Get regions using the following method:
4849 * Make a region list using:
4850 * (a) any selected regions
4851 * (b) the intersection of any selected tracks and the edit point(*)
4852 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4854 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4856 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4860 Editor::get_regions_from_selection_and_edit_point ()
4862 RegionSelection regions;
4864 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4865 regions.add (entered_regionview);
4867 regions = selection->regions;
4870 if ( regions.empty() ) {
4871 TrackViewList tracks = selection->tracks;
4873 if (!tracks.empty()) {
4874 /* no region selected or entered, but some selected tracks:
4875 * act on all regions on the selected tracks at the edit point
4877 framepos_t const where = get_preferred_edit_position ();
4878 get_regions_at(regions, where, tracks);
4885 /** Get regions using the following method:
4887 * Make a region list using:
4888 * (a) any selected regions
4889 * (b) the intersection of any selected tracks and the edit point(*)
4890 * (c) if neither exists, then whatever region is under the mouse
4892 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4894 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4897 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4899 RegionSelection regions;
4901 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4902 regions.add (entered_regionview);
4904 regions = selection->regions;
4907 if ( regions.empty() ) {
4908 TrackViewList tracks = selection->tracks;
4910 if (!tracks.empty()) {
4911 /* no region selected or entered, but some selected tracks:
4912 * act on all regions on the selected tracks at the edit point
4914 get_regions_at(regions, pos, tracks);
4921 /** Start with regions that are selected, or the entered regionview if none are selected.
4922 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4923 * of the regions that we started with.
4927 Editor::get_regions_from_selection_and_entered () const
4929 RegionSelection regions = selection->regions;
4931 if (regions.empty() && entered_regionview) {
4932 regions.add (entered_regionview);
4939 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4941 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4942 RouteTimeAxisView* rtav;
4944 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4945 boost::shared_ptr<Playlist> pl;
4946 std::vector<boost::shared_ptr<Region> > results;
4947 boost::shared_ptr<Track> tr;
4949 if ((tr = rtav->track()) == 0) {
4954 if ((pl = (tr->playlist())) != 0) {
4955 boost::shared_ptr<Region> r = pl->region_by_id (id);
4957 RegionView* rv = rtav->view()->find_view (r);
4959 regions.push_back (rv);
4968 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4971 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4972 MidiTimeAxisView* mtav;
4974 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4976 mtav->get_per_region_note_selection (selection);
4983 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4985 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4987 RouteTimeAxisView* tatv;
4989 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4991 boost::shared_ptr<Playlist> pl;
4992 vector<boost::shared_ptr<Region> > results;
4994 boost::shared_ptr<Track> tr;
4996 if ((tr = tatv->track()) == 0) {
5001 if ((pl = (tr->playlist())) != 0) {
5002 if (src_comparison) {
5003 pl->get_source_equivalent_regions (region, results);
5005 pl->get_region_list_equivalent_regions (region, results);
5009 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5010 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5011 regions.push_back (marv);
5020 Editor::show_rhythm_ferret ()
5022 if (rhythm_ferret == 0) {
5023 rhythm_ferret = new RhythmFerret(*this);
5026 rhythm_ferret->set_session (_session);
5027 rhythm_ferret->show ();
5028 rhythm_ferret->present ();
5032 Editor::first_idle ()
5034 MessageDialog* dialog = 0;
5036 if (track_views.size() > 1) {
5037 Timers::TimerSuspender t;
5038 dialog = new MessageDialog (
5039 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5043 ARDOUR_UI::instance()->flush_pending ();
5046 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5050 // first idle adds route children (automation tracks), so we need to redisplay here
5051 _routes->redisplay ();
5055 if (_session->undo_depth() == 0) {
5056 undo_action->set_sensitive(false);
5058 redo_action->set_sensitive(false);
5059 begin_selection_op_history ();
5065 Editor::_idle_resize (gpointer arg)
5067 return ((Editor*)arg)->idle_resize ();
5071 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5073 if (resize_idle_id < 0) {
5074 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5075 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5076 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5078 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5079 _pending_resize_amount = 0;
5082 /* make a note of the smallest resulting height, so that we can clamp the
5083 lower limit at TimeAxisView::hSmall */
5085 int32_t min_resulting = INT32_MAX;
5087 _pending_resize_amount += h;
5088 _pending_resize_view = view;
5090 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5092 if (selection->tracks.contains (_pending_resize_view)) {
5093 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5094 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5098 if (min_resulting < 0) {
5103 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5104 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5108 /** Handle pending resizing of tracks */
5110 Editor::idle_resize ()
5112 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5114 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5115 selection->tracks.contains (_pending_resize_view)) {
5117 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5118 if (*i != _pending_resize_view) {
5119 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5124 _pending_resize_amount = 0;
5125 _group_tabs->set_dirty ();
5126 resize_idle_id = -1;
5134 ENSURE_GUI_THREAD (*this, &Editor::located);
5137 playhead_cursor->set_position (_session->audible_frame ());
5138 if (_follow_playhead && !_pending_initial_locate) {
5139 reset_x_origin_to_follow_playhead ();
5143 _pending_locate_request = false;
5144 _pending_initial_locate = false;
5148 Editor::region_view_added (RegionView * rv)
5150 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5151 if (rv->region ()->id () == (*pr)) {
5152 selection->add (rv);
5153 selection->regions.pending.erase (pr);
5158 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5160 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5161 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5162 if (rv->region()->id () == (*rnote).first) {
5163 mrv->select_notes ((*rnote).second);
5164 selection->pending_midi_note_selection.erase(rnote);
5170 _summary->set_background_dirty ();
5174 Editor::region_view_removed ()
5176 _summary->set_background_dirty ();
5180 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5182 TrackViewList::const_iterator j = track_views.begin ();
5183 while (j != track_views.end()) {
5184 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5185 if (rtv && rtv->route() == r) {
5196 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5200 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5201 TimeAxisView* tv = axis_view_from_route (*i);
5211 Editor::suspend_route_redisplay ()
5214 _routes->suspend_redisplay();
5219 Editor::resume_route_redisplay ()
5222 _routes->redisplay(); // queue redisplay
5223 _routes->resume_redisplay();
5228 Editor::add_routes (RouteList& routes)
5230 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5232 RouteTimeAxisView *rtv;
5233 list<RouteTimeAxisView*> new_views;
5234 TrackViewList new_selection;
5235 bool from_scratch = (track_views.size() == 0);
5237 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5238 boost::shared_ptr<Route> route = (*x);
5240 if (route->is_auditioner() || route->is_monitor()) {
5244 DataType dt = route->input()->default_type();
5246 if (dt == ARDOUR::DataType::AUDIO) {
5247 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5248 rtv->set_route (route);
5249 } else if (dt == ARDOUR::DataType::MIDI) {
5250 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5251 rtv->set_route (route);
5253 throw unknown_type();
5256 new_views.push_back (rtv);
5257 track_views.push_back (rtv);
5258 new_selection.push_back (rtv);
5260 rtv->effective_gain_display ();
5262 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5263 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5266 if (new_views.size() > 0) {
5267 _routes->routes_added (new_views);
5268 _summary->routes_added (new_views);
5271 if (!from_scratch) {
5272 selection->tracks.clear();
5273 selection->add (new_selection);
5274 begin_selection_op_history();
5277 if (show_editor_mixer_when_tracks_arrive) {
5278 show_editor_mixer (true);
5281 editor_list_button.set_sensitive (true);
5285 Editor::timeaxisview_deleted (TimeAxisView *tv)
5287 if (tv == entered_track) {
5291 if (_session && _session->deletion_in_progress()) {
5292 /* the situation is under control */
5296 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5298 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5300 _routes->route_removed (tv);
5302 TimeAxisView::Children c = tv->get_child_list ();
5303 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5304 if (entered_track == i->get()) {
5309 /* remove it from the list of track views */
5311 TrackViewList::iterator i;
5313 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5314 i = track_views.erase (i);
5317 /* update whatever the current mixer strip is displaying, if revelant */
5319 boost::shared_ptr<Route> route;
5322 route = rtav->route ();
5325 if (current_mixer_strip && current_mixer_strip->route() == route) {
5327 TimeAxisView* next_tv;
5329 if (track_views.empty()) {
5331 } else if (i == track_views.end()) {
5332 next_tv = track_views.front();
5339 set_selected_mixer_strip (*next_tv);
5341 /* make the editor mixer strip go away setting the
5342 * button to inactive (which also unticks the menu option)
5345 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5351 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5353 if (apply_to_selection) {
5354 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5356 TrackSelection::iterator j = i;
5359 hide_track_in_display (*i, false);
5364 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5366 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5367 // this will hide the mixer strip
5368 set_selected_mixer_strip (*tv);
5371 _routes->hide_track_in_display (*tv);
5376 Editor::sync_track_view_list_and_routes ()
5378 track_views = TrackViewList (_routes->views ());
5380 _summary->set_background_dirty();
5381 _group_tabs->set_dirty ();
5383 return false; // do not call again (until needed)
5387 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5389 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5394 /** Find a RouteTimeAxisView by the ID of its route */
5396 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5398 RouteTimeAxisView* v;
5400 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5401 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5402 if(v->route()->id() == id) {
5412 Editor::fit_route_group (RouteGroup *g)
5414 TrackViewList ts = axis_views_from_routes (g->route_list ());
5419 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5421 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5424 _session->cancel_audition ();
5428 if (_session->is_auditioning()) {
5429 _session->cancel_audition ();
5430 if (r == last_audition_region) {
5435 _session->audition_region (r);
5436 last_audition_region = r;
5441 Editor::hide_a_region (boost::shared_ptr<Region> r)
5443 r->set_hidden (true);
5447 Editor::show_a_region (boost::shared_ptr<Region> r)
5449 r->set_hidden (false);
5453 Editor::audition_region_from_region_list ()
5455 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5459 Editor::hide_region_from_region_list ()
5461 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5465 Editor::show_region_in_region_list ()
5467 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5471 Editor::step_edit_status_change (bool yn)
5474 start_step_editing ();
5476 stop_step_editing ();
5481 Editor::start_step_editing ()
5483 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5487 Editor::stop_step_editing ()
5489 step_edit_connection.disconnect ();
5493 Editor::check_step_edit ()
5495 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5496 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5498 mtv->check_step_edit ();
5502 return true; // do it again, till we stop
5506 Editor::scroll_press (Direction dir)
5508 ++_scroll_callbacks;
5510 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5511 /* delay the first auto-repeat */
5517 scroll_backward (1);
5525 scroll_up_one_track ();
5529 scroll_down_one_track ();
5533 /* do hacky auto-repeat */
5534 if (!_scroll_connection.connected ()) {
5536 _scroll_connection = Glib::signal_timeout().connect (
5537 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5540 _scroll_callbacks = 0;
5547 Editor::scroll_release ()
5549 _scroll_connection.disconnect ();
5552 /** Queue a change for the Editor viewport x origin to follow the playhead */
5554 Editor::reset_x_origin_to_follow_playhead ()
5556 framepos_t const frame = playhead_cursor->current_frame ();
5558 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5560 if (_session->transport_speed() < 0) {
5562 if (frame > (current_page_samples() / 2)) {
5563 center_screen (frame-(current_page_samples()/2));
5565 center_screen (current_page_samples()/2);
5572 if (frame < leftmost_frame) {
5574 if (_session->transport_rolling()) {
5575 /* rolling; end up with the playhead at the right of the page */
5576 l = frame - current_page_samples ();
5578 /* not rolling: end up with the playhead 1/4 of the way along the page */
5579 l = frame - current_page_samples() / 4;
5583 if (_session->transport_rolling()) {
5584 /* rolling: end up with the playhead on the left of the page */
5587 /* not rolling: end up with the playhead 3/4 of the way along the page */
5588 l = frame - 3 * current_page_samples() / 4;
5596 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5602 Editor::super_rapid_screen_update ()
5604 if (!_session || !_session->engine().running()) {
5608 /* METERING / MIXER STRIPS */
5610 /* update track meters, if required */
5611 if (contents().is_mapped() && meters_running) {
5612 RouteTimeAxisView* rtv;
5613 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5614 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5615 rtv->fast_update ();
5620 /* and any current mixer strip */
5621 if (current_mixer_strip) {
5622 current_mixer_strip->fast_update ();
5625 /* PLAYHEAD AND VIEWPORT */
5627 framepos_t const frame = _session->audible_frame();
5629 /* There are a few reasons why we might not update the playhead / viewport stuff:
5631 * 1. we don't update things when there's a pending locate request, otherwise
5632 * when the editor requests a locate there is a chance that this method
5633 * will move the playhead before the locate request is processed, causing
5635 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5636 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5639 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5641 last_update_frame = frame;
5643 if (!_dragging_playhead) {
5644 playhead_cursor->set_position (frame);
5647 if (!_stationary_playhead) {
5649 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5650 /* We only do this if we aren't already
5651 handling a visual change (ie if
5652 pending_visual_change.being_handled is
5653 false) so that these requests don't stack
5654 up there are too many of them to handle in
5657 reset_x_origin_to_follow_playhead ();
5662 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5663 framepos_t const frame = playhead_cursor->current_frame ();
5664 double target = ((double)frame - (double)current_page_samples()/2.0);
5665 if (target <= 0.0) {
5668 // compare to EditorCursor::set_position()
5669 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5670 double const new_pos = sample_to_pixel_unrounded (target);
5671 if (rint (new_pos) != rint (old_pos)) {
5672 reset_x_origin (pixel_to_sample (floor (new_pos)));
5683 Editor::session_going_away ()
5685 _have_idled = false;
5687 _session_connections.drop_connections ();
5689 super_rapid_screen_update_connection.disconnect ();
5691 selection->clear ();
5692 cut_buffer->clear ();
5694 clicked_regionview = 0;
5695 clicked_axisview = 0;
5696 clicked_routeview = 0;
5697 entered_regionview = 0;
5699 last_update_frame = 0;
5702 playhead_cursor->hide ();
5704 /* rip everything out of the list displays */
5708 _route_groups->clear ();
5710 /* do this first so that deleting a track doesn't reset cms to null
5711 and thus cause a leak.
5714 if (current_mixer_strip) {
5715 if (current_mixer_strip->get_parent() != 0) {
5716 global_hpacker.remove (*current_mixer_strip);
5718 delete current_mixer_strip;
5719 current_mixer_strip = 0;
5722 /* delete all trackviews */
5724 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5727 track_views.clear ();
5729 nudge_clock->set_session (0);
5731 editor_list_button.set_active(false);
5732 editor_list_button.set_sensitive(false);
5734 /* clear tempo/meter rulers */
5735 remove_metric_marks ();
5737 clear_marker_display ();
5739 stop_step_editing ();
5743 /* get rid of any existing editor mixer strip */
5745 WindowTitle title(Glib::get_application_name());
5746 title += _("Editor");
5748 own_window()->set_title (title.get_string());
5751 SessionHandlePtr::session_going_away ();
5755 Editor::trigger_script (int i)
5757 LuaInstance::instance()-> call_action (i);
5761 Editor::set_script_action_name (int i, const std::string& n)
5763 string const a = string_compose (X_("script-action-%1"), i + 1);
5764 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5767 act->set_label (string_compose (_("Unset #%1"), i + 1));
5768 act->set_tooltip (_("no action bound"));
5769 act->set_sensitive (false);
5772 act->set_tooltip (n);
5773 act->set_sensitive (true);
5775 KeyEditor::UpdateBindings ();
5779 Editor::show_editor_list (bool yn)
5782 _the_notebook.show ();
5784 _the_notebook.hide ();
5789 Editor::change_region_layering_order (bool from_context_menu)
5791 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5793 if (!clicked_routeview) {
5794 if (layering_order_editor) {
5795 layering_order_editor->hide ();
5800 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5806 boost::shared_ptr<Playlist> pl = track->playlist();
5812 if (layering_order_editor == 0) {
5813 layering_order_editor = new RegionLayeringOrderEditor (*this);
5816 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5817 layering_order_editor->maybe_present ();
5821 Editor::update_region_layering_order_editor ()
5823 if (layering_order_editor && layering_order_editor->is_visible ()) {
5824 change_region_layering_order (true);
5829 Editor::setup_fade_images ()
5831 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5832 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5833 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5834 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5835 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5837 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5838 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5839 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5840 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5841 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5843 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5844 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5845 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5846 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5847 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5849 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5850 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5851 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5852 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5853 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5857 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5859 Editor::action_menu_item (std::string const & name)
5861 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5864 return *manage (a->create_menu_item ());
5868 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5870 EventBox* b = manage (new EventBox);
5871 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5872 Label* l = manage (new Label (name));
5876 _the_notebook.append_page (widget, *b);
5880 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5882 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5883 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5886 if (ev->type == GDK_2BUTTON_PRESS) {
5888 /* double-click on a notebook tab shrinks or expands the notebook */
5890 if (_notebook_shrunk) {
5891 if (pre_notebook_shrink_pane_width) {
5892 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5894 _notebook_shrunk = false;
5896 pre_notebook_shrink_pane_width = edit_pane.get_position();
5898 /* this expands the LHS of the edit pane to cover the notebook
5899 PAGE but leaves the tabs visible.
5901 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5902 _notebook_shrunk = true;
5910 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5912 using namespace Menu_Helpers;
5914 MenuList& items = _control_point_context_menu.items ();
5917 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5918 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5919 if (!can_remove_control_point (item)) {
5920 items.back().set_sensitive (false);
5923 _control_point_context_menu.popup (event->button.button, event->button.time);
5927 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5929 using namespace Menu_Helpers;
5931 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5936 /* We need to get the selection here and pass it to the operations, since
5937 popping up the menu will cause a region leave event which clears
5938 entered_regionview. */
5940 MidiRegionView& mrv = note->region_view();
5941 const RegionSelection rs = get_regions_from_selection_and_entered ();
5942 const uint32_t sel_size = mrv.selection_size ();
5944 MenuList& items = _note_context_menu.items();
5948 items.push_back(MenuElem(_("Delete"),
5949 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5952 items.push_back(MenuElem(_("Edit..."),
5953 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5954 if (sel_size != 1) {
5955 items.back().set_sensitive (false);
5958 items.push_back(MenuElem(_("Transpose..."),
5959 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5962 items.push_back(MenuElem(_("Legatize"),
5963 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5965 items.back().set_sensitive (false);
5968 items.push_back(MenuElem(_("Quantize..."),
5969 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5971 items.push_back(MenuElem(_("Remove Overlap"),
5972 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5974 items.back().set_sensitive (false);
5977 items.push_back(MenuElem(_("Transform..."),
5978 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5980 _note_context_menu.popup (event->button.button, event->button.time);
5984 Editor::zoom_vertical_modifier_released()
5986 _stepping_axis_view = 0;
5990 Editor::ui_parameter_changed (string parameter)
5992 if (parameter == "icon-set") {
5993 while (!_cursor_stack.empty()) {
5994 _cursor_stack.pop_back();
5996 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5997 _cursor_stack.push_back(_cursors->grabber);
5998 } else if (parameter == "draggable-playhead") {
5999 if (_verbose_cursor) {
6000 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6006 Editor::use_own_window (bool and_fill_it)
6008 bool new_window = !own_window();
6010 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6012 if (win && new_window) {
6013 win->set_name ("EditorWindow");
6015 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6017 // win->signal_realize().connect (*this, &Editor::on_realize);
6018 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6019 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6020 win->set_data ("ardour-bindings", bindings);
6025 DisplaySuspender ds;
6026 contents().show_all ();
6028 /* XXX: this is a bit unfortunate; it would probably
6029 be nicer if we could just call show () above rather
6030 than needing the show_all ()
6033 /* re-hide stuff if necessary */
6034 editor_list_button_toggled ();
6035 parameter_changed ("show-summary");
6036 parameter_changed ("show-group-tabs");
6037 parameter_changed ("show-zoom-tools");
6039 /* now reset all audio_time_axis heights, because widgets might need
6045 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6046 tv = (static_cast<TimeAxisView*>(*i));
6047 tv->reset_height ();
6050 if (current_mixer_strip) {
6051 current_mixer_strip->hide_things ();
6052 current_mixer_strip->parameter_changed ("mixer-element-visibility");