2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
86 #include "control_protocol/control_protocol.h"
89 #include "analysis_window.h"
90 #include "audio_clock.h"
91 #include "audio_region_view.h"
92 #include "audio_streamview.h"
93 #include "audio_time_axis.h"
94 #include "automation_time_axis.h"
95 #include "bundle_manager.h"
96 #include "crossfade_edit.h"
100 #include "editor_cursors.h"
101 #include "editor_drag.h"
102 #include "editor_group_tabs.h"
103 #include "editor_locations.h"
104 #include "editor_regions.h"
105 #include "editor_route_groups.h"
106 #include "editor_routes.h"
107 #include "editor_snapshots.h"
108 #include "editor_summary.h"
109 #include "export_report.h"
110 #include "global_port_matrix.h"
111 #include "gui_object.h"
112 #include "gui_thread.h"
113 #include "keyboard.h"
114 #include "keyeditor.h"
115 #include "luainstance.h"
117 #include "midi_region_view.h"
118 #include "midi_time_axis.h"
119 #include "mixer_strip.h"
120 #include "mixer_ui.h"
121 #include "mouse_cursors.h"
122 #include "note_base.h"
123 #include "playlist_selector.h"
124 #include "public_editor.h"
125 #include "quantize_dialog.h"
126 #include "region_layering_order_editor.h"
127 #include "rgb_macros.h"
128 #include "rhythm_ferret.h"
129 #include "route_sorter.h"
130 #include "selection.h"
131 #include "simple_progress_dialog.h"
133 #include "tempo_lines.h"
134 #include "time_axis_view.h"
135 #include "time_info_box.h"
137 #include "tooltips.h"
138 #include "ui_config.h"
140 #include "vca_time_axis.h"
141 #include "verbose_cursor.h"
143 #include "pbd/i18n.h"
146 using namespace ARDOUR;
147 using namespace ARDOUR_UI_UTILS;
150 using namespace Glib;
151 using namespace Gtkmm2ext;
152 using namespace Editing;
154 using PBD::internationalize;
156 using Gtkmm2ext::Keyboard;
158 double Editor::timebar_height = 15.0;
160 static const gchar *_snap_type_strings[] = {
194 static const gchar *_snap_mode_strings[] = {
201 static const gchar *_edit_point_strings[] = {
208 static const gchar *_edit_mode_strings[] = {
216 static const gchar *_zoom_focus_strings[] = {
226 #ifdef USE_RUBBERBAND
227 static const gchar *_rb_opt_strings[] = {
230 N_("Balanced multitimbral mixture"),
231 N_("Unpitched percussion with stable notes"),
232 N_("Crisp monophonic instrumental"),
233 N_("Unpitched solo percussion"),
234 N_("Resample without preserving pitch"),
239 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
242 : PublicEditor (global_hpacker)
243 , editor_mixer_strip_width (Wide)
244 , constructed (false)
245 , _playlist_selector (0)
247 , no_save_visual (false)
249 , samples_per_pixel (2048)
250 , zoom_focus (ZoomFocusPlayhead)
251 , mouse_mode (MouseObject)
252 , pre_internal_snap_type (SnapToBeat)
253 , pre_internal_snap_mode (SnapOff)
254 , internal_snap_type (SnapToBeat)
255 , internal_snap_mode (SnapOff)
256 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
257 , _notebook_shrunk (false)
258 , location_marker_color (0)
259 , location_range_color (0)
260 , location_loop_color (0)
261 , location_punch_color (0)
262 , location_cd_marker_color (0)
264 , _show_marker_lines (false)
265 , clicked_axisview (0)
266 , clicked_routeview (0)
267 , clicked_regionview (0)
268 , clicked_selection (0)
269 , clicked_control_point (0)
270 , button_release_can_deselect (true)
271 , _mouse_changed_selection (false)
272 , region_edit_menu_split_item (0)
273 , region_edit_menu_split_multichannel_item (0)
274 , track_region_edit_playlist_menu (0)
275 , track_edit_playlist_submenu (0)
276 , track_selection_edit_playlist_submenu (0)
277 , _popup_region_menu_item (0)
279 , _track_canvas_viewport (0)
280 , within_track_canvas (false)
281 , _verbose_cursor (0)
285 , range_marker_group (0)
286 , transport_marker_group (0)
287 , cd_marker_group (0)
288 , _time_markers_group (0)
289 , hv_scroll_group (0)
291 , cursor_scroll_group (0)
292 , no_scroll_group (0)
293 , _trackview_group (0)
294 , _drag_motion_group (0)
295 , _canvas_drop_zone (0)
296 , no_ruler_shown_update (false)
297 , ruler_grabbed_widget (0)
299 , minsec_mark_interval (0)
300 , minsec_mark_modulo (0)
302 , timecode_mark_modulo (0)
303 , timecode_nmarks (0)
304 , _samples_ruler_interval (0)
307 , bbt_bar_helper_on (0)
308 , bbt_accent_modulo (0)
313 , visible_timebars (0)
314 , editor_ruler_menu (0)
318 , range_marker_bar (0)
319 , transport_marker_bar (0)
321 , minsec_label (_("Mins:Secs"))
322 , bbt_label (_("Bars:Beats"))
323 , timecode_label (_("Timecode"))
324 , samples_label (_("Samples"))
325 , tempo_label (_("Tempo"))
326 , meter_label (_("Meter"))
327 , mark_label (_("Location Markers"))
328 , range_mark_label (_("Range Markers"))
329 , transport_mark_label (_("Loop/Punch Ranges"))
330 , cd_mark_label (_("CD Markers"))
331 , videotl_label (_("Video Timeline"))
333 , playhead_cursor (0)
334 , edit_packer (4, 4, true)
335 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
336 , horizontal_adjustment (0.0, 0.0, 1e16)
337 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
338 , controls_layout (unused_adjustment, vertical_adjustment)
339 , _scroll_callbacks (0)
340 , _visible_canvas_width (0)
341 , _visible_canvas_height (0)
342 , _full_canvas_height (0)
343 , edit_controls_left_menu (0)
344 , edit_controls_right_menu (0)
345 , last_update_frame (0)
346 , cut_buffer_start (0)
347 , cut_buffer_length (0)
348 , button_bindings (0)
352 , current_interthread_info (0)
353 , analysis_window (0)
354 , select_new_marker (false)
356 , scrubbing_direction (0)
357 , scrub_reversals (0)
358 , scrub_reverse_distance (0)
359 , have_pending_keyboard_selection (false)
360 , pending_keyboard_selection_start (0)
361 , _snap_type (SnapToBeat)
362 , _snap_mode (SnapOff)
363 , snap_threshold (5.0)
364 , ignore_gui_changes (false)
365 , _drags (new DragManager (this))
367 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
368 , _dragging_playhead (false)
369 , _dragging_edit_point (false)
370 , _show_measures (true)
371 , _follow_playhead (true)
372 , _stationary_playhead (false)
375 , global_rect_group (0)
376 , time_line_group (0)
377 , tempo_marker_menu (0)
378 , meter_marker_menu (0)
380 , range_marker_menu (0)
381 , transport_marker_menu (0)
382 , new_transport_marker_menu (0)
384 , marker_menu_item (0)
385 , bbt_beat_subdivision (4)
386 , _visible_track_count (-1)
387 , toolbar_selection_clock_table (2,3)
388 , automation_mode_button (_("mode"))
389 , selection (new Selection (this))
390 , cut_buffer (new Selection (this))
391 , _selection_memento (new SelectionMemento())
392 , _all_region_actions_sensitized (false)
393 , _ignore_region_action (false)
394 , _last_region_menu_was_main (false)
395 , _ignore_follow_edits (false)
396 , cd_marker_bar_drag_rect (0)
397 , range_bar_drag_rect (0)
398 , transport_bar_drag_rect (0)
399 , transport_bar_range_rect (0)
400 , transport_bar_preroll_rect (0)
401 , transport_bar_postroll_rect (0)
402 , transport_loop_range_rect (0)
403 , transport_punch_range_rect (0)
404 , transport_punchin_line (0)
405 , transport_punchout_line (0)
406 , transport_preroll_rect (0)
407 , transport_postroll_rect (0)
409 , rubberband_rect (0)
415 , autoscroll_horizontal_allowed (false)
416 , autoscroll_vertical_allowed (false)
418 , autoscroll_widget (0)
419 , show_gain_after_trim (false)
420 , selection_op_cmd_depth (0)
421 , selection_op_history_it (0)
422 , no_save_instant (false)
424 , current_mixer_strip (0)
425 , show_editor_mixer_when_tracks_arrive (false)
426 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
427 , current_stepping_trackview (0)
428 , last_track_height_step_timestamp (0)
430 , entered_regionview (0)
431 , clear_entered_track (false)
432 , _edit_point (EditAtMouse)
433 , meters_running (false)
435 , _have_idled (false)
436 , resize_idle_id (-1)
437 , _pending_resize_amount (0)
438 , _pending_resize_view (0)
439 , _pending_locate_request (false)
440 , _pending_initial_locate (false)
444 , layering_order_editor (0)
445 , _last_cut_copy_source_track (0)
446 , _region_selection_change_updates_region_list (true)
448 , _following_mixer_selection (false)
449 , _control_point_toggled_on_press (false)
450 , _stepping_axis_view (0)
451 , quantize_dialog (0)
452 , _main_menu_disabler (0)
453 , myactions (X_("editor"))
455 /* we are a singleton */
457 PublicEditor::_instance = this;
461 last_event_time.tv_sec = 0;
462 last_event_time.tv_usec = 0;
464 selection_op_history.clear();
467 snap_type_strings = I18N (_snap_type_strings);
468 snap_mode_strings = I18N (_snap_mode_strings);
469 zoom_focus_strings = I18N (_zoom_focus_strings);
470 edit_mode_strings = I18N (_edit_mode_strings);
471 edit_point_strings = I18N (_edit_point_strings);
472 #ifdef USE_RUBBERBAND
473 rb_opt_strings = I18N (_rb_opt_strings);
477 build_edit_mode_menu();
478 build_zoom_focus_menu();
479 build_track_count_menu();
480 build_snap_mode_menu();
481 build_snap_type_menu();
482 build_edit_point_menu();
484 location_marker_color = UIConfiguration::instance().color ("location marker");
485 location_range_color = UIConfiguration::instance().color ("location range");
486 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
487 location_loop_color = UIConfiguration::instance().color ("location loop");
488 location_punch_color = UIConfiguration::instance().color ("location punch");
490 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
492 TimeAxisView::setup_sizes ();
493 ArdourMarker::setup_sizes (timebar_height);
494 TempoCurve::setup_sizes (timebar_height);
496 bbt_label.set_name ("EditorRulerLabel");
497 bbt_label.set_size_request (-1, (int)timebar_height);
498 bbt_label.set_alignment (1.0, 0.5);
499 bbt_label.set_padding (5,0);
501 bbt_label.set_no_show_all();
502 minsec_label.set_name ("EditorRulerLabel");
503 minsec_label.set_size_request (-1, (int)timebar_height);
504 minsec_label.set_alignment (1.0, 0.5);
505 minsec_label.set_padding (5,0);
506 minsec_label.hide ();
507 minsec_label.set_no_show_all();
508 timecode_label.set_name ("EditorRulerLabel");
509 timecode_label.set_size_request (-1, (int)timebar_height);
510 timecode_label.set_alignment (1.0, 0.5);
511 timecode_label.set_padding (5,0);
512 timecode_label.hide ();
513 timecode_label.set_no_show_all();
514 samples_label.set_name ("EditorRulerLabel");
515 samples_label.set_size_request (-1, (int)timebar_height);
516 samples_label.set_alignment (1.0, 0.5);
517 samples_label.set_padding (5,0);
518 samples_label.hide ();
519 samples_label.set_no_show_all();
521 tempo_label.set_name ("EditorRulerLabel");
522 tempo_label.set_size_request (-1, (int)timebar_height);
523 tempo_label.set_alignment (1.0, 0.5);
524 tempo_label.set_padding (5,0);
526 tempo_label.set_no_show_all();
528 meter_label.set_name ("EditorRulerLabel");
529 meter_label.set_size_request (-1, (int)timebar_height);
530 meter_label.set_alignment (1.0, 0.5);
531 meter_label.set_padding (5,0);
533 meter_label.set_no_show_all();
535 if (Profile->get_trx()) {
536 mark_label.set_text (_("Markers"));
538 mark_label.set_name ("EditorRulerLabel");
539 mark_label.set_size_request (-1, (int)timebar_height);
540 mark_label.set_alignment (1.0, 0.5);
541 mark_label.set_padding (5,0);
543 mark_label.set_no_show_all();
545 cd_mark_label.set_name ("EditorRulerLabel");
546 cd_mark_label.set_size_request (-1, (int)timebar_height);
547 cd_mark_label.set_alignment (1.0, 0.5);
548 cd_mark_label.set_padding (5,0);
549 cd_mark_label.hide();
550 cd_mark_label.set_no_show_all();
552 videotl_bar_height = 4;
553 videotl_label.set_name ("EditorRulerLabel");
554 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
555 videotl_label.set_alignment (1.0, 0.5);
556 videotl_label.set_padding (5,0);
557 videotl_label.hide();
558 videotl_label.set_no_show_all();
560 range_mark_label.set_name ("EditorRulerLabel");
561 range_mark_label.set_size_request (-1, (int)timebar_height);
562 range_mark_label.set_alignment (1.0, 0.5);
563 range_mark_label.set_padding (5,0);
564 range_mark_label.hide();
565 range_mark_label.set_no_show_all();
567 transport_mark_label.set_name ("EditorRulerLabel");
568 transport_mark_label.set_size_request (-1, (int)timebar_height);
569 transport_mark_label.set_alignment (1.0, 0.5);
570 transport_mark_label.set_padding (5,0);
571 transport_mark_label.hide();
572 transport_mark_label.set_no_show_all();
574 initialize_canvas ();
576 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
578 _summary = new EditorSummary (this);
580 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
581 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
583 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
585 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
586 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
588 edit_controls_vbox.set_spacing (0);
589 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
590 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
592 HBox* h = manage (new HBox);
593 _group_tabs = new EditorGroupTabs (this);
594 if (!ARDOUR::Profile->get_trx()) {
595 h->pack_start (*_group_tabs, PACK_SHRINK);
597 h->pack_start (edit_controls_vbox);
598 controls_layout.add (*h);
600 controls_layout.set_name ("EditControlsBase");
601 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
602 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
603 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
605 _cursors = new MouseCursors;
606 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
607 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
609 /* Push default cursor to ever-present bottom of cursor stack. */
610 push_canvas_cursor(_cursors->grabber);
612 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
614 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
615 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
616 pad_line_1->set_outline_color (0xFF0000FF);
622 edit_packer.set_col_spacings (0);
623 edit_packer.set_row_spacings (0);
624 edit_packer.set_homogeneous (false);
625 edit_packer.set_border_width (0);
626 edit_packer.set_name ("EditorWindow");
628 time_bars_event_box.add (time_bars_vbox);
629 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
630 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
632 /* labels for the time bars */
633 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
635 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
637 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
639 bottom_hbox.set_border_width (2);
640 bottom_hbox.set_spacing (3);
642 _route_groups = new EditorRouteGroups (this);
643 _routes = new EditorRoutes (this);
644 _regions = new EditorRegions (this);
645 _snapshots = new EditorSnapshots (this);
646 _locations = new EditorLocations (this);
647 _time_info_box = new TimeInfoBox ();
649 /* these are static location signals */
651 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
655 add_notebook_page (_("Regions"), _regions->widget ());
656 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
657 add_notebook_page (_("Snapshots"), _snapshots->widget ());
658 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
659 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
661 _the_notebook.set_show_tabs (true);
662 _the_notebook.set_scrollable (true);
663 _the_notebook.popup_disable ();
664 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
665 _the_notebook.show_all ();
667 _notebook_shrunk = false;
670 /* Pick up some settings we need to cache, early */
672 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
675 if (settings && (prop = settings->property ("notebook-shrunk"))) {
676 _notebook_shrunk = string_is_affirmative (prop->value ());
679 editor_summary_pane.set_check_divider_position (true);
680 editor_summary_pane.add (edit_packer);
682 Button* summary_arrows_left_left = manage (new Button);
683 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
684 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
685 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
687 Button* summary_arrows_left_right = manage (new Button);
688 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
689 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
690 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
692 VBox* summary_arrows_left = manage (new VBox);
693 summary_arrows_left->pack_start (*summary_arrows_left_left);
694 summary_arrows_left->pack_start (*summary_arrows_left_right);
696 Button* summary_arrows_right_up = manage (new Button);
697 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
698 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
699 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
701 Button* summary_arrows_right_down = manage (new Button);
702 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
703 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
704 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
706 VBox* summary_arrows_right = manage (new VBox);
707 summary_arrows_right->pack_start (*summary_arrows_right_up);
708 summary_arrows_right->pack_start (*summary_arrows_right_down);
710 Frame* summary_frame = manage (new Frame);
711 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
713 summary_frame->add (*_summary);
714 summary_frame->show ();
716 _summary_hbox.pack_start (*summary_arrows_left, false, false);
717 _summary_hbox.pack_start (*summary_frame, true, true);
718 _summary_hbox.pack_start (*summary_arrows_right, false, false);
720 if (!ARDOUR::Profile->get_trx()) {
721 editor_summary_pane.add (_summary_hbox);
724 edit_pane.set_check_divider_position (true);
725 edit_pane.add (editor_summary_pane);
726 if (!ARDOUR::Profile->get_trx()) {
727 VBox* editor_list_vbox = manage (new VBox);
728 editor_list_vbox->pack_start (*_time_info_box, false, false, 0);
729 editor_list_vbox->pack_start (_the_notebook);
730 edit_pane.add (*editor_list_vbox);
731 edit_pane.set_child_minsize (*editor_list_vbox, 30); /* rough guess at width of notebook tabs */
734 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
735 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
742 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
743 /* initial allocation is 90% to canvas, 10% to notebook */
744 edit_pane.set_divider (0, 0.90);
746 edit_pane.set_divider (0, fract);
749 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
750 /* initial allocation is 90% to canvas, 10% to summary */
751 editor_summary_pane.set_divider (0, 0.90);
754 editor_summary_pane.set_divider (0, fract);
758 global_vpacker.set_spacing (2);
759 global_vpacker.set_border_width (0);
762 EventBox *spacer = manage (new EventBox ()); spacer->set_size_request(-1, 1);
763 spacer->signal_expose_event().connect (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::spacer_expose), false); spacer->show();
764 // global_vpacker.pack_start (*spacer, false, false, 0);
766 global_vpacker.pack_start (toolbar_hbox, false, false);
767 global_vpacker.pack_start (edit_pane, true, true);
768 global_hpacker.pack_start (global_vpacker, true, true);
770 /* need to show the "contents" widget so that notebook will show if tab is switched to
773 global_hpacker.show ();
775 /* register actions now so that set_state() can find them and set toggles/checks etc */
782 _playlist_selector = new PlaylistSelector();
783 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
785 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
789 nudge_forward_button.set_name ("nudge button");
790 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
792 nudge_backward_button.set_name ("nudge button");
793 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
795 fade_context_menu.set_name ("ArdourContextMenu");
797 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
799 /* allow external control surfaces/protocols to do various things */
801 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
802 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
803 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
804 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
805 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
806 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
807 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
808 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
809 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
810 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
811 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
812 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
813 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
814 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
816 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
817 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
818 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
819 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
820 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
822 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
826 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
828 /* problematic: has to return a value and thus cannot be x-thread */
830 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
832 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
833 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
835 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
837 _ignore_region_action = false;
838 _last_region_menu_was_main = false;
839 _popup_region_menu_item = 0;
841 _ignore_follow_edits = false;
843 _show_marker_lines = false;
845 /* Button bindings */
847 button_bindings = new Bindings ("editor-mouse");
849 XMLNode* node = button_settings();
851 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
852 button_bindings->load_operation (**i);
858 /* grab current parameter state */
859 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
860 UIConfiguration::instance().map_parameters (pc);
862 setup_fade_images ();
864 LuaInstance::instance(); // instantiate
865 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
872 delete button_bindings;
874 delete _route_groups;
875 delete _track_canvas_viewport;
878 delete _verbose_cursor;
879 delete quantize_dialog;
885 delete _playlist_selector;
886 delete _time_info_box;
888 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
894 Editor::button_settings () const
896 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
897 XMLNode* node = find_named_node (*settings, X_("Buttons"));
900 node = new XMLNode (X_("Buttons"));
907 Editor::get_smart_mode () const
909 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
913 Editor::catch_vanishing_regionview (RegionView *rv)
915 /* note: the selection will take care of the vanishing
916 audioregionview by itself.
919 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
923 if (clicked_regionview == rv) {
924 clicked_regionview = 0;
927 if (entered_regionview == rv) {
928 set_entered_regionview (0);
931 if (!_all_region_actions_sensitized) {
932 sensitize_all_region_actions (true);
937 Editor::set_entered_regionview (RegionView* rv)
939 if (rv == entered_regionview) {
943 if (entered_regionview) {
944 entered_regionview->exited ();
947 entered_regionview = rv;
949 if (entered_regionview != 0) {
950 entered_regionview->entered ();
953 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
954 /* This RegionView entry might have changed what region actions
955 are allowed, so sensitize them all in case a key is pressed.
957 sensitize_all_region_actions (true);
962 Editor::set_entered_track (TimeAxisView* tav)
965 entered_track->exited ();
971 entered_track->entered ();
976 Editor::instant_save ()
978 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
983 _session->add_instant_xml(get_state());
985 Config->add_instant_xml(get_state());
990 Editor::control_vertical_zoom_in_all ()
992 tav_zoom_smooth (false, true);
996 Editor::control_vertical_zoom_out_all ()
998 tav_zoom_smooth (true, true);
1002 Editor::control_vertical_zoom_in_selected ()
1004 tav_zoom_smooth (false, false);
1008 Editor::control_vertical_zoom_out_selected ()
1010 tav_zoom_smooth (true, false);
1014 Editor::control_view (uint32_t view)
1016 goto_visual_state (view);
1020 Editor::control_unselect ()
1022 selection->clear_tracks ();
1026 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1028 TimeAxisView* tav = axis_view_from_stripable (s);
1032 case Selection::Add:
1033 selection->add (tav);
1035 case Selection::Toggle:
1036 selection->toggle (tav);
1038 case Selection::Extend:
1040 case Selection::Set:
1041 selection->set (tav);
1045 selection->clear_tracks ();
1050 Editor::control_step_tracks_up ()
1052 scroll_tracks_up_line ();
1056 Editor::control_step_tracks_down ()
1058 scroll_tracks_down_line ();
1062 Editor::control_scroll (float fraction)
1064 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1070 double step = fraction * current_page_samples();
1073 _control_scroll_target is an optional<T>
1075 it acts like a pointer to an framepos_t, with
1076 a operator conversion to boolean to check
1077 that it has a value could possibly use
1078 playhead_cursor->current_frame to store the
1079 value and a boolean in the class to know
1080 when it's out of date
1083 if (!_control_scroll_target) {
1084 _control_scroll_target = _session->transport_frame();
1085 _dragging_playhead = true;
1088 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1089 *_control_scroll_target = 0;
1090 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1091 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1093 *_control_scroll_target += (framepos_t) trunc (step);
1096 /* move visuals, we'll catch up with it later */
1098 playhead_cursor->set_position (*_control_scroll_target);
1099 UpdateAllTransportClocks (*_control_scroll_target);
1101 if (*_control_scroll_target > (current_page_samples() / 2)) {
1102 /* try to center PH in window */
1103 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1109 Now we do a timeout to actually bring the session to the right place
1110 according to the playhead. This is to avoid reading disk buffers on every
1111 call to control_scroll, which is driven by ScrollTimeline and therefore
1112 probably by a control surface wheel which can generate lots of events.
1114 /* cancel the existing timeout */
1116 control_scroll_connection.disconnect ();
1118 /* add the next timeout */
1120 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1124 Editor::deferred_control_scroll (framepos_t /*target*/)
1126 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1127 // reset for next stream
1128 _control_scroll_target = boost::none;
1129 _dragging_playhead = false;
1134 Editor::access_action (std::string action_group, std::string action_item)
1140 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1143 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1151 Editor::on_realize ()
1155 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1156 start_lock_event_timing ();
1161 Editor::start_lock_event_timing ()
1163 /* check if we should lock the GUI every 30 seconds */
1165 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1169 Editor::generic_event_handler (GdkEvent* ev)
1172 case GDK_BUTTON_PRESS:
1173 case GDK_BUTTON_RELEASE:
1174 case GDK_MOTION_NOTIFY:
1176 case GDK_KEY_RELEASE:
1177 if (contents().is_mapped()) {
1178 gettimeofday (&last_event_time, 0);
1182 case GDK_LEAVE_NOTIFY:
1183 switch (ev->crossing.detail) {
1184 case GDK_NOTIFY_UNKNOWN:
1185 case GDK_NOTIFY_INFERIOR:
1186 case GDK_NOTIFY_ANCESTOR:
1188 case GDK_NOTIFY_VIRTUAL:
1189 case GDK_NOTIFY_NONLINEAR:
1190 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1191 /* leaving window, so reset focus, thus ending any and
1192 all text entry operations.
1194 ARDOUR_UI::instance()->reset_focus (&contents());
1207 Editor::lock_timeout_callback ()
1209 struct timeval now, delta;
1211 gettimeofday (&now, 0);
1213 timersub (&now, &last_event_time, &delta);
1215 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1217 /* don't call again. Returning false will effectively
1218 disconnect us from the timer callback.
1220 unlock() will call start_lock_event_timing() to get things
1230 Editor::map_position_change (framepos_t frame)
1232 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1234 if (_session == 0) {
1238 if (_follow_playhead) {
1239 center_screen (frame);
1242 playhead_cursor->set_position (frame);
1246 Editor::center_screen (framepos_t frame)
1248 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1250 /* if we're off the page, then scroll.
1253 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1254 center_screen_internal (frame, page);
1259 Editor::center_screen_internal (framepos_t frame, float page)
1264 frame -= (framepos_t) page;
1269 reset_x_origin (frame);
1274 Editor::update_title ()
1276 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1278 if (!own_window()) {
1283 bool dirty = _session->dirty();
1285 string session_name;
1287 if (_session->snap_name() != _session->name()) {
1288 session_name = _session->snap_name();
1290 session_name = _session->name();
1294 session_name = "*" + session_name;
1297 WindowTitle title(session_name);
1298 title += S_("Window|Editor");
1299 title += Glib::get_application_name();
1300 own_window()->set_title (title.get_string());
1302 /* ::session_going_away() will have taken care of it */
1307 Editor::set_session (Session *t)
1309 SessionHandlePtr::set_session (t);
1315 _playlist_selector->set_session (_session);
1316 nudge_clock->set_session (_session);
1317 _summary->set_session (_session);
1318 _group_tabs->set_session (_session);
1319 _route_groups->set_session (_session);
1320 _regions->set_session (_session);
1321 _snapshots->set_session (_session);
1322 _routes->set_session (_session);
1323 _locations->set_session (_session);
1324 _time_info_box->set_session (_session);
1326 if (rhythm_ferret) {
1327 rhythm_ferret->set_session (_session);
1330 if (analysis_window) {
1331 analysis_window->set_session (_session);
1335 sfbrowser->set_session (_session);
1338 compute_fixed_ruler_scale ();
1340 /* Make sure we have auto loop and auto punch ranges */
1342 Location* loc = _session->locations()->auto_loop_location();
1344 loc->set_name (_("Loop"));
1347 loc = _session->locations()->auto_punch_location();
1350 loc->set_name (_("Punch"));
1353 refresh_location_display ();
1355 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1356 the selected Marker; this needs the LocationMarker list to be available.
1358 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1359 set_state (*node, Stateful::loading_state_version);
1361 /* catch up with the playhead */
1363 _session->request_locate (playhead_cursor->current_frame ());
1364 _pending_initial_locate = true;
1368 /* These signals can all be emitted by a non-GUI thread. Therefore the
1369 handlers for them must not attempt to directly interact with the GUI,
1370 but use PBD::Signal<T>::connect() which accepts an event loop
1371 ("context") where the handler will be asked to run.
1374 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1375 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1376 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1377 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1378 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1379 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1380 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1381 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1382 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1383 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1384 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1385 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1386 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1387 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1388 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1390 playhead_cursor->show ();
1392 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1393 Config->map_parameters (pc);
1394 _session->config.map_parameters (pc);
1396 restore_ruler_visibility ();
1397 //tempo_map_changed (PropertyChange (0));
1398 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1400 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1401 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1404 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1405 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1408 switch (_snap_type) {
1409 case SnapToRegionStart:
1410 case SnapToRegionEnd:
1411 case SnapToRegionSync:
1412 case SnapToRegionBoundary:
1413 build_region_boundary_cache ();
1420 /* catch up on selection of stripables (other selection state is lost
1421 * when a session is closed
1426 _session->get_stripables (sl);
1427 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1428 if ((*s)->presentation_info().selected()) {
1429 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1431 tl.push_back (rtav);
1436 selection->set (tl);
1439 /* register for undo history */
1440 _session->register_with_memento_command_factory(id(), this);
1441 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1443 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1445 LuaInstance::instance()->set_session(_session);
1447 start_updating_meters ();
1451 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1453 if (a->get_name() == "RegionMenu") {
1454 /* When the main menu's region menu is opened, we setup the actions so that they look right
1455 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1456 so we resensitize all region actions when the entered regionview or the region selection
1457 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1458 happens after the region context menu is opened. So we set a flag here, too.
1462 sensitize_the_right_region_actions ();
1463 _last_region_menu_was_main = true;
1468 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1470 using namespace Menu_Helpers;
1472 void (Editor::*emf)(FadeShape);
1473 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1476 images = &_xfade_in_images;
1477 emf = &Editor::set_fade_in_shape;
1479 images = &_xfade_out_images;
1480 emf = &Editor::set_fade_out_shape;
1485 _("Linear (for highly correlated material)"),
1486 *(*images)[FadeLinear],
1487 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 _("Constant power"),
1496 *(*images)[FadeConstantPower],
1497 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1500 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1505 *(*images)[FadeSymmetric],
1506 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1510 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1515 *(*images)[FadeSlow],
1516 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1519 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1524 *(*images)[FadeFast],
1525 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1528 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1531 /** Pop up a context menu for when the user clicks on a start crossfade */
1533 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1535 using namespace Menu_Helpers;
1536 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1541 MenuList& items (xfade_in_context_menu.items());
1544 if (arv->audio_region()->fade_in_active()) {
1545 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1547 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1550 items.push_back (SeparatorElem());
1551 fill_xfade_menu (items, true);
1553 xfade_in_context_menu.popup (button, time);
1556 /** Pop up a context menu for when the user clicks on an end crossfade */
1558 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1560 using namespace Menu_Helpers;
1561 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1566 MenuList& items (xfade_out_context_menu.items());
1569 if (arv->audio_region()->fade_out_active()) {
1570 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1572 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1575 items.push_back (SeparatorElem());
1576 fill_xfade_menu (items, false);
1578 xfade_out_context_menu.popup (button, time);
1582 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1584 using namespace Menu_Helpers;
1585 Menu* (Editor::*build_menu_function)();
1588 switch (item_type) {
1590 case RegionViewName:
1591 case RegionViewNameHighlight:
1592 case LeftFrameHandle:
1593 case RightFrameHandle:
1594 if (with_selection) {
1595 build_menu_function = &Editor::build_track_selection_context_menu;
1597 build_menu_function = &Editor::build_track_region_context_menu;
1602 if (with_selection) {
1603 build_menu_function = &Editor::build_track_selection_context_menu;
1605 build_menu_function = &Editor::build_track_context_menu;
1610 if (clicked_routeview->track()) {
1611 build_menu_function = &Editor::build_track_context_menu;
1613 build_menu_function = &Editor::build_track_bus_context_menu;
1618 /* probably shouldn't happen but if it does, we don't care */
1622 menu = (this->*build_menu_function)();
1623 menu->set_name ("ArdourContextMenu");
1625 /* now handle specific situations */
1627 switch (item_type) {
1629 case RegionViewName:
1630 case RegionViewNameHighlight:
1631 case LeftFrameHandle:
1632 case RightFrameHandle:
1633 if (!with_selection) {
1634 if (region_edit_menu_split_item) {
1635 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1636 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1638 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1641 if (region_edit_menu_split_multichannel_item) {
1642 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1643 region_edit_menu_split_multichannel_item->set_sensitive (true);
1645 region_edit_menu_split_multichannel_item->set_sensitive (false);
1658 /* probably shouldn't happen but if it does, we don't care */
1662 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1664 /* Bounce to disk */
1666 using namespace Menu_Helpers;
1667 MenuList& edit_items = menu->items();
1669 edit_items.push_back (SeparatorElem());
1671 switch (clicked_routeview->audio_track()->freeze_state()) {
1672 case AudioTrack::NoFreeze:
1673 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1676 case AudioTrack::Frozen:
1677 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1680 case AudioTrack::UnFrozen:
1681 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1687 if (item_type == StreamItem && clicked_routeview) {
1688 clicked_routeview->build_underlay_menu(menu);
1691 /* When the region menu is opened, we setup the actions so that they look right
1694 sensitize_the_right_region_actions ();
1695 _last_region_menu_was_main = false;
1697 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1698 menu->popup (button, time);
1702 Editor::build_track_context_menu ()
1704 using namespace Menu_Helpers;
1706 MenuList& edit_items = track_context_menu.items();
1709 add_dstream_context_items (edit_items);
1710 return &track_context_menu;
1714 Editor::build_track_bus_context_menu ()
1716 using namespace Menu_Helpers;
1718 MenuList& edit_items = track_context_menu.items();
1721 add_bus_context_items (edit_items);
1722 return &track_context_menu;
1726 Editor::build_track_region_context_menu ()
1728 using namespace Menu_Helpers;
1729 MenuList& edit_items = track_region_context_menu.items();
1732 /* we've just cleared the track region context menu, so the menu that these
1733 two items were on will have disappeared; stop them dangling.
1735 region_edit_menu_split_item = 0;
1736 region_edit_menu_split_multichannel_item = 0;
1738 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1741 boost::shared_ptr<Track> tr;
1742 boost::shared_ptr<Playlist> pl;
1744 if ((tr = rtv->track())) {
1745 add_region_context_items (edit_items, tr);
1749 add_dstream_context_items (edit_items);
1751 return &track_region_context_menu;
1755 Editor::loudness_analyze_region_selection ()
1760 Selection& s (PublicEditor::instance ().get_selection ());
1761 RegionSelection ars = s.regions;
1762 ARDOUR::AnalysisGraph ag (_session);
1763 framecnt_t total_work = 0;
1765 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1766 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1770 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1773 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1774 total_work += arv->region ()->length ();
1777 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1779 ag.set_total_frames (total_work);
1780 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1783 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1784 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1788 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1792 ag.analyze_region (ar);
1795 if (!ag.canceled ()) {
1796 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1802 Editor::loudness_analyze_range_selection ()
1807 Selection& s (PublicEditor::instance ().get_selection ());
1808 TimeSelection ts = s.time;
1809 ARDOUR::AnalysisGraph ag (_session);
1810 framecnt_t total_work = 0;
1812 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1813 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1817 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1821 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1822 total_work += j->length ();
1826 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1828 ag.set_total_frames (total_work);
1829 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1832 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1833 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1837 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1841 ag.analyze_range (rui->route (), pl, ts);
1844 if (!ag.canceled ()) {
1845 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1851 Editor::spectral_analyze_region_selection ()
1853 if (analysis_window == 0) {
1854 analysis_window = new AnalysisWindow();
1857 analysis_window->set_session(_session);
1859 analysis_window->show_all();
1862 analysis_window->set_regionmode();
1863 analysis_window->analyze();
1865 analysis_window->present();
1869 Editor::spectral_analyze_range_selection()
1871 if (analysis_window == 0) {
1872 analysis_window = new AnalysisWindow();
1875 analysis_window->set_session(_session);
1877 analysis_window->show_all();
1880 analysis_window->set_rangemode();
1881 analysis_window->analyze();
1883 analysis_window->present();
1887 Editor::build_track_selection_context_menu ()
1889 using namespace Menu_Helpers;
1890 MenuList& edit_items = track_selection_context_menu.items();
1891 edit_items.clear ();
1893 add_selection_context_items (edit_items);
1894 // edit_items.push_back (SeparatorElem());
1895 // add_dstream_context_items (edit_items);
1897 return &track_selection_context_menu;
1901 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1903 using namespace Menu_Helpers;
1905 /* OK, stick the region submenu at the top of the list, and then add
1909 RegionSelection rs = get_regions_from_selection_and_entered ();
1911 string::size_type pos = 0;
1912 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1914 /* we have to hack up the region name because "_" has a special
1915 meaning for menu titles.
1918 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1919 menu_item_name.replace (pos, 1, "__");
1923 if (_popup_region_menu_item == 0) {
1924 _popup_region_menu_item = new MenuItem (menu_item_name);
1925 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1926 _popup_region_menu_item->show ();
1928 _popup_region_menu_item->set_label (menu_item_name);
1931 /* No latering allowed in later is higher layering model */
1932 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1933 if (act && Config->get_layer_model() == LaterHigher) {
1934 act->set_sensitive (false);
1936 act->set_sensitive (true);
1939 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1941 edit_items.push_back (*_popup_region_menu_item);
1942 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1943 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1945 edit_items.push_back (SeparatorElem());
1948 /** Add context menu items relevant to selection ranges.
1949 * @param edit_items List to add the items to.
1952 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1954 using namespace Menu_Helpers;
1956 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1957 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1959 edit_items.push_back (SeparatorElem());
1960 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1962 edit_items.push_back (SeparatorElem());
1963 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1964 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1966 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (
1970 _("Move Range Start to Previous Region Boundary"),
1971 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1975 edit_items.push_back (
1977 _("Move Range Start to Next Region Boundary"),
1978 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1982 edit_items.push_back (
1984 _("Move Range End to Previous Region Boundary"),
1985 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1989 edit_items.push_back (
1991 _("Move Range End to Next Region Boundary"),
1992 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1996 edit_items.push_back (SeparatorElem());
1997 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1998 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
2000 edit_items.push_back (SeparatorElem());
2001 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2003 edit_items.push_back (SeparatorElem());
2004 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2005 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2006 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2008 edit_items.push_back (SeparatorElem());
2009 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2011 edit_items.push_back (SeparatorElem());
2012 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2013 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2015 edit_items.push_back (SeparatorElem());
2016 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2017 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2018 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2019 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2020 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2021 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2022 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2028 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2030 using namespace Menu_Helpers;
2034 Menu *play_menu = manage (new Menu);
2035 MenuList& play_items = play_menu->items();
2036 play_menu->set_name ("ArdourContextMenu");
2038 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2039 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2040 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2041 play_items.push_back (SeparatorElem());
2042 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2044 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2048 Menu *select_menu = manage (new Menu);
2049 MenuList& select_items = select_menu->items();
2050 select_menu->set_name ("ArdourContextMenu");
2052 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2053 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2054 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2055 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2056 select_items.push_back (SeparatorElem());
2057 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2058 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2059 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2060 select_items.push_back (SeparatorElem());
2061 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2062 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2063 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2064 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2065 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2066 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2067 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2069 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2073 Menu *cutnpaste_menu = manage (new Menu);
2074 MenuList& cutnpaste_items = cutnpaste_menu->items();
2075 cutnpaste_menu->set_name ("ArdourContextMenu");
2077 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2078 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2079 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2081 cutnpaste_items.push_back (SeparatorElem());
2083 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2084 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2086 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2088 /* Adding new material */
2090 edit_items.push_back (SeparatorElem());
2091 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2092 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2096 Menu *nudge_menu = manage (new Menu());
2097 MenuList& nudge_items = nudge_menu->items();
2098 nudge_menu->set_name ("ArdourContextMenu");
2100 edit_items.push_back (SeparatorElem());
2101 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2102 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2103 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2104 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2106 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2110 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2112 using namespace Menu_Helpers;
2116 Menu *play_menu = manage (new Menu);
2117 MenuList& play_items = play_menu->items();
2118 play_menu->set_name ("ArdourContextMenu");
2120 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2121 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2122 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2126 Menu *select_menu = manage (new Menu);
2127 MenuList& select_items = select_menu->items();
2128 select_menu->set_name ("ArdourContextMenu");
2130 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2131 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2132 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2133 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2134 select_items.push_back (SeparatorElem());
2135 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2136 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2137 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2138 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2140 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2144 Menu *cutnpaste_menu = manage (new Menu);
2145 MenuList& cutnpaste_items = cutnpaste_menu->items();
2146 cutnpaste_menu->set_name ("ArdourContextMenu");
2148 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2149 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2150 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2152 Menu *nudge_menu = manage (new Menu());
2153 MenuList& nudge_items = nudge_menu->items();
2154 nudge_menu->set_name ("ArdourContextMenu");
2156 edit_items.push_back (SeparatorElem());
2157 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2158 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2159 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2160 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2162 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2166 Editor::snap_type() const
2172 Editor::snap_musical() const
2174 switch (_snap_type) {
2175 case SnapToBeatDiv128:
2176 case SnapToBeatDiv64:
2177 case SnapToBeatDiv32:
2178 case SnapToBeatDiv28:
2179 case SnapToBeatDiv24:
2180 case SnapToBeatDiv20:
2181 case SnapToBeatDiv16:
2182 case SnapToBeatDiv14:
2183 case SnapToBeatDiv12:
2184 case SnapToBeatDiv10:
2185 case SnapToBeatDiv8:
2186 case SnapToBeatDiv7:
2187 case SnapToBeatDiv6:
2188 case SnapToBeatDiv5:
2189 case SnapToBeatDiv4:
2190 case SnapToBeatDiv3:
2191 case SnapToBeatDiv2:
2203 Editor::snap_mode() const
2209 Editor::set_snap_to (SnapType st)
2211 unsigned int snap_ind = (unsigned int)st;
2213 if (internal_editing()) {
2214 internal_snap_type = st;
2216 pre_internal_snap_type = st;
2221 if (snap_ind > snap_type_strings.size() - 1) {
2223 _snap_type = (SnapType)snap_ind;
2226 string str = snap_type_strings[snap_ind];
2228 if (str != snap_type_selector.get_text()) {
2229 snap_type_selector.set_text (str);
2234 switch (_snap_type) {
2235 case SnapToBeatDiv128:
2236 case SnapToBeatDiv64:
2237 case SnapToBeatDiv32:
2238 case SnapToBeatDiv28:
2239 case SnapToBeatDiv24:
2240 case SnapToBeatDiv20:
2241 case SnapToBeatDiv16:
2242 case SnapToBeatDiv14:
2243 case SnapToBeatDiv12:
2244 case SnapToBeatDiv10:
2245 case SnapToBeatDiv8:
2246 case SnapToBeatDiv7:
2247 case SnapToBeatDiv6:
2248 case SnapToBeatDiv5:
2249 case SnapToBeatDiv4:
2250 case SnapToBeatDiv3:
2251 case SnapToBeatDiv2: {
2252 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2253 update_tempo_based_rulers ();
2257 case SnapToRegionStart:
2258 case SnapToRegionEnd:
2259 case SnapToRegionSync:
2260 case SnapToRegionBoundary:
2261 build_region_boundary_cache ();
2269 redisplay_tempo (false);
2271 SnapChanged (); /* EMIT SIGNAL */
2275 Editor::set_snap_mode (SnapMode mode)
2277 string str = snap_mode_strings[(int)mode];
2279 if (internal_editing()) {
2280 internal_snap_mode = mode;
2282 pre_internal_snap_mode = mode;
2287 if (str != snap_mode_selector.get_text ()) {
2288 snap_mode_selector.set_text (str);
2295 Editor::set_edit_point_preference (EditPoint ep, bool force)
2297 bool changed = (_edit_point != ep);
2300 if (Profile->get_mixbus())
2301 if (ep == EditAtSelectedMarker)
2302 ep = EditAtPlayhead;
2304 string str = edit_point_strings[(int)ep];
2305 if (str != edit_point_selector.get_text ()) {
2306 edit_point_selector.set_text (str);
2309 update_all_enter_cursors();
2311 if (!force && !changed) {
2315 const char* action=NULL;
2317 switch (_edit_point) {
2318 case EditAtPlayhead:
2319 action = "edit-at-playhead";
2321 case EditAtSelectedMarker:
2322 action = "edit-at-marker";
2325 action = "edit-at-mouse";
2329 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2331 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2335 bool in_track_canvas;
2337 if (!mouse_frame (foo, in_track_canvas)) {
2338 in_track_canvas = false;
2341 reset_canvas_action_sensitivity (in_track_canvas);
2347 Editor::set_state (const XMLNode& node, int version)
2349 XMLProperty const * prop;
2351 PBD::Unwinder<bool> nsi (no_save_instant, true);
2354 Tabbable::set_state (node, version);
2356 if (_session && (prop = node.property ("playhead"))) {
2358 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2360 playhead_cursor->set_position (pos);
2362 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2363 playhead_cursor->set_position (0);
2366 playhead_cursor->set_position (0);
2369 if ((prop = node.property ("mixer-width"))) {
2370 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2373 if ((prop = node.property ("zoom-focus"))) {
2374 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2376 zoom_focus_selection_done (zoom_focus);
2379 if ((prop = node.property ("zoom"))) {
2380 /* older versions of ardour used floating point samples_per_pixel */
2381 double f = PBD::atof (prop->value());
2382 reset_zoom (llrintf (f));
2384 reset_zoom (samples_per_pixel);
2387 if ((prop = node.property ("visible-track-count"))) {
2388 set_visible_track_count (PBD::atoi (prop->value()));
2391 if ((prop = node.property ("snap-to"))) {
2392 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2393 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2395 set_snap_to (_snap_type);
2398 if ((prop = node.property ("snap-mode"))) {
2399 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2400 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2401 * snap_mode_selection_done() will only mark an already active item as active
2402 * which does not trigger set_text().
2404 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2406 set_snap_mode (_snap_mode);
2409 if ((prop = node.property ("internal-snap-to"))) {
2410 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2413 if ((prop = node.property ("internal-snap-mode"))) {
2414 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2417 if ((prop = node.property ("pre-internal-snap-to"))) {
2418 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2421 if ((prop = node.property ("pre-internal-snap-mode"))) {
2422 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2425 if ((prop = node.property ("mouse-mode"))) {
2426 MouseMode m = str2mousemode(prop->value());
2427 set_mouse_mode (m, true);
2429 set_mouse_mode (MouseObject, true);
2432 if ((prop = node.property ("left-frame")) != 0) {
2434 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2438 reset_x_origin (pos);
2442 if ((prop = node.property ("y-origin")) != 0) {
2443 reset_y_origin (atof (prop->value ()));
2446 if ((prop = node.property ("join-object-range"))) {
2447 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2448 bool yn = string_is_affirmative (prop->value());
2450 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2451 tact->set_active (!yn);
2452 tact->set_active (yn);
2454 set_mouse_mode(mouse_mode, true);
2457 if ((prop = node.property ("edit-point"))) {
2458 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2460 set_edit_point_preference (_edit_point);
2463 if ((prop = node.property ("show-measures"))) {
2464 bool yn = string_is_affirmative (prop->value());
2465 _show_measures = yn;
2468 if ((prop = node.property ("follow-playhead"))) {
2469 bool yn = string_is_affirmative (prop->value());
2470 set_follow_playhead (yn);
2473 if ((prop = node.property ("stationary-playhead"))) {
2474 bool yn = string_is_affirmative (prop->value());
2475 set_stationary_playhead (yn);
2478 if ((prop = node.property ("region-list-sort-type"))) {
2479 RegionListSortType st;
2480 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2483 if ((prop = node.property ("show-editor-mixer"))) {
2485 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2488 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2489 bool yn = string_is_affirmative (prop->value());
2491 /* do it twice to force the change */
2493 tact->set_active (!yn);
2494 tact->set_active (yn);
2497 if ((prop = node.property ("show-editor-list"))) {
2499 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2502 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2503 bool yn = string_is_affirmative (prop->value());
2505 /* do it twice to force the change */
2507 tact->set_active (!yn);
2508 tact->set_active (yn);
2511 if ((prop = node.property (X_("editor-list-page")))) {
2512 _the_notebook.set_current_page (atoi (prop->value ()));
2515 if ((prop = node.property (X_("show-marker-lines")))) {
2516 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2518 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2519 bool yn = string_is_affirmative (prop->value ());
2521 tact->set_active (!yn);
2522 tact->set_active (yn);
2525 XMLNodeList children = node.children ();
2526 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2527 selection->set_state (**i, Stateful::current_state_version);
2528 _regions->set_state (**i);
2531 if ((prop = node.property ("maximised"))) {
2532 bool yn = string_is_affirmative (prop->value());
2533 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2535 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2536 bool fs = tact && tact->get_active();
2538 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2542 if ((prop = node.property ("nudge-clock-value"))) {
2544 sscanf (prop->value().c_str(), "%" PRId64, &f);
2545 nudge_clock->set (f);
2547 nudge_clock->set_mode (AudioClock::Timecode);
2548 nudge_clock->set (_session->frame_rate() * 5, true);
2553 * Not all properties may have been in XML, but
2554 * those that are linked to a private variable may need changing
2559 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2561 yn = _show_measures;
2562 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2563 /* do it twice to force the change */
2564 tact->set_active (!yn);
2565 tact->set_active (yn);
2568 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2569 yn = _follow_playhead;
2571 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2572 if (tact->get_active() != yn) {
2573 tact->set_active (yn);
2577 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2578 yn = _stationary_playhead;
2580 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2581 if (tact->get_active() != yn) {
2582 tact->set_active (yn);
2587 return LuaInstance::instance()->set_state(node);
2591 Editor::get_state ()
2593 XMLNode* node = new XMLNode (X_("Editor"));
2597 id().print (buf, sizeof (buf));
2598 node->add_property ("id", buf);
2600 node->add_child_nocopy (Tabbable::get_state());
2602 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2603 node->add_property("edit-horizontal-pane-pos", string(buf));
2604 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2605 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2606 node->add_property("edit-vertical-pane-pos", string(buf));
2608 maybe_add_mixer_strip_width (*node);
2610 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2612 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2613 node->add_property ("zoom", buf);
2614 node->add_property ("snap-to", enum_2_string (_snap_type));
2615 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2616 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2617 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2618 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2619 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2620 node->add_property ("edit-point", enum_2_string (_edit_point));
2621 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2622 node->add_property ("visible-track-count", buf);
2624 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2625 node->add_property ("playhead", buf);
2626 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2627 node->add_property ("left-frame", buf);
2628 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2629 node->add_property ("y-origin", buf);
2631 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2632 node->add_property ("maximised", _maximised ? "yes" : "no");
2633 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2634 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2635 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2636 node->add_property ("mouse-mode", enum2str(mouse_mode));
2637 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2639 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2641 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2642 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2645 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2647 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2648 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2651 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2652 node->add_property (X_("editor-list-page"), buf);
2654 if (button_bindings) {
2655 XMLNode* bb = new XMLNode (X_("Buttons"));
2656 button_bindings->save (*bb);
2657 node->add_child_nocopy (*bb);
2660 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2662 node->add_child_nocopy (selection->get_state ());
2663 node->add_child_nocopy (_regions->get_state ());
2665 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2666 node->add_property ("nudge-clock-value", buf);
2668 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2669 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2674 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2675 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2677 * @return pair: TimeAxisView that y is over, layer index.
2679 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2680 * in stacked or expanded region display mode, otherwise 0.
2682 std::pair<TimeAxisView *, double>
2683 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2685 if (!trackview_relative_offset) {
2686 y -= _trackview_group->canvas_origin().y;
2690 return std::make_pair ( (TimeAxisView *) 0, 0);
2693 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2695 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2702 return std::make_pair ( (TimeAxisView *) 0, 0);
2705 /** Snap a position to the grid, if appropriate, taking into account current
2706 * grid settings and also the state of any snap modifier keys that may be pressed.
2707 * @param start Position to snap.
2708 * @param event Event to get current key modifier information from, or 0.
2711 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2713 if (!_session || !event) {
2717 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2718 if (_snap_mode == SnapOff) {
2719 snap_to_internal (start, direction, for_mark);
2722 if (_snap_mode != SnapOff) {
2723 snap_to_internal (start, direction, for_mark);
2724 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2725 /* SnapOff, but we pressed the snap_delta modifier */
2726 snap_to_internal (start, direction, for_mark);
2732 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2734 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2738 snap_to_internal (start, direction, for_mark, ensure_snap);
2742 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2744 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2745 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2747 switch (_snap_type) {
2748 case SnapToTimecodeFrame:
2749 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2750 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2751 /* start is already on a whole timecode frame, do nothing */
2752 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2753 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2755 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2759 case SnapToTimecodeSeconds:
2760 if (_session->config.get_timecode_offset_negative()) {
2761 start += _session->config.get_timecode_offset ();
2763 start -= _session->config.get_timecode_offset ();
2765 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2766 (start % one_timecode_second == 0)) {
2767 /* start is already on a whole second, do nothing */
2768 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2769 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2771 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2774 if (_session->config.get_timecode_offset_negative()) {
2775 start -= _session->config.get_timecode_offset ();
2777 start += _session->config.get_timecode_offset ();
2781 case SnapToTimecodeMinutes:
2782 if (_session->config.get_timecode_offset_negative()) {
2783 start += _session->config.get_timecode_offset ();
2785 start -= _session->config.get_timecode_offset ();
2787 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2788 (start % one_timecode_minute == 0)) {
2789 /* start is already on a whole minute, do nothing */
2790 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2791 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2793 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2795 if (_session->config.get_timecode_offset_negative()) {
2796 start -= _session->config.get_timecode_offset ();
2798 start += _session->config.get_timecode_offset ();
2802 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2803 abort(); /*NOTREACHED*/
2808 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2810 const framepos_t one_second = _session->frame_rate();
2811 const framepos_t one_minute = _session->frame_rate() * 60;
2812 framepos_t presnap = start;
2816 switch (_snap_type) {
2817 case SnapToTimecodeFrame:
2818 case SnapToTimecodeSeconds:
2819 case SnapToTimecodeMinutes:
2820 return timecode_snap_to_internal (start, direction, for_mark);
2823 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2824 start % (one_second/75) == 0) {
2825 /* start is already on a whole CD frame, do nothing */
2826 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2827 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2829 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2834 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2835 start % one_second == 0) {
2836 /* start is already on a whole second, do nothing */
2837 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2838 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2840 start = (framepos_t) floor ((double) start / one_second) * one_second;
2845 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2846 start % one_minute == 0) {
2847 /* start is already on a whole minute, do nothing */
2848 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2849 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2851 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2856 start = _session->tempo_map().round_to_bar (start, direction);
2860 start = _session->tempo_map().round_to_beat (start, direction);
2863 case SnapToBeatDiv128:
2864 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2866 case SnapToBeatDiv64:
2867 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2869 case SnapToBeatDiv32:
2870 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2872 case SnapToBeatDiv28:
2873 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2875 case SnapToBeatDiv24:
2876 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2878 case SnapToBeatDiv20:
2879 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2881 case SnapToBeatDiv16:
2882 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2884 case SnapToBeatDiv14:
2885 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2887 case SnapToBeatDiv12:
2888 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2890 case SnapToBeatDiv10:
2891 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2893 case SnapToBeatDiv8:
2894 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2896 case SnapToBeatDiv7:
2897 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2899 case SnapToBeatDiv6:
2900 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2902 case SnapToBeatDiv5:
2903 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2905 case SnapToBeatDiv4:
2906 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2908 case SnapToBeatDiv3:
2909 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2911 case SnapToBeatDiv2:
2912 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2920 _session->locations()->marks_either_side (start, before, after);
2922 if (before == max_framepos && after == max_framepos) {
2923 /* No marks to snap to, so just don't snap */
2925 } else if (before == max_framepos) {
2927 } else if (after == max_framepos) {
2929 } else if (before != max_framepos && after != max_framepos) {
2930 /* have before and after */
2931 if ((start - before) < (after - start)) {
2940 case SnapToRegionStart:
2941 case SnapToRegionEnd:
2942 case SnapToRegionSync:
2943 case SnapToRegionBoundary:
2944 if (!region_boundary_cache.empty()) {
2946 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2947 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2949 if (direction > 0) {
2950 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2952 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2955 if (next != region_boundary_cache.begin ()) {
2960 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2961 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2963 if (start > (p + n) / 2) {
2972 switch (_snap_mode) {
2982 if (presnap > start) {
2983 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2987 } else if (presnap < start) {
2988 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2994 /* handled at entry */
3002 Editor::setup_toolbar ()
3004 HBox* mode_box = manage(new HBox);
3005 mode_box->set_border_width (2);
3006 mode_box->set_spacing(2);
3008 HBox* mouse_mode_box = manage (new HBox);
3009 HBox* mouse_mode_hbox = manage (new HBox);
3010 VBox* mouse_mode_vbox = manage (new VBox);
3011 Alignment* mouse_mode_align = manage (new Alignment);
3013 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3014 mouse_mode_size_group->add_widget (smart_mode_button);
3015 mouse_mode_size_group->add_widget (mouse_move_button);
3016 mouse_mode_size_group->add_widget (mouse_cut_button);
3017 mouse_mode_size_group->add_widget (mouse_select_button);
3018 mouse_mode_size_group->add_widget (mouse_timefx_button);
3019 mouse_mode_size_group->add_widget (mouse_audition_button);
3020 mouse_mode_size_group->add_widget (mouse_draw_button);
3021 mouse_mode_size_group->add_widget (mouse_content_button);
3023 mouse_mode_size_group->add_widget (zoom_in_button);
3024 mouse_mode_size_group->add_widget (zoom_out_button);
3025 mouse_mode_size_group->add_widget (zoom_preset_selector);
3026 mouse_mode_size_group->add_widget (zoom_out_full_button);
3027 mouse_mode_size_group->add_widget (zoom_focus_selector);
3029 mouse_mode_size_group->add_widget (tav_shrink_button);
3030 mouse_mode_size_group->add_widget (tav_expand_button);
3031 mouse_mode_size_group->add_widget (visible_tracks_selector);
3033 mouse_mode_size_group->add_widget (snap_type_selector);
3034 mouse_mode_size_group->add_widget (snap_mode_selector);
3036 mouse_mode_size_group->add_widget (edit_point_selector);
3037 mouse_mode_size_group->add_widget (edit_mode_selector);
3039 mouse_mode_size_group->add_widget (*nudge_clock);
3040 mouse_mode_size_group->add_widget (nudge_forward_button);
3041 mouse_mode_size_group->add_widget (nudge_backward_button);
3043 mouse_mode_hbox->set_spacing (2);
3045 if (!ARDOUR::Profile->get_trx()) {
3046 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3049 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3050 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3052 if (!ARDOUR::Profile->get_mixbus()) {
3053 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3056 if (!ARDOUR::Profile->get_trx()) {
3057 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3058 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3059 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3060 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3063 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3065 mouse_mode_align->add (*mouse_mode_vbox);
3066 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3068 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3070 edit_mode_selector.set_name ("mouse mode button");
3072 if (!ARDOUR::Profile->get_trx()) {
3073 mode_box->pack_start (edit_mode_selector, false, false);
3076 mode_box->pack_start (*mouse_mode_box, false, false);
3080 _zoom_box.set_spacing (2);
3081 _zoom_box.set_border_width (2);
3085 zoom_preset_selector.set_name ("zoom button");
3086 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3087 zoom_preset_selector.set_size_request (42, -1);
3089 zoom_in_button.set_name ("zoom button");
3090 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3091 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3092 zoom_in_button.set_related_action (act);
3094 zoom_out_button.set_name ("zoom button");
3095 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3096 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3097 zoom_out_button.set_related_action (act);
3099 zoom_out_full_button.set_name ("zoom button");
3100 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3101 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3102 zoom_out_full_button.set_related_action (act);
3104 zoom_focus_selector.set_name ("zoom button");
3106 if (ARDOUR::Profile->get_mixbus()) {
3107 _zoom_box.pack_start (zoom_preset_selector, false, false);
3108 } else if (ARDOUR::Profile->get_trx()) {
3109 mode_box->pack_start (zoom_out_button, false, false);
3110 mode_box->pack_start (zoom_in_button, false, false);
3112 _zoom_box.pack_start (zoom_out_button, false, false);
3113 _zoom_box.pack_start (zoom_in_button, false, false);
3114 _zoom_box.pack_start (zoom_out_full_button, false, false);
3115 _zoom_box.pack_start (zoom_focus_selector, false, false);
3118 /* Track zoom buttons */
3119 _track_box.set_spacing (2);
3120 _track_box.set_border_width (2);
3122 visible_tracks_selector.set_name ("zoom button");
3123 if (Profile->get_mixbus()) {
3124 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3125 visible_tracks_selector.set_size_request (42, -1);
3127 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3130 tav_expand_button.set_name ("zoom button");
3131 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3132 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3133 tav_expand_button.set_related_action (act);
3135 tav_shrink_button.set_name ("zoom button");
3136 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3137 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3138 tav_shrink_button.set_related_action (act);
3140 if (ARDOUR::Profile->get_mixbus()) {
3141 _track_box.pack_start (visible_tracks_selector);
3142 } else if (ARDOUR::Profile->get_trx()) {
3143 _track_box.pack_start (tav_shrink_button);
3144 _track_box.pack_start (tav_expand_button);
3146 _track_box.pack_start (visible_tracks_selector);
3147 _track_box.pack_start (tav_shrink_button);
3148 _track_box.pack_start (tav_expand_button);
3151 snap_box.set_spacing (2);
3152 snap_box.set_border_width (2);
3154 snap_type_selector.set_name ("mouse mode button");
3156 snap_mode_selector.set_name ("mouse mode button");
3158 edit_point_selector.set_name ("mouse mode button");
3160 snap_box.pack_start (snap_mode_selector, false, false);
3161 snap_box.pack_start (snap_type_selector, false, false);
3164 HBox *ep_box = manage (new HBox);
3165 ep_box->set_spacing (2);
3166 ep_box->set_border_width (2);
3168 ep_box->pack_start (edit_point_selector, false, false);
3172 HBox *nudge_box = manage (new HBox);
3173 nudge_box->set_spacing (2);
3174 nudge_box->set_border_width (2);
3176 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3177 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3179 nudge_box->pack_start (nudge_backward_button, false, false);
3180 nudge_box->pack_start (nudge_forward_button, false, false);
3181 nudge_box->pack_start (*nudge_clock, false, false);
3184 /* Pack everything in... */
3186 toolbar_hbox.set_spacing (2);
3187 toolbar_hbox.set_border_width (2);
3189 toolbar_hbox.pack_start (*mode_box, false, false);
3191 if (!ARDOUR::Profile->get_trx()) {
3194 EventBox *spacer = manage (new EventBox ()); spacer->set_size_request(3, 12);
3195 spacer->signal_expose_event().connect (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::spacer_expose), false); spacer->show();
3196 toolbar_hbox.pack_start (*spacer, false, false, 3);
3198 toolbar_hbox.pack_start (_zoom_box, false, false);
3201 spacer = manage (new EventBox ()); spacer->set_size_request(3, 12);
3202 spacer->signal_expose_event().connect (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::spacer_expose), false); spacer->show();
3203 toolbar_hbox.pack_start (*spacer, false, false, 3);
3205 toolbar_hbox.pack_start (_track_box, false, false);
3208 spacer = manage (new EventBox ()); spacer->set_size_request(3, 12);
3209 spacer->signal_expose_event().connect (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::spacer_expose), false); spacer->show();
3210 toolbar_hbox.pack_start (*spacer, false, false, 3);
3212 toolbar_hbox.pack_start (snap_box, false, false);
3215 spacer = manage (new EventBox ()); spacer->set_size_request(3, 12);
3216 spacer->signal_expose_event().connect (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::spacer_expose), false); spacer->show();
3217 toolbar_hbox.pack_start (*spacer, false, false, 3);
3219 toolbar_hbox.pack_start (*ep_box, false, false);
3222 spacer = manage (new EventBox ()); spacer->set_size_request(3, 12);
3223 spacer->signal_expose_event().connect (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::spacer_expose), false); spacer->show();
3224 toolbar_hbox.pack_start (*spacer, false, false, 3);
3226 toolbar_hbox.pack_start (*nudge_box, false, false);
3229 toolbar_hbox.show_all ();
3233 Editor::build_edit_point_menu ()
3235 using namespace Menu_Helpers;
3237 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3238 if(!Profile->get_mixbus())
3239 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3240 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3242 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3246 Editor::build_edit_mode_menu ()
3248 using namespace Menu_Helpers;
3250 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3251 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3252 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3253 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3255 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3259 Editor::build_snap_mode_menu ()
3261 using namespace Menu_Helpers;
3263 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3264 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3265 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3267 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3271 Editor::build_snap_type_menu ()
3273 using namespace Menu_Helpers;
3275 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3276 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3277 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3278 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3279 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3280 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3281 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3282 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3283 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3284 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3287 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3288 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3289 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3290 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3291 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3292 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3293 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3294 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3295 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3296 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3297 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3298 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3299 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3300 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3301 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3302 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3303 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3304 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3306 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3311 Editor::setup_tooltips ()
3313 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3314 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3315 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3316 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3317 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3318 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3319 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3320 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3321 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3322 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3323 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3324 set_tooltip (zoom_in_button, _("Zoom In"));
3325 set_tooltip (zoom_out_button, _("Zoom Out"));
3326 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3327 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3328 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3329 set_tooltip (tav_expand_button, _("Expand Tracks"));
3330 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3331 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3332 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3333 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3334 set_tooltip (edit_point_selector, _("Edit Point"));
3335 set_tooltip (edit_mode_selector, _("Edit Mode"));
3336 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3340 Editor::convert_drop_to_paths (
3341 vector<string>& paths,
3342 const RefPtr<Gdk::DragContext>& /*context*/,
3345 const SelectionData& data,
3349 if (_session == 0) {
3353 vector<string> uris = data.get_uris();
3357 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3358 are actually URI lists. So do it by hand.
3361 if (data.get_target() != "text/plain") {
3365 /* Parse the "uri-list" format that Nautilus provides,
3366 where each pathname is delimited by \r\n.
3368 THERE MAY BE NO NULL TERMINATING CHAR!!!
3371 string txt = data.get_text();
3375 p = (char *) malloc (txt.length() + 1);
3376 txt.copy (p, txt.length(), 0);
3377 p[txt.length()] = '\0';
3383 while (g_ascii_isspace (*p))
3387 while (*q && (*q != '\n') && (*q != '\r')) {
3394 while (q > p && g_ascii_isspace (*q))
3399 uris.push_back (string (p, q - p + 1));
3403 p = strchr (p, '\n');
3415 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3416 if ((*i).substr (0,7) == "file://") {
3417 paths.push_back (Glib::filename_from_uri (*i));
3425 Editor::new_tempo_section ()
3430 Editor::map_transport_state ()
3432 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3434 if (_session && _session->transport_stopped()) {
3435 have_pending_keyboard_selection = false;
3438 update_loop_range_view ();
3444 Editor::begin_selection_op_history ()
3446 selection_op_cmd_depth = 0;
3447 selection_op_history_it = 0;
3449 while(!selection_op_history.empty()) {
3450 delete selection_op_history.front();
3451 selection_op_history.pop_front();
3454 selection_undo_action->set_sensitive (false);
3455 selection_redo_action->set_sensitive (false);
3456 selection_op_history.push_front (&_selection_memento->get_state ());
3460 Editor::begin_reversible_selection_op (string name)
3463 //cerr << name << endl;
3464 /* begin/commit pairs can be nested */
3465 selection_op_cmd_depth++;
3470 Editor::commit_reversible_selection_op ()
3473 if (selection_op_cmd_depth == 1) {
3475 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3477 The user has undone some selection ops and then made a new one,
3478 making anything earlier in the list invalid.
3481 list<XMLNode *>::iterator it = selection_op_history.begin();
3482 list<XMLNode *>::iterator e_it = it;
3483 advance (e_it, selection_op_history_it);
3485 for ( ; it != e_it; ++it) {
3488 selection_op_history.erase (selection_op_history.begin(), e_it);
3491 selection_op_history.push_front (&_selection_memento->get_state ());
3492 selection_op_history_it = 0;
3494 selection_undo_action->set_sensitive (true);
3495 selection_redo_action->set_sensitive (false);
3498 if (selection_op_cmd_depth > 0) {
3499 selection_op_cmd_depth--;
3505 Editor::undo_selection_op ()
3508 selection_op_history_it++;
3510 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3511 if (n == selection_op_history_it) {
3512 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3513 selection_redo_action->set_sensitive (true);
3517 /* is there an earlier entry? */
3518 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3519 selection_undo_action->set_sensitive (false);
3525 Editor::redo_selection_op ()
3528 if (selection_op_history_it > 0) {
3529 selection_op_history_it--;
3532 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3533 if (n == selection_op_history_it) {
3534 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3535 selection_undo_action->set_sensitive (true);
3540 if (selection_op_history_it == 0) {
3541 selection_redo_action->set_sensitive (false);
3547 Editor::begin_reversible_command (string name)
3550 before.push_back (&_selection_memento->get_state ());
3551 _session->begin_reversible_command (name);
3556 Editor::begin_reversible_command (GQuark q)
3559 before.push_back (&_selection_memento->get_state ());
3560 _session->begin_reversible_command (q);
3565 Editor::abort_reversible_command ()
3568 while(!before.empty()) {
3569 delete before.front();
3572 _session->abort_reversible_command ();
3577 Editor::commit_reversible_command ()
3580 if (before.size() == 1) {
3581 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3582 redo_action->set_sensitive(false);
3583 undo_action->set_sensitive(true);
3584 begin_selection_op_history ();
3587 if (before.empty()) {
3588 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3593 _session->commit_reversible_command ();
3598 Editor::history_changed ()
3602 if (undo_action && _session) {
3603 if (_session->undo_depth() == 0) {
3604 label = S_("Command|Undo");
3606 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3608 undo_action->property_label() = label;
3611 if (redo_action && _session) {
3612 if (_session->redo_depth() == 0) {
3614 redo_action->set_sensitive (false);
3616 label = string_compose(_("Redo (%1)"), _session->next_redo());
3617 redo_action->set_sensitive (true);
3619 redo_action->property_label() = label;
3624 Editor::duplicate_range (bool with_dialog)
3628 RegionSelection rs = get_regions_from_selection_and_entered ();
3630 if ( selection->time.length() == 0 && rs.empty()) {
3636 ArdourDialog win (_("Duplicate"));
3637 Label label (_("Number of duplications:"));
3638 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3639 SpinButton spinner (adjustment, 0.0, 1);
3642 win.get_vbox()->set_spacing (12);
3643 win.get_vbox()->pack_start (hbox);
3644 hbox.set_border_width (6);
3645 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3647 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3648 place, visually. so do this by hand.
3651 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3652 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3653 spinner.grab_focus();
3659 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3660 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3661 win.set_default_response (RESPONSE_ACCEPT);
3663 spinner.grab_focus ();
3665 switch (win.run ()) {
3666 case RESPONSE_ACCEPT:
3672 times = adjustment.get_value();
3675 if ((current_mouse_mode() == Editing::MouseRange)) {
3676 if (selection->time.length()) {
3677 duplicate_selection (times);
3679 } else if (get_smart_mode()) {
3680 if (selection->time.length()) {
3681 duplicate_selection (times);
3683 duplicate_some_regions (rs, times);
3685 duplicate_some_regions (rs, times);
3690 Editor::set_edit_mode (EditMode m)
3692 Config->set_edit_mode (m);
3696 Editor::cycle_edit_mode ()
3698 switch (Config->get_edit_mode()) {
3700 Config->set_edit_mode (Ripple);
3704 Config->set_edit_mode (Lock);
3707 Config->set_edit_mode (Slide);
3713 Editor::edit_mode_selection_done ( EditMode m )
3715 Config->set_edit_mode ( m );
3719 Editor::snap_type_selection_done (SnapType snaptype)
3721 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3723 ract->set_active ();
3728 Editor::snap_mode_selection_done (SnapMode mode)
3730 RefPtr<RadioAction> ract = snap_mode_action (mode);
3733 ract->set_active (true);
3738 Editor::cycle_edit_point (bool with_marker)
3740 if(Profile->get_mixbus())
3741 with_marker = false;
3743 switch (_edit_point) {
3745 set_edit_point_preference (EditAtPlayhead);
3747 case EditAtPlayhead:
3749 set_edit_point_preference (EditAtSelectedMarker);
3751 set_edit_point_preference (EditAtMouse);
3754 case EditAtSelectedMarker:
3755 set_edit_point_preference (EditAtMouse);
3761 Editor::edit_point_selection_done (EditPoint ep)
3763 set_edit_point_preference ( ep );
3767 Editor::build_zoom_focus_menu ()
3769 using namespace Menu_Helpers;
3771 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3772 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3773 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3774 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3775 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3776 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3778 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3782 Editor::zoom_focus_selection_done ( ZoomFocus f )
3784 RefPtr<RadioAction> ract = zoom_focus_action (f);
3786 ract->set_active ();
3791 Editor::build_track_count_menu ()
3793 using namespace Menu_Helpers;
3795 if (!Profile->get_mixbus()) {
3796 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3797 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3798 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3799 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3800 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3801 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3802 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3803 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3804 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3805 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3806 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3807 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3808 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3810 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3811 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3812 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3813 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3814 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3815 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3816 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3817 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3818 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3819 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3821 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3822 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3823 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3824 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3825 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3826 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3827 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3828 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3829 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3830 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3831 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3836 Editor::set_zoom_preset (int64_t ms)
3839 temporal_zoom_session();
3843 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3844 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3848 Editor::set_visible_track_count (int32_t n)
3850 _visible_track_count = n;
3852 /* if the canvas hasn't really been allocated any size yet, just
3853 record the desired number of visible tracks and return. when canvas
3854 allocation happens, we will get called again and then we can do the
3858 if (_visible_canvas_height <= 1) {
3864 DisplaySuspender ds;
3866 if (_visible_track_count > 0) {
3867 h = trackviews_height() / _visible_track_count;
3868 std::ostringstream s;
3869 s << _visible_track_count;
3871 } else if (_visible_track_count == 0) {
3873 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3874 if ((*i)->marked_for_display()) {
3878 h = trackviews_height() / n;
3881 /* negative value means that the visible track count has
3882 been overridden by explicit track height changes.
3884 visible_tracks_selector.set_text (X_("*"));
3888 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3889 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3892 if (str != visible_tracks_selector.get_text()) {
3893 visible_tracks_selector.set_text (str);
3898 Editor::override_visible_track_count ()
3900 _visible_track_count = -1;
3901 visible_tracks_selector.set_text ( _("*") );
3905 Editor::edit_controls_button_release (GdkEventButton* ev)
3907 if (Keyboard::is_context_menu_event (ev)) {
3908 ARDOUR_UI::instance()->add_route ();
3909 } else if (ev->button == 1) {
3910 selection->clear_tracks ();
3917 Editor::mouse_select_button_release (GdkEventButton* ev)
3919 /* this handles just right-clicks */
3921 if (ev->button != 3) {
3929 Editor::set_zoom_focus (ZoomFocus f)
3931 string str = zoom_focus_strings[(int)f];
3933 if (str != zoom_focus_selector.get_text()) {
3934 zoom_focus_selector.set_text (str);
3937 if (zoom_focus != f) {
3944 Editor::cycle_zoom_focus ()
3946 switch (zoom_focus) {
3948 set_zoom_focus (ZoomFocusRight);
3950 case ZoomFocusRight:
3951 set_zoom_focus (ZoomFocusCenter);
3953 case ZoomFocusCenter:
3954 set_zoom_focus (ZoomFocusPlayhead);
3956 case ZoomFocusPlayhead:
3957 set_zoom_focus (ZoomFocusMouse);
3959 case ZoomFocusMouse:
3960 set_zoom_focus (ZoomFocusEdit);
3963 set_zoom_focus (ZoomFocusLeft);
3969 Editor::set_show_measures (bool yn)
3971 if (_show_measures != yn) {
3974 if ((_show_measures = yn) == true) {
3976 tempo_lines->show();
3979 std::vector<TempoMap::BBTPoint> grid;
3980 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3981 draw_measures (grid);
3989 Editor::toggle_follow_playhead ()
3991 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3993 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3994 set_follow_playhead (tact->get_active());
3998 /** @param yn true to follow playhead, otherwise false.
3999 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4002 Editor::set_follow_playhead (bool yn, bool catch_up)
4004 if (_follow_playhead != yn) {
4005 if ((_follow_playhead = yn) == true && catch_up) {
4007 reset_x_origin_to_follow_playhead ();
4014 Editor::toggle_stationary_playhead ()
4016 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4018 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4019 set_stationary_playhead (tact->get_active());
4024 Editor::set_stationary_playhead (bool yn)
4026 if (_stationary_playhead != yn) {
4027 if ((_stationary_playhead = yn) == true) {
4029 // FIXME need a 3.0 equivalent of this 2.X call
4030 // update_current_screen ();
4037 Editor::playlist_selector () const
4039 return *_playlist_selector;
4043 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4045 if (paste_count == 0) {
4046 /* don't bother calculating an offset that will be zero anyway */
4050 /* calculate basic unsnapped multi-paste offset */
4051 framecnt_t offset = paste_count * duration;
4053 /* snap offset so pos + offset is aligned to the grid */
4054 framepos_t offset_pos = pos + offset;
4055 snap_to(offset_pos, RoundUpMaybe);
4056 offset = offset_pos - pos;
4062 Editor::get_grid_beat_divisions(framepos_t position)
4064 switch (_snap_type) {
4065 case SnapToBeatDiv128: return 128;
4066 case SnapToBeatDiv64: return 64;
4067 case SnapToBeatDiv32: return 32;
4068 case SnapToBeatDiv28: return 28;
4069 case SnapToBeatDiv24: return 24;
4070 case SnapToBeatDiv20: return 20;
4071 case SnapToBeatDiv16: return 16;
4072 case SnapToBeatDiv14: return 14;
4073 case SnapToBeatDiv12: return 12;
4074 case SnapToBeatDiv10: return 10;
4075 case SnapToBeatDiv8: return 8;
4076 case SnapToBeatDiv7: return 7;
4077 case SnapToBeatDiv6: return 6;
4078 case SnapToBeatDiv5: return 5;
4079 case SnapToBeatDiv4: return 4;
4080 case SnapToBeatDiv3: return 3;
4081 case SnapToBeatDiv2: return 2;
4087 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4088 if the grid is non-musical, returns 0.
4089 if the grid is snapped to bars, returns -1.
4090 @param event_state the current keyboard modifier mask.
4093 Editor::get_grid_music_divisions (uint32_t event_state)
4095 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4099 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4103 switch (_snap_type) {
4104 case SnapToBeatDiv128: return 128;
4105 case SnapToBeatDiv64: return 64;
4106 case SnapToBeatDiv32: return 32;
4107 case SnapToBeatDiv28: return 28;
4108 case SnapToBeatDiv24: return 24;
4109 case SnapToBeatDiv20: return 20;
4110 case SnapToBeatDiv16: return 16;
4111 case SnapToBeatDiv14: return 14;
4112 case SnapToBeatDiv12: return 12;
4113 case SnapToBeatDiv10: return 10;
4114 case SnapToBeatDiv8: return 8;
4115 case SnapToBeatDiv7: return 7;
4116 case SnapToBeatDiv6: return 6;
4117 case SnapToBeatDiv5: return 5;
4118 case SnapToBeatDiv4: return 4;
4119 case SnapToBeatDiv3: return 3;
4120 case SnapToBeatDiv2: return 2;
4121 case SnapToBeat: return 1;
4122 case SnapToBar : return -1;
4129 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4133 const unsigned divisions = get_grid_beat_divisions(position);
4135 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4138 switch (_snap_type) {
4140 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4143 const Meter& m = _session->tempo_map().meter_at_frame (position);
4144 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4152 return Evoral::Beats();
4156 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4160 ret = nudge_clock->current_duration (pos);
4161 next = ret + 1; /* XXXX fix me */
4167 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4169 ArdourDialog dialog (_("Playlist Deletion"));
4170 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4171 "If it is kept, its audio files will not be cleaned.\n"
4172 "If it is deleted, audio files used by it alone will be cleaned."),
4175 dialog.set_position (WIN_POS_CENTER);
4176 dialog.get_vbox()->pack_start (label);
4180 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4181 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4182 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4183 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4184 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4186 // by default gtk uses the left most button
4187 keep->grab_focus ();
4189 switch (dialog.run ()) {
4191 /* keep this and all remaining ones */
4196 /* delete this and all others */
4200 case RESPONSE_ACCEPT:
4201 /* delete the playlist */
4205 case RESPONSE_REJECT:
4206 /* keep the playlist */
4218 Editor::audio_region_selection_covers (framepos_t where)
4220 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4221 if ((*a)->region()->covers (where)) {
4230 Editor::prepare_for_cleanup ()
4232 cut_buffer->clear_regions ();
4233 cut_buffer->clear_playlists ();
4235 selection->clear_regions ();
4236 selection->clear_playlists ();
4238 _regions->suspend_redisplay ();
4242 Editor::finish_cleanup ()
4244 _regions->resume_redisplay ();
4248 Editor::transport_loop_location()
4251 return _session->locations()->auto_loop_location();
4258 Editor::transport_punch_location()
4261 return _session->locations()->auto_punch_location();
4268 Editor::control_layout_scroll (GdkEventScroll* ev)
4270 /* Just forward to the normal canvas scroll method. The coordinate
4271 systems are different but since the canvas is always larger than the
4272 track headers, and aligned with the trackview area, this will work.
4274 In the not too distant future this layout is going away anyway and
4275 headers will be on the canvas.
4277 return canvas_scroll_event (ev, false);
4281 Editor::session_state_saved (string)
4284 _snapshots->redisplay ();
4288 Editor::maximise_editing_space ()
4294 Gtk::Window* toplevel = current_toplevel();
4297 toplevel->fullscreen ();
4303 Editor::restore_editing_space ()
4309 Gtk::Window* toplevel = current_toplevel();
4312 toplevel->unfullscreen();
4318 * Make new playlists for a given track and also any others that belong
4319 * to the same active route group with the `select' property.
4324 Editor::new_playlists (TimeAxisView* v)
4326 begin_reversible_command (_("new playlists"));
4327 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4328 _session->playlists->get (playlists);
4329 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4330 commit_reversible_command ();
4334 * Use a copy of the current playlist for a given track and also any others that belong
4335 * to the same active route group with the `select' property.
4340 Editor::copy_playlists (TimeAxisView* v)
4342 begin_reversible_command (_("copy playlists"));
4343 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4344 _session->playlists->get (playlists);
4345 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4346 commit_reversible_command ();
4349 /** Clear the current playlist for a given track and also any others that belong
4350 * to the same active route group with the `select' property.
4355 Editor::clear_playlists (TimeAxisView* v)
4357 begin_reversible_command (_("clear playlists"));
4358 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4359 _session->playlists->get (playlists);
4360 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4361 commit_reversible_command ();
4365 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4367 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4371 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4373 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4377 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4379 atv.clear_playlist ();
4383 Editor::get_y_origin () const
4385 return vertical_adjustment.get_value ();
4388 /** Queue up a change to the viewport x origin.
4389 * @param frame New x origin.
4392 Editor::reset_x_origin (framepos_t frame)
4394 pending_visual_change.add (VisualChange::TimeOrigin);
4395 pending_visual_change.time_origin = frame;
4396 ensure_visual_change_idle_handler ();
4400 Editor::reset_y_origin (double y)
4402 pending_visual_change.add (VisualChange::YOrigin);
4403 pending_visual_change.y_origin = y;
4404 ensure_visual_change_idle_handler ();
4408 Editor::reset_zoom (framecnt_t spp)
4410 if (spp == samples_per_pixel) {
4414 pending_visual_change.add (VisualChange::ZoomLevel);
4415 pending_visual_change.samples_per_pixel = spp;
4416 ensure_visual_change_idle_handler ();
4420 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4422 reset_x_origin (frame);
4425 if (!no_save_visual) {
4426 undo_visual_stack.push_back (current_visual_state(false));
4430 Editor::VisualState::VisualState (bool with_tracks)
4431 : gui_state (with_tracks ? new GUIObjectState : 0)
4435 Editor::VisualState::~VisualState ()
4440 Editor::VisualState*
4441 Editor::current_visual_state (bool with_tracks)
4443 VisualState* vs = new VisualState (with_tracks);
4444 vs->y_position = vertical_adjustment.get_value();
4445 vs->samples_per_pixel = samples_per_pixel;
4446 vs->leftmost_frame = leftmost_frame;
4447 vs->zoom_focus = zoom_focus;
4450 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4457 Editor::undo_visual_state ()
4459 if (undo_visual_stack.empty()) {
4463 VisualState* vs = undo_visual_stack.back();
4464 undo_visual_stack.pop_back();
4467 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4470 use_visual_state (*vs);
4475 Editor::redo_visual_state ()
4477 if (redo_visual_stack.empty()) {
4481 VisualState* vs = redo_visual_stack.back();
4482 redo_visual_stack.pop_back();
4484 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4485 // why do we check here?
4486 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4489 use_visual_state (*vs);
4494 Editor::swap_visual_state ()
4496 if (undo_visual_stack.empty()) {
4497 redo_visual_state ();
4499 undo_visual_state ();
4504 Editor::use_visual_state (VisualState& vs)
4506 PBD::Unwinder<bool> nsv (no_save_visual, true);
4507 DisplaySuspender ds;
4509 vertical_adjustment.set_value (vs.y_position);
4511 set_zoom_focus (vs.zoom_focus);
4512 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4515 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4517 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4518 (*i)->clear_property_cache();
4519 (*i)->reset_visual_state ();
4523 _routes->update_visibility ();
4526 /** This is the core function that controls the zoom level of the canvas. It is called
4527 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4528 * @param spp new number of samples per pixel
4531 Editor::set_samples_per_pixel (framecnt_t spp)
4537 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4538 const framecnt_t lots_of_pixels = 4000;
4540 /* if the zoom level is greater than what you'd get trying to display 3
4541 * days of audio on a really big screen, then it's too big.
4544 if (spp * lots_of_pixels > three_days) {
4548 samples_per_pixel = spp;
4551 tempo_lines->tempo_map_changed();
4554 bool const showing_time_selection = selection->time.length() > 0;
4556 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4557 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4558 (*i)->reshow_selection (selection->time);
4562 ZoomChanged (); /* EMIT_SIGNAL */
4564 ArdourCanvas::GtkCanvasViewport* c;
4566 c = get_track_canvas();
4568 c->canvas()->zoomed ();
4571 if (playhead_cursor) {
4572 playhead_cursor->set_position (playhead_cursor->current_frame ());
4575 refresh_location_display();
4576 _summary->set_overlays_dirty ();
4578 update_marker_labels ();
4584 Editor::playhead_cursor_sample () const
4586 return playhead_cursor->current_frame();
4590 Editor::queue_visual_videotimeline_update ()
4593 * pending_visual_change.add (VisualChange::VideoTimeline);
4594 * or maybe even more specific: which videotimeline-image
4595 * currently it calls update_video_timeline() to update
4596 * _all outdated_ images on the video-timeline.
4597 * see 'exposeimg()' in video_image_frame.cc
4599 ensure_visual_change_idle_handler ();
4603 Editor::ensure_visual_change_idle_handler ()
4605 if (pending_visual_change.idle_handler_id < 0) {
4606 // see comment in add_to_idle_resize above.
4607 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4608 pending_visual_change.being_handled = false;
4613 Editor::_idle_visual_changer (void* arg)
4615 return static_cast<Editor*>(arg)->idle_visual_changer ();
4619 Editor::idle_visual_changer ()
4621 /* set_horizontal_position() below (and maybe other calls) call
4622 gtk_main_iteration(), so it's possible that a signal will be handled
4623 half-way through this method. If this signal wants an
4624 idle_visual_changer we must schedule another one after this one, so
4625 mark the idle_handler_id as -1 here to allow that. Also make a note
4626 that we are doing the visual change, so that changes in response to
4627 super-rapid-screen-update can be dropped if we are still processing
4631 pending_visual_change.idle_handler_id = -1;
4632 pending_visual_change.being_handled = true;
4634 VisualChange vc = pending_visual_change;
4636 pending_visual_change.pending = (VisualChange::Type) 0;
4638 visual_changer (vc);
4640 pending_visual_change.being_handled = false;
4642 return 0; /* this is always a one-shot call */
4646 Editor::visual_changer (const VisualChange& vc)
4648 double const last_time_origin = horizontal_position ();
4650 if (vc.pending & VisualChange::ZoomLevel) {
4651 set_samples_per_pixel (vc.samples_per_pixel);
4653 compute_fixed_ruler_scale ();
4655 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4656 update_tempo_based_rulers ();
4658 update_video_timeline();
4661 if (vc.pending & VisualChange::TimeOrigin) {
4662 set_horizontal_position (vc.time_origin / samples_per_pixel);
4665 if (vc.pending & VisualChange::YOrigin) {
4666 vertical_adjustment.set_value (vc.y_origin);
4669 if (last_time_origin == horizontal_position ()) {
4670 /* changed signal not emitted */
4671 update_fixed_rulers ();
4672 redisplay_tempo (true);
4675 if (!(vc.pending & VisualChange::ZoomLevel)) {
4676 update_video_timeline();
4679 _summary->set_overlays_dirty ();
4682 struct EditorOrderTimeAxisSorter {
4683 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4684 return a->order () < b->order ();
4689 Editor::sort_track_selection (TrackViewList& sel)
4691 EditorOrderTimeAxisSorter cmp;
4696 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4699 framepos_t where = 0;
4700 EditPoint ep = _edit_point;
4702 if (Profile->get_mixbus()) {
4703 if (ep == EditAtSelectedMarker) {
4704 ep = EditAtPlayhead;
4708 if (from_outside_canvas && (ep == EditAtMouse)) {
4709 ep = EditAtPlayhead;
4710 } else if (from_context_menu && (ep == EditAtMouse)) {
4711 return canvas_event_sample (&context_click_event, 0, 0);
4714 if (entered_marker) {
4715 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4716 return entered_marker->position();
4719 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4720 ep = EditAtSelectedMarker;
4723 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4724 ep = EditAtPlayhead;
4728 case EditAtPlayhead:
4729 if (_dragging_playhead) {
4730 where = *_control_scroll_target;
4732 where = _session->audible_frame();
4734 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4737 case EditAtSelectedMarker:
4738 if (!selection->markers.empty()) {
4740 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4743 where = loc->start();
4747 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4755 if (!mouse_frame (where, ignored)) {
4756 /* XXX not right but what can we do ? */
4760 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4768 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4770 if (!_session) return;
4772 begin_reversible_command (cmd);
4776 if ((tll = transport_loop_location()) == 0) {
4777 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4778 XMLNode &before = _session->locations()->get_state();
4779 _session->locations()->add (loc, true);
4780 _session->set_auto_loop_location (loc);
4781 XMLNode &after = _session->locations()->get_state();
4782 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4784 XMLNode &before = tll->get_state();
4785 tll->set_hidden (false, this);
4786 tll->set (start, end);
4787 XMLNode &after = tll->get_state();
4788 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4791 commit_reversible_command ();
4795 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4797 if (!_session) return;
4799 begin_reversible_command (cmd);
4803 if ((tpl = transport_punch_location()) == 0) {
4804 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4805 XMLNode &before = _session->locations()->get_state();
4806 _session->locations()->add (loc, true);
4807 _session->set_auto_punch_location (loc);
4808 XMLNode &after = _session->locations()->get_state();
4809 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4811 XMLNode &before = tpl->get_state();
4812 tpl->set_hidden (false, this);
4813 tpl->set (start, end);
4814 XMLNode &after = tpl->get_state();
4815 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4818 commit_reversible_command ();
4821 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4822 * @param rs List to which found regions are added.
4823 * @param where Time to look at.
4824 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4827 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4829 const TrackViewList* tracks;
4832 tracks = &track_views;
4837 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4839 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4842 boost::shared_ptr<Track> tr;
4843 boost::shared_ptr<Playlist> pl;
4845 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4847 boost::shared_ptr<RegionList> regions = pl->regions_at (
4848 (framepos_t) floor ( (double) where * tr->speed()));
4850 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4851 RegionView* rv = rtv->view()->find_view (*i);
4862 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4864 const TrackViewList* tracks;
4867 tracks = &track_views;
4872 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4873 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4875 boost::shared_ptr<Track> tr;
4876 boost::shared_ptr<Playlist> pl;
4878 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4880 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4881 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4883 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4885 RegionView* rv = rtv->view()->find_view (*i);
4896 /** Get regions using the following method:
4898 * Make a region list using:
4899 * (a) any selected regions
4900 * (b) the intersection of any selected tracks and the edit point(*)
4901 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4903 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4905 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4909 Editor::get_regions_from_selection_and_edit_point ()
4911 RegionSelection regions;
4913 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4914 regions.add (entered_regionview);
4916 regions = selection->regions;
4919 if ( regions.empty() ) {
4920 TrackViewList tracks = selection->tracks;
4922 if (!tracks.empty()) {
4923 /* no region selected or entered, but some selected tracks:
4924 * act on all regions on the selected tracks at the edit point
4926 framepos_t const where = get_preferred_edit_position ();
4927 get_regions_at(regions, where, tracks);
4934 /** Get regions using the following method:
4936 * Make a region list using:
4937 * (a) any selected regions
4938 * (b) the intersection of any selected tracks and the edit point(*)
4939 * (c) if neither exists, then whatever region is under the mouse
4941 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4943 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4946 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4948 RegionSelection regions;
4950 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4951 regions.add (entered_regionview);
4953 regions = selection->regions;
4956 if ( regions.empty() ) {
4957 TrackViewList tracks = selection->tracks;
4959 if (!tracks.empty()) {
4960 /* no region selected or entered, but some selected tracks:
4961 * act on all regions on the selected tracks at the edit point
4963 get_regions_at(regions, pos, tracks);
4970 /** Start with regions that are selected, or the entered regionview if none are selected.
4971 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4972 * of the regions that we started with.
4976 Editor::get_regions_from_selection_and_entered () const
4978 RegionSelection regions = selection->regions;
4980 if (regions.empty() && entered_regionview) {
4981 regions.add (entered_regionview);
4988 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4990 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4991 RouteTimeAxisView* rtav;
4993 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4994 boost::shared_ptr<Playlist> pl;
4995 std::vector<boost::shared_ptr<Region> > results;
4996 boost::shared_ptr<Track> tr;
4998 if ((tr = rtav->track()) == 0) {
5003 if ((pl = (tr->playlist())) != 0) {
5004 boost::shared_ptr<Region> r = pl->region_by_id (id);
5006 RegionView* rv = rtav->view()->find_view (r);
5008 regions.push_back (rv);
5017 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5020 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5021 MidiTimeAxisView* mtav;
5023 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5025 mtav->get_per_region_note_selection (selection);
5032 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5034 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5036 RouteTimeAxisView* tatv;
5038 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5040 boost::shared_ptr<Playlist> pl;
5041 vector<boost::shared_ptr<Region> > results;
5043 boost::shared_ptr<Track> tr;
5045 if ((tr = tatv->track()) == 0) {
5050 if ((pl = (tr->playlist())) != 0) {
5051 if (src_comparison) {
5052 pl->get_source_equivalent_regions (region, results);
5054 pl->get_region_list_equivalent_regions (region, results);
5058 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5059 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5060 regions.push_back (marv);
5069 Editor::show_rhythm_ferret ()
5071 if (rhythm_ferret == 0) {
5072 rhythm_ferret = new RhythmFerret(*this);
5075 rhythm_ferret->set_session (_session);
5076 rhythm_ferret->show ();
5077 rhythm_ferret->present ();
5081 Editor::first_idle ()
5083 MessageDialog* dialog = 0;
5085 if (track_views.size() > 1) {
5086 Timers::TimerSuspender t;
5087 dialog = new MessageDialog (
5088 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5092 ARDOUR_UI::instance()->flush_pending (60);
5095 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5099 // first idle adds route children (automation tracks), so we need to redisplay here
5100 _routes->redisplay ();
5104 if (_session->undo_depth() == 0) {
5105 undo_action->set_sensitive(false);
5107 redo_action->set_sensitive(false);
5108 begin_selection_op_history ();
5114 Editor::_idle_resize (gpointer arg)
5116 return ((Editor*)arg)->idle_resize ();
5120 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5122 if (resize_idle_id < 0) {
5123 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5124 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5125 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5127 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5128 _pending_resize_amount = 0;
5131 /* make a note of the smallest resulting height, so that we can clamp the
5132 lower limit at TimeAxisView::hSmall */
5134 int32_t min_resulting = INT32_MAX;
5136 _pending_resize_amount += h;
5137 _pending_resize_view = view;
5139 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5141 if (selection->tracks.contains (_pending_resize_view)) {
5142 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5143 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5147 if (min_resulting < 0) {
5152 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5153 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5157 /** Handle pending resizing of tracks */
5159 Editor::idle_resize ()
5161 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5163 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5164 selection->tracks.contains (_pending_resize_view)) {
5166 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5167 if (*i != _pending_resize_view) {
5168 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5173 _pending_resize_amount = 0;
5174 _group_tabs->set_dirty ();
5175 resize_idle_id = -1;
5183 ENSURE_GUI_THREAD (*this, &Editor::located);
5186 playhead_cursor->set_position (_session->audible_frame ());
5187 if (_follow_playhead && !_pending_initial_locate) {
5188 reset_x_origin_to_follow_playhead ();
5192 _pending_locate_request = false;
5193 _pending_initial_locate = false;
5197 Editor::region_view_added (RegionView * rv)
5199 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5200 if (rv->region ()->id () == (*pr)) {
5201 selection->add (rv);
5202 selection->regions.pending.erase (pr);
5207 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5209 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5210 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5211 if (rv->region()->id () == (*rnote).first) {
5212 mrv->select_notes ((*rnote).second);
5213 selection->pending_midi_note_selection.erase(rnote);
5219 _summary->set_background_dirty ();
5223 Editor::region_view_removed ()
5225 _summary->set_background_dirty ();
5229 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5231 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5232 if ((*j)->stripable() == s) {
5242 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5246 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5247 TimeAxisView* tv = axis_view_from_stripable (*i);
5257 Editor::suspend_route_redisplay ()
5260 _routes->suspend_redisplay();
5265 Editor::resume_route_redisplay ()
5268 _routes->redisplay(); // queue redisplay
5269 _routes->resume_redisplay();
5274 Editor::add_vcas (VCAList& vlist)
5278 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5279 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5282 add_stripables (sl);
5286 Editor::add_routes (RouteList& rlist)
5290 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5294 add_stripables (sl);
5298 Editor::add_stripables (StripableList& sl)
5300 list<TimeAxisView*> new_views;
5301 boost::shared_ptr<VCA> v;
5302 boost::shared_ptr<Route> r;
5303 TrackViewList new_selection;
5304 bool from_scratch = (track_views.size() == 0);
5306 sl.sort (StripablePresentationInfoSorter());
5308 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5310 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5312 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5314 new_views.push_back (vtv);
5316 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5318 if (r->is_auditioner() || r->is_monitor()) {
5322 RouteTimeAxisView* rtv;
5323 DataType dt = r->input()->default_type();
5325 if (dt == ARDOUR::DataType::AUDIO) {
5326 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5328 } else if (dt == ARDOUR::DataType::MIDI) {
5329 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5332 throw unknown_type();
5335 new_views.push_back (rtv);
5336 track_views.push_back (rtv);
5337 new_selection.push_back (rtv);
5339 rtv->effective_gain_display ();
5341 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5342 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5346 if (new_views.size() > 0) {
5347 _routes->time_axis_views_added (new_views);
5348 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5351 /* note: !new_selection.empty() means that we got some routes rather
5355 if (!from_scratch && !new_selection.empty()) {
5356 selection->tracks.clear();
5357 selection->add (new_selection);
5358 begin_selection_op_history();
5361 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5362 show_editor_mixer (true);
5365 editor_list_button.set_sensitive (true);
5369 Editor::timeaxisview_deleted (TimeAxisView *tv)
5371 if (tv == entered_track) {
5375 if (_session && _session->deletion_in_progress()) {
5376 /* the situation is under control */
5380 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5382 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5384 _routes->route_removed (tv);
5386 TimeAxisView::Children c = tv->get_child_list ();
5387 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5388 if (entered_track == i->get()) {
5393 /* remove it from the list of track views */
5395 TrackViewList::iterator i;
5397 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5398 i = track_views.erase (i);
5401 /* update whatever the current mixer strip is displaying, if revelant */
5403 boost::shared_ptr<Route> route;
5406 route = rtav->route ();
5409 if (current_mixer_strip && current_mixer_strip->route() == route) {
5411 TimeAxisView* next_tv;
5413 if (track_views.empty()) {
5415 } else if (i == track_views.end()) {
5416 next_tv = track_views.front();
5423 set_selected_mixer_strip (*next_tv);
5425 /* make the editor mixer strip go away setting the
5426 * button to inactive (which also unticks the menu option)
5429 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5435 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5437 if (apply_to_selection) {
5438 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5440 TrackSelection::iterator j = i;
5443 hide_track_in_display (*i, false);
5448 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5450 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5451 // this will hide the mixer strip
5452 set_selected_mixer_strip (*tv);
5455 _routes->hide_track_in_display (*tv);
5460 Editor::sync_track_view_list_and_routes ()
5462 track_views = TrackViewList (_routes->views ());
5464 _summary->set_background_dirty();
5465 _group_tabs->set_dirty ();
5467 return false; // do not call again (until needed)
5471 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5473 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5478 /** Find a RouteTimeAxisView by the ID of its route */
5480 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5482 RouteTimeAxisView* v;
5484 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5485 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5486 if(v->route()->id() == id) {
5496 Editor::fit_route_group (RouteGroup *g)
5498 TrackViewList ts = axis_views_from_routes (g->route_list ());
5503 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5505 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5508 _session->cancel_audition ();
5512 if (_session->is_auditioning()) {
5513 _session->cancel_audition ();
5514 if (r == last_audition_region) {
5519 _session->audition_region (r);
5520 last_audition_region = r;
5525 Editor::hide_a_region (boost::shared_ptr<Region> r)
5527 r->set_hidden (true);
5531 Editor::show_a_region (boost::shared_ptr<Region> r)
5533 r->set_hidden (false);
5537 Editor::audition_region_from_region_list ()
5539 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5543 Editor::hide_region_from_region_list ()
5545 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5549 Editor::show_region_in_region_list ()
5551 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5555 Editor::step_edit_status_change (bool yn)
5558 start_step_editing ();
5560 stop_step_editing ();
5565 Editor::start_step_editing ()
5567 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5571 Editor::stop_step_editing ()
5573 step_edit_connection.disconnect ();
5577 Editor::check_step_edit ()
5579 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5580 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5582 mtv->check_step_edit ();
5586 return true; // do it again, till we stop
5590 Editor::scroll_press (Direction dir)
5592 ++_scroll_callbacks;
5594 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5595 /* delay the first auto-repeat */
5601 scroll_backward (1);
5609 scroll_up_one_track ();
5613 scroll_down_one_track ();
5617 /* do hacky auto-repeat */
5618 if (!_scroll_connection.connected ()) {
5620 _scroll_connection = Glib::signal_timeout().connect (
5621 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5624 _scroll_callbacks = 0;
5631 Editor::scroll_release ()
5633 _scroll_connection.disconnect ();
5636 /** Queue a change for the Editor viewport x origin to follow the playhead */
5638 Editor::reset_x_origin_to_follow_playhead ()
5640 framepos_t const frame = playhead_cursor->current_frame ();
5642 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5644 if (_session->transport_speed() < 0) {
5646 if (frame > (current_page_samples() / 2)) {
5647 center_screen (frame-(current_page_samples()/2));
5649 center_screen (current_page_samples()/2);
5656 if (frame < leftmost_frame) {
5658 if (_session->transport_rolling()) {
5659 /* rolling; end up with the playhead at the right of the page */
5660 l = frame - current_page_samples ();
5662 /* not rolling: end up with the playhead 1/4 of the way along the page */
5663 l = frame - current_page_samples() / 4;
5667 if (_session->transport_rolling()) {
5668 /* rolling: end up with the playhead on the left of the page */
5671 /* not rolling: end up with the playhead 3/4 of the way along the page */
5672 l = frame - 3 * current_page_samples() / 4;
5680 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5686 Editor::super_rapid_screen_update ()
5688 if (!_session || !_session->engine().running()) {
5692 /* METERING / MIXER STRIPS */
5694 /* update track meters, if required */
5695 if (contents().is_mapped() && meters_running) {
5696 RouteTimeAxisView* rtv;
5697 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5698 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5699 rtv->fast_update ();
5704 /* and any current mixer strip */
5705 if (current_mixer_strip) {
5706 current_mixer_strip->fast_update ();
5709 /* PLAYHEAD AND VIEWPORT */
5711 framepos_t const frame = _session->audible_frame();
5713 /* There are a few reasons why we might not update the playhead / viewport stuff:
5715 * 1. we don't update things when there's a pending locate request, otherwise
5716 * when the editor requests a locate there is a chance that this method
5717 * will move the playhead before the locate request is processed, causing
5719 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5720 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5723 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5725 last_update_frame = frame;
5727 if (!_dragging_playhead) {
5728 playhead_cursor->set_position (frame);
5731 if (!_stationary_playhead) {
5733 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5734 /* We only do this if we aren't already
5735 handling a visual change (ie if
5736 pending_visual_change.being_handled is
5737 false) so that these requests don't stack
5738 up there are too many of them to handle in
5741 reset_x_origin_to_follow_playhead ();
5746 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5747 framepos_t const frame = playhead_cursor->current_frame ();
5748 double target = ((double)frame - (double)current_page_samples()/2.0);
5749 if (target <= 0.0) {
5752 // compare to EditorCursor::set_position()
5753 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5754 double const new_pos = sample_to_pixel_unrounded (target);
5755 if (rint (new_pos) != rint (old_pos)) {
5756 reset_x_origin (pixel_to_sample (floor (new_pos)));
5767 Editor::session_going_away ()
5769 _have_idled = false;
5771 _session_connections.drop_connections ();
5773 super_rapid_screen_update_connection.disconnect ();
5775 selection->clear ();
5776 cut_buffer->clear ();
5778 clicked_regionview = 0;
5779 clicked_axisview = 0;
5780 clicked_routeview = 0;
5781 entered_regionview = 0;
5783 last_update_frame = 0;
5786 playhead_cursor->hide ();
5788 /* rip everything out of the list displays */
5792 _route_groups->clear ();
5794 /* do this first so that deleting a track doesn't reset cms to null
5795 and thus cause a leak.
5798 if (current_mixer_strip) {
5799 if (current_mixer_strip->get_parent() != 0) {
5800 global_hpacker.remove (*current_mixer_strip);
5802 delete current_mixer_strip;
5803 current_mixer_strip = 0;
5806 /* delete all trackviews */
5808 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5811 track_views.clear ();
5813 nudge_clock->set_session (0);
5815 editor_list_button.set_active(false);
5816 editor_list_button.set_sensitive(false);
5818 /* clear tempo/meter rulers */
5819 remove_metric_marks ();
5821 clear_marker_display ();
5823 stop_step_editing ();
5827 /* get rid of any existing editor mixer strip */
5829 WindowTitle title(Glib::get_application_name());
5830 title += _("Editor");
5832 own_window()->set_title (title.get_string());
5835 SessionHandlePtr::session_going_away ();
5839 Editor::trigger_script (int i)
5841 LuaInstance::instance()-> call_action (i);
5845 Editor::set_script_action_name (int i, const std::string& n)
5847 string const a = string_compose (X_("script-action-%1"), i + 1);
5848 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5851 act->set_label (string_compose (_("Unset #%1"), i + 1));
5852 act->set_tooltip (_("no action bound"));
5853 act->set_sensitive (false);
5856 act->set_tooltip (n);
5857 act->set_sensitive (true);
5859 KeyEditor::UpdateBindings ();
5863 Editor::show_editor_list (bool yn)
5866 _the_notebook.show ();
5868 _the_notebook.hide ();
5873 Editor::change_region_layering_order (bool from_context_menu)
5875 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5877 if (!clicked_routeview) {
5878 if (layering_order_editor) {
5879 layering_order_editor->hide ();
5884 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5890 boost::shared_ptr<Playlist> pl = track->playlist();
5896 if (layering_order_editor == 0) {
5897 layering_order_editor = new RegionLayeringOrderEditor (*this);
5900 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5901 layering_order_editor->maybe_present ();
5905 Editor::update_region_layering_order_editor ()
5907 if (layering_order_editor && layering_order_editor->is_visible ()) {
5908 change_region_layering_order (true);
5913 Editor::setup_fade_images ()
5915 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5916 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5917 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5918 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5919 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5921 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5922 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5923 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5924 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5925 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5927 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5928 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5929 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5930 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5931 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5933 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5934 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5935 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5936 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5937 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5941 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5943 Editor::action_menu_item (std::string const & name)
5945 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5948 return *manage (a->create_menu_item ());
5952 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5954 EventBox* b = manage (new EventBox);
5955 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5956 Label* l = manage (new Label (name));
5960 _the_notebook.append_page (widget, *b);
5964 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5966 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5967 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5970 if (ev->type == GDK_2BUTTON_PRESS) {
5972 /* double-click on a notebook tab shrinks or expands the notebook */
5974 if (_notebook_shrunk) {
5975 if (pre_notebook_shrink_pane_width) {
5976 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5978 _notebook_shrunk = false;
5980 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5982 /* this expands the LHS of the edit pane to cover the notebook
5983 PAGE but leaves the tabs visible.
5985 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5986 _notebook_shrunk = true;
5994 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5996 using namespace Menu_Helpers;
5998 MenuList& items = _control_point_context_menu.items ();
6001 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6002 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6003 if (!can_remove_control_point (item)) {
6004 items.back().set_sensitive (false);
6007 _control_point_context_menu.popup (event->button.button, event->button.time);
6011 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6013 using namespace Menu_Helpers;
6015 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6020 /* We need to get the selection here and pass it to the operations, since
6021 popping up the menu will cause a region leave event which clears
6022 entered_regionview. */
6024 MidiRegionView& mrv = note->region_view();
6025 const RegionSelection rs = get_regions_from_selection_and_entered ();
6026 const uint32_t sel_size = mrv.selection_size ();
6028 MenuList& items = _note_context_menu.items();
6032 items.push_back(MenuElem(_("Delete"),
6033 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6036 items.push_back(MenuElem(_("Edit..."),
6037 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6038 if (sel_size != 1) {
6039 items.back().set_sensitive (false);
6042 items.push_back(MenuElem(_("Transpose..."),
6043 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6046 items.push_back(MenuElem(_("Legatize"),
6047 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6049 items.back().set_sensitive (false);
6052 items.push_back(MenuElem(_("Quantize..."),
6053 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6055 items.push_back(MenuElem(_("Remove Overlap"),
6056 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6058 items.back().set_sensitive (false);
6061 items.push_back(MenuElem(_("Transform..."),
6062 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6064 _note_context_menu.popup (event->button.button, event->button.time);
6068 Editor::zoom_vertical_modifier_released()
6070 _stepping_axis_view = 0;
6074 Editor::ui_parameter_changed (string parameter)
6076 if (parameter == "icon-set") {
6077 while (!_cursor_stack.empty()) {
6078 _cursor_stack.pop_back();
6080 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6081 _cursor_stack.push_back(_cursors->grabber);
6082 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6083 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6085 } else if (parameter == "draggable-playhead") {
6086 if (_verbose_cursor) {
6087 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6093 Editor::use_own_window (bool and_fill_it)
6095 bool new_window = !own_window();
6097 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6099 if (win && new_window) {
6100 win->set_name ("EditorWindow");
6102 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6104 // win->signal_realize().connect (*this, &Editor::on_realize);
6105 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6106 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6107 win->set_data ("ardour-bindings", bindings);
6112 DisplaySuspender ds;
6113 contents().show_all ();
6115 /* XXX: this is a bit unfortunate; it would probably
6116 be nicer if we could just call show () above rather
6117 than needing the show_all ()
6120 /* re-hide stuff if necessary */
6121 editor_list_button_toggled ();
6122 parameter_changed ("show-summary");
6123 parameter_changed ("show-group-tabs");
6124 parameter_changed ("show-zoom-tools");
6126 /* now reset all audio_time_axis heights, because widgets might need
6132 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6133 tv = (static_cast<TimeAxisView*>(*i));
6134 tv->reset_height ();
6137 if (current_mixer_strip) {
6138 current_mixer_strip->hide_things ();
6139 current_mixer_strip->parameter_changed ("mixer-element-visibility");