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_marker_menu (0)
395 , meter_marker_menu (0)
397 , range_marker_menu (0)
398 , transport_marker_menu (0)
399 , new_transport_marker_menu (0)
401 , marker_menu_item (0)
402 , bbt_beat_subdivision (4)
403 , _visible_track_count (-1)
404 , toolbar_selection_clock_table (2,3)
405 , automation_mode_button (_("mode"))
406 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
407 , selection (new Selection (this))
408 , cut_buffer (new Selection (this))
409 , _selection_memento (new SelectionMemento())
410 , _all_region_actions_sensitized (false)
411 , _ignore_region_action (false)
412 , _last_region_menu_was_main (false)
413 , _ignore_follow_edits (false)
414 , cd_marker_bar_drag_rect (0)
415 , range_bar_drag_rect (0)
416 , transport_bar_drag_rect (0)
417 , transport_bar_range_rect (0)
418 , transport_bar_preroll_rect (0)
419 , transport_bar_postroll_rect (0)
420 , transport_loop_range_rect (0)
421 , transport_punch_range_rect (0)
422 , transport_punchin_line (0)
423 , transport_punchout_line (0)
424 , transport_preroll_rect (0)
425 , transport_postroll_rect (0)
427 , rubberband_rect (0)
433 , autoscroll_horizontal_allowed (false)
434 , autoscroll_vertical_allowed (false)
436 , autoscroll_widget (0)
437 , show_gain_after_trim (false)
438 , selection_op_cmd_depth (0)
439 , selection_op_history_it (0)
440 , no_save_instant (false)
442 , current_mixer_strip (0)
443 , show_editor_mixer_when_tracks_arrive (false)
444 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
445 , current_stepping_trackview (0)
446 , last_track_height_step_timestamp (0)
448 , entered_regionview (0)
449 , clear_entered_track (false)
450 , _edit_point (EditAtMouse)
451 , meters_running (false)
453 , _have_idled (false)
454 , resize_idle_id (-1)
455 , _pending_resize_amount (0)
456 , _pending_resize_view (0)
457 , _pending_locate_request (false)
458 , _pending_initial_locate (false)
462 , layering_order_editor (0)
463 , _last_cut_copy_source_track (0)
464 , _region_selection_change_updates_region_list (true)
466 , _following_mixer_selection (false)
467 , _control_point_toggled_on_press (false)
468 , _stepping_axis_view (0)
469 , quantize_dialog (0)
470 , _main_menu_disabler (0)
471 , myactions (X_("editor"))
473 /* we are a singleton */
475 PublicEditor::_instance = this;
479 last_event_time.tv_sec = 0;
480 last_event_time.tv_usec = 0;
482 selection_op_history.clear();
485 snap_type_strings = I18N (_snap_type_strings);
486 snap_mode_strings = I18N (_snap_mode_strings);
487 zoom_focus_strings = I18N (_zoom_focus_strings);
488 edit_mode_strings = I18N (_edit_mode_strings);
489 edit_point_strings = I18N (_edit_point_strings);
490 #ifdef USE_RUBBERBAND
491 rb_opt_strings = I18N (_rb_opt_strings);
495 build_edit_mode_menu();
496 build_zoom_focus_menu();
497 build_track_count_menu();
498 build_snap_mode_menu();
499 build_snap_type_menu();
500 build_edit_point_menu();
502 location_marker_color = UIConfiguration::instance().color ("location marker");
503 location_range_color = UIConfiguration::instance().color ("location range");
504 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
505 location_loop_color = UIConfiguration::instance().color ("location loop");
506 location_punch_color = UIConfiguration::instance().color ("location punch");
508 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
510 TimeAxisView::setup_sizes ();
511 ArdourMarker::setup_sizes (timebar_height);
512 TempoCurve::setup_sizes (timebar_height);
514 bbt_label.set_name ("EditorRulerLabel");
515 bbt_label.set_size_request (-1, (int)timebar_height);
516 bbt_label.set_alignment (1.0, 0.5);
517 bbt_label.set_padding (5,0);
519 bbt_label.set_no_show_all();
520 minsec_label.set_name ("EditorRulerLabel");
521 minsec_label.set_size_request (-1, (int)timebar_height);
522 minsec_label.set_alignment (1.0, 0.5);
523 minsec_label.set_padding (5,0);
524 minsec_label.hide ();
525 minsec_label.set_no_show_all();
526 timecode_label.set_name ("EditorRulerLabel");
527 timecode_label.set_size_request (-1, (int)timebar_height);
528 timecode_label.set_alignment (1.0, 0.5);
529 timecode_label.set_padding (5,0);
530 timecode_label.hide ();
531 timecode_label.set_no_show_all();
532 samples_label.set_name ("EditorRulerLabel");
533 samples_label.set_size_request (-1, (int)timebar_height);
534 samples_label.set_alignment (1.0, 0.5);
535 samples_label.set_padding (5,0);
536 samples_label.hide ();
537 samples_label.set_no_show_all();
539 tempo_label.set_name ("EditorRulerLabel");
540 tempo_label.set_size_request (-1, (int)timebar_height);
541 tempo_label.set_alignment (1.0, 0.5);
542 tempo_label.set_padding (5,0);
544 tempo_label.set_no_show_all();
546 meter_label.set_name ("EditorRulerLabel");
547 meter_label.set_size_request (-1, (int)timebar_height);
548 meter_label.set_alignment (1.0, 0.5);
549 meter_label.set_padding (5,0);
551 meter_label.set_no_show_all();
553 if (Profile->get_trx()) {
554 mark_label.set_text (_("Markers"));
556 mark_label.set_name ("EditorRulerLabel");
557 mark_label.set_size_request (-1, (int)timebar_height);
558 mark_label.set_alignment (1.0, 0.5);
559 mark_label.set_padding (5,0);
561 mark_label.set_no_show_all();
563 cd_mark_label.set_name ("EditorRulerLabel");
564 cd_mark_label.set_size_request (-1, (int)timebar_height);
565 cd_mark_label.set_alignment (1.0, 0.5);
566 cd_mark_label.set_padding (5,0);
567 cd_mark_label.hide();
568 cd_mark_label.set_no_show_all();
570 videotl_bar_height = 4;
571 videotl_label.set_name ("EditorRulerLabel");
572 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
573 videotl_label.set_alignment (1.0, 0.5);
574 videotl_label.set_padding (5,0);
575 videotl_label.hide();
576 videotl_label.set_no_show_all();
578 range_mark_label.set_name ("EditorRulerLabel");
579 range_mark_label.set_size_request (-1, (int)timebar_height);
580 range_mark_label.set_alignment (1.0, 0.5);
581 range_mark_label.set_padding (5,0);
582 range_mark_label.hide();
583 range_mark_label.set_no_show_all();
585 transport_mark_label.set_name ("EditorRulerLabel");
586 transport_mark_label.set_size_request (-1, (int)timebar_height);
587 transport_mark_label.set_alignment (1.0, 0.5);
588 transport_mark_label.set_padding (5,0);
589 transport_mark_label.hide();
590 transport_mark_label.set_no_show_all();
592 initialize_canvas ();
594 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
596 _summary = new EditorSummary (this);
598 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
599 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
601 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
603 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
604 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
606 edit_controls_vbox.set_spacing (0);
607 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
608 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
610 HBox* h = manage (new HBox);
611 _group_tabs = new EditorGroupTabs (this);
612 if (!ARDOUR::Profile->get_trx()) {
613 h->pack_start (*_group_tabs, PACK_SHRINK);
615 h->pack_start (edit_controls_vbox);
616 controls_layout.add (*h);
618 controls_layout.set_name ("EditControlsBase");
619 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
620 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
621 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
623 _cursors = new MouseCursors;
624 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
625 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
627 /* Push default cursor to ever-present bottom of cursor stack. */
628 push_canvas_cursor(_cursors->grabber);
630 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
632 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
633 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
634 pad_line_1->set_outline_color (0xFF0000FF);
640 edit_packer.set_col_spacings (0);
641 edit_packer.set_row_spacings (0);
642 edit_packer.set_homogeneous (false);
643 edit_packer.set_border_width (0);
644 edit_packer.set_name ("EditorWindow");
646 time_bars_event_box.add (time_bars_vbox);
647 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
648 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
650 /* labels for the time bars */
651 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
653 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
655 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
657 bottom_hbox.set_border_width (2);
658 bottom_hbox.set_spacing (3);
660 _route_groups = new EditorRouteGroups (this);
661 _routes = new EditorRoutes (this);
662 _regions = new EditorRegions (this);
663 _snapshots = new EditorSnapshots (this);
664 _locations = new EditorLocations (this);
666 /* these are static location signals */
668 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
669 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
670 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
672 add_notebook_page (_("Regions"), _regions->widget ());
673 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
674 add_notebook_page (_("Snapshots"), _snapshots->widget ());
675 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
676 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
678 _the_notebook.set_show_tabs (true);
679 _the_notebook.set_scrollable (true);
680 _the_notebook.popup_disable ();
681 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
682 _the_notebook.show_all ();
684 _notebook_shrunk = false;
686 editor_summary_pane.pack1(edit_packer);
688 Button* summary_arrows_left_left = manage (new Button);
689 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
690 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
691 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
693 Button* summary_arrows_left_right = manage (new Button);
694 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
695 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
696 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
698 VBox* summary_arrows_left = manage (new VBox);
699 summary_arrows_left->pack_start (*summary_arrows_left_left);
700 summary_arrows_left->pack_start (*summary_arrows_left_right);
702 Button* summary_arrows_right_up = manage (new Button);
703 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
704 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
705 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
707 Button* summary_arrows_right_down = manage (new Button);
708 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
709 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
710 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
712 VBox* summary_arrows_right = manage (new VBox);
713 summary_arrows_right->pack_start (*summary_arrows_right_up);
714 summary_arrows_right->pack_start (*summary_arrows_right_down);
716 Frame* summary_frame = manage (new Frame);
717 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
719 summary_frame->add (*_summary);
720 summary_frame->show ();
722 _summary_hbox.pack_start (*summary_arrows_left, false, false);
723 _summary_hbox.pack_start (*summary_frame, true, true);
724 _summary_hbox.pack_start (*summary_arrows_right, false, false);
726 if (!ARDOUR::Profile->get_trx()) {
727 editor_summary_pane.pack2 (_summary_hbox);
730 edit_pane.pack1 (editor_summary_pane, true, true);
731 if (!ARDOUR::Profile->get_trx()) {
732 edit_pane.pack2 (_the_notebook, false, true);
735 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
737 /* XXX: editor_summary_pane might need similar to the edit_pane */
739 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
741 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
742 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
744 top_hbox.pack_start (toolbar_frame);
746 HBox *hbox = manage (new HBox);
747 hbox->pack_start (edit_pane, true, true);
749 global_vpacker.pack_start (top_hbox, false, false);
750 global_vpacker.pack_start (*hbox, true, true);
751 global_hpacker.pack_start (global_vpacker, true, true);
753 /* need to show the "contents" widget so that notebook will show if tab is switched to
756 global_hpacker.show ();
758 /* register actions now so that set_state() can find them and set toggles/checks etc */
765 _playlist_selector = new PlaylistSelector();
766 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
768 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
772 nudge_forward_button.set_name ("nudge button");
773 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
775 nudge_backward_button.set_name ("nudge button");
776 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
778 fade_context_menu.set_name ("ArdourContextMenu");
780 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
782 /* allow external control surfaces/protocols to do various things */
784 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
785 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
786 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
787 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
788 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
789 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
790 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
791 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
792 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
793 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
794 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
795 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
796 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
797 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
799 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
800 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
801 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
802 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
803 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
805 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
807 /* problematic: has to return a value and thus cannot be x-thread */
809 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
811 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
812 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
814 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
816 _ignore_region_action = false;
817 _last_region_menu_was_main = false;
818 _popup_region_menu_item = 0;
820 _ignore_follow_edits = false;
822 _show_marker_lines = false;
824 /* Button bindings */
826 button_bindings = new Bindings ("editor-mouse");
828 XMLNode* node = button_settings();
830 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
831 button_bindings->load_operation (**i);
837 /* grab current parameter state */
838 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
839 UIConfiguration::instance().map_parameters (pc);
841 setup_fade_images ();
843 LuaInstance::instance(); // instantiate
844 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
851 delete button_bindings;
853 delete _route_groups;
854 delete _track_canvas_viewport;
857 delete quantize_dialog;
863 delete _playlist_selector;
865 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
871 Editor::button_settings () const
873 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
874 XMLNode* node = find_named_node (*settings, X_("Buttons"));
877 node = new XMLNode (X_("Buttons"));
884 Editor::get_smart_mode () const
886 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
890 Editor::catch_vanishing_regionview (RegionView *rv)
892 /* note: the selection will take care of the vanishing
893 audioregionview by itself.
896 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
900 if (clicked_regionview == rv) {
901 clicked_regionview = 0;
904 if (entered_regionview == rv) {
905 set_entered_regionview (0);
908 if (!_all_region_actions_sensitized) {
909 sensitize_all_region_actions (true);
914 Editor::set_entered_regionview (RegionView* rv)
916 if (rv == entered_regionview) {
920 if (entered_regionview) {
921 entered_regionview->exited ();
924 entered_regionview = rv;
926 if (entered_regionview != 0) {
927 entered_regionview->entered ();
930 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
931 /* This RegionView entry might have changed what region actions
932 are allowed, so sensitize them all in case a key is pressed.
934 sensitize_all_region_actions (true);
939 Editor::set_entered_track (TimeAxisView* tav)
942 entered_track->exited ();
948 entered_track->entered ();
953 Editor::instant_save ()
955 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
960 _session->add_instant_xml(get_state());
962 Config->add_instant_xml(get_state());
967 Editor::control_vertical_zoom_in_all ()
969 tav_zoom_smooth (false, true);
973 Editor::control_vertical_zoom_out_all ()
975 tav_zoom_smooth (true, true);
979 Editor::control_vertical_zoom_in_selected ()
981 tav_zoom_smooth (false, false);
985 Editor::control_vertical_zoom_out_selected ()
987 tav_zoom_smooth (true, false);
991 Editor::control_view (uint32_t view)
993 goto_visual_state (view);
997 Editor::control_unselect ()
999 selection->clear_tracks ();
1003 Editor::control_select (uint32_t rid, Selection::Operation op)
1005 /* handles the (static) signal from the ControlProtocol class that
1006 * requests setting the selected track to a given RID
1013 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1019 TimeAxisView* tav = axis_view_from_route (r);
1023 case Selection::Add:
1024 selection->add (tav);
1026 case Selection::Toggle:
1027 selection->toggle (tav);
1029 case Selection::Extend:
1031 case Selection::Set:
1032 selection->set (tav);
1036 selection->clear_tracks ();
1041 Editor::control_step_tracks_up ()
1043 scroll_tracks_up_line ();
1047 Editor::control_step_tracks_down ()
1049 scroll_tracks_down_line ();
1053 Editor::control_scroll (float fraction)
1055 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1061 double step = fraction * current_page_samples();
1064 _control_scroll_target is an optional<T>
1066 it acts like a pointer to an framepos_t, with
1067 a operator conversion to boolean to check
1068 that it has a value could possibly use
1069 playhead_cursor->current_frame to store the
1070 value and a boolean in the class to know
1071 when it's out of date
1074 if (!_control_scroll_target) {
1075 _control_scroll_target = _session->transport_frame();
1076 _dragging_playhead = true;
1079 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1080 *_control_scroll_target = 0;
1081 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1082 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1084 *_control_scroll_target += (framepos_t) trunc (step);
1087 /* move visuals, we'll catch up with it later */
1089 playhead_cursor->set_position (*_control_scroll_target);
1090 UpdateAllTransportClocks (*_control_scroll_target);
1092 if (*_control_scroll_target > (current_page_samples() / 2)) {
1093 /* try to center PH in window */
1094 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1100 Now we do a timeout to actually bring the session to the right place
1101 according to the playhead. This is to avoid reading disk buffers on every
1102 call to control_scroll, which is driven by ScrollTimeline and therefore
1103 probably by a control surface wheel which can generate lots of events.
1105 /* cancel the existing timeout */
1107 control_scroll_connection.disconnect ();
1109 /* add the next timeout */
1111 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1115 Editor::deferred_control_scroll (framepos_t /*target*/)
1117 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1118 // reset for next stream
1119 _control_scroll_target = boost::none;
1120 _dragging_playhead = false;
1125 Editor::access_action (std::string action_group, std::string action_item)
1131 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1134 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1142 Editor::on_realize ()
1146 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1147 start_lock_event_timing ();
1152 Editor::start_lock_event_timing ()
1154 /* check if we should lock the GUI every 30 seconds */
1156 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1160 Editor::generic_event_handler (GdkEvent* ev)
1163 case GDK_BUTTON_PRESS:
1164 case GDK_BUTTON_RELEASE:
1165 case GDK_MOTION_NOTIFY:
1167 case GDK_KEY_RELEASE:
1168 if (contents().is_mapped()) {
1169 gettimeofday (&last_event_time, 0);
1173 case GDK_LEAVE_NOTIFY:
1174 switch (ev->crossing.detail) {
1175 case GDK_NOTIFY_UNKNOWN:
1176 case GDK_NOTIFY_INFERIOR:
1177 case GDK_NOTIFY_ANCESTOR:
1179 case GDK_NOTIFY_VIRTUAL:
1180 case GDK_NOTIFY_NONLINEAR:
1181 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1182 /* leaving window, so reset focus, thus ending any and
1183 all text entry operations.
1185 reset_focus (&contents());
1198 Editor::lock_timeout_callback ()
1200 struct timeval now, delta;
1202 gettimeofday (&now, 0);
1204 timersub (&now, &last_event_time, &delta);
1206 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1208 /* don't call again. Returning false will effectively
1209 disconnect us from the timer callback.
1211 unlock() will call start_lock_event_timing() to get things
1221 Editor::map_position_change (framepos_t frame)
1223 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1225 if (_session == 0) {
1229 if (_follow_playhead) {
1230 center_screen (frame);
1233 playhead_cursor->set_position (frame);
1237 Editor::center_screen (framepos_t frame)
1239 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1241 /* if we're off the page, then scroll.
1244 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1245 center_screen_internal (frame, page);
1250 Editor::center_screen_internal (framepos_t frame, float page)
1255 frame -= (framepos_t) page;
1260 reset_x_origin (frame);
1265 Editor::update_title ()
1267 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1269 if (!own_window()) {
1274 bool dirty = _session->dirty();
1276 string session_name;
1278 if (_session->snap_name() != _session->name()) {
1279 session_name = _session->snap_name();
1281 session_name = _session->name();
1285 session_name = "*" + session_name;
1288 WindowTitle title(session_name);
1289 title += S_("Window|Editor");
1290 title += Glib::get_application_name();
1291 own_window()->set_title (title.get_string());
1293 /* ::session_going_away() will have taken care of it */
1298 Editor::set_session (Session *t)
1300 SessionHandlePtr::set_session (t);
1306 _playlist_selector->set_session (_session);
1307 nudge_clock->set_session (_session);
1308 _summary->set_session (_session);
1309 _group_tabs->set_session (_session);
1310 _route_groups->set_session (_session);
1311 _regions->set_session (_session);
1312 _snapshots->set_session (_session);
1313 _routes->set_session (_session);
1314 _locations->set_session (_session);
1316 if (rhythm_ferret) {
1317 rhythm_ferret->set_session (_session);
1320 if (analysis_window) {
1321 analysis_window->set_session (_session);
1325 sfbrowser->set_session (_session);
1328 compute_fixed_ruler_scale ();
1330 /* Make sure we have auto loop and auto punch ranges */
1332 Location* loc = _session->locations()->auto_loop_location();
1334 loc->set_name (_("Loop"));
1337 loc = _session->locations()->auto_punch_location();
1340 loc->set_name (_("Punch"));
1343 refresh_location_display ();
1345 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1346 the selected Marker; this needs the LocationMarker list to be available.
1348 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1349 set_state (*node, Stateful::loading_state_version);
1351 /* catch up with the playhead */
1353 _session->request_locate (playhead_cursor->current_frame ());
1354 _pending_initial_locate = true;
1358 /* These signals can all be emitted by a non-GUI thread. Therefore the
1359 handlers for them must not attempt to directly interact with the GUI,
1360 but use PBD::Signal<T>::connect() which accepts an event loop
1361 ("context") where the handler will be asked to run.
1364 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1365 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1366 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1367 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1368 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1369 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1370 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1371 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1372 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1373 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1374 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1375 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1376 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1377 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1379 playhead_cursor->show ();
1381 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1382 Config->map_parameters (pc);
1383 _session->config.map_parameters (pc);
1385 restore_ruler_visibility ();
1386 //tempo_map_changed (PropertyChange (0));
1387 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1389 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1390 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1393 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1394 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1397 switch (_snap_type) {
1398 case SnapToRegionStart:
1399 case SnapToRegionEnd:
1400 case SnapToRegionSync:
1401 case SnapToRegionBoundary:
1402 build_region_boundary_cache ();
1409 /* register for undo history */
1410 _session->register_with_memento_command_factory(id(), this);
1411 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1413 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1415 LuaInstance::instance()->set_session(_session);
1417 start_updating_meters ();
1421 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1423 if (a->get_name() == "RegionMenu") {
1424 /* When the main menu's region menu is opened, we setup the actions so that they look right
1425 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1426 so we resensitize all region actions when the entered regionview or the region selection
1427 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1428 happens after the region context menu is opened. So we set a flag here, too.
1432 sensitize_the_right_region_actions ();
1433 _last_region_menu_was_main = true;
1438 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1440 using namespace Menu_Helpers;
1442 void (Editor::*emf)(FadeShape);
1443 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1446 images = &_xfade_in_images;
1447 emf = &Editor::set_fade_in_shape;
1449 images = &_xfade_out_images;
1450 emf = &Editor::set_fade_out_shape;
1455 _("Linear (for highly correlated material)"),
1456 *(*images)[FadeLinear],
1457 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1461 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1465 _("Constant power"),
1466 *(*images)[FadeConstantPower],
1467 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1470 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 *(*images)[FadeSymmetric],
1476 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 *(*images)[FadeSlow],
1486 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 *(*images)[FadeFast],
1495 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1498 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 /** Pop up a context menu for when the user clicks on a start crossfade */
1503 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1505 using namespace Menu_Helpers;
1506 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1511 MenuList& items (xfade_in_context_menu.items());
1514 if (arv->audio_region()->fade_in_active()) {
1515 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1517 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1520 items.push_back (SeparatorElem());
1521 fill_xfade_menu (items, true);
1523 xfade_in_context_menu.popup (button, time);
1526 /** Pop up a context menu for when the user clicks on an end crossfade */
1528 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1530 using namespace Menu_Helpers;
1531 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1536 MenuList& items (xfade_out_context_menu.items());
1539 if (arv->audio_region()->fade_out_active()) {
1540 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1542 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1545 items.push_back (SeparatorElem());
1546 fill_xfade_menu (items, false);
1548 xfade_out_context_menu.popup (button, time);
1552 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1554 using namespace Menu_Helpers;
1555 Menu* (Editor::*build_menu_function)();
1558 switch (item_type) {
1560 case RegionViewName:
1561 case RegionViewNameHighlight:
1562 case LeftFrameHandle:
1563 case RightFrameHandle:
1564 if (with_selection) {
1565 build_menu_function = &Editor::build_track_selection_context_menu;
1567 build_menu_function = &Editor::build_track_region_context_menu;
1572 if (with_selection) {
1573 build_menu_function = &Editor::build_track_selection_context_menu;
1575 build_menu_function = &Editor::build_track_context_menu;
1580 if (clicked_routeview->track()) {
1581 build_menu_function = &Editor::build_track_context_menu;
1583 build_menu_function = &Editor::build_track_bus_context_menu;
1588 /* probably shouldn't happen but if it does, we don't care */
1592 menu = (this->*build_menu_function)();
1593 menu->set_name ("ArdourContextMenu");
1595 /* now handle specific situations */
1597 switch (item_type) {
1599 case RegionViewName:
1600 case RegionViewNameHighlight:
1601 case LeftFrameHandle:
1602 case RightFrameHandle:
1603 if (!with_selection) {
1604 if (region_edit_menu_split_item) {
1605 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1606 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1608 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1611 if (region_edit_menu_split_multichannel_item) {
1612 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1613 region_edit_menu_split_multichannel_item->set_sensitive (true);
1615 region_edit_menu_split_multichannel_item->set_sensitive (false);
1628 /* probably shouldn't happen but if it does, we don't care */
1632 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1634 /* Bounce to disk */
1636 using namespace Menu_Helpers;
1637 MenuList& edit_items = menu->items();
1639 edit_items.push_back (SeparatorElem());
1641 switch (clicked_routeview->audio_track()->freeze_state()) {
1642 case AudioTrack::NoFreeze:
1643 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1646 case AudioTrack::Frozen:
1647 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1650 case AudioTrack::UnFrozen:
1651 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1657 if (item_type == StreamItem && clicked_routeview) {
1658 clicked_routeview->build_underlay_menu(menu);
1661 /* When the region menu is opened, we setup the actions so that they look right
1664 sensitize_the_right_region_actions ();
1665 _last_region_menu_was_main = false;
1667 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1668 menu->popup (button, time);
1672 Editor::build_track_context_menu ()
1674 using namespace Menu_Helpers;
1676 MenuList& edit_items = track_context_menu.items();
1679 add_dstream_context_items (edit_items);
1680 return &track_context_menu;
1684 Editor::build_track_bus_context_menu ()
1686 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_context_menu.items();
1691 add_bus_context_items (edit_items);
1692 return &track_context_menu;
1696 Editor::build_track_region_context_menu ()
1698 using namespace Menu_Helpers;
1699 MenuList& edit_items = track_region_context_menu.items();
1702 /* we've just cleared the track region context menu, so the menu that these
1703 two items were on will have disappeared; stop them dangling.
1705 region_edit_menu_split_item = 0;
1706 region_edit_menu_split_multichannel_item = 0;
1708 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1711 boost::shared_ptr<Track> tr;
1712 boost::shared_ptr<Playlist> pl;
1714 if ((tr = rtv->track())) {
1715 add_region_context_items (edit_items, tr);
1719 add_dstream_context_items (edit_items);
1721 return &track_region_context_menu;
1725 Editor::loudness_analyze_region_selection ()
1730 Selection& s (PublicEditor::instance ().get_selection ());
1731 RegionSelection ars = s.regions;
1732 ARDOUR::AnalysisGraph ag (_session);
1733 framecnt_t total_work = 0;
1735 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1736 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1740 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1743 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1744 total_work += arv->region ()->length ();
1747 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1749 ag.set_total_frames (total_work);
1750 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1753 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1754 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1758 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1762 ag.analyze_region (ar);
1765 if (!ag.canceled ()) {
1766 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1772 Editor::loudness_analyze_range_selection ()
1777 Selection& s (PublicEditor::instance ().get_selection ());
1778 TimeSelection ts = s.time;
1779 ARDOUR::AnalysisGraph ag (_session);
1780 framecnt_t total_work = 0;
1782 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1783 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1787 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1791 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1792 total_work += j->length ();
1796 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1798 ag.set_total_frames (total_work);
1799 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1802 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1803 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1807 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1811 ag.analyze_range (rui->route (), pl, ts);
1814 if (!ag.canceled ()) {
1815 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1821 Editor::spectral_analyze_region_selection ()
1823 if (analysis_window == 0) {
1824 analysis_window = new AnalysisWindow();
1827 analysis_window->set_session(_session);
1829 analysis_window->show_all();
1832 analysis_window->set_regionmode();
1833 analysis_window->analyze();
1835 analysis_window->present();
1839 Editor::spectral_analyze_range_selection()
1841 if (analysis_window == 0) {
1842 analysis_window = new AnalysisWindow();
1845 analysis_window->set_session(_session);
1847 analysis_window->show_all();
1850 analysis_window->set_rangemode();
1851 analysis_window->analyze();
1853 analysis_window->present();
1857 Editor::build_track_selection_context_menu ()
1859 using namespace Menu_Helpers;
1860 MenuList& edit_items = track_selection_context_menu.items();
1861 edit_items.clear ();
1863 add_selection_context_items (edit_items);
1864 // edit_items.push_back (SeparatorElem());
1865 // add_dstream_context_items (edit_items);
1867 return &track_selection_context_menu;
1871 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1873 using namespace Menu_Helpers;
1875 /* OK, stick the region submenu at the top of the list, and then add
1879 RegionSelection rs = get_regions_from_selection_and_entered ();
1881 string::size_type pos = 0;
1882 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1884 /* we have to hack up the region name because "_" has a special
1885 meaning for menu titles.
1888 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1889 menu_item_name.replace (pos, 1, "__");
1893 if (_popup_region_menu_item == 0) {
1894 _popup_region_menu_item = new MenuItem (menu_item_name);
1895 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1896 _popup_region_menu_item->show ();
1898 _popup_region_menu_item->set_label (menu_item_name);
1901 /* No latering allowed in later is higher layering model */
1902 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1903 if (act && Config->get_layer_model() == LaterHigher) {
1904 act->set_sensitive (false);
1906 act->set_sensitive (true);
1909 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1911 edit_items.push_back (*_popup_region_menu_item);
1912 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1913 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1915 edit_items.push_back (SeparatorElem());
1918 /** Add context menu items relevant to selection ranges.
1919 * @param edit_items List to add the items to.
1922 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1924 using namespace Menu_Helpers;
1926 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1927 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1929 edit_items.push_back (SeparatorElem());
1930 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1932 edit_items.push_back (SeparatorElem());
1933 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1934 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1936 edit_items.push_back (SeparatorElem());
1938 edit_items.push_back (
1940 _("Move Range Start to Previous Region Boundary"),
1941 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1945 edit_items.push_back (
1947 _("Move Range Start to Next Region Boundary"),
1948 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1952 edit_items.push_back (
1954 _("Move Range End to Previous Region Boundary"),
1955 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1959 edit_items.push_back (
1961 _("Move Range End to Next Region Boundary"),
1962 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1966 edit_items.push_back (SeparatorElem());
1967 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1968 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1970 edit_items.push_back (SeparatorElem());
1971 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1973 edit_items.push_back (SeparatorElem());
1974 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1975 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1976 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1978 edit_items.push_back (SeparatorElem());
1979 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1981 edit_items.push_back (SeparatorElem());
1982 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1983 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1985 edit_items.push_back (SeparatorElem());
1986 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1987 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1988 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1989 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1990 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1991 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1992 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1998 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2000 using namespace Menu_Helpers;
2004 Menu *play_menu = manage (new Menu);
2005 MenuList& play_items = play_menu->items();
2006 play_menu->set_name ("ArdourContextMenu");
2008 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2009 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2010 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2011 play_items.push_back (SeparatorElem());
2012 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2014 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2018 Menu *select_menu = manage (new Menu);
2019 MenuList& select_items = select_menu->items();
2020 select_menu->set_name ("ArdourContextMenu");
2022 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2023 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2024 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2025 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2026 select_items.push_back (SeparatorElem());
2027 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2028 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2029 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2030 select_items.push_back (SeparatorElem());
2031 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2032 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2033 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2034 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2035 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2036 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2037 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2039 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2043 Menu *cutnpaste_menu = manage (new Menu);
2044 MenuList& cutnpaste_items = cutnpaste_menu->items();
2045 cutnpaste_menu->set_name ("ArdourContextMenu");
2047 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2048 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2049 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2051 cutnpaste_items.push_back (SeparatorElem());
2053 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2054 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2056 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2058 /* Adding new material */
2060 edit_items.push_back (SeparatorElem());
2061 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2062 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2066 Menu *nudge_menu = manage (new Menu());
2067 MenuList& nudge_items = nudge_menu->items();
2068 nudge_menu->set_name ("ArdourContextMenu");
2070 edit_items.push_back (SeparatorElem());
2071 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2072 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2074 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2076 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2080 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2082 using namespace Menu_Helpers;
2086 Menu *play_menu = manage (new Menu);
2087 MenuList& play_items = play_menu->items();
2088 play_menu->set_name ("ArdourContextMenu");
2090 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2091 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2092 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2096 Menu *select_menu = manage (new Menu);
2097 MenuList& select_items = select_menu->items();
2098 select_menu->set_name ("ArdourContextMenu");
2100 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2101 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2102 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2103 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2104 select_items.push_back (SeparatorElem());
2105 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2106 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2107 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2108 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2110 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2114 Menu *cutnpaste_menu = manage (new Menu);
2115 MenuList& cutnpaste_items = cutnpaste_menu->items();
2116 cutnpaste_menu->set_name ("ArdourContextMenu");
2118 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2119 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2120 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2122 Menu *nudge_menu = manage (new Menu());
2123 MenuList& nudge_items = nudge_menu->items();
2124 nudge_menu->set_name ("ArdourContextMenu");
2126 edit_items.push_back (SeparatorElem());
2127 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2128 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2129 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2130 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2132 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2136 Editor::snap_type() const
2142 Editor::snap_musical() const
2144 switch (_snap_type) {
2145 case SnapToBeatDiv128:
2146 case SnapToBeatDiv64:
2147 case SnapToBeatDiv32:
2148 case SnapToBeatDiv28:
2149 case SnapToBeatDiv24:
2150 case SnapToBeatDiv20:
2151 case SnapToBeatDiv16:
2152 case SnapToBeatDiv14:
2153 case SnapToBeatDiv12:
2154 case SnapToBeatDiv10:
2155 case SnapToBeatDiv8:
2156 case SnapToBeatDiv7:
2157 case SnapToBeatDiv6:
2158 case SnapToBeatDiv5:
2159 case SnapToBeatDiv4:
2160 case SnapToBeatDiv3:
2161 case SnapToBeatDiv2:
2173 Editor::snap_mode() const
2179 Editor::set_snap_to (SnapType st)
2181 unsigned int snap_ind = (unsigned int)st;
2183 if (internal_editing()) {
2184 internal_snap_type = st;
2186 pre_internal_snap_type = st;
2191 if (snap_ind > snap_type_strings.size() - 1) {
2193 _snap_type = (SnapType)snap_ind;
2196 string str = snap_type_strings[snap_ind];
2198 if (str != snap_type_selector.get_text()) {
2199 snap_type_selector.set_text (str);
2204 switch (_snap_type) {
2205 case SnapToBeatDiv128:
2206 case SnapToBeatDiv64:
2207 case SnapToBeatDiv32:
2208 case SnapToBeatDiv28:
2209 case SnapToBeatDiv24:
2210 case SnapToBeatDiv20:
2211 case SnapToBeatDiv16:
2212 case SnapToBeatDiv14:
2213 case SnapToBeatDiv12:
2214 case SnapToBeatDiv10:
2215 case SnapToBeatDiv8:
2216 case SnapToBeatDiv7:
2217 case SnapToBeatDiv6:
2218 case SnapToBeatDiv5:
2219 case SnapToBeatDiv4:
2220 case SnapToBeatDiv3:
2221 case SnapToBeatDiv2: {
2222 std::vector<TempoMap::BBTPoint> grid;
2223 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2224 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2225 update_tempo_based_rulers (grid);
2229 case SnapToRegionStart:
2230 case SnapToRegionEnd:
2231 case SnapToRegionSync:
2232 case SnapToRegionBoundary:
2233 build_region_boundary_cache ();
2241 redisplay_tempo (false);
2243 SnapChanged (); /* EMIT SIGNAL */
2247 Editor::set_snap_mode (SnapMode mode)
2249 string str = snap_mode_strings[(int)mode];
2251 if (internal_editing()) {
2252 internal_snap_mode = mode;
2254 pre_internal_snap_mode = mode;
2259 if (str != snap_mode_selector.get_text ()) {
2260 snap_mode_selector.set_text (str);
2267 Editor::set_edit_point_preference (EditPoint ep, bool force)
2269 bool changed = (_edit_point != ep);
2272 if (Profile->get_mixbus())
2273 if (ep == EditAtSelectedMarker)
2274 ep = EditAtPlayhead;
2276 string str = edit_point_strings[(int)ep];
2277 if (str != edit_point_selector.get_text ()) {
2278 edit_point_selector.set_text (str);
2281 update_all_enter_cursors();
2283 if (!force && !changed) {
2287 const char* action=NULL;
2289 switch (_edit_point) {
2290 case EditAtPlayhead:
2291 action = "edit-at-playhead";
2293 case EditAtSelectedMarker:
2294 action = "edit-at-marker";
2297 action = "edit-at-mouse";
2301 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2303 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2307 bool in_track_canvas;
2309 if (!mouse_frame (foo, in_track_canvas)) {
2310 in_track_canvas = false;
2313 reset_canvas_action_sensitivity (in_track_canvas);
2319 Editor::set_state (const XMLNode& node, int version)
2321 XMLProperty const * prop;
2323 PBD::Unwinder<bool> nsi (no_save_instant, true);
2325 Tabbable::set_state (node, version);
2327 if (_session && (prop = node.property ("playhead"))) {
2329 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2331 playhead_cursor->set_position (pos);
2333 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2334 playhead_cursor->set_position (0);
2337 playhead_cursor->set_position (0);
2340 if ((prop = node.property ("mixer-width"))) {
2341 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2344 if ((prop = node.property ("zoom-focus"))) {
2345 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2348 if ((prop = node.property ("zoom"))) {
2349 /* older versions of ardour used floating point samples_per_pixel */
2350 double f = PBD::atof (prop->value());
2351 reset_zoom (llrintf (f));
2353 reset_zoom (samples_per_pixel);
2356 if ((prop = node.property ("visible-track-count"))) {
2357 set_visible_track_count (PBD::atoi (prop->value()));
2360 if ((prop = node.property ("snap-to"))) {
2361 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2362 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2365 if ((prop = node.property ("snap-mode"))) {
2366 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2367 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2368 * snap_mode_selection_done() will only mark an already active item as active
2369 * which does not trigger set_text().
2371 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2374 if ((prop = node.property ("internal-snap-to"))) {
2375 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2378 if ((prop = node.property ("internal-snap-mode"))) {
2379 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2382 if ((prop = node.property ("pre-internal-snap-to"))) {
2383 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2386 if ((prop = node.property ("pre-internal-snap-mode"))) {
2387 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2390 if ((prop = node.property ("mouse-mode"))) {
2391 MouseMode m = str2mousemode(prop->value());
2392 set_mouse_mode (m, true);
2394 set_mouse_mode (MouseObject, true);
2397 if ((prop = node.property ("left-frame")) != 0) {
2399 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2403 reset_x_origin (pos);
2407 if ((prop = node.property ("y-origin")) != 0) {
2408 reset_y_origin (atof (prop->value ()));
2411 if ((prop = node.property ("join-object-range"))) {
2412 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2413 bool yn = string_is_affirmative (prop->value());
2415 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2416 tact->set_active (!yn);
2417 tact->set_active (yn);
2419 set_mouse_mode(mouse_mode, true);
2422 if ((prop = node.property ("edit-point"))) {
2423 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2426 if ((prop = node.property ("show-measures"))) {
2427 bool yn = string_is_affirmative (prop->value());
2428 _show_measures = yn;
2431 if ((prop = node.property ("follow-playhead"))) {
2432 bool yn = string_is_affirmative (prop->value());
2433 set_follow_playhead (yn);
2436 if ((prop = node.property ("stationary-playhead"))) {
2437 bool yn = string_is_affirmative (prop->value());
2438 set_stationary_playhead (yn);
2441 if ((prop = node.property ("region-list-sort-type"))) {
2442 RegionListSortType st;
2443 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2446 if ((prop = node.property ("show-editor-mixer"))) {
2448 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2451 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2452 bool yn = string_is_affirmative (prop->value());
2454 /* do it twice to force the change */
2456 tact->set_active (!yn);
2457 tact->set_active (yn);
2460 if ((prop = node.property ("show-editor-list"))) {
2462 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2465 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2466 bool yn = string_is_affirmative (prop->value());
2468 /* do it twice to force the change */
2470 tact->set_active (!yn);
2471 tact->set_active (yn);
2474 if ((prop = node.property (X_("editor-list-page")))) {
2475 _the_notebook.set_current_page (atoi (prop->value ()));
2478 if ((prop = node.property (X_("show-marker-lines")))) {
2479 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2481 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2482 bool yn = string_is_affirmative (prop->value ());
2484 tact->set_active (!yn);
2485 tact->set_active (yn);
2488 XMLNodeList children = node.children ();
2489 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2490 selection->set_state (**i, Stateful::current_state_version);
2491 _regions->set_state (**i);
2494 if ((prop = node.property ("maximised"))) {
2495 bool yn = string_is_affirmative (prop->value());
2496 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2498 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2499 bool fs = tact && tact->get_active();
2501 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2505 if ((prop = node.property ("nudge-clock-value"))) {
2507 sscanf (prop->value().c_str(), "%" PRId64, &f);
2508 nudge_clock->set (f);
2510 nudge_clock->set_mode (AudioClock::Timecode);
2511 nudge_clock->set (_session->frame_rate() * 5, true);
2516 * Not all properties may have been in XML, but
2517 * those that are linked to a private variable may need changing
2522 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2524 yn = _show_measures;
2525 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2526 /* do it twice to force the change */
2527 tact->set_active (!yn);
2528 tact->set_active (yn);
2531 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2532 yn = _follow_playhead;
2534 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2535 if (tact->get_active() != yn) {
2536 tact->set_active (yn);
2540 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2541 yn = _stationary_playhead;
2543 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2544 if (tact->get_active() != yn) {
2545 tact->set_active (yn);
2550 return LuaInstance::instance()->set_state(node);
2554 Editor::get_state ()
2556 XMLNode* node = new XMLNode (X_("Editor"));
2559 id().print (buf, sizeof (buf));
2560 node->add_property ("id", buf);
2562 node->add_child_nocopy (Tabbable::get_state());
2564 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2565 node->add_property("edit-horizontal-pane-pos", string(buf));
2566 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2567 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2568 node->add_property("edit-vertical-pane-pos", string(buf));
2570 maybe_add_mixer_strip_width (*node);
2572 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2574 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2575 node->add_property ("zoom", buf);
2576 node->add_property ("snap-to", enum_2_string (_snap_type));
2577 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2578 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2579 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2580 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2581 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2582 node->add_property ("edit-point", enum_2_string (_edit_point));
2583 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2584 node->add_property ("visible-track-count", buf);
2586 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2587 node->add_property ("playhead", buf);
2588 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2589 node->add_property ("left-frame", buf);
2590 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2591 node->add_property ("y-origin", buf);
2593 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2594 node->add_property ("maximised", _maximised ? "yes" : "no");
2595 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2596 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2597 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2598 node->add_property ("mouse-mode", enum2str(mouse_mode));
2599 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2601 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2603 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2604 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2607 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2609 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2610 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2613 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2614 node->add_property (X_("editor-list-page"), buf);
2616 if (button_bindings) {
2617 XMLNode* bb = new XMLNode (X_("Buttons"));
2618 button_bindings->save (*bb);
2619 node->add_child_nocopy (*bb);
2622 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2624 node->add_child_nocopy (selection->get_state ());
2625 node->add_child_nocopy (_regions->get_state ());
2627 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2628 node->add_property ("nudge-clock-value", buf);
2630 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2631 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2636 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2637 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2639 * @return pair: TimeAxisView that y is over, layer index.
2641 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2642 * in stacked or expanded region display mode, otherwise 0.
2644 std::pair<TimeAxisView *, double>
2645 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2647 if (!trackview_relative_offset) {
2648 y -= _trackview_group->canvas_origin().y;
2652 return std::make_pair ( (TimeAxisView *) 0, 0);
2655 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2657 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2664 return std::make_pair ( (TimeAxisView *) 0, 0);
2667 /** Snap a position to the grid, if appropriate, taking into account current
2668 * grid settings and also the state of any snap modifier keys that may be pressed.
2669 * @param start Position to snap.
2670 * @param event Event to get current key modifier information from, or 0.
2673 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2675 if (!_session || !event) {
2679 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2680 if (_snap_mode == SnapOff) {
2681 snap_to_internal (start, direction, for_mark);
2684 if (_snap_mode != SnapOff) {
2685 snap_to_internal (start, direction, for_mark);
2686 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2687 /* SnapOff, but we pressed the snap_delta modifier */
2688 snap_to_internal (start, direction, for_mark);
2694 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2696 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2700 snap_to_internal (start, direction, for_mark, ensure_snap);
2704 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2706 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2707 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2709 switch (_snap_type) {
2710 case SnapToTimecodeFrame:
2711 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2712 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2713 /* start is already on a whole timecode frame, do nothing */
2714 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2715 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2717 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2721 case SnapToTimecodeSeconds:
2722 if (_session->config.get_timecode_offset_negative()) {
2723 start += _session->config.get_timecode_offset ();
2725 start -= _session->config.get_timecode_offset ();
2727 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2728 (start % one_timecode_second == 0)) {
2729 /* start is already on a whole second, do nothing */
2730 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2731 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2733 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2736 if (_session->config.get_timecode_offset_negative()) {
2737 start -= _session->config.get_timecode_offset ();
2739 start += _session->config.get_timecode_offset ();
2743 case SnapToTimecodeMinutes:
2744 if (_session->config.get_timecode_offset_negative()) {
2745 start += _session->config.get_timecode_offset ();
2747 start -= _session->config.get_timecode_offset ();
2749 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2750 (start % one_timecode_minute == 0)) {
2751 /* start is already on a whole minute, do nothing */
2752 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2753 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2755 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2757 if (_session->config.get_timecode_offset_negative()) {
2758 start -= _session->config.get_timecode_offset ();
2760 start += _session->config.get_timecode_offset ();
2764 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2765 abort(); /*NOTREACHED*/
2770 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2772 const framepos_t one_second = _session->frame_rate();
2773 const framepos_t one_minute = _session->frame_rate() * 60;
2774 framepos_t presnap = start;
2778 switch (_snap_type) {
2779 case SnapToTimecodeFrame:
2780 case SnapToTimecodeSeconds:
2781 case SnapToTimecodeMinutes:
2782 return timecode_snap_to_internal (start, direction, for_mark);
2785 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2786 start % (one_second/75) == 0) {
2787 /* start is already on a whole CD frame, do nothing */
2788 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2789 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2791 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2796 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2797 start % one_second == 0) {
2798 /* start is already on a whole second, do nothing */
2799 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2800 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2802 start = (framepos_t) floor ((double) start / one_second) * one_second;
2807 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2808 start % one_minute == 0) {
2809 /* start is already on a whole minute, do nothing */
2810 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2811 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2813 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2818 start = _session->tempo_map().round_to_bar (start, direction);
2822 start = _session->tempo_map().round_to_beat (start, direction);
2825 case SnapToBeatDiv128:
2826 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2828 case SnapToBeatDiv64:
2829 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2831 case SnapToBeatDiv32:
2832 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2834 case SnapToBeatDiv28:
2835 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2837 case SnapToBeatDiv24:
2838 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2840 case SnapToBeatDiv20:
2841 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2843 case SnapToBeatDiv16:
2844 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2846 case SnapToBeatDiv14:
2847 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2849 case SnapToBeatDiv12:
2850 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2852 case SnapToBeatDiv10:
2853 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2855 case SnapToBeatDiv8:
2856 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2858 case SnapToBeatDiv7:
2859 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2861 case SnapToBeatDiv6:
2862 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2864 case SnapToBeatDiv5:
2865 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2867 case SnapToBeatDiv4:
2868 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2870 case SnapToBeatDiv3:
2871 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2873 case SnapToBeatDiv2:
2874 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2882 _session->locations()->marks_either_side (start, before, after);
2884 if (before == max_framepos && after == max_framepos) {
2885 /* No marks to snap to, so just don't snap */
2887 } else if (before == max_framepos) {
2889 } else if (after == max_framepos) {
2891 } else if (before != max_framepos && after != max_framepos) {
2892 /* have before and after */
2893 if ((start - before) < (after - start)) {
2902 case SnapToRegionStart:
2903 case SnapToRegionEnd:
2904 case SnapToRegionSync:
2905 case SnapToRegionBoundary:
2906 if (!region_boundary_cache.empty()) {
2908 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2909 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2911 if (direction > 0) {
2912 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2914 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2917 if (next != region_boundary_cache.begin ()) {
2922 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2923 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2925 if (start > (p + n) / 2) {
2934 switch (_snap_mode) {
2944 if (presnap > start) {
2945 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2949 } else if (presnap < start) {
2950 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2956 /* handled at entry */
2964 Editor::setup_toolbar ()
2966 HBox* mode_box = manage(new HBox);
2967 mode_box->set_border_width (2);
2968 mode_box->set_spacing(2);
2970 HBox* mouse_mode_box = manage (new HBox);
2971 HBox* mouse_mode_hbox = manage (new HBox);
2972 VBox* mouse_mode_vbox = manage (new VBox);
2973 Alignment* mouse_mode_align = manage (new Alignment);
2975 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2976 mouse_mode_size_group->add_widget (smart_mode_button);
2977 mouse_mode_size_group->add_widget (mouse_move_button);
2978 mouse_mode_size_group->add_widget (mouse_cut_button);
2979 mouse_mode_size_group->add_widget (mouse_select_button);
2980 mouse_mode_size_group->add_widget (mouse_timefx_button);
2981 mouse_mode_size_group->add_widget (mouse_audition_button);
2982 mouse_mode_size_group->add_widget (mouse_draw_button);
2983 mouse_mode_size_group->add_widget (mouse_content_button);
2985 mouse_mode_size_group->add_widget (zoom_in_button);
2986 mouse_mode_size_group->add_widget (zoom_out_button);
2987 mouse_mode_size_group->add_widget (zoom_preset_selector);
2988 mouse_mode_size_group->add_widget (zoom_out_full_button);
2989 mouse_mode_size_group->add_widget (zoom_focus_selector);
2991 mouse_mode_size_group->add_widget (tav_shrink_button);
2992 mouse_mode_size_group->add_widget (tav_expand_button);
2993 mouse_mode_size_group->add_widget (visible_tracks_selector);
2995 mouse_mode_size_group->add_widget (snap_type_selector);
2996 mouse_mode_size_group->add_widget (snap_mode_selector);
2998 mouse_mode_size_group->add_widget (edit_point_selector);
2999 mouse_mode_size_group->add_widget (edit_mode_selector);
3001 mouse_mode_size_group->add_widget (*nudge_clock);
3002 mouse_mode_size_group->add_widget (nudge_forward_button);
3003 mouse_mode_size_group->add_widget (nudge_backward_button);
3005 mouse_mode_hbox->set_spacing (2);
3007 if (!ARDOUR::Profile->get_trx()) {
3008 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3011 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3012 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3014 if (!ARDOUR::Profile->get_mixbus()) {
3015 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3018 if (!ARDOUR::Profile->get_trx()) {
3019 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3020 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3021 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3022 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3025 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3027 mouse_mode_align->add (*mouse_mode_vbox);
3028 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3030 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3032 edit_mode_selector.set_name ("mouse mode button");
3034 if (!ARDOUR::Profile->get_trx()) {
3035 mode_box->pack_start (edit_mode_selector, false, false);
3038 mode_box->pack_start (*mouse_mode_box, false, false);
3042 _zoom_box.set_spacing (2);
3043 _zoom_box.set_border_width (2);
3047 zoom_preset_selector.set_name ("zoom button");
3048 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3049 zoom_preset_selector.set_size_request (42, -1);
3051 zoom_in_button.set_name ("zoom button");
3052 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3053 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3054 zoom_in_button.set_related_action (act);
3056 zoom_out_button.set_name ("zoom button");
3057 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3058 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3059 zoom_out_button.set_related_action (act);
3061 zoom_out_full_button.set_name ("zoom button");
3062 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3063 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3064 zoom_out_full_button.set_related_action (act);
3066 zoom_focus_selector.set_name ("zoom button");
3068 if (ARDOUR::Profile->get_mixbus()) {
3069 _zoom_box.pack_start (zoom_preset_selector, false, false);
3070 } else if (ARDOUR::Profile->get_trx()) {
3071 mode_box->pack_start (zoom_out_button, false, false);
3072 mode_box->pack_start (zoom_in_button, false, false);
3074 _zoom_box.pack_start (zoom_out_button, false, false);
3075 _zoom_box.pack_start (zoom_in_button, false, false);
3076 _zoom_box.pack_start (zoom_out_full_button, false, false);
3077 _zoom_box.pack_start (zoom_focus_selector, false, false);
3080 /* Track zoom buttons */
3081 visible_tracks_selector.set_name ("zoom button");
3082 if (Profile->get_mixbus()) {
3083 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3084 visible_tracks_selector.set_size_request (42, -1);
3086 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3089 tav_expand_button.set_name ("zoom button");
3090 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3091 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3092 tav_expand_button.set_related_action (act);
3094 tav_shrink_button.set_name ("zoom button");
3095 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3096 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3097 tav_shrink_button.set_related_action (act);
3099 if (ARDOUR::Profile->get_mixbus()) {
3100 _zoom_box.pack_start (visible_tracks_selector);
3101 } else if (ARDOUR::Profile->get_trx()) {
3102 _zoom_box.pack_start (tav_shrink_button);
3103 _zoom_box.pack_start (tav_expand_button);
3105 _zoom_box.pack_start (visible_tracks_selector);
3106 _zoom_box.pack_start (tav_shrink_button);
3107 _zoom_box.pack_start (tav_expand_button);
3110 snap_box.set_spacing (2);
3111 snap_box.set_border_width (2);
3113 snap_type_selector.set_name ("mouse mode button");
3115 snap_mode_selector.set_name ("mouse mode button");
3117 edit_point_selector.set_name ("mouse mode button");
3119 snap_box.pack_start (snap_mode_selector, false, false);
3120 snap_box.pack_start (snap_type_selector, false, false);
3121 snap_box.pack_start (edit_point_selector, false, false);
3125 HBox *nudge_box = manage (new HBox);
3126 nudge_box->set_spacing (2);
3127 nudge_box->set_border_width (2);
3129 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3130 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3132 nudge_box->pack_start (nudge_backward_button, false, false);
3133 nudge_box->pack_start (nudge_forward_button, false, false);
3134 nudge_box->pack_start (*nudge_clock, false, false);
3137 /* Pack everything in... */
3139 HBox* hbox = manage (new HBox);
3140 hbox->set_spacing(2);
3142 toolbar_hbox.set_spacing (2);
3143 toolbar_hbox.set_border_width (1);
3145 toolbar_hbox.pack_start (*mode_box, false, false);
3146 if (!ARDOUR::Profile->get_trx()) {
3147 toolbar_hbox.pack_start (_zoom_box, false, false);
3148 toolbar_hbox.pack_start (*hbox, false, false);
3151 if (!ARDOUR::Profile->get_trx()) {
3152 hbox->pack_start (snap_box, false, false);
3153 hbox->pack_start (*nudge_box, false, false);
3158 toolbar_base.set_name ("ToolBarBase");
3159 toolbar_base.add (toolbar_hbox);
3161 _toolbar_viewport.add (toolbar_base);
3162 /* stick to the required height but allow width to vary if there's not enough room */
3163 _toolbar_viewport.set_size_request (1, -1);
3165 toolbar_frame.set_shadow_type (SHADOW_OUT);
3166 toolbar_frame.set_name ("BaseFrame");
3167 toolbar_frame.add (_toolbar_viewport);
3171 Editor::build_edit_point_menu ()
3173 using namespace Menu_Helpers;
3175 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3176 if(!Profile->get_mixbus())
3177 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3178 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3180 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3184 Editor::build_edit_mode_menu ()
3186 using namespace Menu_Helpers;
3188 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3189 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3190 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3191 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3193 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3197 Editor::build_snap_mode_menu ()
3199 using namespace Menu_Helpers;
3201 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3202 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3203 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3205 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3209 Editor::build_snap_type_menu ()
3211 using namespace Menu_Helpers;
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3244 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3249 Editor::setup_tooltips ()
3251 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3252 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3253 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3254 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3255 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3256 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3257 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3258 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3259 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3260 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3261 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3262 set_tooltip (zoom_in_button, _("Zoom In"));
3263 set_tooltip (zoom_out_button, _("Zoom Out"));
3264 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3265 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3266 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3267 set_tooltip (tav_expand_button, _("Expand Tracks"));
3268 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3269 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3270 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3271 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3272 set_tooltip (edit_point_selector, _("Edit Point"));
3273 set_tooltip (edit_mode_selector, _("Edit Mode"));
3274 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3278 Editor::convert_drop_to_paths (
3279 vector<string>& paths,
3280 const RefPtr<Gdk::DragContext>& /*context*/,
3283 const SelectionData& data,
3287 if (_session == 0) {
3291 vector<string> uris = data.get_uris();
3295 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3296 are actually URI lists. So do it by hand.
3299 if (data.get_target() != "text/plain") {
3303 /* Parse the "uri-list" format that Nautilus provides,
3304 where each pathname is delimited by \r\n.
3306 THERE MAY BE NO NULL TERMINATING CHAR!!!
3309 string txt = data.get_text();
3313 p = (char *) malloc (txt.length() + 1);
3314 txt.copy (p, txt.length(), 0);
3315 p[txt.length()] = '\0';
3321 while (g_ascii_isspace (*p))
3325 while (*q && (*q != '\n') && (*q != '\r')) {
3332 while (q > p && g_ascii_isspace (*q))
3337 uris.push_back (string (p, q - p + 1));
3341 p = strchr (p, '\n');
3353 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3354 if ((*i).substr (0,7) == "file://") {
3355 paths.push_back (Glib::filename_from_uri (*i));
3363 Editor::new_tempo_section ()
3368 Editor::map_transport_state ()
3370 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3372 if (_session && _session->transport_stopped()) {
3373 have_pending_keyboard_selection = false;
3376 update_loop_range_view ();
3382 Editor::begin_selection_op_history ()
3384 selection_op_cmd_depth = 0;
3385 selection_op_history_it = 0;
3387 while(!selection_op_history.empty()) {
3388 delete selection_op_history.front();
3389 selection_op_history.pop_front();
3392 selection_undo_action->set_sensitive (false);
3393 selection_redo_action->set_sensitive (false);
3394 selection_op_history.push_front (&_selection_memento->get_state ());
3398 Editor::begin_reversible_selection_op (string name)
3401 //cerr << name << endl;
3402 /* begin/commit pairs can be nested */
3403 selection_op_cmd_depth++;
3408 Editor::commit_reversible_selection_op ()
3411 if (selection_op_cmd_depth == 1) {
3413 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3415 The user has undone some selection ops and then made a new one,
3416 making anything earlier in the list invalid.
3419 list<XMLNode *>::iterator it = selection_op_history.begin();
3420 list<XMLNode *>::iterator e_it = it;
3421 advance (e_it, selection_op_history_it);
3423 for ( ; it != e_it; ++it) {
3426 selection_op_history.erase (selection_op_history.begin(), e_it);
3429 selection_op_history.push_front (&_selection_memento->get_state ());
3430 selection_op_history_it = 0;
3432 selection_undo_action->set_sensitive (true);
3433 selection_redo_action->set_sensitive (false);
3436 if (selection_op_cmd_depth > 0) {
3437 selection_op_cmd_depth--;
3443 Editor::undo_selection_op ()
3446 selection_op_history_it++;
3448 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3449 if (n == selection_op_history_it) {
3450 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3451 selection_redo_action->set_sensitive (true);
3455 /* is there an earlier entry? */
3456 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3457 selection_undo_action->set_sensitive (false);
3463 Editor::redo_selection_op ()
3466 if (selection_op_history_it > 0) {
3467 selection_op_history_it--;
3470 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3471 if (n == selection_op_history_it) {
3472 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3473 selection_undo_action->set_sensitive (true);
3478 if (selection_op_history_it == 0) {
3479 selection_redo_action->set_sensitive (false);
3485 Editor::begin_reversible_command (string name)
3488 before.push_back (&_selection_memento->get_state ());
3489 _session->begin_reversible_command (name);
3494 Editor::begin_reversible_command (GQuark q)
3497 before.push_back (&_selection_memento->get_state ());
3498 _session->begin_reversible_command (q);
3503 Editor::abort_reversible_command ()
3506 while(!before.empty()) {
3507 delete before.front();
3510 _session->abort_reversible_command ();
3515 Editor::commit_reversible_command ()
3518 if (before.size() == 1) {
3519 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3520 redo_action->set_sensitive(false);
3521 undo_action->set_sensitive(true);
3522 begin_selection_op_history ();
3525 if (before.empty()) {
3526 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3531 _session->commit_reversible_command ();
3536 Editor::history_changed ()
3540 if (undo_action && _session) {
3541 if (_session->undo_depth() == 0) {
3542 label = S_("Command|Undo");
3544 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3546 undo_action->property_label() = label;
3549 if (redo_action && _session) {
3550 if (_session->redo_depth() == 0) {
3552 redo_action->set_sensitive (false);
3554 label = string_compose(_("Redo (%1)"), _session->next_redo());
3555 redo_action->set_sensitive (true);
3557 redo_action->property_label() = label;
3562 Editor::duplicate_range (bool with_dialog)
3566 RegionSelection rs = get_regions_from_selection_and_entered ();
3568 if ( selection->time.length() == 0 && rs.empty()) {
3574 ArdourDialog win (_("Duplicate"));
3575 Label label (_("Number of duplications:"));
3576 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3577 SpinButton spinner (adjustment, 0.0, 1);
3580 win.get_vbox()->set_spacing (12);
3581 win.get_vbox()->pack_start (hbox);
3582 hbox.set_border_width (6);
3583 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3585 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3586 place, visually. so do this by hand.
3589 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3590 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3591 spinner.grab_focus();
3597 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3598 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3599 win.set_default_response (RESPONSE_ACCEPT);
3601 spinner.grab_focus ();
3603 switch (win.run ()) {
3604 case RESPONSE_ACCEPT:
3610 times = adjustment.get_value();
3613 if ((current_mouse_mode() == Editing::MouseRange)) {
3614 if (selection->time.length()) {
3615 duplicate_selection (times);
3617 } else if (get_smart_mode()) {
3618 if (selection->time.length()) {
3619 duplicate_selection (times);
3621 duplicate_some_regions (rs, times);
3623 duplicate_some_regions (rs, times);
3628 Editor::set_edit_mode (EditMode m)
3630 Config->set_edit_mode (m);
3634 Editor::cycle_edit_mode ()
3636 switch (Config->get_edit_mode()) {
3638 Config->set_edit_mode (Ripple);
3642 Config->set_edit_mode (Lock);
3645 Config->set_edit_mode (Slide);
3651 Editor::edit_mode_selection_done ( EditMode m )
3653 Config->set_edit_mode ( m );
3657 Editor::snap_type_selection_done (SnapType snaptype)
3659 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3661 ract->set_active ();
3666 Editor::snap_mode_selection_done (SnapMode mode)
3668 RefPtr<RadioAction> ract = snap_mode_action (mode);
3671 ract->set_active (true);
3676 Editor::cycle_edit_point (bool with_marker)
3678 if(Profile->get_mixbus())
3679 with_marker = false;
3681 switch (_edit_point) {
3683 set_edit_point_preference (EditAtPlayhead);
3685 case EditAtPlayhead:
3687 set_edit_point_preference (EditAtSelectedMarker);
3689 set_edit_point_preference (EditAtMouse);
3692 case EditAtSelectedMarker:
3693 set_edit_point_preference (EditAtMouse);
3699 Editor::edit_point_selection_done (EditPoint ep)
3701 set_edit_point_preference ( ep );
3705 Editor::build_zoom_focus_menu ()
3707 using namespace Menu_Helpers;
3709 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3710 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3711 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3712 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3713 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3714 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3716 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3720 Editor::zoom_focus_selection_done ( ZoomFocus f )
3722 RefPtr<RadioAction> ract = zoom_focus_action (f);
3724 ract->set_active ();
3729 Editor::build_track_count_menu ()
3731 using namespace Menu_Helpers;
3733 if (!Profile->get_mixbus()) {
3734 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3740 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3744 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3745 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3746 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3748 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3749 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3750 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3751 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3752 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3753 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3754 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3755 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3756 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3757 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3759 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3760 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3761 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3762 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3763 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3764 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3765 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3766 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3767 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3768 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3769 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3774 Editor::set_zoom_preset (int64_t ms)
3777 temporal_zoom_session();
3781 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3782 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3786 Editor::set_visible_track_count (int32_t n)
3788 _visible_track_count = n;
3790 /* if the canvas hasn't really been allocated any size yet, just
3791 record the desired number of visible tracks and return. when canvas
3792 allocation happens, we will get called again and then we can do the
3796 if (_visible_canvas_height <= 1) {
3802 DisplaySuspender ds;
3804 if (_visible_track_count > 0) {
3805 h = trackviews_height() / _visible_track_count;
3806 std::ostringstream s;
3807 s << _visible_track_count;
3809 } else if (_visible_track_count == 0) {
3811 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3812 if ((*i)->marked_for_display()) {
3816 h = trackviews_height() / n;
3819 /* negative value means that the visible track count has
3820 been overridden by explicit track height changes.
3822 visible_tracks_selector.set_text (X_("*"));
3826 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3827 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3830 if (str != visible_tracks_selector.get_text()) {
3831 visible_tracks_selector.set_text (str);
3836 Editor::override_visible_track_count ()
3838 _visible_track_count = -1;
3839 visible_tracks_selector.set_text ( _("*") );
3843 Editor::edit_controls_button_release (GdkEventButton* ev)
3845 if (Keyboard::is_context_menu_event (ev)) {
3846 ARDOUR_UI::instance()->add_route ();
3847 } else if (ev->button == 1) {
3848 selection->clear_tracks ();
3855 Editor::mouse_select_button_release (GdkEventButton* ev)
3857 /* this handles just right-clicks */
3859 if (ev->button != 3) {
3867 Editor::set_zoom_focus (ZoomFocus f)
3869 string str = zoom_focus_strings[(int)f];
3871 if (str != zoom_focus_selector.get_text()) {
3872 zoom_focus_selector.set_text (str);
3875 if (zoom_focus != f) {
3882 Editor::cycle_zoom_focus ()
3884 switch (zoom_focus) {
3886 set_zoom_focus (ZoomFocusRight);
3888 case ZoomFocusRight:
3889 set_zoom_focus (ZoomFocusCenter);
3891 case ZoomFocusCenter:
3892 set_zoom_focus (ZoomFocusPlayhead);
3894 case ZoomFocusPlayhead:
3895 set_zoom_focus (ZoomFocusMouse);
3897 case ZoomFocusMouse:
3898 set_zoom_focus (ZoomFocusEdit);
3901 set_zoom_focus (ZoomFocusLeft);
3907 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3909 /* recover or initialize pane positions. do this here rather than earlier because
3910 we don't want the positions to change the child allocations, which they seem to do.
3914 XMLProperty const * prop;
3916 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3925 XMLNode* geometry = find_named_node (*node, "geometry");
3927 if (which == static_cast<Paned*> (&edit_pane)) {
3929 if (done & Horizontal) {
3933 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3934 _notebook_shrunk = string_is_affirmative (prop->value ());
3937 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3938 /* initial allocation is 90% to canvas, 10% to notebook */
3939 pos = (int) floor (alloc.get_width() * 0.90f);
3940 snprintf (buf, sizeof(buf), "%d", pos);
3942 pos = atoi (prop->value());
3945 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3946 edit_pane.set_position (pos);
3949 done = (Pane) (done | Horizontal);
3951 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3953 if (done & Vertical) {
3957 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3958 /* initial allocation is 90% to canvas, 10% to summary */
3959 pos = (int) floor (alloc.get_height() * 0.90f);
3960 snprintf (buf, sizeof(buf), "%d", pos);
3963 pos = atoi (prop->value());
3966 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3967 editor_summary_pane.set_position (pos);
3970 done = (Pane) (done | Vertical);
3975 Editor::set_show_measures (bool yn)
3977 if (_show_measures != yn) {
3980 if ((_show_measures = yn) == true) {
3982 tempo_lines->show();
3985 std::vector<TempoMap::BBTPoint> grid;
3986 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3987 draw_measures (grid);
3995 Editor::toggle_follow_playhead ()
3997 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3999 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4000 set_follow_playhead (tact->get_active());
4004 /** @param yn true to follow playhead, otherwise false.
4005 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4008 Editor::set_follow_playhead (bool yn, bool catch_up)
4010 if (_follow_playhead != yn) {
4011 if ((_follow_playhead = yn) == true && catch_up) {
4013 reset_x_origin_to_follow_playhead ();
4020 Editor::toggle_stationary_playhead ()
4022 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4024 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4025 set_stationary_playhead (tact->get_active());
4030 Editor::set_stationary_playhead (bool yn)
4032 if (_stationary_playhead != yn) {
4033 if ((_stationary_playhead = yn) == true) {
4035 // FIXME need a 3.0 equivalent of this 2.X call
4036 // update_current_screen ();
4043 Editor::playlist_selector () const
4045 return *_playlist_selector;
4049 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4051 if (paste_count == 0) {
4052 /* don't bother calculating an offset that will be zero anyway */
4056 /* calculate basic unsnapped multi-paste offset */
4057 framecnt_t offset = paste_count * duration;
4059 /* snap offset so pos + offset is aligned to the grid */
4060 framepos_t offset_pos = pos + offset;
4061 snap_to(offset_pos, RoundUpMaybe);
4062 offset = offset_pos - pos;
4068 Editor::get_grid_beat_divisions(framepos_t position)
4070 switch (_snap_type) {
4071 case SnapToBeatDiv128: return 128;
4072 case SnapToBeatDiv64: return 64;
4073 case SnapToBeatDiv32: return 32;
4074 case SnapToBeatDiv28: return 28;
4075 case SnapToBeatDiv24: return 24;
4076 case SnapToBeatDiv20: return 20;
4077 case SnapToBeatDiv16: return 16;
4078 case SnapToBeatDiv14: return 14;
4079 case SnapToBeatDiv12: return 12;
4080 case SnapToBeatDiv10: return 10;
4081 case SnapToBeatDiv8: return 8;
4082 case SnapToBeatDiv7: return 7;
4083 case SnapToBeatDiv6: return 6;
4084 case SnapToBeatDiv5: return 5;
4085 case SnapToBeatDiv4: return 4;
4086 case SnapToBeatDiv3: return 3;
4087 case SnapToBeatDiv2: return 2;
4094 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4098 const unsigned divisions = get_grid_beat_divisions(position);
4100 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4103 switch (_snap_type) {
4105 return Evoral::Beats(1.0);
4108 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4116 return Evoral::Beats();
4120 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4124 ret = nudge_clock->current_duration (pos);
4125 next = ret + 1; /* XXXX fix me */
4131 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4133 ArdourDialog dialog (_("Playlist Deletion"));
4134 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4135 "If it is kept, its audio files will not be cleaned.\n"
4136 "If it is deleted, audio files used by it alone will be cleaned."),
4139 dialog.set_position (WIN_POS_CENTER);
4140 dialog.get_vbox()->pack_start (label);
4144 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4145 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4146 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4147 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4148 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4150 // by default gtk uses the left most button
4151 keep->grab_focus ();
4153 switch (dialog.run ()) {
4155 /* keep this and all remaining ones */
4160 /* delete this and all others */
4164 case RESPONSE_ACCEPT:
4165 /* delete the playlist */
4169 case RESPONSE_REJECT:
4170 /* keep the playlist */
4182 Editor::audio_region_selection_covers (framepos_t where)
4184 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4185 if ((*a)->region()->covers (where)) {
4194 Editor::prepare_for_cleanup ()
4196 cut_buffer->clear_regions ();
4197 cut_buffer->clear_playlists ();
4199 selection->clear_regions ();
4200 selection->clear_playlists ();
4202 _regions->suspend_redisplay ();
4206 Editor::finish_cleanup ()
4208 _regions->resume_redisplay ();
4212 Editor::transport_loop_location()
4215 return _session->locations()->auto_loop_location();
4222 Editor::transport_punch_location()
4225 return _session->locations()->auto_punch_location();
4232 Editor::control_layout_scroll (GdkEventScroll* ev)
4234 /* Just forward to the normal canvas scroll method. The coordinate
4235 systems are different but since the canvas is always larger than the
4236 track headers, and aligned with the trackview area, this will work.
4238 In the not too distant future this layout is going away anyway and
4239 headers will be on the canvas.
4241 return canvas_scroll_event (ev, false);
4245 Editor::session_state_saved (string)
4248 _snapshots->redisplay ();
4252 Editor::maximise_editing_space ()
4258 Gtk::Window* toplevel = current_toplevel();
4261 toplevel->fullscreen ();
4267 Editor::restore_editing_space ()
4273 Gtk::Window* toplevel = current_toplevel();
4276 toplevel->unfullscreen();
4282 * Make new playlists for a given track and also any others that belong
4283 * to the same active route group with the `select' property.
4288 Editor::new_playlists (TimeAxisView* v)
4290 begin_reversible_command (_("new playlists"));
4291 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4292 _session->playlists->get (playlists);
4293 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4294 commit_reversible_command ();
4298 * Use a copy of the current playlist for a given track and also any others that belong
4299 * to the same active route group with the `select' property.
4304 Editor::copy_playlists (TimeAxisView* v)
4306 begin_reversible_command (_("copy playlists"));
4307 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4308 _session->playlists->get (playlists);
4309 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4310 commit_reversible_command ();
4313 /** Clear the current playlist for a given track and also any others that belong
4314 * to the same active route group with the `select' property.
4319 Editor::clear_playlists (TimeAxisView* v)
4321 begin_reversible_command (_("clear playlists"));
4322 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4323 _session->playlists->get (playlists);
4324 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4325 commit_reversible_command ();
4329 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4331 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4335 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4337 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4341 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4343 atv.clear_playlist ();
4347 Editor::get_y_origin () const
4349 return vertical_adjustment.get_value ();
4352 /** Queue up a change to the viewport x origin.
4353 * @param frame New x origin.
4356 Editor::reset_x_origin (framepos_t frame)
4358 pending_visual_change.add (VisualChange::TimeOrigin);
4359 pending_visual_change.time_origin = frame;
4360 ensure_visual_change_idle_handler ();
4364 Editor::reset_y_origin (double y)
4366 pending_visual_change.add (VisualChange::YOrigin);
4367 pending_visual_change.y_origin = y;
4368 ensure_visual_change_idle_handler ();
4372 Editor::reset_zoom (framecnt_t spp)
4374 if (spp == samples_per_pixel) {
4378 pending_visual_change.add (VisualChange::ZoomLevel);
4379 pending_visual_change.samples_per_pixel = spp;
4380 ensure_visual_change_idle_handler ();
4384 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4386 reset_x_origin (frame);
4389 if (!no_save_visual) {
4390 undo_visual_stack.push_back (current_visual_state(false));
4394 Editor::VisualState::VisualState (bool with_tracks)
4395 : gui_state (with_tracks ? new GUIObjectState : 0)
4399 Editor::VisualState::~VisualState ()
4404 Editor::VisualState*
4405 Editor::current_visual_state (bool with_tracks)
4407 VisualState* vs = new VisualState (with_tracks);
4408 vs->y_position = vertical_adjustment.get_value();
4409 vs->samples_per_pixel = samples_per_pixel;
4410 vs->leftmost_frame = leftmost_frame;
4411 vs->zoom_focus = zoom_focus;
4414 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4421 Editor::undo_visual_state ()
4423 if (undo_visual_stack.empty()) {
4427 VisualState* vs = undo_visual_stack.back();
4428 undo_visual_stack.pop_back();
4431 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4434 use_visual_state (*vs);
4439 Editor::redo_visual_state ()
4441 if (redo_visual_stack.empty()) {
4445 VisualState* vs = redo_visual_stack.back();
4446 redo_visual_stack.pop_back();
4448 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4449 // why do we check here?
4450 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4453 use_visual_state (*vs);
4458 Editor::swap_visual_state ()
4460 if (undo_visual_stack.empty()) {
4461 redo_visual_state ();
4463 undo_visual_state ();
4468 Editor::use_visual_state (VisualState& vs)
4470 PBD::Unwinder<bool> nsv (no_save_visual, true);
4471 DisplaySuspender ds;
4473 vertical_adjustment.set_value (vs.y_position);
4475 set_zoom_focus (vs.zoom_focus);
4476 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4479 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4481 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4482 (*i)->clear_property_cache();
4483 (*i)->reset_visual_state ();
4487 _routes->update_visibility ();
4490 /** This is the core function that controls the zoom level of the canvas. It is called
4491 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4492 * @param spp new number of samples per pixel
4495 Editor::set_samples_per_pixel (framecnt_t spp)
4501 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4502 const framecnt_t lots_of_pixels = 4000;
4504 /* if the zoom level is greater than what you'd get trying to display 3
4505 * days of audio on a really big screen, then it's too big.
4508 if (spp * lots_of_pixels > three_days) {
4512 samples_per_pixel = spp;
4515 tempo_lines->tempo_map_changed();
4518 bool const showing_time_selection = selection->time.length() > 0;
4520 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4521 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4522 (*i)->reshow_selection (selection->time);
4526 ZoomChanged (); /* EMIT_SIGNAL */
4528 ArdourCanvas::GtkCanvasViewport* c;
4530 c = get_track_canvas();
4532 c->canvas()->zoomed ();
4535 if (playhead_cursor) {
4536 playhead_cursor->set_position (playhead_cursor->current_frame ());
4539 refresh_location_display();
4540 _summary->set_overlays_dirty ();
4542 update_marker_labels ();
4548 Editor::queue_visual_videotimeline_update ()
4551 * pending_visual_change.add (VisualChange::VideoTimeline);
4552 * or maybe even more specific: which videotimeline-image
4553 * currently it calls update_video_timeline() to update
4554 * _all outdated_ images on the video-timeline.
4555 * see 'exposeimg()' in video_image_frame.cc
4557 ensure_visual_change_idle_handler ();
4561 Editor::ensure_visual_change_idle_handler ()
4563 if (pending_visual_change.idle_handler_id < 0) {
4564 // see comment in add_to_idle_resize above.
4565 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4566 pending_visual_change.being_handled = false;
4571 Editor::_idle_visual_changer (void* arg)
4573 return static_cast<Editor*>(arg)->idle_visual_changer ();
4577 Editor::idle_visual_changer ()
4579 /* set_horizontal_position() below (and maybe other calls) call
4580 gtk_main_iteration(), so it's possible that a signal will be handled
4581 half-way through this method. If this signal wants an
4582 idle_visual_changer we must schedule another one after this one, so
4583 mark the idle_handler_id as -1 here to allow that. Also make a note
4584 that we are doing the visual change, so that changes in response to
4585 super-rapid-screen-update can be dropped if we are still processing
4589 pending_visual_change.idle_handler_id = -1;
4590 pending_visual_change.being_handled = true;
4592 VisualChange vc = pending_visual_change;
4594 pending_visual_change.pending = (VisualChange::Type) 0;
4596 visual_changer (vc);
4598 pending_visual_change.being_handled = false;
4600 return 0; /* this is always a one-shot call */
4604 Editor::visual_changer (const VisualChange& vc)
4606 double const last_time_origin = horizontal_position ();
4608 if (vc.pending & VisualChange::ZoomLevel) {
4609 set_samples_per_pixel (vc.samples_per_pixel);
4611 compute_fixed_ruler_scale ();
4613 std::vector<TempoMap::BBTPoint> grid;
4614 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4615 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4616 update_tempo_based_rulers (grid);
4618 update_video_timeline();
4621 if (vc.pending & VisualChange::TimeOrigin) {
4622 set_horizontal_position (vc.time_origin / samples_per_pixel);
4625 if (vc.pending & VisualChange::YOrigin) {
4626 vertical_adjustment.set_value (vc.y_origin);
4629 if (last_time_origin == horizontal_position ()) {
4630 /* changed signal not emitted */
4631 update_fixed_rulers ();
4632 redisplay_tempo (true);
4635 if (!(vc.pending & VisualChange::ZoomLevel)) {
4636 update_video_timeline();
4639 _summary->set_overlays_dirty ();
4642 struct EditorOrderTimeAxisSorter {
4643 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4644 return a->order () < b->order ();
4649 Editor::sort_track_selection (TrackViewList& sel)
4651 EditorOrderTimeAxisSorter cmp;
4656 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4659 framepos_t where = 0;
4660 EditPoint ep = _edit_point;
4662 if (Profile->get_mixbus())
4663 if (ep == EditAtSelectedMarker)
4664 ep = EditAtPlayhead;
4666 if (from_outside_canvas && (ep == EditAtMouse)) {
4667 ep = EditAtPlayhead;
4668 } else if (from_context_menu && (ep == EditAtMouse)) {
4669 return canvas_event_sample (&context_click_event, 0, 0);
4672 if (entered_marker) {
4673 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4674 return entered_marker->position();
4677 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4678 ep = EditAtSelectedMarker;
4681 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4682 ep = EditAtPlayhead;
4686 case EditAtPlayhead:
4687 if (_dragging_playhead) {
4688 where = *_control_scroll_target;
4690 where = _session->audible_frame();
4692 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4695 case EditAtSelectedMarker:
4696 if (!selection->markers.empty()) {
4698 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4701 where = loc->start();
4705 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4713 if (!mouse_frame (where, ignored)) {
4714 /* XXX not right but what can we do ? */
4718 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4726 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4728 if (!_session) return;
4730 begin_reversible_command (cmd);
4734 if ((tll = transport_loop_location()) == 0) {
4735 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4736 XMLNode &before = _session->locations()->get_state();
4737 _session->locations()->add (loc, true);
4738 _session->set_auto_loop_location (loc);
4739 XMLNode &after = _session->locations()->get_state();
4740 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4742 XMLNode &before = tll->get_state();
4743 tll->set_hidden (false, this);
4744 tll->set (start, end);
4745 XMLNode &after = tll->get_state();
4746 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4749 commit_reversible_command ();
4753 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4755 if (!_session) return;
4757 begin_reversible_command (cmd);
4761 if ((tpl = transport_punch_location()) == 0) {
4762 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4763 XMLNode &before = _session->locations()->get_state();
4764 _session->locations()->add (loc, true);
4765 _session->set_auto_punch_location (loc);
4766 XMLNode &after = _session->locations()->get_state();
4767 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4769 XMLNode &before = tpl->get_state();
4770 tpl->set_hidden (false, this);
4771 tpl->set (start, end);
4772 XMLNode &after = tpl->get_state();
4773 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4776 commit_reversible_command ();
4779 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4780 * @param rs List to which found regions are added.
4781 * @param where Time to look at.
4782 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4785 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4787 const TrackViewList* tracks;
4790 tracks = &track_views;
4795 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4797 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4800 boost::shared_ptr<Track> tr;
4801 boost::shared_ptr<Playlist> pl;
4803 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4805 boost::shared_ptr<RegionList> regions = pl->regions_at (
4806 (framepos_t) floor ( (double) where * tr->speed()));
4808 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4809 RegionView* rv = rtv->view()->find_view (*i);
4820 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4822 const TrackViewList* tracks;
4825 tracks = &track_views;
4830 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4831 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4833 boost::shared_ptr<Track> tr;
4834 boost::shared_ptr<Playlist> pl;
4836 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4838 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4839 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4841 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4843 RegionView* rv = rtv->view()->find_view (*i);
4854 /** Get regions using the following method:
4856 * Make a region list using:
4857 * (a) any selected regions
4858 * (b) the intersection of any selected tracks and the edit point(*)
4859 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4861 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4863 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4867 Editor::get_regions_from_selection_and_edit_point ()
4869 RegionSelection regions;
4871 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4872 regions.add (entered_regionview);
4874 regions = selection->regions;
4877 if ( regions.empty() ) {
4878 TrackViewList tracks = selection->tracks;
4880 if (!tracks.empty()) {
4881 /* no region selected or entered, but some selected tracks:
4882 * act on all regions on the selected tracks at the edit point
4884 framepos_t const where = get_preferred_edit_position ();
4885 get_regions_at(regions, where, tracks);
4892 /** Get regions using the following method:
4894 * Make a region list using:
4895 * (a) any selected regions
4896 * (b) the intersection of any selected tracks and the edit point(*)
4897 * (c) if neither exists, then whatever region is under the mouse
4899 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4901 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4904 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4906 RegionSelection regions;
4908 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4909 regions.add (entered_regionview);
4911 regions = selection->regions;
4914 if ( regions.empty() ) {
4915 TrackViewList tracks = selection->tracks;
4917 if (!tracks.empty()) {
4918 /* no region selected or entered, but some selected tracks:
4919 * act on all regions on the selected tracks at the edit point
4921 get_regions_at(regions, pos, tracks);
4928 /** Start with regions that are selected, or the entered regionview if none are selected.
4929 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4930 * of the regions that we started with.
4934 Editor::get_regions_from_selection_and_entered () const
4936 RegionSelection regions = selection->regions;
4938 if (regions.empty() && entered_regionview) {
4939 regions.add (entered_regionview);
4946 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4948 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4949 RouteTimeAxisView* rtav;
4951 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4952 boost::shared_ptr<Playlist> pl;
4953 std::vector<boost::shared_ptr<Region> > results;
4954 boost::shared_ptr<Track> tr;
4956 if ((tr = rtav->track()) == 0) {
4961 if ((pl = (tr->playlist())) != 0) {
4962 boost::shared_ptr<Region> r = pl->region_by_id (id);
4964 RegionView* rv = rtav->view()->find_view (r);
4966 regions.push_back (rv);
4975 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4978 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4979 MidiTimeAxisView* mtav;
4981 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4983 mtav->get_per_region_note_selection (selection);
4990 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4992 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4994 RouteTimeAxisView* tatv;
4996 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4998 boost::shared_ptr<Playlist> pl;
4999 vector<boost::shared_ptr<Region> > results;
5001 boost::shared_ptr<Track> tr;
5003 if ((tr = tatv->track()) == 0) {
5008 if ((pl = (tr->playlist())) != 0) {
5009 if (src_comparison) {
5010 pl->get_source_equivalent_regions (region, results);
5012 pl->get_region_list_equivalent_regions (region, results);
5016 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5017 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5018 regions.push_back (marv);
5027 Editor::show_rhythm_ferret ()
5029 if (rhythm_ferret == 0) {
5030 rhythm_ferret = new RhythmFerret(*this);
5033 rhythm_ferret->set_session (_session);
5034 rhythm_ferret->show ();
5035 rhythm_ferret->present ();
5039 Editor::first_idle ()
5041 MessageDialog* dialog = 0;
5043 if (track_views.size() > 1) {
5044 Timers::TimerSuspender t;
5045 dialog = new MessageDialog (
5046 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5050 ARDOUR_UI::instance()->flush_pending ();
5053 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5057 // first idle adds route children (automation tracks), so we need to redisplay here
5058 _routes->redisplay ();
5062 if (_session->undo_depth() == 0) {
5063 undo_action->set_sensitive(false);
5065 redo_action->set_sensitive(false);
5066 begin_selection_op_history ();
5072 Editor::_idle_resize (gpointer arg)
5074 return ((Editor*)arg)->idle_resize ();
5078 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5080 if (resize_idle_id < 0) {
5081 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5082 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5083 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5085 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5086 _pending_resize_amount = 0;
5089 /* make a note of the smallest resulting height, so that we can clamp the
5090 lower limit at TimeAxisView::hSmall */
5092 int32_t min_resulting = INT32_MAX;
5094 _pending_resize_amount += h;
5095 _pending_resize_view = view;
5097 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5099 if (selection->tracks.contains (_pending_resize_view)) {
5100 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5101 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5105 if (min_resulting < 0) {
5110 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5111 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5115 /** Handle pending resizing of tracks */
5117 Editor::idle_resize ()
5119 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5121 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5122 selection->tracks.contains (_pending_resize_view)) {
5124 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5125 if (*i != _pending_resize_view) {
5126 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5131 _pending_resize_amount = 0;
5132 _group_tabs->set_dirty ();
5133 resize_idle_id = -1;
5141 ENSURE_GUI_THREAD (*this, &Editor::located);
5144 playhead_cursor->set_position (_session->audible_frame ());
5145 if (_follow_playhead && !_pending_initial_locate) {
5146 reset_x_origin_to_follow_playhead ();
5150 _pending_locate_request = false;
5151 _pending_initial_locate = false;
5155 Editor::region_view_added (RegionView * rv)
5157 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5158 if (rv->region ()->id () == (*pr)) {
5159 selection->add (rv);
5160 selection->regions.pending.erase (pr);
5165 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5167 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5168 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5169 if (rv->region()->id () == (*rnote).first) {
5170 mrv->select_notes ((*rnote).second);
5171 selection->pending_midi_note_selection.erase(rnote);
5177 _summary->set_background_dirty ();
5181 Editor::region_view_removed ()
5183 _summary->set_background_dirty ();
5187 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5189 TrackViewList::const_iterator j = track_views.begin ();
5190 while (j != track_views.end()) {
5191 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5192 if (rtv && rtv->route() == r) {
5203 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5207 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5208 TimeAxisView* tv = axis_view_from_route (*i);
5218 Editor::suspend_route_redisplay ()
5221 _routes->suspend_redisplay();
5226 Editor::resume_route_redisplay ()
5229 _routes->redisplay(); // queue redisplay
5230 _routes->resume_redisplay();
5235 Editor::add_routes (RouteList& routes)
5237 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5239 RouteTimeAxisView *rtv;
5240 list<RouteTimeAxisView*> new_views;
5241 TrackViewList new_selection;
5242 bool from_scratch = (track_views.size() == 0);
5244 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5245 boost::shared_ptr<Route> route = (*x);
5247 if (route->is_auditioner() || route->is_monitor()) {
5251 DataType dt = route->input()->default_type();
5253 if (dt == ARDOUR::DataType::AUDIO) {
5254 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5255 rtv->set_route (route);
5256 } else if (dt == ARDOUR::DataType::MIDI) {
5257 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5258 rtv->set_route (route);
5260 throw unknown_type();
5263 new_views.push_back (rtv);
5264 track_views.push_back (rtv);
5265 new_selection.push_back (rtv);
5267 rtv->effective_gain_display ();
5269 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5270 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5273 if (new_views.size() > 0) {
5274 _routes->routes_added (new_views);
5275 _summary->routes_added (new_views);
5278 if (!from_scratch) {
5279 selection->tracks.clear();
5280 selection->add (new_selection);
5281 begin_selection_op_history();
5284 if (show_editor_mixer_when_tracks_arrive) {
5285 show_editor_mixer (true);
5288 editor_list_button.set_sensitive (true);
5292 Editor::timeaxisview_deleted (TimeAxisView *tv)
5294 if (tv == entered_track) {
5298 if (_session && _session->deletion_in_progress()) {
5299 /* the situation is under control */
5303 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5305 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5307 _routes->route_removed (tv);
5309 TimeAxisView::Children c = tv->get_child_list ();
5310 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5311 if (entered_track == i->get()) {
5316 /* remove it from the list of track views */
5318 TrackViewList::iterator i;
5320 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5321 i = track_views.erase (i);
5324 /* update whatever the current mixer strip is displaying, if revelant */
5326 boost::shared_ptr<Route> route;
5329 route = rtav->route ();
5332 if (current_mixer_strip && current_mixer_strip->route() == route) {
5334 TimeAxisView* next_tv;
5336 if (track_views.empty()) {
5338 } else if (i == track_views.end()) {
5339 next_tv = track_views.front();
5346 set_selected_mixer_strip (*next_tv);
5348 /* make the editor mixer strip go away setting the
5349 * button to inactive (which also unticks the menu option)
5352 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5358 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5360 if (apply_to_selection) {
5361 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5363 TrackSelection::iterator j = i;
5366 hide_track_in_display (*i, false);
5371 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5373 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5374 // this will hide the mixer strip
5375 set_selected_mixer_strip (*tv);
5378 _routes->hide_track_in_display (*tv);
5383 Editor::sync_track_view_list_and_routes ()
5385 track_views = TrackViewList (_routes->views ());
5387 _summary->set_background_dirty();
5388 _group_tabs->set_dirty ();
5390 return false; // do not call again (until needed)
5394 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5396 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5401 /** Find a RouteTimeAxisView by the ID of its route */
5403 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5405 RouteTimeAxisView* v;
5407 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5408 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5409 if(v->route()->id() == id) {
5419 Editor::fit_route_group (RouteGroup *g)
5421 TrackViewList ts = axis_views_from_routes (g->route_list ());
5426 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5428 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5431 _session->cancel_audition ();
5435 if (_session->is_auditioning()) {
5436 _session->cancel_audition ();
5437 if (r == last_audition_region) {
5442 _session->audition_region (r);
5443 last_audition_region = r;
5448 Editor::hide_a_region (boost::shared_ptr<Region> r)
5450 r->set_hidden (true);
5454 Editor::show_a_region (boost::shared_ptr<Region> r)
5456 r->set_hidden (false);
5460 Editor::audition_region_from_region_list ()
5462 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5466 Editor::hide_region_from_region_list ()
5468 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5472 Editor::show_region_in_region_list ()
5474 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5478 Editor::step_edit_status_change (bool yn)
5481 start_step_editing ();
5483 stop_step_editing ();
5488 Editor::start_step_editing ()
5490 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5494 Editor::stop_step_editing ()
5496 step_edit_connection.disconnect ();
5500 Editor::check_step_edit ()
5502 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5503 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5505 mtv->check_step_edit ();
5509 return true; // do it again, till we stop
5513 Editor::scroll_press (Direction dir)
5515 ++_scroll_callbacks;
5517 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5518 /* delay the first auto-repeat */
5524 scroll_backward (1);
5532 scroll_up_one_track ();
5536 scroll_down_one_track ();
5540 /* do hacky auto-repeat */
5541 if (!_scroll_connection.connected ()) {
5543 _scroll_connection = Glib::signal_timeout().connect (
5544 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5547 _scroll_callbacks = 0;
5554 Editor::scroll_release ()
5556 _scroll_connection.disconnect ();
5559 /** Queue a change for the Editor viewport x origin to follow the playhead */
5561 Editor::reset_x_origin_to_follow_playhead ()
5563 framepos_t const frame = playhead_cursor->current_frame ();
5565 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5567 if (_session->transport_speed() < 0) {
5569 if (frame > (current_page_samples() / 2)) {
5570 center_screen (frame-(current_page_samples()/2));
5572 center_screen (current_page_samples()/2);
5579 if (frame < leftmost_frame) {
5581 if (_session->transport_rolling()) {
5582 /* rolling; end up with the playhead at the right of the page */
5583 l = frame - current_page_samples ();
5585 /* not rolling: end up with the playhead 1/4 of the way along the page */
5586 l = frame - current_page_samples() / 4;
5590 if (_session->transport_rolling()) {
5591 /* rolling: end up with the playhead on the left of the page */
5594 /* not rolling: end up with the playhead 3/4 of the way along the page */
5595 l = frame - 3 * current_page_samples() / 4;
5603 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5609 Editor::super_rapid_screen_update ()
5611 if (!_session || !_session->engine().running()) {
5615 /* METERING / MIXER STRIPS */
5617 /* update track meters, if required */
5618 if (contents().is_mapped() && meters_running) {
5619 RouteTimeAxisView* rtv;
5620 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5621 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5622 rtv->fast_update ();
5627 /* and any current mixer strip */
5628 if (current_mixer_strip) {
5629 current_mixer_strip->fast_update ();
5632 /* PLAYHEAD AND VIEWPORT */
5634 framepos_t const frame = _session->audible_frame();
5636 /* There are a few reasons why we might not update the playhead / viewport stuff:
5638 * 1. we don't update things when there's a pending locate request, otherwise
5639 * when the editor requests a locate there is a chance that this method
5640 * will move the playhead before the locate request is processed, causing
5642 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5643 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5646 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5648 last_update_frame = frame;
5650 if (!_dragging_playhead) {
5651 playhead_cursor->set_position (frame);
5654 if (!_stationary_playhead) {
5656 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5657 /* We only do this if we aren't already
5658 handling a visual change (ie if
5659 pending_visual_change.being_handled is
5660 false) so that these requests don't stack
5661 up there are too many of them to handle in
5664 reset_x_origin_to_follow_playhead ();
5669 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5670 framepos_t const frame = playhead_cursor->current_frame ();
5671 double target = ((double)frame - (double)current_page_samples()/2.0);
5672 if (target <= 0.0) {
5675 // compare to EditorCursor::set_position()
5676 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5677 double const new_pos = sample_to_pixel_unrounded (target);
5678 if (rint (new_pos) != rint (old_pos)) {
5679 reset_x_origin (pixel_to_sample (floor (new_pos)));
5690 Editor::session_going_away ()
5692 _have_idled = false;
5694 _session_connections.drop_connections ();
5696 super_rapid_screen_update_connection.disconnect ();
5698 selection->clear ();
5699 cut_buffer->clear ();
5701 clicked_regionview = 0;
5702 clicked_axisview = 0;
5703 clicked_routeview = 0;
5704 entered_regionview = 0;
5706 last_update_frame = 0;
5709 playhead_cursor->hide ();
5711 /* rip everything out of the list displays */
5715 _route_groups->clear ();
5717 /* do this first so that deleting a track doesn't reset cms to null
5718 and thus cause a leak.
5721 if (current_mixer_strip) {
5722 if (current_mixer_strip->get_parent() != 0) {
5723 global_hpacker.remove (*current_mixer_strip);
5725 delete current_mixer_strip;
5726 current_mixer_strip = 0;
5729 /* delete all trackviews */
5731 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5734 track_views.clear ();
5736 nudge_clock->set_session (0);
5738 editor_list_button.set_active(false);
5739 editor_list_button.set_sensitive(false);
5741 /* clear tempo/meter rulers */
5742 remove_metric_marks ();
5744 clear_marker_display ();
5746 stop_step_editing ();
5750 /* get rid of any existing editor mixer strip */
5752 WindowTitle title(Glib::get_application_name());
5753 title += _("Editor");
5755 own_window()->set_title (title.get_string());
5758 SessionHandlePtr::session_going_away ();
5762 Editor::trigger_script (int i)
5764 LuaInstance::instance()-> call_action (i);
5768 Editor::set_script_action_name (int i, const std::string& n)
5770 string const a = string_compose (X_("script-action-%1"), i + 1);
5771 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5774 act->set_label (string_compose (_("Unset #%1"), i + 1));
5775 act->set_tooltip (_("no action bound"));
5776 act->set_sensitive (false);
5779 act->set_tooltip (n);
5780 act->set_sensitive (true);
5782 KeyEditor::UpdateBindings ();
5786 Editor::show_editor_list (bool yn)
5789 _the_notebook.show ();
5791 _the_notebook.hide ();
5796 Editor::change_region_layering_order (bool from_context_menu)
5798 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5800 if (!clicked_routeview) {
5801 if (layering_order_editor) {
5802 layering_order_editor->hide ();
5807 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5813 boost::shared_ptr<Playlist> pl = track->playlist();
5819 if (layering_order_editor == 0) {
5820 layering_order_editor = new RegionLayeringOrderEditor (*this);
5823 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5824 layering_order_editor->maybe_present ();
5828 Editor::update_region_layering_order_editor ()
5830 if (layering_order_editor && layering_order_editor->is_visible ()) {
5831 change_region_layering_order (true);
5836 Editor::setup_fade_images ()
5838 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5839 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5840 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5841 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5842 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5844 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5845 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5846 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5847 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5848 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5850 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5851 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5852 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5853 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5854 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5856 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5857 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5858 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5859 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5860 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5864 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5866 Editor::action_menu_item (std::string const & name)
5868 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5871 return *manage (a->create_menu_item ());
5875 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5877 EventBox* b = manage (new EventBox);
5878 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5879 Label* l = manage (new Label (name));
5883 _the_notebook.append_page (widget, *b);
5887 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5889 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5890 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5893 if (ev->type == GDK_2BUTTON_PRESS) {
5895 /* double-click on a notebook tab shrinks or expands the notebook */
5897 if (_notebook_shrunk) {
5898 if (pre_notebook_shrink_pane_width) {
5899 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5901 _notebook_shrunk = false;
5903 pre_notebook_shrink_pane_width = edit_pane.get_position();
5905 /* this expands the LHS of the edit pane to cover the notebook
5906 PAGE but leaves the tabs visible.
5908 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5909 _notebook_shrunk = true;
5917 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5919 using namespace Menu_Helpers;
5921 MenuList& items = _control_point_context_menu.items ();
5924 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5925 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5926 if (!can_remove_control_point (item)) {
5927 items.back().set_sensitive (false);
5930 _control_point_context_menu.popup (event->button.button, event->button.time);
5934 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5936 using namespace Menu_Helpers;
5938 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5943 /* We need to get the selection here and pass it to the operations, since
5944 popping up the menu will cause a region leave event which clears
5945 entered_regionview. */
5947 MidiRegionView& mrv = note->region_view();
5948 const RegionSelection rs = get_regions_from_selection_and_entered ();
5949 const uint32_t sel_size = mrv.selection_size ();
5951 MenuList& items = _note_context_menu.items();
5955 items.push_back(MenuElem(_("Delete"),
5956 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5959 items.push_back(MenuElem(_("Edit..."),
5960 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5961 if (sel_size != 1) {
5962 items.back().set_sensitive (false);
5965 items.push_back(MenuElem(_("Transpose..."),
5966 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5969 items.push_back(MenuElem(_("Legatize"),
5970 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5972 items.back().set_sensitive (false);
5975 items.push_back(MenuElem(_("Quantize..."),
5976 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5978 items.push_back(MenuElem(_("Remove Overlap"),
5979 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5981 items.back().set_sensitive (false);
5984 items.push_back(MenuElem(_("Transform..."),
5985 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5987 _note_context_menu.popup (event->button.button, event->button.time);
5991 Editor::zoom_vertical_modifier_released()
5993 _stepping_axis_view = 0;
5997 Editor::ui_parameter_changed (string parameter)
5999 if (parameter == "icon-set") {
6000 while (!_cursor_stack.empty()) {
6001 _cursor_stack.pop_back();
6003 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6004 _cursor_stack.push_back(_cursors->grabber);
6005 } else if (parameter == "draggable-playhead") {
6006 if (_verbose_cursor) {
6007 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6013 Editor::use_own_window (bool and_fill_it)
6015 bool new_window = !own_window();
6017 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6019 if (win && new_window) {
6020 win->set_name ("EditorWindow");
6022 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6024 // win->signal_realize().connect (*this, &Editor::on_realize);
6025 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6026 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6027 win->set_data ("ardour-bindings", bindings);
6032 DisplaySuspender ds;
6033 contents().show_all ();
6035 /* XXX: this is a bit unfortunate; it would probably
6036 be nicer if we could just call show () above rather
6037 than needing the show_all ()
6040 /* re-hide stuff if necessary */
6041 editor_list_button_toggled ();
6042 parameter_changed ("show-summary");
6043 parameter_changed ("show-group-tabs");
6044 parameter_changed ("show-zoom-tools");
6046 /* now reset all audio_time_axis heights, because widgets might need
6052 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6053 tv = (static_cast<TimeAxisView*>(*i));
6054 tv->reset_height ();
6057 if (current_mixer_strip) {
6058 current_mixer_strip->hide_things ();
6059 current_mixer_strip->parameter_changed ("mixer-element-visibility");