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/gtk_ui.h"
61 #include "gtkmm2ext/keyboard.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
66 #include "ardour/analysis_graph.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
78 #include "ardour/vca_manager.h"
79 #include "ardour/vca.h"
81 #include "canvas/debug.h"
82 #include "canvas/text.h"
84 #include "widgets/ardour_spacer.h"
85 #include "widgets/eventboxext.h"
86 #include "widgets/tooltips.h"
88 #include "control_protocol/control_protocol.h"
91 #include "analysis_window.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
101 #include "editing_convert.h"
103 #include "editor_cursors.h"
104 #include "editor_drag.h"
105 #include "editor_group_tabs.h"
106 #include "editor_locations.h"
107 #include "editor_regions.h"
108 #include "editor_route_groups.h"
109 #include "editor_routes.h"
110 #include "editor_snapshots.h"
111 #include "editor_summary.h"
112 #include "enums_convert.h"
113 #include "export_report.h"
114 #include "global_port_matrix.h"
115 #include "gui_object.h"
116 #include "gui_thread.h"
117 #include "keyboard.h"
118 #include "luainstance.h"
120 #include "midi_region_view.h"
121 #include "midi_time_axis.h"
122 #include "mixer_strip.h"
123 #include "mixer_ui.h"
124 #include "mouse_cursors.h"
125 #include "note_base.h"
126 #include "playlist_selector.h"
127 #include "public_editor.h"
128 #include "quantize_dialog.h"
129 #include "region_layering_order_editor.h"
130 #include "rgb_macros.h"
131 #include "rhythm_ferret.h"
132 #include "route_sorter.h"
133 #include "selection.h"
134 #include "simple_progress_dialog.h"
136 #include "tempo_lines.h"
137 #include "time_axis_view.h"
138 #include "time_info_box.h"
140 #include "ui_config.h"
142 #include "vca_time_axis.h"
143 #include "verbose_cursor.h"
145 #include "pbd/i18n.h"
148 using namespace ARDOUR;
149 using namespace ArdourWidgets;
150 using namespace ARDOUR_UI_UTILS;
153 using namespace Glib;
154 using namespace Gtkmm2ext;
155 using namespace Editing;
157 using PBD::internationalize;
159 using Gtkmm2ext::Keyboard;
161 double Editor::timebar_height = 15.0;
163 static const gchar *_snap_type_strings[] = {
197 static const gchar *_snap_mode_strings[] = {
204 static const gchar *_edit_point_strings[] = {
211 static const gchar *_edit_mode_strings[] = {
219 static const gchar *_zoom_focus_strings[] = {
229 #ifdef USE_RUBBERBAND
230 static const gchar *_rb_opt_strings[] = {
233 N_("Balanced multitimbral mixture"),
234 N_("Unpitched percussion with stable notes"),
235 N_("Crisp monophonic instrumental"),
236 N_("Unpitched solo percussion"),
237 N_("Resample without preserving pitch"),
242 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
245 : PublicEditor (global_hpacker)
246 , editor_mixer_strip_width (Wide)
247 , constructed (false)
248 , _playlist_selector (0)
250 , no_save_visual (false)
251 , _leftmost_sample (0)
252 , samples_per_pixel (2048)
253 , zoom_focus (ZoomFocusPlayhead)
254 , mouse_mode (MouseObject)
255 , pre_internal_snap_type (SnapToBeat)
256 , pre_internal_snap_mode (SnapOff)
257 , internal_snap_type (SnapToBeat)
258 , internal_snap_mode (SnapOff)
259 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
260 , _notebook_shrunk (false)
261 , location_marker_color (0)
262 , location_range_color (0)
263 , location_loop_color (0)
264 , location_punch_color (0)
265 , location_cd_marker_color (0)
267 , _show_marker_lines (false)
268 , clicked_axisview (0)
269 , clicked_routeview (0)
270 , clicked_regionview (0)
271 , clicked_selection (0)
272 , clicked_control_point (0)
273 , button_release_can_deselect (true)
274 , _mouse_changed_selection (false)
275 , region_edit_menu_split_item (0)
276 , region_edit_menu_split_multichannel_item (0)
277 , track_region_edit_playlist_menu (0)
278 , track_edit_playlist_submenu (0)
279 , track_selection_edit_playlist_submenu (0)
280 , _popup_region_menu_item (0)
282 , _track_canvas_viewport (0)
283 , within_track_canvas (false)
284 , _verbose_cursor (0)
288 , range_marker_group (0)
289 , transport_marker_group (0)
290 , cd_marker_group (0)
291 , _time_markers_group (0)
292 , hv_scroll_group (0)
294 , cursor_scroll_group (0)
295 , no_scroll_group (0)
296 , _trackview_group (0)
297 , _drag_motion_group (0)
298 , _canvas_drop_zone (0)
299 , no_ruler_shown_update (false)
300 , ruler_grabbed_widget (0)
302 , minsec_mark_interval (0)
303 , minsec_mark_modulo (0)
305 , timecode_ruler_scale (timecode_show_many_hours)
306 , timecode_mark_modulo (0)
307 , timecode_nmarks (0)
308 , _samples_ruler_interval (0)
309 , bbt_ruler_scale (bbt_show_many)
312 , bbt_bar_helper_on (0)
313 , bbt_accent_modulo (0)
318 , visible_timebars (0)
319 , editor_ruler_menu (0)
323 , range_marker_bar (0)
324 , transport_marker_bar (0)
326 , minsec_label (_("Mins:Secs"))
327 , bbt_label (_("Bars:Beats"))
328 , timecode_label (_("Timecode"))
329 , samples_label (_("Samples"))
330 , tempo_label (_("Tempo"))
331 , meter_label (_("Meter"))
332 , mark_label (_("Location Markers"))
333 , range_mark_label (_("Range Markers"))
334 , transport_mark_label (_("Loop/Punch Ranges"))
335 , cd_mark_label (_("CD Markers"))
336 , videotl_label (_("Video Timeline"))
339 , playhead_cursor (0)
340 , edit_packer (4, 4, true)
341 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
342 , horizontal_adjustment (0.0, 0.0, 1e16)
343 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
344 , controls_layout (unused_adjustment, vertical_adjustment)
345 , _scroll_callbacks (0)
346 , _visible_canvas_width (0)
347 , _visible_canvas_height (0)
348 , _full_canvas_height (0)
349 , edit_controls_left_menu (0)
350 , edit_controls_right_menu (0)
351 , visual_change_queued(false)
352 , _last_update_time (0)
353 , _err_screen_engine (0)
354 , cut_buffer_start (0)
355 , cut_buffer_length (0)
356 , button_bindings (0)
357 , last_paste_pos (-1)
360 , current_interthread_info (0)
361 , analysis_window (0)
362 , select_new_marker (false)
364 , scrubbing_direction (0)
365 , scrub_reversals (0)
366 , scrub_reverse_distance (0)
367 , have_pending_keyboard_selection (false)
368 , pending_keyboard_selection_start (0)
369 , _snap_type (SnapToBeat)
370 , _snap_mode (SnapOff)
371 , ignore_gui_changes (false)
372 , _drags (new DragManager (this))
374 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
375 , _dragging_playhead (false)
376 , _dragging_edit_point (false)
377 , _show_measures (true)
378 , _follow_playhead (true)
379 , _stationary_playhead (false)
382 , global_rect_group (0)
383 , time_line_group (0)
384 , tempo_marker_menu (0)
385 , meter_marker_menu (0)
387 , range_marker_menu (0)
388 , transport_marker_menu (0)
389 , new_transport_marker_menu (0)
391 , marker_menu_item (0)
392 , bbt_beat_subdivision (4)
393 , _visible_track_count (-1)
394 , toolbar_selection_clock_table (2,3)
395 , automation_mode_button (_("mode"))
396 , selection (new Selection (this, true))
397 , cut_buffer (new Selection (this, false))
398 , _selection_memento (new SelectionMemento())
399 , _all_region_actions_sensitized (false)
400 , _ignore_region_action (false)
401 , _last_region_menu_was_main (false)
402 , _track_selection_change_without_scroll (false)
403 , _editor_track_selection_change_without_scroll (false)
404 , cd_marker_bar_drag_rect (0)
405 , range_bar_drag_rect (0)
406 , transport_bar_drag_rect (0)
407 , transport_bar_range_rect (0)
408 , transport_bar_preroll_rect (0)
409 , transport_bar_postroll_rect (0)
410 , transport_loop_range_rect (0)
411 , transport_punch_range_rect (0)
412 , transport_punchin_line (0)
413 , transport_punchout_line (0)
414 , transport_preroll_rect (0)
415 , transport_postroll_rect (0)
417 , rubberband_rect (0)
423 , autoscroll_horizontal_allowed (false)
424 , autoscroll_vertical_allowed (false)
426 , autoscroll_widget (0)
427 , show_gain_after_trim (false)
428 , selection_op_cmd_depth (0)
429 , selection_op_history_it (0)
430 , no_save_instant (false)
432 , current_mixer_strip (0)
433 , show_editor_mixer_when_tracks_arrive (false)
434 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
435 , current_stepping_trackview (0)
436 , last_track_height_step_timestamp (0)
438 , entered_regionview (0)
439 , clear_entered_track (false)
440 , _edit_point (EditAtMouse)
441 , meters_running (false)
443 , _have_idled (false)
444 , resize_idle_id (-1)
445 , _pending_resize_amount (0)
446 , _pending_resize_view (0)
447 , _pending_locate_request (false)
448 , _pending_initial_locate (false)
452 , layering_order_editor (0)
453 , _last_cut_copy_source_track (0)
454 , _region_selection_change_updates_region_list (true)
456 , _following_mixer_selection (false)
457 , _control_point_toggled_on_press (false)
458 , _stepping_axis_view (0)
459 , quantize_dialog (0)
460 , _main_menu_disabler (0)
461 , myactions (X_("editor"))
463 /* we are a singleton */
465 PublicEditor::_instance = this;
469 last_event_time.tv_sec = 0;
470 last_event_time.tv_usec = 0;
472 selection_op_history.clear();
475 snap_type_strings = I18N (_snap_type_strings);
476 snap_mode_strings = I18N (_snap_mode_strings);
477 zoom_focus_strings = I18N (_zoom_focus_strings);
478 edit_mode_strings = I18N (_edit_mode_strings);
479 edit_point_strings = I18N (_edit_point_strings);
480 #ifdef USE_RUBBERBAND
481 rb_opt_strings = I18N (_rb_opt_strings);
485 build_edit_mode_menu();
486 build_zoom_focus_menu();
487 build_track_count_menu();
488 build_snap_mode_menu();
489 build_snap_type_menu();
490 build_edit_point_menu();
492 location_marker_color = UIConfiguration::instance().color ("location marker");
493 location_range_color = UIConfiguration::instance().color ("location range");
494 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
495 location_loop_color = UIConfiguration::instance().color ("location loop");
496 location_punch_color = UIConfiguration::instance().color ("location punch");
498 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
500 TimeAxisView::setup_sizes ();
501 ArdourMarker::setup_sizes (timebar_height);
502 TempoCurve::setup_sizes (timebar_height);
504 bbt_label.set_name ("EditorRulerLabel");
505 bbt_label.set_size_request (-1, (int)timebar_height);
506 bbt_label.set_alignment (1.0, 0.5);
507 bbt_label.set_padding (5,0);
509 bbt_label.set_no_show_all();
510 minsec_label.set_name ("EditorRulerLabel");
511 minsec_label.set_size_request (-1, (int)timebar_height);
512 minsec_label.set_alignment (1.0, 0.5);
513 minsec_label.set_padding (5,0);
514 minsec_label.hide ();
515 minsec_label.set_no_show_all();
516 timecode_label.set_name ("EditorRulerLabel");
517 timecode_label.set_size_request (-1, (int)timebar_height);
518 timecode_label.set_alignment (1.0, 0.5);
519 timecode_label.set_padding (5,0);
520 timecode_label.hide ();
521 timecode_label.set_no_show_all();
522 samples_label.set_name ("EditorRulerLabel");
523 samples_label.set_size_request (-1, (int)timebar_height);
524 samples_label.set_alignment (1.0, 0.5);
525 samples_label.set_padding (5,0);
526 samples_label.hide ();
527 samples_label.set_no_show_all();
529 tempo_label.set_name ("EditorRulerLabel");
530 tempo_label.set_size_request (-1, (int)timebar_height);
531 tempo_label.set_alignment (1.0, 0.5);
532 tempo_label.set_padding (5,0);
534 tempo_label.set_no_show_all();
536 meter_label.set_name ("EditorRulerLabel");
537 meter_label.set_size_request (-1, (int)timebar_height);
538 meter_label.set_alignment (1.0, 0.5);
539 meter_label.set_padding (5,0);
541 meter_label.set_no_show_all();
543 if (Profile->get_trx()) {
544 mark_label.set_text (_("Markers"));
546 mark_label.set_name ("EditorRulerLabel");
547 mark_label.set_size_request (-1, (int)timebar_height);
548 mark_label.set_alignment (1.0, 0.5);
549 mark_label.set_padding (5,0);
551 mark_label.set_no_show_all();
553 cd_mark_label.set_name ("EditorRulerLabel");
554 cd_mark_label.set_size_request (-1, (int)timebar_height);
555 cd_mark_label.set_alignment (1.0, 0.5);
556 cd_mark_label.set_padding (5,0);
557 cd_mark_label.hide();
558 cd_mark_label.set_no_show_all();
560 videotl_bar_height = 4;
561 videotl_label.set_name ("EditorRulerLabel");
562 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
563 videotl_label.set_alignment (1.0, 0.5);
564 videotl_label.set_padding (5,0);
565 videotl_label.hide();
566 videotl_label.set_no_show_all();
568 range_mark_label.set_name ("EditorRulerLabel");
569 range_mark_label.set_size_request (-1, (int)timebar_height);
570 range_mark_label.set_alignment (1.0, 0.5);
571 range_mark_label.set_padding (5,0);
572 range_mark_label.hide();
573 range_mark_label.set_no_show_all();
575 transport_mark_label.set_name ("EditorRulerLabel");
576 transport_mark_label.set_size_request (-1, (int)timebar_height);
577 transport_mark_label.set_alignment (1.0, 0.5);
578 transport_mark_label.set_padding (5,0);
579 transport_mark_label.hide();
580 transport_mark_label.set_no_show_all();
582 initialize_canvas ();
584 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
586 _summary = new EditorSummary (this);
588 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
590 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
592 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
593 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
595 edit_controls_vbox.set_spacing (0);
596 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
597 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
599 HBox* h = manage (new HBox);
600 _group_tabs = new EditorGroupTabs (this);
601 if (!ARDOUR::Profile->get_trx()) {
602 h->pack_start (*_group_tabs, PACK_SHRINK);
604 h->pack_start (edit_controls_vbox);
605 controls_layout.add (*h);
607 controls_layout.set_name ("EditControlsBase");
608 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
609 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
610 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
612 _cursors = new MouseCursors;
613 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
614 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
616 /* Push default cursor to ever-present bottom of cursor stack. */
617 push_canvas_cursor(_cursors->grabber);
619 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
621 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
622 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
623 pad_line_1->set_outline_color (0xFF0000FF);
629 edit_packer.set_col_spacings (0);
630 edit_packer.set_row_spacings (0);
631 edit_packer.set_homogeneous (false);
632 edit_packer.set_border_width (0);
633 edit_packer.set_name ("EditorWindow");
635 time_bars_event_box.add (time_bars_vbox);
636 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
637 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
639 /* labels for the time bars */
640 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
642 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
644 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
646 bottom_hbox.set_border_width (2);
647 bottom_hbox.set_spacing (3);
649 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
651 _route_groups = new EditorRouteGroups (this);
652 _routes = new EditorRoutes (this);
653 _regions = new EditorRegions (this);
654 _snapshots = new EditorSnapshots (this);
655 _locations = new EditorLocations (this);
656 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
658 /* these are static location signals */
660 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
661 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
662 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
664 add_notebook_page (_("Regions"), _regions->widget ());
665 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
666 add_notebook_page (_("Snapshots"), _snapshots->widget ());
667 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
668 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
670 _the_notebook.set_show_tabs (true);
671 _the_notebook.set_scrollable (true);
672 _the_notebook.popup_disable ();
673 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
674 _the_notebook.show_all ();
676 _notebook_shrunk = false;
679 /* Pick up some settings we need to cache, early */
681 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
684 settings->get_property ("notebook-shrunk", _notebook_shrunk);
687 editor_summary_pane.set_check_divider_position (true);
688 editor_summary_pane.add (edit_packer);
690 Button* summary_arrow_left = manage (new Button);
691 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
692 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
693 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
695 Button* summary_arrow_right = manage (new Button);
696 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
697 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
698 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 VBox* summary_arrows_left = manage (new VBox);
701 summary_arrows_left->pack_start (*summary_arrow_left);
703 VBox* summary_arrows_right = manage (new VBox);
704 summary_arrows_right->pack_start (*summary_arrow_right);
706 Frame* summary_sample = manage (new Frame);
707 summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
709 summary_sample->add (*_summary);
710 summary_sample->show ();
712 _summary_hbox.pack_start (*summary_arrows_left, false, false);
713 _summary_hbox.pack_start (*summary_sample, true, true);
714 _summary_hbox.pack_start (*summary_arrows_right, false, false);
716 if (!ARDOUR::Profile->get_trx()) {
717 editor_summary_pane.add (_summary_hbox);
720 edit_pane.set_check_divider_position (true);
721 edit_pane.add (editor_summary_pane);
722 if (!ARDOUR::Profile->get_trx()) {
723 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
724 _editor_list_vbox.pack_start (_the_notebook);
725 edit_pane.add (_editor_list_vbox);
726 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
729 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
730 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
733 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
734 /* initial allocation is 90% to canvas, 10% to notebook */
737 edit_pane.set_divider (0, fract);
739 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
740 /* initial allocation is 90% to canvas, 10% to summary */
743 editor_summary_pane.set_divider (0, fract);
745 global_vpacker.set_spacing (2);
746 global_vpacker.set_border_width (0);
748 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
750 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
751 ebox->set_name("EditorWindow");
752 ebox->add (toolbar_hbox);
754 Gtk::EventBox* epane_box = manage (new EventBoxExt); //a themeable box
755 epane_box->set_name("EditorWindow");
756 epane_box->add (edit_pane);
758 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); //a themeable box
759 epane_box2->set_name("EditorWindow");
760 epane_box2->add (global_vpacker);
762 global_vpacker.pack_start (*ebox, false, false);
763 global_vpacker.pack_start (*epane_box, true, true);
764 global_hpacker.pack_start (*epane_box2, true, true);
766 /* need to show the "contents" widget so that notebook will show if tab is switched to
769 global_hpacker.show ();
771 /* register actions now so that set_state() can find them and set toggles/checks etc */
778 _playlist_selector = new PlaylistSelector();
779 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
781 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
785 nudge_forward_button.set_name ("nudge button");
786 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
788 nudge_backward_button.set_name ("nudge button");
789 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
791 fade_context_menu.set_name ("ArdourContextMenu");
793 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
795 /* allow external control surfaces/protocols to do various things */
797 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
798 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
799 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
800 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
801 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
802 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
803 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
804 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
805 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
806 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
807 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
808 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
809 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
810 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
812 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
813 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
814 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
815 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
816 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
818 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
822 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
824 /* problematic: has to return a value and thus cannot be x-thread */
826 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
828 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
829 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
831 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
833 _ignore_region_action = false;
834 _last_region_menu_was_main = false;
835 _popup_region_menu_item = 0;
837 _show_marker_lines = false;
839 /* Button bindings */
841 button_bindings = new Bindings ("editor-mouse");
843 XMLNode* node = button_settings();
845 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
846 button_bindings->load_operation (**i);
852 /* grab current parameter state */
853 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
854 UIConfiguration::instance().map_parameters (pc);
856 setup_fade_images ();
863 delete button_bindings;
865 delete _route_groups;
866 delete _track_canvas_viewport;
869 delete _verbose_cursor;
870 delete quantize_dialog;
876 delete _playlist_selector;
877 delete _time_info_box;
882 LuaInstance::destroy_instance ();
884 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
887 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
890 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
896 Editor::button_settings () const
898 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
899 XMLNode* node = find_named_node (*settings, X_("Buttons"));
902 node = new XMLNode (X_("Buttons"));
909 Editor::get_smart_mode () const
911 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
915 Editor::catch_vanishing_regionview (RegionView *rv)
917 /* note: the selection will take care of the vanishing
918 audioregionview by itself.
921 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
925 if (clicked_regionview == rv) {
926 clicked_regionview = 0;
929 if (entered_regionview == rv) {
930 set_entered_regionview (0);
933 if (!_all_region_actions_sensitized) {
934 sensitize_all_region_actions (true);
939 Editor::set_entered_regionview (RegionView* rv)
941 if (rv == entered_regionview) {
945 if (entered_regionview) {
946 entered_regionview->exited ();
949 entered_regionview = rv;
951 if (entered_regionview != 0) {
952 entered_regionview->entered ();
955 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
956 /* This RegionView entry might have changed what region actions
957 are allowed, so sensitize them all in case a key is pressed.
959 sensitize_all_region_actions (true);
964 Editor::set_entered_track (TimeAxisView* tav)
967 entered_track->exited ();
973 entered_track->entered ();
978 Editor::instant_save ()
980 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
985 _session->add_instant_xml(get_state());
987 Config->add_instant_xml(get_state());
992 Editor::control_vertical_zoom_in_all ()
994 tav_zoom_smooth (false, true);
998 Editor::control_vertical_zoom_out_all ()
1000 tav_zoom_smooth (true, true);
1004 Editor::control_vertical_zoom_in_selected ()
1006 tav_zoom_smooth (false, false);
1010 Editor::control_vertical_zoom_out_selected ()
1012 tav_zoom_smooth (true, false);
1016 Editor::control_view (uint32_t view)
1018 goto_visual_state (view);
1022 Editor::control_unselect ()
1024 selection->clear_tracks ();
1028 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1030 TimeAxisView* tav = time_axis_view_from_stripable (s);
1034 case Selection::Add:
1035 selection->add (tav);
1037 case Selection::Toggle:
1038 selection->toggle (tav);
1040 case Selection::Extend:
1042 case Selection::Set:
1043 selection->set (tav);
1047 selection->clear_tracks ();
1052 Editor::control_step_tracks_up ()
1054 scroll_tracks_up_line ();
1058 Editor::control_step_tracks_down ()
1060 scroll_tracks_down_line ();
1064 Editor::control_scroll (float fraction)
1066 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1072 double step = fraction * current_page_samples();
1075 _control_scroll_target is an optional<T>
1077 it acts like a pointer to an samplepos_t, with
1078 a operator conversion to boolean to check
1079 that it has a value could possibly use
1080 playhead_cursor->current_sample to store the
1081 value and a boolean in the class to know
1082 when it's out of date
1085 if (!_control_scroll_target) {
1086 _control_scroll_target = _session->transport_sample();
1087 _dragging_playhead = true;
1090 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1091 *_control_scroll_target = 0;
1092 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1093 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1095 *_control_scroll_target += (samplepos_t) trunc (step);
1098 /* move visuals, we'll catch up with it later */
1100 playhead_cursor->set_position (*_control_scroll_target);
1101 UpdateAllTransportClocks (*_control_scroll_target);
1103 if (*_control_scroll_target > (current_page_samples() / 2)) {
1104 /* try to center PH in window */
1105 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1111 Now we do a timeout to actually bring the session to the right place
1112 according to the playhead. This is to avoid reading disk buffers on every
1113 call to control_scroll, which is driven by ScrollTimeline and therefore
1114 probably by a control surface wheel which can generate lots of events.
1116 /* cancel the existing timeout */
1118 control_scroll_connection.disconnect ();
1120 /* add the next timeout */
1122 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1126 Editor::deferred_control_scroll (samplepos_t /*target*/)
1128 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1129 // reset for next stream
1130 _control_scroll_target = boost::none;
1131 _dragging_playhead = false;
1136 Editor::access_action (const std::string& action_group, const std::string& action_item)
1142 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1145 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1153 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1155 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1159 Editor::on_realize ()
1163 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1164 start_lock_event_timing ();
1169 Editor::start_lock_event_timing ()
1171 /* check if we should lock the GUI every 30 seconds */
1173 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1177 Editor::generic_event_handler (GdkEvent* ev)
1180 case GDK_BUTTON_PRESS:
1181 case GDK_BUTTON_RELEASE:
1182 case GDK_MOTION_NOTIFY:
1184 case GDK_KEY_RELEASE:
1185 if (contents().is_mapped()) {
1186 gettimeofday (&last_event_time, 0);
1190 case GDK_LEAVE_NOTIFY:
1191 switch (ev->crossing.detail) {
1192 case GDK_NOTIFY_UNKNOWN:
1193 case GDK_NOTIFY_INFERIOR:
1194 case GDK_NOTIFY_ANCESTOR:
1196 case GDK_NOTIFY_VIRTUAL:
1197 case GDK_NOTIFY_NONLINEAR:
1198 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1199 /* leaving window, so reset focus, thus ending any and
1200 all text entry operations.
1202 ARDOUR_UI::instance()->reset_focus (&contents());
1215 Editor::lock_timeout_callback ()
1217 struct timeval now, delta;
1219 gettimeofday (&now, 0);
1221 timersub (&now, &last_event_time, &delta);
1223 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1225 /* don't call again. Returning false will effectively
1226 disconnect us from the timer callback.
1228 unlock() will call start_lock_event_timing() to get things
1238 Editor::map_position_change (samplepos_t sample)
1240 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1242 if (_session == 0) {
1246 if (_follow_playhead) {
1247 center_screen (sample);
1250 playhead_cursor->set_position (sample);
1254 Editor::center_screen (samplepos_t sample)
1256 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1258 /* if we're off the page, then scroll.
1261 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1262 center_screen_internal (sample, page);
1267 Editor::center_screen_internal (samplepos_t sample, float page)
1271 if (sample > page) {
1272 sample -= (samplepos_t) page;
1277 reset_x_origin (sample);
1282 Editor::update_title ()
1284 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1286 if (!own_window()) {
1291 bool dirty = _session->dirty();
1293 string session_name;
1295 if (_session->snap_name() != _session->name()) {
1296 session_name = _session->snap_name();
1298 session_name = _session->name();
1302 session_name = "*" + session_name;
1305 WindowTitle title(session_name);
1306 title += S_("Window|Editor");
1307 title += Glib::get_application_name();
1308 own_window()->set_title (title.get_string());
1310 /* ::session_going_away() will have taken care of it */
1315 Editor::set_session (Session *t)
1317 SessionHandlePtr::set_session (t);
1323 //initialize _leftmost_sample to the extents of the session
1324 //this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample before the visible state has been loaded from instant.xml
1325 _leftmost_sample = session_gui_extents().first;
1327 _playlist_selector->set_session (_session);
1328 nudge_clock->set_session (_session);
1329 _summary->set_session (_session);
1330 _group_tabs->set_session (_session);
1331 _route_groups->set_session (_session);
1332 _regions->set_session (_session);
1333 _snapshots->set_session (_session);
1334 _routes->set_session (_session);
1335 _locations->set_session (_session);
1336 _time_info_box->set_session (_session);
1338 if (rhythm_ferret) {
1339 rhythm_ferret->set_session (_session);
1342 if (analysis_window) {
1343 analysis_window->set_session (_session);
1347 sfbrowser->set_session (_session);
1350 compute_fixed_ruler_scale ();
1352 /* Make sure we have auto loop and auto punch ranges */
1354 Location* loc = _session->locations()->auto_loop_location();
1356 loc->set_name (_("Loop"));
1359 loc = _session->locations()->auto_punch_location();
1362 loc->set_name (_("Punch"));
1365 refresh_location_display ();
1367 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1368 the selected Marker; this needs the LocationMarker list to be available.
1370 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1371 set_state (*node, Stateful::loading_state_version);
1373 /* catch up on selection state, etc. */
1376 sc.add (Properties::selected);
1377 presentation_info_changed (sc);
1379 /* catch up with the playhead */
1381 _session->request_locate (playhead_cursor->current_sample ());
1382 _pending_initial_locate = true;
1386 /* These signals can all be emitted by a non-GUI thread. Therefore the
1387 handlers for them must not attempt to directly interact with the GUI,
1388 but use PBD::Signal<T>::connect() which accepts an event loop
1389 ("context") where the handler will be asked to run.
1392 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1393 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1394 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1395 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1396 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1397 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1398 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1399 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1400 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1401 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1402 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1403 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1404 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1405 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1406 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1407 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1409 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1410 playhead_cursor->show ();
1412 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1413 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1414 snapped_cursor->show ();
1416 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1417 Config->map_parameters (pc);
1418 _session->config.map_parameters (pc);
1420 restore_ruler_visibility ();
1421 //tempo_map_changed (PropertyChange (0));
1422 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1424 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1425 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1428 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1429 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1432 switch (_snap_type) {
1433 case SnapToRegionStart:
1434 case SnapToRegionEnd:
1435 case SnapToRegionSync:
1436 case SnapToRegionBoundary:
1437 build_region_boundary_cache ();
1444 /* register for undo history */
1445 _session->register_with_memento_command_factory(id(), this);
1446 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1448 LuaInstance::instance()->set_session(_session);
1450 start_updating_meters ();
1454 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1456 using namespace Menu_Helpers;
1458 void (Editor::*emf)(FadeShape);
1459 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1462 images = &_xfade_in_images;
1463 emf = &Editor::set_fade_in_shape;
1465 images = &_xfade_out_images;
1466 emf = &Editor::set_fade_out_shape;
1471 _("Linear (for highly correlated material)"),
1472 *(*images)[FadeLinear],
1473 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1477 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1481 _("Constant power"),
1482 *(*images)[FadeConstantPower],
1483 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 *(*images)[FadeSymmetric],
1492 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *(*images)[FadeSlow],
1502 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1510 *(*images)[FadeFast],
1511 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1514 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1517 /** Pop up a context menu for when the user clicks on a start crossfade */
1519 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1521 using namespace Menu_Helpers;
1522 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1527 MenuList& items (xfade_in_context_menu.items());
1530 if (arv->audio_region()->fade_in_active()) {
1531 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1533 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1536 items.push_back (SeparatorElem());
1537 fill_xfade_menu (items, true);
1539 xfade_in_context_menu.popup (button, time);
1542 /** Pop up a context menu for when the user clicks on an end crossfade */
1544 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1546 using namespace Menu_Helpers;
1547 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1552 MenuList& items (xfade_out_context_menu.items());
1555 if (arv->audio_region()->fade_out_active()) {
1556 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1558 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1561 items.push_back (SeparatorElem());
1562 fill_xfade_menu (items, false);
1564 xfade_out_context_menu.popup (button, time);
1568 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1570 using namespace Menu_Helpers;
1571 Menu* (Editor::*build_menu_function)();
1574 switch (item_type) {
1576 case RegionViewName:
1577 case RegionViewNameHighlight:
1578 case LeftFrameHandle:
1579 case RightFrameHandle:
1580 if (with_selection) {
1581 build_menu_function = &Editor::build_track_selection_context_menu;
1583 build_menu_function = &Editor::build_track_region_context_menu;
1588 if (with_selection) {
1589 build_menu_function = &Editor::build_track_selection_context_menu;
1591 build_menu_function = &Editor::build_track_context_menu;
1596 if (clicked_routeview->track()) {
1597 build_menu_function = &Editor::build_track_context_menu;
1599 build_menu_function = &Editor::build_track_bus_context_menu;
1604 /* probably shouldn't happen but if it does, we don't care */
1608 menu = (this->*build_menu_function)();
1609 menu->set_name ("ArdourContextMenu");
1611 /* now handle specific situations */
1613 switch (item_type) {
1615 case RegionViewName:
1616 case RegionViewNameHighlight:
1617 case LeftFrameHandle:
1618 case RightFrameHandle:
1619 if (!with_selection) {
1620 if (region_edit_menu_split_item) {
1621 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1622 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1624 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1627 if (region_edit_menu_split_multichannel_item) {
1628 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1629 region_edit_menu_split_multichannel_item->set_sensitive (true);
1631 region_edit_menu_split_multichannel_item->set_sensitive (false);
1644 /* probably shouldn't happen but if it does, we don't care */
1648 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1650 /* Bounce to disk */
1652 using namespace Menu_Helpers;
1653 MenuList& edit_items = menu->items();
1655 edit_items.push_back (SeparatorElem());
1657 switch (clicked_routeview->audio_track()->freeze_state()) {
1658 case AudioTrack::NoFreeze:
1659 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1662 case AudioTrack::Frozen:
1663 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1666 case AudioTrack::UnFrozen:
1667 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1673 if (item_type == StreamItem && clicked_routeview) {
1674 clicked_routeview->build_underlay_menu(menu);
1677 /* When the region menu is opened, we setup the actions so that they look right
1680 sensitize_the_right_region_actions (false);
1681 _last_region_menu_was_main = false;
1683 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1684 menu->popup (button, time);
1688 Editor::build_track_context_menu ()
1690 using namespace Menu_Helpers;
1692 MenuList& edit_items = track_context_menu.items();
1695 add_dstream_context_items (edit_items);
1696 return &track_context_menu;
1700 Editor::build_track_bus_context_menu ()
1702 using namespace Menu_Helpers;
1704 MenuList& edit_items = track_context_menu.items();
1707 add_bus_context_items (edit_items);
1708 return &track_context_menu;
1712 Editor::build_track_region_context_menu ()
1714 using namespace Menu_Helpers;
1715 MenuList& edit_items = track_region_context_menu.items();
1718 /* we've just cleared the track region context menu, so the menu that these
1719 two items were on will have disappeared; stop them dangling.
1721 region_edit_menu_split_item = 0;
1722 region_edit_menu_split_multichannel_item = 0;
1724 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1727 boost::shared_ptr<Track> tr;
1728 boost::shared_ptr<Playlist> pl;
1730 if ((tr = rtv->track())) {
1731 add_region_context_items (edit_items, tr);
1735 add_dstream_context_items (edit_items);
1737 return &track_region_context_menu;
1741 Editor::loudness_analyze_region_selection ()
1746 Selection& s (PublicEditor::instance ().get_selection ());
1747 RegionSelection ars = s.regions;
1748 ARDOUR::AnalysisGraph ag (_session);
1749 samplecnt_t total_work = 0;
1751 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1752 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1756 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1759 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1760 total_work += arv->region ()->length ();
1763 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1765 ag.set_total_samples (total_work);
1766 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1769 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1770 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1774 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1778 ag.analyze_region (ar);
1781 if (!ag.canceled ()) {
1782 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1788 Editor::loudness_analyze_range_selection ()
1793 Selection& s (PublicEditor::instance ().get_selection ());
1794 TimeSelection ts = s.time;
1795 ARDOUR::AnalysisGraph ag (_session);
1796 samplecnt_t total_work = 0;
1798 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1799 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1803 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1807 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1808 total_work += j->length ();
1812 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1814 ag.set_total_samples (total_work);
1815 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1818 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1819 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1823 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1827 ag.analyze_range (rui->route (), pl, ts);
1830 if (!ag.canceled ()) {
1831 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1837 Editor::spectral_analyze_region_selection ()
1839 if (analysis_window == 0) {
1840 analysis_window = new AnalysisWindow();
1843 analysis_window->set_session(_session);
1845 analysis_window->show_all();
1848 analysis_window->set_regionmode();
1849 analysis_window->analyze();
1851 analysis_window->present();
1855 Editor::spectral_analyze_range_selection()
1857 if (analysis_window == 0) {
1858 analysis_window = new AnalysisWindow();
1861 analysis_window->set_session(_session);
1863 analysis_window->show_all();
1866 analysis_window->set_rangemode();
1867 analysis_window->analyze();
1869 analysis_window->present();
1873 Editor::build_track_selection_context_menu ()
1875 using namespace Menu_Helpers;
1876 MenuList& edit_items = track_selection_context_menu.items();
1877 edit_items.clear ();
1879 add_selection_context_items (edit_items);
1880 // edit_items.push_back (SeparatorElem());
1881 // add_dstream_context_items (edit_items);
1883 return &track_selection_context_menu;
1887 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1889 using namespace Menu_Helpers;
1891 /* OK, stick the region submenu at the top of the list, and then add
1895 RegionSelection rs = get_regions_from_selection_and_entered ();
1897 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1899 if (_popup_region_menu_item == 0) {
1900 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1901 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1902 _popup_region_menu_item->show ();
1904 _popup_region_menu_item->set_label (menu_item_name);
1907 /* No layering allowed in later is higher layering model */
1908 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1909 if (act && Config->get_layer_model() == LaterHigher) {
1910 act->set_sensitive (false);
1912 act->set_sensitive (true);
1915 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1917 edit_items.push_back (*_popup_region_menu_item);
1918 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1919 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1921 edit_items.push_back (SeparatorElem());
1924 /** Add context menu items relevant to selection ranges.
1925 * @param edit_items List to add the items to.
1928 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1930 using namespace Menu_Helpers;
1932 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1933 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1935 edit_items.push_back (SeparatorElem());
1936 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1938 edit_items.push_back (SeparatorElem());
1939 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1940 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1942 edit_items.push_back (SeparatorElem());
1944 edit_items.push_back (
1946 _("Move Range Start to Previous Region Boundary"),
1947 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1951 edit_items.push_back (
1953 _("Move Range Start to Next Region Boundary"),
1954 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1958 edit_items.push_back (
1960 _("Move Range End to Previous Region Boundary"),
1961 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1965 edit_items.push_back (
1967 _("Move Range End to Next Region Boundary"),
1968 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1972 edit_items.push_back (SeparatorElem());
1973 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1974 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1976 edit_items.push_back (SeparatorElem());
1977 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1979 edit_items.push_back (SeparatorElem());
1980 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1981 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1982 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1984 edit_items.push_back (SeparatorElem());
1985 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1987 edit_items.push_back (SeparatorElem());
1988 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1989 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1991 edit_items.push_back (SeparatorElem());
1992 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1993 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1994 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1995 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1996 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1997 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1998 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2004 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2006 using namespace Menu_Helpers;
2010 Menu *play_menu = manage (new Menu);
2011 MenuList& play_items = play_menu->items();
2012 play_menu->set_name ("ArdourContextMenu");
2014 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2015 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2016 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2017 play_items.push_back (SeparatorElem());
2018 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2020 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2024 Menu *select_menu = manage (new Menu);
2025 MenuList& select_items = select_menu->items();
2026 select_menu->set_name ("ArdourContextMenu");
2028 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2029 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2030 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2031 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2032 select_items.push_back (SeparatorElem());
2033 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2034 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2035 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2036 select_items.push_back (SeparatorElem());
2037 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2038 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2039 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2040 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2041 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2042 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2043 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2045 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2049 Menu *cutnpaste_menu = manage (new Menu);
2050 MenuList& cutnpaste_items = cutnpaste_menu->items();
2051 cutnpaste_menu->set_name ("ArdourContextMenu");
2053 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2054 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2055 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2057 cutnpaste_items.push_back (SeparatorElem());
2059 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2060 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2062 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2064 /* Adding new material */
2066 edit_items.push_back (SeparatorElem());
2067 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2068 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2072 Menu *nudge_menu = manage (new Menu());
2073 MenuList& nudge_items = nudge_menu->items();
2074 nudge_menu->set_name ("ArdourContextMenu");
2076 edit_items.push_back (SeparatorElem());
2077 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2078 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2079 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2080 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2082 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2086 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2088 using namespace Menu_Helpers;
2092 Menu *play_menu = manage (new Menu);
2093 MenuList& play_items = play_menu->items();
2094 play_menu->set_name ("ArdourContextMenu");
2096 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2097 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2098 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2102 Menu *select_menu = manage (new Menu);
2103 MenuList& select_items = select_menu->items();
2104 select_menu->set_name ("ArdourContextMenu");
2106 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2107 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2108 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2109 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2110 select_items.push_back (SeparatorElem());
2111 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2112 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2113 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2114 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2116 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2120 Menu *cutnpaste_menu = manage (new Menu);
2121 MenuList& cutnpaste_items = cutnpaste_menu->items();
2122 cutnpaste_menu->set_name ("ArdourContextMenu");
2124 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2125 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2126 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2128 Menu *nudge_menu = manage (new Menu());
2129 MenuList& nudge_items = nudge_menu->items();
2130 nudge_menu->set_name ("ArdourContextMenu");
2132 edit_items.push_back (SeparatorElem());
2133 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2134 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2135 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2136 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2138 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2142 Editor::snap_type() const
2148 Editor::snap_musical() const
2150 switch (_snap_type) {
2151 case SnapToBeatDiv128:
2152 case SnapToBeatDiv64:
2153 case SnapToBeatDiv32:
2154 case SnapToBeatDiv28:
2155 case SnapToBeatDiv24:
2156 case SnapToBeatDiv20:
2157 case SnapToBeatDiv16:
2158 case SnapToBeatDiv14:
2159 case SnapToBeatDiv12:
2160 case SnapToBeatDiv10:
2161 case SnapToBeatDiv8:
2162 case SnapToBeatDiv7:
2163 case SnapToBeatDiv6:
2164 case SnapToBeatDiv5:
2165 case SnapToBeatDiv4:
2166 case SnapToBeatDiv3:
2167 case SnapToBeatDiv2:
2179 Editor::snap_mode() const
2185 Editor::set_snap_to (SnapType st)
2187 unsigned int snap_ind = (unsigned int)st;
2189 if (internal_editing()) {
2190 internal_snap_type = st;
2192 pre_internal_snap_type = st;
2197 if (snap_ind > snap_type_strings.size() - 1) {
2199 _snap_type = (SnapType)snap_ind;
2202 string str = snap_type_strings[snap_ind];
2204 if (str != snap_type_selector.get_text()) {
2205 snap_type_selector.set_text (str);
2210 switch (_snap_type) {
2211 case SnapToBeatDiv128:
2212 case SnapToBeatDiv64:
2213 case SnapToBeatDiv32:
2214 case SnapToBeatDiv28:
2215 case SnapToBeatDiv24:
2216 case SnapToBeatDiv20:
2217 case SnapToBeatDiv16:
2218 case SnapToBeatDiv14:
2219 case SnapToBeatDiv12:
2220 case SnapToBeatDiv10:
2221 case SnapToBeatDiv8:
2222 case SnapToBeatDiv7:
2223 case SnapToBeatDiv6:
2224 case SnapToBeatDiv5:
2225 case SnapToBeatDiv4:
2226 case SnapToBeatDiv3:
2227 case SnapToBeatDiv2: {
2228 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2229 update_tempo_based_rulers ();
2233 case SnapToRegionStart:
2234 case SnapToRegionEnd:
2235 case SnapToRegionSync:
2236 case SnapToRegionBoundary:
2237 build_region_boundary_cache ();
2245 redisplay_tempo (false);
2247 SnapChanged (); /* EMIT SIGNAL */
2251 Editor::set_snap_mode (SnapMode mode)
2253 string str = snap_mode_strings[(int)mode];
2255 if (internal_editing()) {
2256 internal_snap_mode = mode;
2258 pre_internal_snap_mode = mode;
2263 if (str != snap_mode_selector.get_text ()) {
2264 snap_mode_selector.set_text (str);
2271 Editor::set_edit_point_preference (EditPoint ep, bool force)
2273 bool changed = (_edit_point != ep);
2276 if (Profile->get_mixbus())
2277 if (ep == EditAtSelectedMarker)
2278 ep = EditAtPlayhead;
2280 string str = edit_point_strings[(int)ep];
2281 if (str != edit_point_selector.get_text ()) {
2282 edit_point_selector.set_text (str);
2285 update_all_enter_cursors();
2287 if (!force && !changed) {
2291 const char* action=NULL;
2293 switch (_edit_point) {
2294 case EditAtPlayhead:
2295 //ToDo: hide or show mouse_cursor
2296 action = "edit-at-playhead";
2298 case EditAtSelectedMarker:
2299 action = "edit-at-marker";
2302 action = "edit-at-mouse";
2306 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2308 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2312 bool in_track_canvas;
2314 if (!mouse_sample (foo, in_track_canvas)) {
2315 in_track_canvas = false;
2318 reset_canvas_action_sensitivity (in_track_canvas);
2319 sensitize_the_right_region_actions (false);
2325 Editor::set_state (const XMLNode& node, int version)
2328 PBD::Unwinder<bool> nsi (no_save_instant, true);
2331 Tabbable::set_state (node, version);
2334 if (_session && node.get_property ("playhead", ph_pos)) {
2336 playhead_cursor->set_position (ph_pos);
2338 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2339 playhead_cursor->set_position (0);
2342 playhead_cursor->set_position (0);
2345 node.get_property ("mixer-width", editor_mixer_strip_width);
2347 node.get_property ("zoom-focus", zoom_focus);
2348 zoom_focus_selection_done (zoom_focus);
2351 if (node.get_property ("zoom", z)) {
2352 /* older versions of ardour used floating point samples_per_pixel */
2353 reset_zoom (llrintf (z));
2355 reset_zoom (samples_per_pixel);
2359 if (node.get_property ("visible-track-count", cnt)) {
2360 set_visible_track_count (cnt);
2364 if (!node.get_property ("snap-to", snap_type)) {
2365 snap_type = _snap_type;
2367 set_snap_to (snap_type);
2370 if (node.get_property ("snap-mode", sm)) {
2371 snap_mode_selection_done(sm);
2372 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2373 * snap_mode_selection_done() will only mark an already active item as active
2374 * which does not trigger set_text().
2378 set_snap_mode (_snap_mode);
2381 node.get_property ("internal-snap-to", internal_snap_type);
2382 node.get_property ("internal-snap-mode", internal_snap_mode);
2383 node.get_property ("pre-internal-snap-to", pre_internal_snap_type);
2384 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2387 if (node.get_property ("mouse-mode", mm_str)) {
2388 MouseMode m = str2mousemode(mm_str);
2389 set_mouse_mode (m, true);
2391 set_mouse_mode (MouseObject, true);
2395 if (node.get_property ("left-frame", lf_pos)) {
2399 reset_x_origin (lf_pos);
2403 if (node.get_property ("y-origin", y_origin)) {
2404 reset_y_origin (y_origin);
2407 if (node.get_property ("join-object-range", yn)) {
2408 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2410 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2411 tact->set_active (!yn);
2412 tact->set_active (yn);
2414 set_mouse_mode(mouse_mode, true);
2418 if (node.get_property ("edit-point", ep)) {
2419 set_edit_point_preference (ep, true);
2421 set_edit_point_preference (_edit_point);
2424 node.get_property ("show-measures", _show_measures);
2426 if (node.get_property ("follow-playhead", yn)) {
2427 set_follow_playhead (yn);
2430 if (node.get_property ("stationary-playhead", yn)) {
2431 set_stationary_playhead (yn);
2434 RegionListSortType sort_type;
2435 if (node.get_property ("region-list-sort-type", sort_type)) {
2436 _regions->reset_sort_type (sort_type, true);
2439 if (node.get_property ("show-editor-mixer", yn)) {
2441 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2444 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2446 /* do it twice to force the change */
2448 tact->set_active (!yn);
2449 tact->set_active (yn);
2452 if (node.get_property ("show-editor-list", yn)) {
2454 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2457 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2459 /* do it twice to force the change */
2461 tact->set_active (!yn);
2462 tact->set_active (yn);
2466 if (node.get_property (X_("editor-list-page"), el_page)) {
2467 _the_notebook.set_current_page (el_page);
2470 if (node.get_property (X_("show-marker-lines"), yn)) {
2471 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2473 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2475 tact->set_active (!yn);
2476 tact->set_active (yn);
2479 XMLNodeList children = node.children ();
2480 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2481 selection->set_state (**i, Stateful::current_state_version);
2482 _regions->set_state (**i);
2483 _locations->set_state (**i);
2486 if (node.get_property ("maximised", yn)) {
2487 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2489 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2490 bool fs = tact && tact->get_active();
2492 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2496 samplepos_t nudge_clock_value;
2497 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2498 nudge_clock->set (nudge_clock_value);
2500 nudge_clock->set_mode (AudioClock::Timecode);
2501 nudge_clock->set (_session->sample_rate() * 5, true);
2506 * Not all properties may have been in XML, but
2507 * those that are linked to a private variable may need changing
2511 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2513 yn = _show_measures;
2514 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2515 /* do it twice to force the change */
2516 tact->set_active (!yn);
2517 tact->set_active (yn);
2520 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2521 yn = _follow_playhead;
2523 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2524 if (tact->get_active() != yn) {
2525 tact->set_active (yn);
2529 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2530 yn = _stationary_playhead;
2532 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2533 if (tact->get_active() != yn) {
2534 tact->set_active (yn);
2539 return LuaInstance::instance()->set_state(node);
2543 Editor::get_state ()
2545 XMLNode* node = new XMLNode (X_("Editor"));
2547 node->set_property ("id", id().to_s ());
2549 node->add_child_nocopy (Tabbable::get_state());
2551 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2552 node->set_property("notebook-shrunk", _notebook_shrunk);
2553 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2555 maybe_add_mixer_strip_width (*node);
2557 node->set_property ("zoom-focus", zoom_focus);
2559 node->set_property ("zoom", samples_per_pixel);
2560 node->set_property ("snap-to", _snap_type);
2561 node->set_property ("snap-mode", _snap_mode);
2562 node->set_property ("internal-snap-to", internal_snap_type);
2563 node->set_property ("internal-snap-mode", internal_snap_mode);
2564 node->set_property ("pre-internal-snap-to", pre_internal_snap_type);
2565 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2566 node->set_property ("edit-point", _edit_point);
2567 node->set_property ("visible-track-count", _visible_track_count);
2569 node->set_property ("playhead", playhead_cursor->current_sample ());
2570 node->set_property ("left-frame", _leftmost_sample);
2571 node->set_property ("y-origin", vertical_adjustment.get_value ());
2573 node->set_property ("show-measures", _show_measures);
2574 node->set_property ("maximised", _maximised);
2575 node->set_property ("follow-playhead", _follow_playhead);
2576 node->set_property ("stationary-playhead", _stationary_playhead);
2577 node->set_property ("region-list-sort-type", _regions->sort_type ());
2578 node->set_property ("mouse-mode", mouse_mode);
2579 node->set_property ("join-object-range", smart_mode_action->get_active ());
2581 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2583 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2584 node->set_property (X_("show-editor-mixer"), tact->get_active());
2587 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2589 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2590 node->set_property (X_("show-editor-list"), tact->get_active());
2593 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2595 if (button_bindings) {
2596 XMLNode* bb = new XMLNode (X_("Buttons"));
2597 button_bindings->save (*bb);
2598 node->add_child_nocopy (*bb);
2601 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2603 node->add_child_nocopy (selection->get_state ());
2604 node->add_child_nocopy (_regions->get_state ());
2606 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2608 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2609 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2610 node->add_child_nocopy (_locations->get_state ());
2615 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2616 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2618 * @return pair: TimeAxisView that y is over, layer index.
2620 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2621 * in stacked or expanded region display mode, otherwise 0.
2623 std::pair<TimeAxisView *, double>
2624 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2626 if (!trackview_relative_offset) {
2627 y -= _trackview_group->canvas_origin().y;
2631 return std::make_pair ( (TimeAxisView *) 0, 0);
2634 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2636 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2643 return std::make_pair ( (TimeAxisView *) 0, 0);
2647 Editor::set_snapped_cursor_position (samplepos_t pos)
2649 if ( _edit_point == EditAtMouse ) {
2650 snapped_cursor->set_position(pos);
2655 /** Snap a position to the grid, if appropriate, taking into account current
2656 * grid settings and also the state of any snap modifier keys that may be pressed.
2657 * @param start Position to snap.
2658 * @param event Event to get current key modifier information from, or 0.
2661 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2663 if (!_session || !event) {
2667 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2668 if (_snap_mode == SnapOff) {
2669 snap_to_internal (start, direction, for_mark);
2671 start.set (start.sample, 0);
2674 if (_snap_mode != SnapOff) {
2675 snap_to_internal (start, direction, for_mark);
2676 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2677 /* SnapOff, but we pressed the snap_delta modifier */
2678 snap_to_internal (start, direction, for_mark);
2680 start.set (start.sample, 0);
2686 Editor::snap_to (MusicSample& start, RoundMode direction, bool for_mark, bool ensure_snap)
2688 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2689 start.set (start.sample, 0);
2693 snap_to_internal (start, direction, for_mark, ensure_snap);
2697 Editor::timecode_snap_to_internal (MusicSample& pos, RoundMode direction, bool /*for_mark*/)
2699 samplepos_t start = pos.sample;
2700 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2701 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2703 switch (_snap_type) {
2704 case SnapToTimecodeFrame:
2705 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2706 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2707 /* start is already on a whole timecode frame, do nothing */
2708 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2709 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2711 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2715 case SnapToTimecodeSeconds:
2716 if (_session->config.get_timecode_offset_negative()) {
2717 start += _session->config.get_timecode_offset ();
2719 start -= _session->config.get_timecode_offset ();
2721 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2722 (start % one_timecode_second == 0)) {
2723 /* start is already on a whole second, do nothing */
2724 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2725 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2727 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2730 if (_session->config.get_timecode_offset_negative()) {
2731 start -= _session->config.get_timecode_offset ();
2733 start += _session->config.get_timecode_offset ();
2737 case SnapToTimecodeMinutes:
2738 if (_session->config.get_timecode_offset_negative()) {
2739 start += _session->config.get_timecode_offset ();
2741 start -= _session->config.get_timecode_offset ();
2743 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2744 (start % one_timecode_minute == 0)) {
2745 /* start is already on a whole minute, do nothing */
2746 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2747 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2749 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2751 if (_session->config.get_timecode_offset_negative()) {
2752 start -= _session->config.get_timecode_offset ();
2754 start += _session->config.get_timecode_offset ();
2758 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2759 abort(); /*NOTREACHED*/
2766 Editor::snap_to_internal (MusicSample& start, RoundMode direction, bool for_mark, bool ensure_snap)
2768 const samplepos_t one_second = _session->sample_rate();
2769 const samplepos_t one_minute = _session->sample_rate() * 60;
2770 samplepos_t presnap = start.sample;
2774 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
2776 switch (_snap_type) {
2777 case SnapToTimecodeFrame:
2778 case SnapToTimecodeSeconds:
2779 case SnapToTimecodeMinutes:
2780 return timecode_snap_to_internal (start, direction, for_mark);
2783 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2784 start.sample % (one_second/75) == 0) {
2785 /* start is already on a whole CD sample, do nothing */
2786 } else if (((direction == 0) && (start.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2787 start.sample = (samplepos_t) ceil ((double) start.sample / (one_second / 75)) * (one_second / 75);
2789 start.sample = (samplepos_t) floor ((double) start.sample / (one_second / 75)) * (one_second / 75);
2792 start.set (start.sample, 0);
2797 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2798 start.sample % one_second == 0) {
2799 /* start is already on a whole second, do nothing */
2800 } else if (((direction == 0) && (start.sample % one_second > one_second / 2)) || (direction > 0)) {
2801 start.sample = (samplepos_t) ceil ((double) start.sample / one_second) * one_second;
2803 start.sample = (samplepos_t) floor ((double) start.sample / one_second) * one_second;
2806 start.set (start.sample, 0);
2811 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2812 start.sample % one_minute == 0) {
2813 /* start is already on a whole minute, do nothing */
2814 } else if (((direction == 0) && (start.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2815 start.sample = (samplepos_t) ceil ((double) start.sample / one_minute) * one_minute;
2817 start.sample = (samplepos_t) floor ((double) start.sample / one_minute) * one_minute;
2820 start.set (start.sample, 0);
2825 start = _session->tempo_map().round_to_bar (start.sample, direction);
2829 start = _session->tempo_map().round_to_beat (start.sample, direction);
2832 case SnapToBeatDiv128:
2833 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 128, direction);
2835 case SnapToBeatDiv64:
2836 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 64, direction);
2838 case SnapToBeatDiv32:
2839 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 32, direction);
2841 case SnapToBeatDiv28:
2842 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 28, direction);
2844 case SnapToBeatDiv24:
2845 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 24, direction);
2847 case SnapToBeatDiv20:
2848 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 20, direction);
2850 case SnapToBeatDiv16:
2851 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 16, direction);
2853 case SnapToBeatDiv14:
2854 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 14, direction);
2856 case SnapToBeatDiv12:
2857 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 12, direction);
2859 case SnapToBeatDiv10:
2860 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 10, direction);
2862 case SnapToBeatDiv8:
2863 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 8, direction);
2865 case SnapToBeatDiv7:
2866 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 7, direction);
2868 case SnapToBeatDiv6:
2869 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 6, direction);
2871 case SnapToBeatDiv5:
2872 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 5, direction);
2874 case SnapToBeatDiv4:
2875 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 4, direction);
2877 case SnapToBeatDiv3:
2878 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 3, direction);
2880 case SnapToBeatDiv2:
2881 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 2, direction);
2889 _session->locations()->marks_either_side (start.sample, before, after);
2891 if (before == max_samplepos && after == max_samplepos) {
2892 /* No marks to snap to, so just don't snap */
2894 } else if (before == max_samplepos) {
2895 start.sample = after;
2896 } else if (after == max_samplepos) {
2897 start.sample = before;
2898 } else if (before != max_samplepos && after != max_samplepos) {
2899 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2900 start.sample = after;
2901 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2902 start.sample = before;
2903 else if (direction == 0 ) {
2904 if ((start.sample - before) < (after - start.sample)) {
2905 start.sample = before;
2907 start.sample = after;
2912 start.set (start.sample, 0);
2916 case SnapToRegionStart:
2917 case SnapToRegionEnd:
2918 case SnapToRegionSync:
2919 case SnapToRegionBoundary:
2920 if (!region_boundary_cache.empty()) {
2922 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2923 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2925 if (direction > 0) {
2926 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.sample);
2928 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.sample);
2931 if (next != region_boundary_cache.begin ()) {
2936 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2937 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2939 if (start.sample > (p + n) / 2) {
2946 start.set (start.sample, 0);
2951 switch (_snap_mode) {
2961 if (presnap > start.sample) {
2962 if (presnap > (start.sample + snap_threshold_s)) {
2963 start.set (presnap, 0);
2966 } else if (presnap < start.sample) {
2967 if (presnap < (start.sample - snap_threshold_s)) {
2968 start.set (presnap, 0);
2973 /* handled at entry */
2980 Editor::setup_toolbar ()
2982 HBox* mode_box = manage(new HBox);
2983 mode_box->set_border_width (2);
2984 mode_box->set_spacing(2);
2986 HBox* mouse_mode_box = manage (new HBox);
2987 HBox* mouse_mode_hbox = manage (new HBox);
2988 VBox* mouse_mode_vbox = manage (new VBox);
2989 Alignment* mouse_mode_align = manage (new Alignment);
2991 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2992 mouse_mode_size_group->add_widget (smart_mode_button);
2993 mouse_mode_size_group->add_widget (mouse_move_button);
2994 mouse_mode_size_group->add_widget (mouse_cut_button);
2995 mouse_mode_size_group->add_widget (mouse_select_button);
2996 mouse_mode_size_group->add_widget (mouse_timefx_button);
2997 mouse_mode_size_group->add_widget (mouse_audition_button);
2998 mouse_mode_size_group->add_widget (mouse_draw_button);
2999 mouse_mode_size_group->add_widget (mouse_content_button);
3001 if (!Profile->get_mixbus()) {
3002 mouse_mode_size_group->add_widget (zoom_in_button);
3003 mouse_mode_size_group->add_widget (zoom_out_button);
3004 mouse_mode_size_group->add_widget (zoom_out_full_button);
3005 mouse_mode_size_group->add_widget (zoom_focus_selector);
3006 mouse_mode_size_group->add_widget (tav_shrink_button);
3007 mouse_mode_size_group->add_widget (tav_expand_button);
3009 mouse_mode_size_group->add_widget (zoom_preset_selector);
3010 mouse_mode_size_group->add_widget (visible_tracks_selector);
3013 mouse_mode_size_group->add_widget (snap_type_selector);
3014 mouse_mode_size_group->add_widget (snap_mode_selector);
3016 mouse_mode_size_group->add_widget (edit_point_selector);
3017 mouse_mode_size_group->add_widget (edit_mode_selector);
3019 mouse_mode_size_group->add_widget (*nudge_clock);
3020 mouse_mode_size_group->add_widget (nudge_forward_button);
3021 mouse_mode_size_group->add_widget (nudge_backward_button);
3023 mouse_mode_hbox->set_spacing (2);
3025 if (!ARDOUR::Profile->get_trx()) {
3026 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3029 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3030 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3032 if (!ARDOUR::Profile->get_mixbus()) {
3033 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3036 if (!ARDOUR::Profile->get_trx()) {
3037 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3038 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3039 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3040 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3043 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3045 mouse_mode_align->add (*mouse_mode_vbox);
3046 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3048 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3050 edit_mode_selector.set_name ("mouse mode button");
3052 if (!ARDOUR::Profile->get_trx()) {
3053 mode_box->pack_start (edit_mode_selector, false, false);
3056 mode_box->pack_start (*mouse_mode_box, false, false);
3060 _zoom_box.set_spacing (2);
3061 _zoom_box.set_border_width (2);
3065 zoom_preset_selector.set_name ("zoom button");
3066 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3068 zoom_in_button.set_name ("zoom button");
3069 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3070 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3071 zoom_in_button.set_related_action (act);
3073 zoom_out_button.set_name ("zoom button");
3074 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3075 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3076 zoom_out_button.set_related_action (act);
3078 zoom_out_full_button.set_name ("zoom button");
3079 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3080 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3081 zoom_out_full_button.set_related_action (act);
3083 zoom_focus_selector.set_name ("zoom button");
3085 if (ARDOUR::Profile->get_mixbus()) {
3086 _zoom_box.pack_start (zoom_preset_selector, false, false);
3087 } else if (ARDOUR::Profile->get_trx()) {
3088 mode_box->pack_start (zoom_out_button, false, false);
3089 mode_box->pack_start (zoom_in_button, false, false);
3091 _zoom_box.pack_start (zoom_out_button, false, false);
3092 _zoom_box.pack_start (zoom_in_button, false, false);
3093 _zoom_box.pack_start (zoom_out_full_button, false, false);
3094 _zoom_box.pack_start (zoom_focus_selector, false, false);
3097 /* Track zoom buttons */
3098 _track_box.set_spacing (2);
3099 _track_box.set_border_width (2);
3101 visible_tracks_selector.set_name ("zoom button");
3102 if (Profile->get_mixbus()) {
3103 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3105 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3108 tav_expand_button.set_name ("zoom button");
3109 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3110 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3111 tav_expand_button.set_related_action (act);
3113 tav_shrink_button.set_name ("zoom button");
3114 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3115 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3116 tav_shrink_button.set_related_action (act);
3118 if (ARDOUR::Profile->get_mixbus()) {
3119 _track_box.pack_start (visible_tracks_selector);
3120 } else if (ARDOUR::Profile->get_trx()) {
3121 _track_box.pack_start (tav_shrink_button);
3122 _track_box.pack_start (tav_expand_button);
3124 _track_box.pack_start (visible_tracks_selector);
3125 _track_box.pack_start (tav_shrink_button);
3126 _track_box.pack_start (tav_expand_button);
3129 snap_box.set_spacing (2);
3130 snap_box.set_border_width (2);
3132 snap_type_selector.set_name ("mouse mode button");
3134 snap_mode_selector.set_name ("mouse mode button");
3136 edit_point_selector.set_name ("mouse mode button");
3138 snap_box.pack_start (snap_mode_selector, false, false);
3139 snap_box.pack_start (snap_type_selector, false, false);
3142 HBox *ep_box = manage (new HBox);
3143 ep_box->set_spacing (2);
3144 ep_box->set_border_width (2);
3146 ep_box->pack_start (edit_point_selector, false, false);
3150 HBox *nudge_box = manage (new HBox);
3151 nudge_box->set_spacing (2);
3152 nudge_box->set_border_width (2);
3154 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3155 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3157 nudge_box->pack_start (nudge_backward_button, false, false);
3158 nudge_box->pack_start (nudge_forward_button, false, false);
3159 nudge_box->pack_start (*nudge_clock, false, false);
3162 /* Pack everything in... */
3164 toolbar_hbox.set_spacing (2);
3165 toolbar_hbox.set_border_width (2);
3167 toolbar_hbox.pack_start (*mode_box, false, false);
3169 if (!ARDOUR::Profile->get_trx()) {
3171 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3173 toolbar_hbox.pack_start (_zoom_box, false, false);
3175 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3177 toolbar_hbox.pack_start (_track_box, false, false);
3179 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3181 toolbar_hbox.pack_start (snap_box, false, false);
3183 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3185 toolbar_hbox.pack_start (*ep_box, false, false);
3187 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3189 toolbar_hbox.pack_start (*nudge_box, false, false);
3192 toolbar_hbox.show_all ();
3196 Editor::build_edit_point_menu ()
3198 using namespace Menu_Helpers;
3200 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3201 if(!Profile->get_mixbus())
3202 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3203 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3205 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3209 Editor::build_edit_mode_menu ()
3211 using namespace Menu_Helpers;
3213 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3214 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3215 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3216 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3218 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3222 Editor::build_snap_mode_menu ()
3224 using namespace Menu_Helpers;
3226 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3227 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3228 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3230 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3234 Editor::build_snap_type_menu ()
3236 using namespace Menu_Helpers;
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3269 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3274 Editor::setup_tooltips ()
3276 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3277 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3278 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3279 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3280 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3281 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3282 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3283 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3284 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3285 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3286 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3287 set_tooltip (zoom_in_button, _("Zoom In"));
3288 set_tooltip (zoom_out_button, _("Zoom Out"));
3289 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3290 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3291 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3292 set_tooltip (tav_expand_button, _("Expand Tracks"));
3293 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3294 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3295 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3296 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3297 set_tooltip (edit_point_selector, _("Edit Point"));
3298 set_tooltip (edit_mode_selector, _("Edit Mode"));
3299 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3303 Editor::convert_drop_to_paths (
3304 vector<string>& paths,
3305 const RefPtr<Gdk::DragContext>& /*context*/,
3308 const SelectionData& data,
3312 if (_session == 0) {
3316 vector<string> uris = data.get_uris();
3320 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3321 are actually URI lists. So do it by hand.
3324 if (data.get_target() != "text/plain") {
3328 /* Parse the "uri-list" format that Nautilus provides,
3329 where each pathname is delimited by \r\n.
3331 THERE MAY BE NO NULL TERMINATING CHAR!!!
3334 string txt = data.get_text();
3338 p = (char *) malloc (txt.length() + 1);
3339 txt.copy (p, txt.length(), 0);
3340 p[txt.length()] = '\0';
3346 while (g_ascii_isspace (*p))
3350 while (*q && (*q != '\n') && (*q != '\r')) {
3357 while (q > p && g_ascii_isspace (*q))
3362 uris.push_back (string (p, q - p + 1));
3366 p = strchr (p, '\n');
3378 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3379 if ((*i).substr (0,7) == "file://") {
3380 paths.push_back (Glib::filename_from_uri (*i));
3388 Editor::new_tempo_section ()
3393 Editor::map_transport_state ()
3395 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3397 if (_session && _session->transport_stopped()) {
3398 have_pending_keyboard_selection = false;
3401 update_loop_range_view ();
3405 Editor::transport_looped ()
3407 /* reset Playhead position interpolation.
3408 * see Editor::super_rapid_screen_update
3410 _last_update_time = 0;
3416 Editor::begin_selection_op_history ()
3418 selection_op_cmd_depth = 0;
3419 selection_op_history_it = 0;
3421 while(!selection_op_history.empty()) {
3422 delete selection_op_history.front();
3423 selection_op_history.pop_front();
3426 selection_undo_action->set_sensitive (false);
3427 selection_redo_action->set_sensitive (false);
3428 selection_op_history.push_front (&_selection_memento->get_state ());
3432 Editor::begin_reversible_selection_op (string name)
3435 //cerr << name << endl;
3436 /* begin/commit pairs can be nested */
3437 selection_op_cmd_depth++;
3442 Editor::commit_reversible_selection_op ()
3445 if (selection_op_cmd_depth == 1) {
3447 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3449 The user has undone some selection ops and then made a new one,
3450 making anything earlier in the list invalid.
3453 list<XMLNode *>::iterator it = selection_op_history.begin();
3454 list<XMLNode *>::iterator e_it = it;
3455 advance (e_it, selection_op_history_it);
3457 for ( ; it != e_it; ++it) {
3460 selection_op_history.erase (selection_op_history.begin(), e_it);
3463 selection_op_history.push_front (&_selection_memento->get_state ());
3464 selection_op_history_it = 0;
3466 selection_undo_action->set_sensitive (true);
3467 selection_redo_action->set_sensitive (false);
3470 if (selection_op_cmd_depth > 0) {
3471 selection_op_cmd_depth--;
3477 Editor::undo_selection_op ()
3480 selection_op_history_it++;
3482 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3483 if (n == selection_op_history_it) {
3484 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3485 selection_redo_action->set_sensitive (true);
3489 /* is there an earlier entry? */
3490 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3491 selection_undo_action->set_sensitive (false);
3497 Editor::redo_selection_op ()
3500 if (selection_op_history_it > 0) {
3501 selection_op_history_it--;
3504 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3505 if (n == selection_op_history_it) {
3506 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3507 selection_undo_action->set_sensitive (true);
3512 if (selection_op_history_it == 0) {
3513 selection_redo_action->set_sensitive (false);
3519 Editor::begin_reversible_command (string name)
3522 before.push_back (&_selection_memento->get_state ());
3523 _session->begin_reversible_command (name);
3528 Editor::begin_reversible_command (GQuark q)
3531 before.push_back (&_selection_memento->get_state ());
3532 _session->begin_reversible_command (q);
3537 Editor::abort_reversible_command ()
3540 while(!before.empty()) {
3541 delete before.front();
3544 _session->abort_reversible_command ();
3549 Editor::commit_reversible_command ()
3552 if (before.size() == 1) {
3553 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3554 redo_action->set_sensitive(false);
3555 undo_action->set_sensitive(true);
3556 begin_selection_op_history ();
3559 if (before.empty()) {
3560 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3565 _session->commit_reversible_command ();
3570 Editor::history_changed ()
3574 if (undo_action && _session) {
3575 if (_session->undo_depth() == 0) {
3576 label = S_("Command|Undo");
3578 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3580 undo_action->property_label() = label;
3583 if (redo_action && _session) {
3584 if (_session->redo_depth() == 0) {
3586 redo_action->set_sensitive (false);
3588 label = string_compose(_("Redo (%1)"), _session->next_redo());
3589 redo_action->set_sensitive (true);
3591 redo_action->property_label() = label;
3596 Editor::duplicate_range (bool with_dialog)
3600 RegionSelection rs = get_regions_from_selection_and_entered ();
3602 if ( selection->time.length() == 0 && rs.empty()) {
3608 ArdourDialog win (_("Duplicate"));
3609 Label label (_("Number of duplications:"));
3610 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3611 SpinButton spinner (adjustment, 0.0, 1);
3614 win.get_vbox()->set_spacing (12);
3615 win.get_vbox()->pack_start (hbox);
3616 hbox.set_border_width (6);
3617 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3619 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3620 place, visually. so do this by hand.
3623 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3624 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3625 spinner.grab_focus();
3631 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3632 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3633 win.set_default_response (RESPONSE_ACCEPT);
3635 spinner.grab_focus ();
3637 switch (win.run ()) {
3638 case RESPONSE_ACCEPT:
3644 times = adjustment.get_value();
3647 if ((current_mouse_mode() == Editing::MouseRange)) {
3648 if (selection->time.length()) {
3649 duplicate_selection (times);
3651 } else if (get_smart_mode()) {
3652 if (selection->time.length()) {
3653 duplicate_selection (times);
3655 duplicate_some_regions (rs, times);
3657 duplicate_some_regions (rs, times);
3662 Editor::set_edit_mode (EditMode m)
3664 Config->set_edit_mode (m);
3668 Editor::cycle_edit_mode ()
3670 switch (Config->get_edit_mode()) {
3672 Config->set_edit_mode (Ripple);
3676 Config->set_edit_mode (Lock);
3679 Config->set_edit_mode (Slide);
3685 Editor::edit_mode_selection_done ( EditMode m )
3687 Config->set_edit_mode ( m );
3691 Editor::snap_type_selection_done (SnapType snaptype)
3693 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3695 ract->set_active ();
3700 Editor::snap_mode_selection_done (SnapMode mode)
3702 RefPtr<RadioAction> ract = snap_mode_action (mode);
3705 ract->set_active (true);
3710 Editor::cycle_edit_point (bool with_marker)
3712 if(Profile->get_mixbus())
3713 with_marker = false;
3715 switch (_edit_point) {
3717 set_edit_point_preference (EditAtPlayhead);
3719 case EditAtPlayhead:
3721 set_edit_point_preference (EditAtSelectedMarker);
3723 set_edit_point_preference (EditAtMouse);
3726 case EditAtSelectedMarker:
3727 set_edit_point_preference (EditAtMouse);
3733 Editor::edit_point_selection_done (EditPoint ep)
3735 set_edit_point_preference ( ep );
3739 Editor::build_zoom_focus_menu ()
3741 using namespace Menu_Helpers;
3743 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3744 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3745 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3746 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3747 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3748 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3750 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3754 Editor::zoom_focus_selection_done ( ZoomFocus f )
3756 RefPtr<RadioAction> ract = zoom_focus_action (f);
3758 ract->set_active ();
3763 Editor::build_track_count_menu ()
3765 using namespace Menu_Helpers;
3767 if (!Profile->get_mixbus()) {
3768 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3790 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3791 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3793 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3794 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3795 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3796 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3797 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3798 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3799 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3800 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3801 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3802 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3803 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3804 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3809 Editor::set_zoom_preset (int64_t ms)
3812 temporal_zoom_session();
3816 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3817 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3821 Editor::set_visible_track_count (int32_t n)
3823 _visible_track_count = n;
3825 /* if the canvas hasn't really been allocated any size yet, just
3826 record the desired number of visible tracks and return. when canvas
3827 allocation happens, we will get called again and then we can do the
3831 if (_visible_canvas_height <= 1) {
3837 DisplaySuspender ds;
3839 if (_visible_track_count > 0) {
3840 h = trackviews_height() / _visible_track_count;
3841 std::ostringstream s;
3842 s << _visible_track_count;
3844 } else if (_visible_track_count == 0) {
3846 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3847 if ((*i)->marked_for_display()) {
3849 TimeAxisView::Children cl ((*i)->get_child_list ());
3850 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3851 if ((*j)->marked_for_display()) {
3858 visible_tracks_selector.set_text (X_("*"));
3861 h = trackviews_height() / n;
3864 /* negative value means that the visible track count has
3865 been overridden by explicit track height changes.
3867 visible_tracks_selector.set_text (X_("*"));
3871 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3872 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3875 if (str != visible_tracks_selector.get_text()) {
3876 visible_tracks_selector.set_text (str);
3881 Editor::override_visible_track_count ()
3883 _visible_track_count = -1;
3884 visible_tracks_selector.set_text ( _("*") );
3888 Editor::edit_controls_button_release (GdkEventButton* ev)
3890 if (Keyboard::is_context_menu_event (ev)) {
3891 ARDOUR_UI::instance()->add_route ();
3892 } else if (ev->button == 1) {
3893 selection->clear_tracks ();
3900 Editor::mouse_select_button_release (GdkEventButton* ev)
3902 /* this handles just right-clicks */
3904 if (ev->button != 3) {
3912 Editor::set_zoom_focus (ZoomFocus f)
3914 string str = zoom_focus_strings[(int)f];
3916 if (str != zoom_focus_selector.get_text()) {
3917 zoom_focus_selector.set_text (str);
3920 if (zoom_focus != f) {
3927 Editor::cycle_zoom_focus ()
3929 switch (zoom_focus) {
3931 set_zoom_focus (ZoomFocusRight);
3933 case ZoomFocusRight:
3934 set_zoom_focus (ZoomFocusCenter);
3936 case ZoomFocusCenter:
3937 set_zoom_focus (ZoomFocusPlayhead);
3939 case ZoomFocusPlayhead:
3940 set_zoom_focus (ZoomFocusMouse);
3942 case ZoomFocusMouse:
3943 set_zoom_focus (ZoomFocusEdit);
3946 set_zoom_focus (ZoomFocusLeft);
3952 Editor::set_show_measures (bool yn)
3954 if (_show_measures != yn) {
3957 if ((_show_measures = yn) == true) {
3959 tempo_lines->show();
3962 std::vector<TempoMap::BBTPoint> grid;
3963 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3964 draw_measures (grid);
3972 Editor::toggle_follow_playhead ()
3974 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3976 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3977 set_follow_playhead (tact->get_active());
3981 /** @param yn true to follow playhead, otherwise false.
3982 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3985 Editor::set_follow_playhead (bool yn, bool catch_up)
3987 if (_follow_playhead != yn) {
3988 if ((_follow_playhead = yn) == true && catch_up) {
3990 reset_x_origin_to_follow_playhead ();
3997 Editor::toggle_stationary_playhead ()
3999 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4001 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4002 set_stationary_playhead (tact->get_active());
4007 Editor::set_stationary_playhead (bool yn)
4009 if (_stationary_playhead != yn) {
4010 if ((_stationary_playhead = yn) == true) {
4012 // FIXME need a 3.0 equivalent of this 2.X call
4013 // update_current_screen ();
4020 Editor::playlist_selector () const
4022 return *_playlist_selector;
4026 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4028 if (paste_count == 0) {
4029 /* don't bother calculating an offset that will be zero anyway */
4033 /* calculate basic unsnapped multi-paste offset */
4034 samplecnt_t offset = paste_count * duration;
4036 /* snap offset so pos + offset is aligned to the grid */
4037 MusicSample offset_pos (pos + offset, 0);
4038 snap_to(offset_pos, RoundUpMaybe);
4039 offset = offset_pos.sample - pos;
4045 Editor::get_grid_beat_divisions(samplepos_t position)
4047 switch (_snap_type) {
4048 case SnapToBeatDiv128: return 128;
4049 case SnapToBeatDiv64: return 64;
4050 case SnapToBeatDiv32: return 32;
4051 case SnapToBeatDiv28: return 28;
4052 case SnapToBeatDiv24: return 24;
4053 case SnapToBeatDiv20: return 20;
4054 case SnapToBeatDiv16: return 16;
4055 case SnapToBeatDiv14: return 14;
4056 case SnapToBeatDiv12: return 12;
4057 case SnapToBeatDiv10: return 10;
4058 case SnapToBeatDiv8: return 8;
4059 case SnapToBeatDiv7: return 7;
4060 case SnapToBeatDiv6: return 6;
4061 case SnapToBeatDiv5: return 5;
4062 case SnapToBeatDiv4: return 4;
4063 case SnapToBeatDiv3: return 3;
4064 case SnapToBeatDiv2: return 2;
4070 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4071 if the grid is non-musical, returns 0.
4072 if the grid is snapped to bars, returns -1.
4073 @param event_state the current keyboard modifier mask.
4076 Editor::get_grid_music_divisions (uint32_t event_state)
4078 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4082 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4086 switch (_snap_type) {
4087 case SnapToBeatDiv128: return 128;
4088 case SnapToBeatDiv64: return 64;
4089 case SnapToBeatDiv32: return 32;
4090 case SnapToBeatDiv28: return 28;
4091 case SnapToBeatDiv24: return 24;
4092 case SnapToBeatDiv20: return 20;
4093 case SnapToBeatDiv16: return 16;
4094 case SnapToBeatDiv14: return 14;
4095 case SnapToBeatDiv12: return 12;
4096 case SnapToBeatDiv10: return 10;
4097 case SnapToBeatDiv8: return 8;
4098 case SnapToBeatDiv7: return 7;
4099 case SnapToBeatDiv6: return 6;
4100 case SnapToBeatDiv5: return 5;
4101 case SnapToBeatDiv4: return 4;
4102 case SnapToBeatDiv3: return 3;
4103 case SnapToBeatDiv2: return 2;
4104 case SnapToBeat: return 1;
4105 case SnapToBar : return -1;
4112 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4116 const unsigned divisions = get_grid_beat_divisions(position);
4118 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4121 switch (_snap_type) {
4123 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4126 const Meter& m = _session->tempo_map().meter_at_sample (position);
4127 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4135 return Temporal::Beats();
4139 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4143 ret = nudge_clock->current_duration (pos);
4144 next = ret + 1; /* XXXX fix me */
4150 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4152 ArdourDialog dialog (_("Playlist Deletion"));
4153 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4154 "If it is kept, its audio files will not be cleaned.\n"
4155 "If it is deleted, audio files used by it alone will be cleaned."),
4158 dialog.set_position (WIN_POS_CENTER);
4159 dialog.get_vbox()->pack_start (label);
4163 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4164 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4165 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4166 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4167 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4169 // by default gtk uses the left most button
4170 keep->grab_focus ();
4172 switch (dialog.run ()) {
4174 /* keep this and all remaining ones */
4179 /* delete this and all others */
4183 case RESPONSE_ACCEPT:
4184 /* delete the playlist */
4188 case RESPONSE_REJECT:
4189 /* keep the playlist */
4201 Editor::audio_region_selection_covers (samplepos_t where)
4203 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4204 if ((*a)->region()->covers (where)) {
4213 Editor::prepare_for_cleanup ()
4215 cut_buffer->clear_regions ();
4216 cut_buffer->clear_playlists ();
4218 selection->clear_regions ();
4219 selection->clear_playlists ();
4221 _regions->suspend_redisplay ();
4225 Editor::finish_cleanup ()
4227 _regions->resume_redisplay ();
4231 Editor::transport_loop_location()
4234 return _session->locations()->auto_loop_location();
4241 Editor::transport_punch_location()
4244 return _session->locations()->auto_punch_location();
4251 Editor::control_layout_scroll (GdkEventScroll* ev)
4253 /* Just forward to the normal canvas scroll method. The coordinate
4254 systems are different but since the canvas is always larger than the
4255 track headers, and aligned with the trackview area, this will work.
4257 In the not too distant future this layout is going away anyway and
4258 headers will be on the canvas.
4260 return canvas_scroll_event (ev, false);
4264 Editor::session_state_saved (string)
4267 _snapshots->redisplay ();
4271 Editor::maximise_editing_space ()
4277 Gtk::Window* toplevel = current_toplevel();
4280 toplevel->fullscreen ();
4286 Editor::restore_editing_space ()
4292 Gtk::Window* toplevel = current_toplevel();
4295 toplevel->unfullscreen();
4301 * Make new playlists for a given track and also any others that belong
4302 * to the same active route group with the `select' property.
4307 Editor::new_playlists (TimeAxisView* v)
4309 begin_reversible_command (_("new playlists"));
4310 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4311 _session->playlists->get (playlists);
4312 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4313 commit_reversible_command ();
4317 * Use a copy of the current playlist for a given track and also any others that belong
4318 * to the same active route group with the `select' property.
4323 Editor::copy_playlists (TimeAxisView* v)
4325 begin_reversible_command (_("copy playlists"));
4326 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4327 _session->playlists->get (playlists);
4328 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4329 commit_reversible_command ();
4332 /** Clear the current playlist for a given track and also any others that belong
4333 * to the same active route group with the `select' property.
4338 Editor::clear_playlists (TimeAxisView* v)
4340 begin_reversible_command (_("clear playlists"));
4341 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4342 _session->playlists->get (playlists);
4343 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4344 commit_reversible_command ();
4348 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4350 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4354 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4356 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4360 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4362 atv.clear_playlist ();
4366 Editor::get_y_origin () const
4368 return vertical_adjustment.get_value ();
4371 /** Queue up a change to the viewport x origin.
4372 * @param sample New x origin.
4375 Editor::reset_x_origin (samplepos_t sample)
4377 pending_visual_change.add (VisualChange::TimeOrigin);
4378 pending_visual_change.time_origin = sample;
4379 ensure_visual_change_idle_handler ();
4383 Editor::reset_y_origin (double y)
4385 pending_visual_change.add (VisualChange::YOrigin);
4386 pending_visual_change.y_origin = y;
4387 ensure_visual_change_idle_handler ();
4391 Editor::reset_zoom (samplecnt_t spp)
4393 if (spp == samples_per_pixel) {
4397 pending_visual_change.add (VisualChange::ZoomLevel);
4398 pending_visual_change.samples_per_pixel = spp;
4399 ensure_visual_change_idle_handler ();
4403 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4405 reset_x_origin (sample);
4408 if (!no_save_visual) {
4409 undo_visual_stack.push_back (current_visual_state(false));
4413 Editor::VisualState::VisualState (bool with_tracks)
4414 : gui_state (with_tracks ? new GUIObjectState : 0)
4418 Editor::VisualState::~VisualState ()
4423 Editor::VisualState*
4424 Editor::current_visual_state (bool with_tracks)
4426 VisualState* vs = new VisualState (with_tracks);
4427 vs->y_position = vertical_adjustment.get_value();
4428 vs->samples_per_pixel = samples_per_pixel;
4429 vs->_leftmost_sample = _leftmost_sample;
4430 vs->zoom_focus = zoom_focus;
4433 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4440 Editor::undo_visual_state ()
4442 if (undo_visual_stack.empty()) {
4446 VisualState* vs = undo_visual_stack.back();
4447 undo_visual_stack.pop_back();
4450 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4453 use_visual_state (*vs);
4458 Editor::redo_visual_state ()
4460 if (redo_visual_stack.empty()) {
4464 VisualState* vs = redo_visual_stack.back();
4465 redo_visual_stack.pop_back();
4467 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4468 // why do we check here?
4469 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4472 use_visual_state (*vs);
4477 Editor::swap_visual_state ()
4479 if (undo_visual_stack.empty()) {
4480 redo_visual_state ();
4482 undo_visual_state ();
4487 Editor::use_visual_state (VisualState& vs)
4489 PBD::Unwinder<bool> nsv (no_save_visual, true);
4490 DisplaySuspender ds;
4492 vertical_adjustment.set_value (vs.y_position);
4494 set_zoom_focus (vs.zoom_focus);
4495 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4498 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4500 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4501 (*i)->clear_property_cache();
4502 (*i)->reset_visual_state ();
4506 _routes->update_visibility ();
4509 /** This is the core function that controls the zoom level of the canvas. It is called
4510 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4511 * @param spp new number of samples per pixel
4514 Editor::set_samples_per_pixel (samplecnt_t spp)
4520 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4521 const samplecnt_t lots_of_pixels = 4000;
4523 /* if the zoom level is greater than what you'd get trying to display 3
4524 * days of audio on a really big screen, then it's too big.
4527 if (spp * lots_of_pixels > three_days) {
4531 samples_per_pixel = spp;
4535 Editor::on_samples_per_pixel_changed ()
4538 tempo_lines->tempo_map_changed(_session->tempo_map().music_origin());
4541 bool const showing_time_selection = selection->time.length() > 0;
4543 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4544 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4545 (*i)->reshow_selection (selection->time);
4549 ZoomChanged (); /* EMIT_SIGNAL */
4551 ArdourCanvas::GtkCanvasViewport* c;
4553 c = get_track_canvas();
4555 c->canvas()->zoomed ();
4558 if (playhead_cursor) {
4559 playhead_cursor->set_position (playhead_cursor->current_sample ());
4562 refresh_location_display();
4563 _summary->set_overlays_dirty ();
4565 update_marker_labels ();
4571 Editor::playhead_cursor_sample () const
4573 return playhead_cursor->current_sample();
4577 Editor::queue_visual_videotimeline_update ()
4579 pending_visual_change.add (VisualChange::VideoTimeline);
4580 ensure_visual_change_idle_handler ();
4584 Editor::ensure_visual_change_idle_handler ()
4586 if (pending_visual_change.idle_handler_id < 0) {
4587 // see comment in add_to_idle_resize above.
4588 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4589 pending_visual_change.being_handled = false;
4594 Editor::_idle_visual_changer (void* arg)
4596 return static_cast<Editor*>(arg)->idle_visual_changer ();
4600 Editor::pre_render ()
4602 visual_change_queued = false;
4604 if (pending_visual_change.pending != 0) {
4605 ensure_visual_change_idle_handler();
4610 Editor::idle_visual_changer ()
4612 pending_visual_change.idle_handler_id = -1;
4614 if (pending_visual_change.pending == 0) {
4618 /* set_horizontal_position() below (and maybe other calls) call
4619 gtk_main_iteration(), so it's possible that a signal will be handled
4620 half-way through this method. If this signal wants an
4621 idle_visual_changer we must schedule another one after this one, so
4622 mark the idle_handler_id as -1 here to allow that. Also make a note
4623 that we are doing the visual change, so that changes in response to
4624 super-rapid-screen-update can be dropped if we are still processing
4628 if (visual_change_queued) {
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 visual_change_queued = true;
4644 return 0; /* this is always a one-shot call */
4648 Editor::visual_changer (const VisualChange& vc)
4651 * Changed first so the correct horizontal canvas position is calculated in
4652 * Editor::set_horizontal_position
4654 if (vc.pending & VisualChange::ZoomLevel) {
4655 set_samples_per_pixel (vc.samples_per_pixel);
4658 if (vc.pending & VisualChange::TimeOrigin) {
4659 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4660 set_horizontal_position (new_time_origin);
4663 if (vc.pending & VisualChange::YOrigin) {
4664 vertical_adjustment.set_value (vc.y_origin);
4668 * Now the canvas is in the final state before render the canvas items that
4669 * support the Item::prepare_for_render interface can calculate the correct
4670 * item to visible canvas intersection.
4672 if (vc.pending & VisualChange::ZoomLevel) {
4673 on_samples_per_pixel_changed ();
4675 compute_fixed_ruler_scale ();
4677 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4678 update_tempo_based_rulers ();
4681 if (!(vc.pending & VisualChange::ZoomLevel)) {
4683 * If the canvas is not being zoomed then the canvas items will not change
4684 * and cause Item::prepare_for_render to be called so do it here manually.
4686 * Not ideal, but I can't think of a better solution atm.
4688 _track_canvas->prepare_for_render();
4691 // If we are only scrolling vertically there is no need to update these
4692 if (vc.pending != VisualChange::YOrigin) {
4693 update_fixed_rulers ();
4694 redisplay_tempo (true);
4696 /* video frames & position need to be updated for zoom, horiz-scroll
4697 * and (explicitly) VisualChange::VideoTimeline.
4699 update_video_timeline();
4702 _summary->set_overlays_dirty ();
4705 struct EditorOrderTimeAxisSorter {
4706 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4707 return a->order () < b->order ();
4712 Editor::sort_track_selection (TrackViewList& sel)
4714 EditorOrderTimeAxisSorter cmp;
4719 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4722 samplepos_t where = 0;
4723 EditPoint ep = _edit_point;
4725 if (Profile->get_mixbus()) {
4726 if (ep == EditAtSelectedMarker) {
4727 ep = EditAtPlayhead;
4731 if (from_outside_canvas && (ep == EditAtMouse)) {
4732 ep = EditAtPlayhead;
4733 } else if (from_context_menu && (ep == EditAtMouse)) {
4734 return canvas_event_sample (&context_click_event, 0, 0);
4737 if (entered_marker) {
4738 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4739 return entered_marker->position();
4742 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4743 ep = EditAtSelectedMarker;
4746 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4747 ep = EditAtPlayhead;
4750 MusicSample snap_mf (0, 0);
4753 case EditAtPlayhead:
4754 if (_dragging_playhead && _control_scroll_target) {
4755 where = *_control_scroll_target;
4757 where = _session->audible_sample();
4759 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4762 case EditAtSelectedMarker:
4763 if (!selection->markers.empty()) {
4765 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4768 where = loc->start();
4772 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4780 if (!mouse_sample (where, ignored)) {
4781 /* XXX not right but what can we do ? */
4784 snap_mf.sample = where;
4786 where = snap_mf.sample;
4787 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4795 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4797 if (!_session) return;
4799 begin_reversible_command (cmd);
4803 if ((tll = transport_loop_location()) == 0) {
4804 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4805 XMLNode &before = _session->locations()->get_state();
4806 _session->locations()->add (loc, true);
4807 _session->set_auto_loop_location (loc);
4808 XMLNode &after = _session->locations()->get_state();
4809 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4811 XMLNode &before = tll->get_state();
4812 tll->set_hidden (false, this);
4813 tll->set (start, end);
4814 XMLNode &after = tll->get_state();
4815 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4818 commit_reversible_command ();
4822 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4824 if (!_session) return;
4826 begin_reversible_command (cmd);
4830 if ((tpl = transport_punch_location()) == 0) {
4831 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4832 XMLNode &before = _session->locations()->get_state();
4833 _session->locations()->add (loc, true);
4834 _session->set_auto_punch_location (loc);
4835 XMLNode &after = _session->locations()->get_state();
4836 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4838 XMLNode &before = tpl->get_state();
4839 tpl->set_hidden (false, this);
4840 tpl->set (start, end);
4841 XMLNode &after = tpl->get_state();
4842 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4845 commit_reversible_command ();
4848 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4849 * @param rs List to which found regions are added.
4850 * @param where Time to look at.
4851 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4854 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4856 const TrackViewList* tracks;
4859 tracks = &track_views;
4864 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4866 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4869 boost::shared_ptr<Track> tr;
4870 boost::shared_ptr<Playlist> pl;
4872 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4874 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4876 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4877 RegionView* rv = rtv->view()->find_view (*i);
4888 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4890 const TrackViewList* tracks;
4893 tracks = &track_views;
4898 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4899 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4901 boost::shared_ptr<Track> tr;
4902 boost::shared_ptr<Playlist> pl;
4904 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4906 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4908 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4910 RegionView* rv = rtv->view()->find_view (*i);
4921 /** Get regions using the following method:
4923 * Make a region list using:
4924 * (a) any selected regions
4925 * (b) the intersection of any selected tracks and the edit point(*)
4926 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4928 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4930 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4934 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4936 RegionSelection regions;
4938 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4939 regions.add (entered_regionview);
4941 regions = selection->regions;
4944 if ( regions.empty() ) {
4945 TrackViewList tracks = selection->tracks;
4947 if (!tracks.empty()) {
4948 /* no region selected or entered, but some selected tracks:
4949 * act on all regions on the selected tracks at the edit point
4951 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4952 get_regions_at(regions, where, tracks);
4959 /** Get regions using the following method:
4961 * Make a region list using:
4962 * (a) any selected regions
4963 * (b) the intersection of any selected tracks and the edit point(*)
4964 * (c) if neither exists, then whatever region is under the mouse
4966 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4968 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4971 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4973 RegionSelection regions;
4975 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4976 regions.add (entered_regionview);
4978 regions = selection->regions;
4981 if ( regions.empty() ) {
4982 TrackViewList tracks = selection->tracks;
4984 if (!tracks.empty()) {
4985 /* no region selected or entered, but some selected tracks:
4986 * act on all regions on the selected tracks at the edit point
4988 get_regions_at(regions, pos, tracks);
4995 /** Start with regions that are selected, or the entered regionview if none are selected.
4996 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4997 * of the regions that we started with.
5001 Editor::get_regions_from_selection_and_entered () const
5003 RegionSelection regions = selection->regions;
5005 if (regions.empty() && entered_regionview) {
5006 regions.add (entered_regionview);
5013 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5015 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5016 RouteTimeAxisView* rtav;
5018 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5019 boost::shared_ptr<Playlist> pl;
5020 std::vector<boost::shared_ptr<Region> > results;
5021 boost::shared_ptr<Track> tr;
5023 if ((tr = rtav->track()) == 0) {
5028 if ((pl = (tr->playlist())) != 0) {
5029 boost::shared_ptr<Region> r = pl->region_by_id (id);
5031 RegionView* rv = rtav->view()->find_view (r);
5033 regions.push_back (rv);
5042 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5045 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5046 MidiTimeAxisView* mtav;
5048 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5050 mtav->get_per_region_note_selection (selection);
5057 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5059 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5061 RouteTimeAxisView* tatv;
5063 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5065 boost::shared_ptr<Playlist> pl;
5066 vector<boost::shared_ptr<Region> > results;
5068 boost::shared_ptr<Track> tr;
5070 if ((tr = tatv->track()) == 0) {
5075 if ((pl = (tr->playlist())) != 0) {
5076 if (src_comparison) {
5077 pl->get_source_equivalent_regions (region, results);
5079 pl->get_region_list_equivalent_regions (region, results);
5083 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5084 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5085 regions.push_back (marv);
5094 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5096 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5097 RouteTimeAxisView* tatv;
5098 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5099 if (!tatv->track()) {
5102 RegionView* marv = tatv->view()->find_view (region);
5112 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5114 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5115 RouteTimeAxisView* rtav;
5116 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5117 if (rtav->route() == route) {
5126 Editor::show_rhythm_ferret ()
5128 if (rhythm_ferret == 0) {
5129 rhythm_ferret = new RhythmFerret(*this);
5132 rhythm_ferret->set_session (_session);
5133 rhythm_ferret->show ();
5134 rhythm_ferret->present ();
5138 Editor::first_idle ()
5140 MessageDialog* dialog = 0;
5142 if (track_views.size() > 1) {
5143 Timers::TimerSuspender t;
5144 dialog = new MessageDialog (
5145 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5149 ARDOUR_UI::instance()->flush_pending (60);
5152 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5156 /* now that all regionviews should exist, setup region selection */
5160 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5161 /* this is cumulative: rs is NOT cleared each time */
5162 get_regionviews_by_id (*pr, rs);
5165 selection->set (rs);
5167 // first idle adds route children (automation tracks), so we need to redisplay here
5168 _routes->redisplay ();
5172 if (_session->undo_depth() == 0) {
5173 undo_action->set_sensitive(false);
5175 redo_action->set_sensitive(false);
5176 begin_selection_op_history ();
5182 Editor::_idle_resize (gpointer arg)
5184 return ((Editor*)arg)->idle_resize ();
5188 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5190 if (resize_idle_id < 0) {
5191 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5192 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5193 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5195 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5196 _pending_resize_amount = 0;
5199 /* make a note of the smallest resulting height, so that we can clamp the
5200 lower limit at TimeAxisView::hSmall */
5202 int32_t min_resulting = INT32_MAX;
5204 _pending_resize_amount += h;
5205 _pending_resize_view = view;
5207 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5209 if (selection->tracks.contains (_pending_resize_view)) {
5210 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5211 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5215 if (min_resulting < 0) {
5220 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5221 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5225 /** Handle pending resizing of tracks */
5227 Editor::idle_resize ()
5229 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5231 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5232 selection->tracks.contains (_pending_resize_view)) {
5234 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5235 if (*i != _pending_resize_view) {
5236 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5241 _pending_resize_amount = 0;
5242 _group_tabs->set_dirty ();
5243 resize_idle_id = -1;
5251 ENSURE_GUI_THREAD (*this, &Editor::located);
5254 playhead_cursor->set_position (_session->audible_sample ());
5255 if (_follow_playhead && !_pending_initial_locate) {
5256 reset_x_origin_to_follow_playhead ();
5260 _pending_locate_request = false;
5261 _pending_initial_locate = false;
5262 _last_update_time = 0;
5266 Editor::region_view_added (RegionView * rv)
5268 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5270 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5271 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5272 if (rv->region()->id () == (*rnote).first) {
5273 mrv->select_notes ((*rnote).second);
5274 selection->pending_midi_note_selection.erase(rnote);
5280 _summary->set_background_dirty ();
5284 Editor::region_view_removed ()
5286 _summary->set_background_dirty ();
5290 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5292 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5293 if ((*j)->stripable() == s) {
5302 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5304 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5305 if ((*j)->control() == c) {
5309 TimeAxisView::Children kids = (*j)->get_child_list ();
5311 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5312 if ((*k)->control() == c) {
5322 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5326 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5327 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5337 Editor::suspend_route_redisplay ()
5340 _routes->suspend_redisplay();
5345 Editor::resume_route_redisplay ()
5348 _routes->redisplay(); // queue redisplay
5349 _routes->resume_redisplay();
5354 Editor::add_vcas (VCAList& vlist)
5358 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5359 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5362 add_stripables (sl);
5366 Editor::add_routes (RouteList& rlist)
5370 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5374 add_stripables (sl);
5378 Editor::add_stripables (StripableList& sl)
5380 list<TimeAxisView*> new_views;
5381 boost::shared_ptr<VCA> v;
5382 boost::shared_ptr<Route> r;
5383 TrackViewList new_selection;
5384 bool from_scratch = (track_views.size() == 0);
5386 sl.sort (Stripable::Sorter());
5388 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5390 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5392 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5394 new_views.push_back (vtv);
5396 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5398 if (r->is_auditioner() || r->is_monitor()) {
5402 RouteTimeAxisView* rtv;
5403 DataType dt = r->input()->default_type();
5405 if (dt == ARDOUR::DataType::AUDIO) {
5406 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5408 } else if (dt == ARDOUR::DataType::MIDI) {
5409 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5412 throw unknown_type();
5415 new_views.push_back (rtv);
5416 track_views.push_back (rtv);
5417 new_selection.push_back (rtv);
5419 rtv->effective_gain_display ();
5421 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5422 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5426 if (new_views.size() > 0) {
5427 _routes->time_axis_views_added (new_views);
5428 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5431 /* note: !new_selection.empty() means that we got some routes rather
5435 if (!from_scratch && !new_selection.empty()) {
5436 selection->set (new_selection);
5437 begin_selection_op_history();
5440 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5441 show_editor_mixer (true);
5444 editor_list_button.set_sensitive (true);
5448 Editor::timeaxisview_deleted (TimeAxisView *tv)
5450 if (tv == entered_track) {
5454 if (_session && _session->deletion_in_progress()) {
5455 /* the situation is under control */
5459 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5461 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5463 _routes->route_removed (tv);
5465 TimeAxisView::Children c = tv->get_child_list ();
5466 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5467 if (entered_track == i->get()) {
5472 /* remove it from the list of track views */
5474 TrackViewList::iterator i;
5476 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5477 i = track_views.erase (i);
5480 /* update whatever the current mixer strip is displaying, if revelant */
5482 boost::shared_ptr<Route> route;
5485 route = rtav->route ();
5488 if (current_mixer_strip && current_mixer_strip->route() == route) {
5490 TimeAxisView* next_tv;
5492 if (track_views.empty()) {
5494 } else if (i == track_views.end()) {
5495 next_tv = track_views.front();
5500 // skip VCAs (cannot be selected, n/a in editor-mixer)
5501 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5502 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5503 next_tv = track_views.front();
5505 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5506 /* just in case: no master, only a VCA remains */
5512 set_selected_mixer_strip (*next_tv);
5514 /* make the editor mixer strip go away setting the
5515 * button to inactive (which also unticks the menu option)
5518 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5524 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5530 DisplaySuspender ds;
5531 PresentationInfo::ChangeSuspender cs;
5533 if (apply_to_selection) {
5534 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5536 TrackSelection::iterator j = i;
5539 hide_track_in_display (*i, false);
5544 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5546 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5547 // this will hide the mixer strip
5548 set_selected_mixer_strip (*tv);
5551 _routes->hide_track_in_display (*tv);
5556 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5561 _routes->show_track_in_display (*tv);
5562 if (move_into_view) {
5563 ensure_time_axis_view_is_visible (*tv, false);
5568 Editor::sync_track_view_list_and_routes ()
5570 track_views = TrackViewList (_routes->views ());
5572 _summary->set_background_dirty();
5573 _group_tabs->set_dirty ();
5575 return false; // do not call again (until needed)
5579 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5581 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5586 /** Find a StripableTimeAxisView by the ID of its stripable */
5587 StripableTimeAxisView*
5588 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5590 StripableTimeAxisView* v;
5592 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5593 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5594 if(v->stripable()->id() == id) {
5604 Editor::fit_route_group (RouteGroup *g)
5606 TrackViewList ts = axis_views_from_routes (g->route_list ());
5611 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5613 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5616 _session->cancel_audition ();
5620 if (_session->is_auditioning()) {
5621 _session->cancel_audition ();
5622 if (r == last_audition_region) {
5627 _session->audition_region (r);
5628 last_audition_region = r;
5633 Editor::hide_a_region (boost::shared_ptr<Region> r)
5635 r->set_hidden (true);
5639 Editor::show_a_region (boost::shared_ptr<Region> r)
5641 r->set_hidden (false);
5645 Editor::audition_region_from_region_list ()
5647 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5651 Editor::hide_region_from_region_list ()
5653 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5657 Editor::show_region_in_region_list ()
5659 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5663 Editor::step_edit_status_change (bool yn)
5666 start_step_editing ();
5668 stop_step_editing ();
5673 Editor::start_step_editing ()
5675 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5679 Editor::stop_step_editing ()
5681 step_edit_connection.disconnect ();
5685 Editor::check_step_edit ()
5687 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5688 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5690 mtv->check_step_edit ();
5694 return true; // do it again, till we stop
5698 Editor::scroll_press (Direction dir)
5700 ++_scroll_callbacks;
5702 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5703 /* delay the first auto-repeat */
5709 scroll_backward (1);
5717 scroll_up_one_track ();
5721 scroll_down_one_track ();
5725 /* do hacky auto-repeat */
5726 if (!_scroll_connection.connected ()) {
5728 _scroll_connection = Glib::signal_timeout().connect (
5729 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5732 _scroll_callbacks = 0;
5739 Editor::scroll_release ()
5741 _scroll_connection.disconnect ();
5744 /** Queue a change for the Editor viewport x origin to follow the playhead */
5746 Editor::reset_x_origin_to_follow_playhead ()
5748 samplepos_t const sample = playhead_cursor->current_sample ();
5750 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5752 if (_session->transport_speed() < 0) {
5754 if (sample > (current_page_samples() / 2)) {
5755 center_screen (sample-(current_page_samples()/2));
5757 center_screen (current_page_samples()/2);
5764 if (sample < _leftmost_sample) {
5766 if (_session->transport_rolling()) {
5767 /* rolling; end up with the playhead at the right of the page */
5768 l = sample - current_page_samples ();
5770 /* not rolling: end up with the playhead 1/4 of the way along the page */
5771 l = sample - current_page_samples() / 4;
5775 if (_session->transport_rolling()) {
5776 /* rolling: end up with the playhead on the left of the page */
5779 /* not rolling: end up with the playhead 3/4 of the way along the page */
5780 l = sample - 3 * current_page_samples() / 4;
5788 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5794 Editor::super_rapid_screen_update ()
5796 if (!_session || !_session->engine().running()) {
5800 /* METERING / MIXER STRIPS */
5802 /* update track meters, if required */
5803 if (contents().is_mapped() && meters_running) {
5804 RouteTimeAxisView* rtv;
5805 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5806 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5807 rtv->fast_update ();
5812 /* and any current mixer strip */
5813 if (current_mixer_strip) {
5814 current_mixer_strip->fast_update ();
5817 bool latent_locate = false;
5818 samplepos_t sample = _session->audible_sample (&latent_locate);
5819 const int64_t now = g_get_monotonic_time ();
5822 if (_session->exporting ()) {
5823 /* freewheel/export may be faster or slower than transport_speed() / SR.
5824 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5826 _last_update_time = 0;
5829 if (_last_update_time > 0) {
5830 /* interpolate and smoothen playhead position */
5831 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5832 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5833 err = sample - guess;
5835 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5836 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5839 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5841 err, _err_screen_engine);
5846 _err_screen_engine = 0;
5849 if (err > 8192 || latent_locate) {
5850 // in case of x-runs or freewheeling
5851 _last_update_time = 0;
5852 sample = _session->audible_sample ();
5854 _last_update_time = now;
5857 //snapped cursor stuff ( the snapped_cursor shows where an operation is going to occur )
5859 MusicSample where (sample, 0);
5860 if ( !UIConfiguration::instance().get_show_snapped_cursor() ) {
5861 snapped_cursor->hide ();
5862 } else if ( _edit_point == EditAtPlayhead && !_dragging_playhead) {
5863 snap_to (where); // can't use snap_to_with_modifier?
5864 snapped_cursor->set_position (where.sample);
5865 snapped_cursor->show ();
5866 } else if ( _edit_point == EditAtSelectedMarker ) {
5867 //NOTE: I don't think EditAtSelectedMarker should snap. they are what they are.
5868 //however, the current editing code -does- snap so I'll draw it that way for now.
5869 MusicSample ms (selection->markers.front()->position(), 0);
5870 snap_to (ms); // should use snap_to_with_modifier?
5871 snapped_cursor->set_position ( ms.sample );
5872 snapped_cursor->show ();
5873 } else if (mouse_sample (where.sample, ignored)) { //cursor is in the editing canvas. show it.
5874 snapped_cursor->show ();
5875 } else { //mouse is out of the editing canvas. hide the snapped_cursor
5876 snapped_cursor->hide ();
5879 /* There are a few reasons why we might not update the playhead / viewport stuff:
5881 * 1. we don't update things when there's a pending locate request, otherwise
5882 * when the editor requests a locate there is a chance that this method
5883 * will move the playhead before the locate request is processed, causing
5885 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5886 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5888 if (_pending_locate_request) {
5889 _last_update_time = 0;
5893 if (_dragging_playhead) {
5894 _last_update_time = 0;
5898 if (playhead_cursor->current_sample () == sample) {
5902 playhead_cursor->set_position (sample);
5904 if (_session->requested_return_sample() >= 0) {
5905 _last_update_time = 0;
5909 if (!_follow_playhead || pending_visual_change.being_handled) {
5910 /* We only do this if we aren't already
5911 * handling a visual change (ie if
5912 * pending_visual_change.being_handled is
5913 * false) so that these requests don't stack
5914 * up there are too many of them to handle in
5920 if (!_stationary_playhead) {
5921 reset_x_origin_to_follow_playhead ();
5923 samplepos_t const sample = playhead_cursor->current_sample ();
5924 double target = ((double)sample - (double)current_page_samples() / 2.0);
5925 if (target <= 0.0) {
5928 // compare to EditorCursor::set_position()
5929 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5930 double const new_pos = sample_to_pixel_unrounded (target);
5931 if (rint (new_pos) != rint (old_pos)) {
5932 reset_x_origin (pixel_to_sample (new_pos));
5939 Editor::session_going_away ()
5941 _have_idled = false;
5943 _session_connections.drop_connections ();
5945 super_rapid_screen_update_connection.disconnect ();
5947 selection->clear ();
5948 cut_buffer->clear ();
5950 clicked_regionview = 0;
5951 clicked_axisview = 0;
5952 clicked_routeview = 0;
5953 entered_regionview = 0;
5955 _last_update_time = 0;
5958 playhead_cursor->hide ();
5960 /* rip everything out of the list displays */
5964 _route_groups->clear ();
5966 /* do this first so that deleting a track doesn't reset cms to null
5967 and thus cause a leak.
5970 if (current_mixer_strip) {
5971 if (current_mixer_strip->get_parent() != 0) {
5972 global_hpacker.remove (*current_mixer_strip);
5974 delete current_mixer_strip;
5975 current_mixer_strip = 0;
5978 /* delete all trackviews */
5980 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5983 track_views.clear ();
5985 nudge_clock->set_session (0);
5987 editor_list_button.set_active(false);
5988 editor_list_button.set_sensitive(false);
5990 /* clear tempo/meter rulers */
5991 remove_metric_marks ();
5993 clear_marker_display ();
5998 stop_step_editing ();
6002 /* get rid of any existing editor mixer strip */
6004 WindowTitle title(Glib::get_application_name());
6005 title += _("Editor");
6007 own_window()->set_title (title.get_string());
6010 SessionHandlePtr::session_going_away ();
6014 Editor::trigger_script (int i)
6016 LuaInstance::instance()-> call_action (i);
6020 Editor::show_editor_list (bool yn)
6023 _editor_list_vbox.show ();
6025 _editor_list_vbox.hide ();
6030 Editor::change_region_layering_order (bool from_context_menu)
6032 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
6034 if (!clicked_routeview) {
6035 if (layering_order_editor) {
6036 layering_order_editor->hide ();
6041 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6047 boost::shared_ptr<Playlist> pl = track->playlist();
6053 if (layering_order_editor == 0) {
6054 layering_order_editor = new RegionLayeringOrderEditor (*this);
6057 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6058 layering_order_editor->maybe_present ();
6062 Editor::update_region_layering_order_editor ()
6064 if (layering_order_editor && layering_order_editor->is_visible ()) {
6065 change_region_layering_order (true);
6070 Editor::setup_fade_images ()
6072 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6073 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6074 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6075 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6076 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6078 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6079 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6080 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6081 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6082 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6086 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6088 Editor::action_menu_item (std::string const & name)
6090 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6093 return *manage (a->create_menu_item ());
6097 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6099 EventBox* b = manage (new EventBox);
6100 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6101 Label* l = manage (new Label (name));
6105 _the_notebook.append_page (widget, *b);
6109 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6111 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6112 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6115 if (ev->type == GDK_2BUTTON_PRESS) {
6117 /* double-click on a notebook tab shrinks or expands the notebook */
6119 if (_notebook_shrunk) {
6120 if (pre_notebook_shrink_pane_width) {
6121 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6123 _notebook_shrunk = false;
6125 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6127 /* this expands the LHS of the edit pane to cover the notebook
6128 PAGE but leaves the tabs visible.
6130 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6131 _notebook_shrunk = true;
6139 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6141 using namespace Menu_Helpers;
6143 MenuList& items = _control_point_context_menu.items ();
6146 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6147 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6148 if (!can_remove_control_point (item)) {
6149 items.back().set_sensitive (false);
6152 _control_point_context_menu.popup (event->button.button, event->button.time);
6156 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6158 using namespace Menu_Helpers;
6160 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6165 /* We need to get the selection here and pass it to the operations, since
6166 popping up the menu will cause a region leave event which clears
6167 entered_regionview. */
6169 MidiRegionView& mrv = note->region_view();
6170 const RegionSelection rs = get_regions_from_selection_and_entered ();
6171 const uint32_t sel_size = mrv.selection_size ();
6173 MenuList& items = _note_context_menu.items();
6177 items.push_back(MenuElem(_("Delete"),
6178 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6181 items.push_back(MenuElem(_("Edit..."),
6182 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6183 if (sel_size != 1) {
6184 items.back().set_sensitive (false);
6187 items.push_back(MenuElem(_("Transpose..."),
6188 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6191 items.push_back(MenuElem(_("Legatize"),
6192 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6194 items.back().set_sensitive (false);
6197 items.push_back(MenuElem(_("Quantize..."),
6198 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6200 items.push_back(MenuElem(_("Remove Overlap"),
6201 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6203 items.back().set_sensitive (false);
6206 items.push_back(MenuElem(_("Transform..."),
6207 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6209 _note_context_menu.popup (event->button.button, event->button.time);
6213 Editor::zoom_vertical_modifier_released()
6215 _stepping_axis_view = 0;
6219 Editor::ui_parameter_changed (string parameter)
6221 if (parameter == "icon-set") {
6222 while (!_cursor_stack.empty()) {
6223 _cursor_stack.pop_back();
6225 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6226 _cursor_stack.push_back(_cursors->grabber);
6227 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6228 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6230 } else if (parameter == "draggable-playhead") {
6231 if (_verbose_cursor) {
6232 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6238 Editor::use_own_window (bool and_fill_it)
6240 bool new_window = !own_window();
6242 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6244 if (win && new_window) {
6245 win->set_name ("EditorWindow");
6247 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6249 // win->signal_realize().connect (*this, &Editor::on_realize);
6250 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6251 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6252 win->set_data ("ardour-bindings", bindings);
6257 DisplaySuspender ds;
6258 contents().show_all ();
6260 /* XXX: this is a bit unfortunate; it would probably
6261 be nicer if we could just call show () above rather
6262 than needing the show_all ()
6265 /* re-hide stuff if necessary */
6266 editor_list_button_toggled ();
6267 parameter_changed ("show-summary");
6268 parameter_changed ("show-group-tabs");
6269 parameter_changed ("show-zoom-tools");
6271 /* now reset all audio_time_axis heights, because widgets might need
6277 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6278 tv = (static_cast<TimeAxisView*>(*i));
6279 tv->reset_height ();
6282 if (current_mixer_strip) {
6283 current_mixer_strip->hide_things ();
6284 current_mixer_strip->parameter_changed ("mixer-element-visibility");