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)
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"))
338 , playhead_cursor (0)
339 , edit_packer (4, 4, true)
340 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
341 , horizontal_adjustment (0.0, 0.0, 1e16)
342 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
343 , controls_layout (unused_adjustment, vertical_adjustment)
344 , _scroll_callbacks (0)
345 , _visible_canvas_width (0)
346 , _visible_canvas_height (0)
347 , _full_canvas_height (0)
348 , edit_controls_left_menu (0)
349 , edit_controls_right_menu (0)
350 , visual_change_queued(false)
351 , _last_update_time (0)
352 , _err_screen_engine (0)
353 , cut_buffer_start (0)
354 , cut_buffer_length (0)
355 , button_bindings (0)
356 , last_paste_pos (-1)
359 , current_interthread_info (0)
360 , analysis_window (0)
361 , select_new_marker (false)
363 , scrubbing_direction (0)
364 , scrub_reversals (0)
365 , scrub_reverse_distance (0)
366 , have_pending_keyboard_selection (false)
367 , pending_keyboard_selection_start (0)
368 , _snap_type (SnapToBeat)
369 , _snap_mode (SnapOff)
370 , snap_threshold (5.0)
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 , cd_marker_bar_drag_rect (0)
404 , range_bar_drag_rect (0)
405 , transport_bar_drag_rect (0)
406 , transport_bar_range_rect (0)
407 , transport_bar_preroll_rect (0)
408 , transport_bar_postroll_rect (0)
409 , transport_loop_range_rect (0)
410 , transport_punch_range_rect (0)
411 , transport_punchin_line (0)
412 , transport_punchout_line (0)
413 , transport_preroll_rect (0)
414 , transport_postroll_rect (0)
416 , rubberband_rect (0)
422 , autoscroll_horizontal_allowed (false)
423 , autoscroll_vertical_allowed (false)
425 , autoscroll_widget (0)
426 , show_gain_after_trim (false)
427 , selection_op_cmd_depth (0)
428 , selection_op_history_it (0)
429 , no_save_instant (false)
431 , current_mixer_strip (0)
432 , show_editor_mixer_when_tracks_arrive (false)
433 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
434 , current_stepping_trackview (0)
435 , last_track_height_step_timestamp (0)
437 , entered_regionview (0)
438 , clear_entered_track (false)
439 , _edit_point (EditAtMouse)
440 , meters_running (false)
442 , _have_idled (false)
443 , resize_idle_id (-1)
444 , _pending_resize_amount (0)
445 , _pending_resize_view (0)
446 , _pending_locate_request (false)
447 , _pending_initial_locate (false)
451 , layering_order_editor (0)
452 , _last_cut_copy_source_track (0)
453 , _region_selection_change_updates_region_list (true)
455 , _following_mixer_selection (false)
456 , _control_point_toggled_on_press (false)
457 , _stepping_axis_view (0)
458 , quantize_dialog (0)
459 , _main_menu_disabler (0)
460 , myactions (X_("editor"))
462 /* we are a singleton */
464 PublicEditor::_instance = this;
468 last_event_time.tv_sec = 0;
469 last_event_time.tv_usec = 0;
471 selection_op_history.clear();
474 snap_type_strings = I18N (_snap_type_strings);
475 snap_mode_strings = I18N (_snap_mode_strings);
476 zoom_focus_strings = I18N (_zoom_focus_strings);
477 edit_mode_strings = I18N (_edit_mode_strings);
478 edit_point_strings = I18N (_edit_point_strings);
479 #ifdef USE_RUBBERBAND
480 rb_opt_strings = I18N (_rb_opt_strings);
484 build_edit_mode_menu();
485 build_zoom_focus_menu();
486 build_track_count_menu();
487 build_snap_mode_menu();
488 build_snap_type_menu();
489 build_edit_point_menu();
491 location_marker_color = UIConfiguration::instance().color ("location marker");
492 location_range_color = UIConfiguration::instance().color ("location range");
493 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
494 location_loop_color = UIConfiguration::instance().color ("location loop");
495 location_punch_color = UIConfiguration::instance().color ("location punch");
497 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
499 TimeAxisView::setup_sizes ();
500 ArdourMarker::setup_sizes (timebar_height);
501 TempoCurve::setup_sizes (timebar_height);
503 bbt_label.set_name ("EditorRulerLabel");
504 bbt_label.set_size_request (-1, (int)timebar_height);
505 bbt_label.set_alignment (1.0, 0.5);
506 bbt_label.set_padding (5,0);
508 bbt_label.set_no_show_all();
509 minsec_label.set_name ("EditorRulerLabel");
510 minsec_label.set_size_request (-1, (int)timebar_height);
511 minsec_label.set_alignment (1.0, 0.5);
512 minsec_label.set_padding (5,0);
513 minsec_label.hide ();
514 minsec_label.set_no_show_all();
515 timecode_label.set_name ("EditorRulerLabel");
516 timecode_label.set_size_request (-1, (int)timebar_height);
517 timecode_label.set_alignment (1.0, 0.5);
518 timecode_label.set_padding (5,0);
519 timecode_label.hide ();
520 timecode_label.set_no_show_all();
521 samples_label.set_name ("EditorRulerLabel");
522 samples_label.set_size_request (-1, (int)timebar_height);
523 samples_label.set_alignment (1.0, 0.5);
524 samples_label.set_padding (5,0);
525 samples_label.hide ();
526 samples_label.set_no_show_all();
528 tempo_label.set_name ("EditorRulerLabel");
529 tempo_label.set_size_request (-1, (int)timebar_height);
530 tempo_label.set_alignment (1.0, 0.5);
531 tempo_label.set_padding (5,0);
533 tempo_label.set_no_show_all();
535 meter_label.set_name ("EditorRulerLabel");
536 meter_label.set_size_request (-1, (int)timebar_height);
537 meter_label.set_alignment (1.0, 0.5);
538 meter_label.set_padding (5,0);
540 meter_label.set_no_show_all();
542 if (Profile->get_trx()) {
543 mark_label.set_text (_("Markers"));
545 mark_label.set_name ("EditorRulerLabel");
546 mark_label.set_size_request (-1, (int)timebar_height);
547 mark_label.set_alignment (1.0, 0.5);
548 mark_label.set_padding (5,0);
550 mark_label.set_no_show_all();
552 cd_mark_label.set_name ("EditorRulerLabel");
553 cd_mark_label.set_size_request (-1, (int)timebar_height);
554 cd_mark_label.set_alignment (1.0, 0.5);
555 cd_mark_label.set_padding (5,0);
556 cd_mark_label.hide();
557 cd_mark_label.set_no_show_all();
559 videotl_bar_height = 4;
560 videotl_label.set_name ("EditorRulerLabel");
561 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
562 videotl_label.set_alignment (1.0, 0.5);
563 videotl_label.set_padding (5,0);
564 videotl_label.hide();
565 videotl_label.set_no_show_all();
567 range_mark_label.set_name ("EditorRulerLabel");
568 range_mark_label.set_size_request (-1, (int)timebar_height);
569 range_mark_label.set_alignment (1.0, 0.5);
570 range_mark_label.set_padding (5,0);
571 range_mark_label.hide();
572 range_mark_label.set_no_show_all();
574 transport_mark_label.set_name ("EditorRulerLabel");
575 transport_mark_label.set_size_request (-1, (int)timebar_height);
576 transport_mark_label.set_alignment (1.0, 0.5);
577 transport_mark_label.set_padding (5,0);
578 transport_mark_label.hide();
579 transport_mark_label.set_no_show_all();
581 initialize_canvas ();
583 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
585 _summary = new EditorSummary (this);
587 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
589 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
591 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
592 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
594 edit_controls_vbox.set_spacing (0);
595 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
596 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
598 HBox* h = manage (new HBox);
599 _group_tabs = new EditorGroupTabs (this);
600 if (!ARDOUR::Profile->get_trx()) {
601 h->pack_start (*_group_tabs, PACK_SHRINK);
603 h->pack_start (edit_controls_vbox);
604 controls_layout.add (*h);
606 controls_layout.set_name ("EditControlsBase");
607 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
608 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
609 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
611 _cursors = new MouseCursors;
612 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
613 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
615 /* Push default cursor to ever-present bottom of cursor stack. */
616 push_canvas_cursor(_cursors->grabber);
618 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
620 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
621 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
622 pad_line_1->set_outline_color (0xFF0000FF);
628 edit_packer.set_col_spacings (0);
629 edit_packer.set_row_spacings (0);
630 edit_packer.set_homogeneous (false);
631 edit_packer.set_border_width (0);
632 edit_packer.set_name ("EditorWindow");
634 time_bars_event_box.add (time_bars_vbox);
635 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
636 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
638 /* labels for the time bars */
639 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
641 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
643 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
645 bottom_hbox.set_border_width (2);
646 bottom_hbox.set_spacing (3);
648 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
650 _route_groups = new EditorRouteGroups (this);
651 _routes = new EditorRoutes (this);
652 _regions = new EditorRegions (this);
653 _snapshots = new EditorSnapshots (this);
654 _locations = new EditorLocations (this);
655 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
657 /* these are static location signals */
659 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
660 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
661 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
663 add_notebook_page (_("Regions"), _regions->widget ());
664 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
665 add_notebook_page (_("Snapshots"), _snapshots->widget ());
666 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
667 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
669 _the_notebook.set_show_tabs (true);
670 _the_notebook.set_scrollable (true);
671 _the_notebook.popup_disable ();
672 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
673 _the_notebook.show_all ();
675 _notebook_shrunk = false;
678 /* Pick up some settings we need to cache, early */
680 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
683 settings->get_property ("notebook-shrunk", _notebook_shrunk);
686 editor_summary_pane.set_check_divider_position (true);
687 editor_summary_pane.add (edit_packer);
689 Button* summary_arrow_left = manage (new Button);
690 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
691 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
692 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
694 Button* summary_arrow_right = manage (new Button);
695 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
696 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
697 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
699 VBox* summary_arrows_left = manage (new VBox);
700 summary_arrows_left->pack_start (*summary_arrow_left);
702 VBox* summary_arrows_right = manage (new VBox);
703 summary_arrows_right->pack_start (*summary_arrow_right);
705 Frame* summary_frame = manage (new Frame);
706 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
708 summary_frame->add (*_summary);
709 summary_frame->show ();
711 _summary_hbox.pack_start (*summary_arrows_left, false, false);
712 _summary_hbox.pack_start (*summary_frame, true, true);
713 _summary_hbox.pack_start (*summary_arrows_right, false, false);
715 if (!ARDOUR::Profile->get_trx()) {
716 editor_summary_pane.add (_summary_hbox);
719 edit_pane.set_check_divider_position (true);
720 edit_pane.add (editor_summary_pane);
721 if (!ARDOUR::Profile->get_trx()) {
722 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
723 _editor_list_vbox.pack_start (_the_notebook);
724 edit_pane.add (_editor_list_vbox);
725 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
728 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
729 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
732 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
733 /* initial allocation is 90% to canvas, 10% to notebook */
736 edit_pane.set_divider (0, fract);
738 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
739 /* initial allocation is 90% to canvas, 10% to summary */
742 editor_summary_pane.set_divider (0, fract);
744 global_vpacker.set_spacing (2);
745 global_vpacker.set_border_width (0);
747 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
749 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
750 ebox->set_name("EditorWindow");
751 ebox->add (toolbar_hbox);
753 Gtk::EventBox* epane_box = manage (new EventBoxExt); //a themeable box
754 epane_box->set_name("EditorWindow");
755 epane_box->add (edit_pane);
757 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); //a themeable box
758 epane_box2->set_name("EditorWindow");
759 epane_box2->add (global_vpacker);
761 global_vpacker.pack_start (*ebox, false, false);
762 global_vpacker.pack_start (*epane_box, true, true);
763 global_hpacker.pack_start (*epane_box2, true, true);
765 /* need to show the "contents" widget so that notebook will show if tab is switched to
768 global_hpacker.show ();
770 /* register actions now so that set_state() can find them and set toggles/checks etc */
777 _playlist_selector = new PlaylistSelector();
778 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
780 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
784 nudge_forward_button.set_name ("nudge button");
785 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
787 nudge_backward_button.set_name ("nudge button");
788 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
790 fade_context_menu.set_name ("ArdourContextMenu");
792 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
794 /* allow external control surfaces/protocols to do various things */
796 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
797 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
798 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
799 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
800 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
801 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
802 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
803 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
804 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
805 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
806 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
807 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
808 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
809 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
811 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
812 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
813 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
814 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
815 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
817 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
821 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
823 /* problematic: has to return a value and thus cannot be x-thread */
825 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
827 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
828 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
830 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
832 _ignore_region_action = false;
833 _last_region_menu_was_main = false;
834 _popup_region_menu_item = 0;
836 _show_marker_lines = false;
838 /* Button bindings */
840 button_bindings = new Bindings ("editor-mouse");
842 XMLNode* node = button_settings();
844 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
845 button_bindings->load_operation (**i);
851 /* grab current parameter state */
852 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
853 UIConfiguration::instance().map_parameters (pc);
855 setup_fade_images ();
862 delete button_bindings;
864 delete _route_groups;
865 delete _track_canvas_viewport;
868 delete _verbose_cursor;
869 delete quantize_dialog;
875 delete _playlist_selector;
876 delete _time_info_box;
881 LuaInstance::destroy_instance ();
883 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
886 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
889 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
895 Editor::button_settings () const
897 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
898 XMLNode* node = find_named_node (*settings, X_("Buttons"));
901 node = new XMLNode (X_("Buttons"));
908 Editor::get_smart_mode () const
910 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
914 Editor::catch_vanishing_regionview (RegionView *rv)
916 /* note: the selection will take care of the vanishing
917 audioregionview by itself.
920 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
924 if (clicked_regionview == rv) {
925 clicked_regionview = 0;
928 if (entered_regionview == rv) {
929 set_entered_regionview (0);
932 if (!_all_region_actions_sensitized) {
933 sensitize_all_region_actions (true);
938 Editor::set_entered_regionview (RegionView* rv)
940 if (rv == entered_regionview) {
944 if (entered_regionview) {
945 entered_regionview->exited ();
948 entered_regionview = rv;
950 if (entered_regionview != 0) {
951 entered_regionview->entered ();
954 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
955 /* This RegionView entry might have changed what region actions
956 are allowed, so sensitize them all in case a key is pressed.
958 sensitize_all_region_actions (true);
963 Editor::set_entered_track (TimeAxisView* tav)
966 entered_track->exited ();
972 entered_track->entered ();
977 Editor::instant_save ()
979 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
984 _session->add_instant_xml(get_state());
986 Config->add_instant_xml(get_state());
991 Editor::control_vertical_zoom_in_all ()
993 tav_zoom_smooth (false, true);
997 Editor::control_vertical_zoom_out_all ()
999 tav_zoom_smooth (true, true);
1003 Editor::control_vertical_zoom_in_selected ()
1005 tav_zoom_smooth (false, false);
1009 Editor::control_vertical_zoom_out_selected ()
1011 tav_zoom_smooth (true, false);
1015 Editor::control_view (uint32_t view)
1017 goto_visual_state (view);
1021 Editor::control_unselect ()
1023 selection->clear_tracks ();
1027 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1029 TimeAxisView* tav = time_axis_view_from_stripable (s);
1033 case Selection::Add:
1034 selection->add (tav);
1036 case Selection::Toggle:
1037 selection->toggle (tav);
1039 case Selection::Extend:
1041 case Selection::Set:
1042 selection->set (tav);
1046 selection->clear_tracks ();
1051 Editor::control_step_tracks_up ()
1053 scroll_tracks_up_line ();
1057 Editor::control_step_tracks_down ()
1059 scroll_tracks_down_line ();
1063 Editor::control_scroll (float fraction)
1065 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1071 double step = fraction * current_page_samples();
1074 _control_scroll_target is an optional<T>
1076 it acts like a pointer to an framepos_t, with
1077 a operator conversion to boolean to check
1078 that it has a value could possibly use
1079 playhead_cursor->current_frame to store the
1080 value and a boolean in the class to know
1081 when it's out of date
1084 if (!_control_scroll_target) {
1085 _control_scroll_target = _session->transport_frame();
1086 _dragging_playhead = true;
1089 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1090 *_control_scroll_target = 0;
1091 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1092 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1094 *_control_scroll_target += (framepos_t) trunc (step);
1097 /* move visuals, we'll catch up with it later */
1099 playhead_cursor->set_position (*_control_scroll_target);
1100 UpdateAllTransportClocks (*_control_scroll_target);
1102 if (*_control_scroll_target > (current_page_samples() / 2)) {
1103 /* try to center PH in window */
1104 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1110 Now we do a timeout to actually bring the session to the right place
1111 according to the playhead. This is to avoid reading disk buffers on every
1112 call to control_scroll, which is driven by ScrollTimeline and therefore
1113 probably by a control surface wheel which can generate lots of events.
1115 /* cancel the existing timeout */
1117 control_scroll_connection.disconnect ();
1119 /* add the next timeout */
1121 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1125 Editor::deferred_control_scroll (framepos_t /*target*/)
1127 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1128 // reset for next stream
1129 _control_scroll_target = boost::none;
1130 _dragging_playhead = false;
1135 Editor::access_action (std::string action_group, std::string action_item)
1141 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1144 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1152 Editor::on_realize ()
1156 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1157 start_lock_event_timing ();
1162 Editor::start_lock_event_timing ()
1164 /* check if we should lock the GUI every 30 seconds */
1166 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1170 Editor::generic_event_handler (GdkEvent* ev)
1173 case GDK_BUTTON_PRESS:
1174 case GDK_BUTTON_RELEASE:
1175 case GDK_MOTION_NOTIFY:
1177 case GDK_KEY_RELEASE:
1178 if (contents().is_mapped()) {
1179 gettimeofday (&last_event_time, 0);
1183 case GDK_LEAVE_NOTIFY:
1184 switch (ev->crossing.detail) {
1185 case GDK_NOTIFY_UNKNOWN:
1186 case GDK_NOTIFY_INFERIOR:
1187 case GDK_NOTIFY_ANCESTOR:
1189 case GDK_NOTIFY_VIRTUAL:
1190 case GDK_NOTIFY_NONLINEAR:
1191 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1192 /* leaving window, so reset focus, thus ending any and
1193 all text entry operations.
1195 ARDOUR_UI::instance()->reset_focus (&contents());
1208 Editor::lock_timeout_callback ()
1210 struct timeval now, delta;
1212 gettimeofday (&now, 0);
1214 timersub (&now, &last_event_time, &delta);
1216 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1218 /* don't call again. Returning false will effectively
1219 disconnect us from the timer callback.
1221 unlock() will call start_lock_event_timing() to get things
1231 Editor::map_position_change (framepos_t frame)
1233 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1235 if (_session == 0) {
1239 if (_follow_playhead) {
1240 center_screen (frame);
1243 playhead_cursor->set_position (frame);
1247 Editor::center_screen (framepos_t frame)
1249 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1251 /* if we're off the page, then scroll.
1254 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1255 center_screen_internal (frame, page);
1260 Editor::center_screen_internal (framepos_t frame, float page)
1265 frame -= (framepos_t) page;
1270 reset_x_origin (frame);
1275 Editor::update_title ()
1277 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1279 if (!own_window()) {
1284 bool dirty = _session->dirty();
1286 string session_name;
1288 if (_session->snap_name() != _session->name()) {
1289 session_name = _session->snap_name();
1291 session_name = _session->name();
1295 session_name = "*" + session_name;
1298 WindowTitle title(session_name);
1299 title += S_("Window|Editor");
1300 title += Glib::get_application_name();
1301 own_window()->set_title (title.get_string());
1303 /* ::session_going_away() will have taken care of it */
1308 Editor::set_session (Session *t)
1310 SessionHandlePtr::set_session (t);
1316 _playlist_selector->set_session (_session);
1317 nudge_clock->set_session (_session);
1318 _summary->set_session (_session);
1319 _group_tabs->set_session (_session);
1320 _route_groups->set_session (_session);
1321 _regions->set_session (_session);
1322 _snapshots->set_session (_session);
1323 _routes->set_session (_session);
1324 _locations->set_session (_session);
1325 _time_info_box->set_session (_session);
1327 if (rhythm_ferret) {
1328 rhythm_ferret->set_session (_session);
1331 if (analysis_window) {
1332 analysis_window->set_session (_session);
1336 sfbrowser->set_session (_session);
1339 compute_fixed_ruler_scale ();
1341 /* Make sure we have auto loop and auto punch ranges */
1343 Location* loc = _session->locations()->auto_loop_location();
1345 loc->set_name (_("Loop"));
1348 loc = _session->locations()->auto_punch_location();
1351 loc->set_name (_("Punch"));
1354 refresh_location_display ();
1356 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1357 the selected Marker; this needs the LocationMarker list to be available.
1359 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1360 set_state (*node, Stateful::loading_state_version);
1362 /* catch up on selection state, etc. */
1365 sc.add (Properties::selected);
1366 presentation_info_changed (sc);
1368 /* catch up with the playhead */
1370 _session->request_locate (playhead_cursor->current_frame ());
1371 _pending_initial_locate = true;
1375 /* These signals can all be emitted by a non-GUI thread. Therefore the
1376 handlers for them must not attempt to directly interact with the GUI,
1377 but use PBD::Signal<T>::connect() which accepts an event loop
1378 ("context") where the handler will be asked to run.
1381 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1382 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1383 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1384 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1385 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1386 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1387 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1388 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1389 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1390 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1391 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1392 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1393 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1394 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1395 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1396 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1398 playhead_cursor->show ();
1400 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1401 Config->map_parameters (pc);
1402 _session->config.map_parameters (pc);
1404 restore_ruler_visibility ();
1405 //tempo_map_changed (PropertyChange (0));
1406 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1408 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1409 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1412 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1413 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1416 switch (_snap_type) {
1417 case SnapToRegionStart:
1418 case SnapToRegionEnd:
1419 case SnapToRegionSync:
1420 case SnapToRegionBoundary:
1421 build_region_boundary_cache ();
1428 /* register for undo history */
1429 _session->register_with_memento_command_factory(id(), this);
1430 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1432 LuaInstance::instance()->set_session(_session);
1434 start_updating_meters ();
1438 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1440 using namespace Menu_Helpers;
1442 void (Editor::*emf)(FadeShape);
1443 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1446 images = &_xfade_in_images;
1447 emf = &Editor::set_fade_in_shape;
1449 images = &_xfade_out_images;
1450 emf = &Editor::set_fade_out_shape;
1455 _("Linear (for highly correlated material)"),
1456 *(*images)[FadeLinear],
1457 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1461 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1465 _("Constant power"),
1466 *(*images)[FadeConstantPower],
1467 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1470 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 *(*images)[FadeSymmetric],
1476 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 *(*images)[FadeSlow],
1486 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 *(*images)[FadeFast],
1495 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1498 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 /** Pop up a context menu for when the user clicks on a start crossfade */
1503 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1505 using namespace Menu_Helpers;
1506 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1511 MenuList& items (xfade_in_context_menu.items());
1514 if (arv->audio_region()->fade_in_active()) {
1515 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1517 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1520 items.push_back (SeparatorElem());
1521 fill_xfade_menu (items, true);
1523 xfade_in_context_menu.popup (button, time);
1526 /** Pop up a context menu for when the user clicks on an end crossfade */
1528 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1530 using namespace Menu_Helpers;
1531 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1536 MenuList& items (xfade_out_context_menu.items());
1539 if (arv->audio_region()->fade_out_active()) {
1540 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1542 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1545 items.push_back (SeparatorElem());
1546 fill_xfade_menu (items, false);
1548 xfade_out_context_menu.popup (button, time);
1552 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1554 using namespace Menu_Helpers;
1555 Menu* (Editor::*build_menu_function)();
1558 switch (item_type) {
1560 case RegionViewName:
1561 case RegionViewNameHighlight:
1562 case LeftFrameHandle:
1563 case RightFrameHandle:
1564 if (with_selection) {
1565 build_menu_function = &Editor::build_track_selection_context_menu;
1567 build_menu_function = &Editor::build_track_region_context_menu;
1572 if (with_selection) {
1573 build_menu_function = &Editor::build_track_selection_context_menu;
1575 build_menu_function = &Editor::build_track_context_menu;
1580 if (clicked_routeview->track()) {
1581 build_menu_function = &Editor::build_track_context_menu;
1583 build_menu_function = &Editor::build_track_bus_context_menu;
1588 /* probably shouldn't happen but if it does, we don't care */
1592 menu = (this->*build_menu_function)();
1593 menu->set_name ("ArdourContextMenu");
1595 /* now handle specific situations */
1597 switch (item_type) {
1599 case RegionViewName:
1600 case RegionViewNameHighlight:
1601 case LeftFrameHandle:
1602 case RightFrameHandle:
1603 if (!with_selection) {
1604 if (region_edit_menu_split_item) {
1605 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1606 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1608 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1611 if (region_edit_menu_split_multichannel_item) {
1612 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1613 region_edit_menu_split_multichannel_item->set_sensitive (true);
1615 region_edit_menu_split_multichannel_item->set_sensitive (false);
1628 /* probably shouldn't happen but if it does, we don't care */
1632 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1634 /* Bounce to disk */
1636 using namespace Menu_Helpers;
1637 MenuList& edit_items = menu->items();
1639 edit_items.push_back (SeparatorElem());
1641 switch (clicked_routeview->audio_track()->freeze_state()) {
1642 case AudioTrack::NoFreeze:
1643 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1646 case AudioTrack::Frozen:
1647 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1650 case AudioTrack::UnFrozen:
1651 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1657 if (item_type == StreamItem && clicked_routeview) {
1658 clicked_routeview->build_underlay_menu(menu);
1661 /* When the region menu is opened, we setup the actions so that they look right
1664 sensitize_the_right_region_actions (false);
1665 _last_region_menu_was_main = false;
1667 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1668 menu->popup (button, time);
1672 Editor::build_track_context_menu ()
1674 using namespace Menu_Helpers;
1676 MenuList& edit_items = track_context_menu.items();
1679 add_dstream_context_items (edit_items);
1680 return &track_context_menu;
1684 Editor::build_track_bus_context_menu ()
1686 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_context_menu.items();
1691 add_bus_context_items (edit_items);
1692 return &track_context_menu;
1696 Editor::build_track_region_context_menu ()
1698 using namespace Menu_Helpers;
1699 MenuList& edit_items = track_region_context_menu.items();
1702 /* we've just cleared the track region context menu, so the menu that these
1703 two items were on will have disappeared; stop them dangling.
1705 region_edit_menu_split_item = 0;
1706 region_edit_menu_split_multichannel_item = 0;
1708 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1711 boost::shared_ptr<Track> tr;
1712 boost::shared_ptr<Playlist> pl;
1714 if ((tr = rtv->track())) {
1715 add_region_context_items (edit_items, tr);
1719 add_dstream_context_items (edit_items);
1721 return &track_region_context_menu;
1725 Editor::loudness_analyze_region_selection ()
1730 Selection& s (PublicEditor::instance ().get_selection ());
1731 RegionSelection ars = s.regions;
1732 ARDOUR::AnalysisGraph ag (_session);
1733 framecnt_t total_work = 0;
1735 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1736 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1740 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1743 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1744 total_work += arv->region ()->length ();
1747 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1749 ag.set_total_frames (total_work);
1750 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1753 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1754 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1758 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1762 ag.analyze_region (ar);
1765 if (!ag.canceled ()) {
1766 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1772 Editor::loudness_analyze_range_selection ()
1777 Selection& s (PublicEditor::instance ().get_selection ());
1778 TimeSelection ts = s.time;
1779 ARDOUR::AnalysisGraph ag (_session);
1780 framecnt_t total_work = 0;
1782 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1783 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1787 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1791 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1792 total_work += j->length ();
1796 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1798 ag.set_total_frames (total_work);
1799 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1802 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1803 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1807 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1811 ag.analyze_range (rui->route (), pl, ts);
1814 if (!ag.canceled ()) {
1815 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1821 Editor::spectral_analyze_region_selection ()
1823 if (analysis_window == 0) {
1824 analysis_window = new AnalysisWindow();
1827 analysis_window->set_session(_session);
1829 analysis_window->show_all();
1832 analysis_window->set_regionmode();
1833 analysis_window->analyze();
1835 analysis_window->present();
1839 Editor::spectral_analyze_range_selection()
1841 if (analysis_window == 0) {
1842 analysis_window = new AnalysisWindow();
1845 analysis_window->set_session(_session);
1847 analysis_window->show_all();
1850 analysis_window->set_rangemode();
1851 analysis_window->analyze();
1853 analysis_window->present();
1857 Editor::build_track_selection_context_menu ()
1859 using namespace Menu_Helpers;
1860 MenuList& edit_items = track_selection_context_menu.items();
1861 edit_items.clear ();
1863 add_selection_context_items (edit_items);
1864 // edit_items.push_back (SeparatorElem());
1865 // add_dstream_context_items (edit_items);
1867 return &track_selection_context_menu;
1871 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1873 using namespace Menu_Helpers;
1875 /* OK, stick the region submenu at the top of the list, and then add
1879 RegionSelection rs = get_regions_from_selection_and_entered ();
1881 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1883 if (_popup_region_menu_item == 0) {
1884 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1885 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1886 _popup_region_menu_item->show ();
1888 _popup_region_menu_item->set_label (menu_item_name);
1891 /* No layering allowed in later is higher layering model */
1892 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1893 if (act && Config->get_layer_model() == LaterHigher) {
1894 act->set_sensitive (false);
1896 act->set_sensitive (true);
1899 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1901 edit_items.push_back (*_popup_region_menu_item);
1902 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1903 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1905 edit_items.push_back (SeparatorElem());
1908 /** Add context menu items relevant to selection ranges.
1909 * @param edit_items List to add the items to.
1912 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1914 using namespace Menu_Helpers;
1916 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1917 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1919 edit_items.push_back (SeparatorElem());
1920 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1922 edit_items.push_back (SeparatorElem());
1923 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1924 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1926 edit_items.push_back (SeparatorElem());
1928 edit_items.push_back (
1930 _("Move Range Start to Previous Region Boundary"),
1931 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1935 edit_items.push_back (
1937 _("Move Range Start to Next Region Boundary"),
1938 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1942 edit_items.push_back (
1944 _("Move Range End to Previous Region Boundary"),
1945 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1949 edit_items.push_back (
1951 _("Move Range End to Next Region Boundary"),
1952 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1956 edit_items.push_back (SeparatorElem());
1957 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1958 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1960 edit_items.push_back (SeparatorElem());
1961 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1963 edit_items.push_back (SeparatorElem());
1964 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1965 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1966 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1971 edit_items.push_back (SeparatorElem());
1972 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1973 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1975 edit_items.push_back (SeparatorElem());
1976 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1977 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1978 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1979 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1980 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1981 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1982 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1988 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1990 using namespace Menu_Helpers;
1994 Menu *play_menu = manage (new Menu);
1995 MenuList& play_items = play_menu->items();
1996 play_menu->set_name ("ArdourContextMenu");
1998 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1999 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2000 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2001 play_items.push_back (SeparatorElem());
2002 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2004 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2008 Menu *select_menu = manage (new Menu);
2009 MenuList& select_items = select_menu->items();
2010 select_menu->set_name ("ArdourContextMenu");
2012 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2013 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2014 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2015 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2016 select_items.push_back (SeparatorElem());
2017 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2018 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2019 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2020 select_items.push_back (SeparatorElem());
2021 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2022 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2023 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2024 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2025 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2026 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2027 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2029 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2033 Menu *cutnpaste_menu = manage (new Menu);
2034 MenuList& cutnpaste_items = cutnpaste_menu->items();
2035 cutnpaste_menu->set_name ("ArdourContextMenu");
2037 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2038 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2039 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2041 cutnpaste_items.push_back (SeparatorElem());
2043 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2044 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2046 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2048 /* Adding new material */
2050 edit_items.push_back (SeparatorElem());
2051 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2052 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2056 Menu *nudge_menu = manage (new Menu());
2057 MenuList& nudge_items = nudge_menu->items();
2058 nudge_menu->set_name ("ArdourContextMenu");
2060 edit_items.push_back (SeparatorElem());
2061 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2062 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2063 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2064 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2066 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2070 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2072 using namespace Menu_Helpers;
2076 Menu *play_menu = manage (new Menu);
2077 MenuList& play_items = play_menu->items();
2078 play_menu->set_name ("ArdourContextMenu");
2080 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2081 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2082 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2086 Menu *select_menu = manage (new Menu);
2087 MenuList& select_items = select_menu->items();
2088 select_menu->set_name ("ArdourContextMenu");
2090 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2091 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2092 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2093 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2094 select_items.push_back (SeparatorElem());
2095 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2096 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2097 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2098 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2100 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2104 Menu *cutnpaste_menu = manage (new Menu);
2105 MenuList& cutnpaste_items = cutnpaste_menu->items();
2106 cutnpaste_menu->set_name ("ArdourContextMenu");
2108 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2109 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2110 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2112 Menu *nudge_menu = manage (new Menu());
2113 MenuList& nudge_items = nudge_menu->items();
2114 nudge_menu->set_name ("ArdourContextMenu");
2116 edit_items.push_back (SeparatorElem());
2117 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2118 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2119 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2120 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2122 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2126 Editor::snap_type() const
2132 Editor::snap_musical() const
2134 switch (_snap_type) {
2135 case SnapToBeatDiv128:
2136 case SnapToBeatDiv64:
2137 case SnapToBeatDiv32:
2138 case SnapToBeatDiv28:
2139 case SnapToBeatDiv24:
2140 case SnapToBeatDiv20:
2141 case SnapToBeatDiv16:
2142 case SnapToBeatDiv14:
2143 case SnapToBeatDiv12:
2144 case SnapToBeatDiv10:
2145 case SnapToBeatDiv8:
2146 case SnapToBeatDiv7:
2147 case SnapToBeatDiv6:
2148 case SnapToBeatDiv5:
2149 case SnapToBeatDiv4:
2150 case SnapToBeatDiv3:
2151 case SnapToBeatDiv2:
2163 Editor::snap_mode() const
2169 Editor::set_snap_to (SnapType st)
2171 unsigned int snap_ind = (unsigned int)st;
2173 if (internal_editing()) {
2174 internal_snap_type = st;
2176 pre_internal_snap_type = st;
2181 if (snap_ind > snap_type_strings.size() - 1) {
2183 _snap_type = (SnapType)snap_ind;
2186 string str = snap_type_strings[snap_ind];
2188 if (str != snap_type_selector.get_text()) {
2189 snap_type_selector.set_text (str);
2194 switch (_snap_type) {
2195 case SnapToBeatDiv128:
2196 case SnapToBeatDiv64:
2197 case SnapToBeatDiv32:
2198 case SnapToBeatDiv28:
2199 case SnapToBeatDiv24:
2200 case SnapToBeatDiv20:
2201 case SnapToBeatDiv16:
2202 case SnapToBeatDiv14:
2203 case SnapToBeatDiv12:
2204 case SnapToBeatDiv10:
2205 case SnapToBeatDiv8:
2206 case SnapToBeatDiv7:
2207 case SnapToBeatDiv6:
2208 case SnapToBeatDiv5:
2209 case SnapToBeatDiv4:
2210 case SnapToBeatDiv3:
2211 case SnapToBeatDiv2: {
2212 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2213 update_tempo_based_rulers ();
2217 case SnapToRegionStart:
2218 case SnapToRegionEnd:
2219 case SnapToRegionSync:
2220 case SnapToRegionBoundary:
2221 build_region_boundary_cache ();
2229 redisplay_tempo (false);
2231 SnapChanged (); /* EMIT SIGNAL */
2235 Editor::set_snap_mode (SnapMode mode)
2237 string str = snap_mode_strings[(int)mode];
2239 if (internal_editing()) {
2240 internal_snap_mode = mode;
2242 pre_internal_snap_mode = mode;
2247 if (str != snap_mode_selector.get_text ()) {
2248 snap_mode_selector.set_text (str);
2255 Editor::set_edit_point_preference (EditPoint ep, bool force)
2257 bool changed = (_edit_point != ep);
2260 if (Profile->get_mixbus())
2261 if (ep == EditAtSelectedMarker)
2262 ep = EditAtPlayhead;
2264 string str = edit_point_strings[(int)ep];
2265 if (str != edit_point_selector.get_text ()) {
2266 edit_point_selector.set_text (str);
2269 update_all_enter_cursors();
2271 if (!force && !changed) {
2275 const char* action=NULL;
2277 switch (_edit_point) {
2278 case EditAtPlayhead:
2279 action = "edit-at-playhead";
2281 case EditAtSelectedMarker:
2282 action = "edit-at-marker";
2285 action = "edit-at-mouse";
2289 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2291 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2295 bool in_track_canvas;
2297 if (!mouse_frame (foo, in_track_canvas)) {
2298 in_track_canvas = false;
2301 reset_canvas_action_sensitivity (in_track_canvas);
2302 sensitize_the_right_region_actions (false);
2308 Editor::set_state (const XMLNode& node, int version)
2311 PBD::Unwinder<bool> nsi (no_save_instant, true);
2314 Tabbable::set_state (node, version);
2317 if (_session && node.get_property ("playhead", ph_pos)) {
2319 playhead_cursor->set_position (ph_pos);
2321 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2322 playhead_cursor->set_position (0);
2325 playhead_cursor->set_position (0);
2328 node.get_property ("mixer-width", editor_mixer_strip_width);
2330 node.get_property ("zoom-focus", zoom_focus);
2331 zoom_focus_selection_done (zoom_focus);
2334 if (node.get_property ("zoom", z)) {
2335 /* older versions of ardour used floating point samples_per_pixel */
2336 reset_zoom (llrintf (z));
2338 reset_zoom (samples_per_pixel);
2342 if (node.get_property ("visible-track-count", cnt)) {
2343 set_visible_track_count (cnt);
2347 if (!node.get_property ("snap-to", snap_type)) {
2348 snap_type = _snap_type;
2350 set_snap_to (snap_type);
2353 if (node.get_property ("snap-mode", sm)) {
2354 snap_mode_selection_done(sm);
2355 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2356 * snap_mode_selection_done() will only mark an already active item as active
2357 * which does not trigger set_text().
2361 set_snap_mode (_snap_mode);
2364 node.get_property ("internal-snap-to", internal_snap_type);
2365 node.get_property ("internal-snap-mode", internal_snap_mode);
2366 node.get_property ("pre-internal-snap-to", pre_internal_snap_type);
2367 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2370 if (node.get_property ("mouse-mode", mm_str)) {
2371 MouseMode m = str2mousemode(mm_str);
2372 set_mouse_mode (m, true);
2374 set_mouse_mode (MouseObject, true);
2378 if (node.get_property ("left-frame", lf_pos)) {
2382 reset_x_origin (lf_pos);
2386 if (node.get_property ("y-origin", y_origin)) {
2387 reset_y_origin (y_origin);
2390 if (node.get_property ("join-object-range", yn)) {
2391 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2393 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2394 tact->set_active (!yn);
2395 tact->set_active (yn);
2397 set_mouse_mode(mouse_mode, true);
2401 if (node.get_property ("edit-point", ep)) {
2402 set_edit_point_preference (ep, true);
2404 set_edit_point_preference (_edit_point);
2407 node.get_property ("show-measures", _show_measures);
2409 if (node.get_property ("follow-playhead", yn)) {
2410 set_follow_playhead (yn);
2413 if (node.get_property ("stationary-playhead", yn)) {
2414 set_stationary_playhead (yn);
2417 RegionListSortType sort_type;
2418 if (node.get_property ("region-list-sort-type", sort_type)) {
2419 _regions->reset_sort_type (sort_type, true);
2422 if (node.get_property ("show-editor-mixer", yn)) {
2424 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2427 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2429 /* do it twice to force the change */
2431 tact->set_active (!yn);
2432 tact->set_active (yn);
2435 if (node.get_property ("show-editor-list", yn)) {
2437 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2440 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2442 /* do it twice to force the change */
2444 tact->set_active (!yn);
2445 tact->set_active (yn);
2449 if (node.get_property (X_("editor-list-page"), el_page)) {
2450 _the_notebook.set_current_page (el_page);
2453 if (node.get_property (X_("show-marker-lines"), yn)) {
2454 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2456 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2458 tact->set_active (!yn);
2459 tact->set_active (yn);
2462 XMLNodeList children = node.children ();
2463 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2464 selection->set_state (**i, Stateful::current_state_version);
2465 _regions->set_state (**i);
2466 _locations->set_state (**i);
2469 if (node.get_property ("maximised", yn)) {
2470 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2472 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2473 bool fs = tact && tact->get_active();
2475 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2479 framepos_t nudge_clock_value;
2480 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2481 nudge_clock->set (nudge_clock_value);
2483 nudge_clock->set_mode (AudioClock::Timecode);
2484 nudge_clock->set (_session->frame_rate() * 5, true);
2489 * Not all properties may have been in XML, but
2490 * those that are linked to a private variable may need changing
2494 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2496 yn = _show_measures;
2497 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2498 /* do it twice to force the change */
2499 tact->set_active (!yn);
2500 tact->set_active (yn);
2503 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2504 yn = _follow_playhead;
2506 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2507 if (tact->get_active() != yn) {
2508 tact->set_active (yn);
2512 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2513 yn = _stationary_playhead;
2515 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2516 if (tact->get_active() != yn) {
2517 tact->set_active (yn);
2522 return LuaInstance::instance()->set_state(node);
2526 Editor::get_state ()
2528 XMLNode* node = new XMLNode (X_("Editor"));
2530 node->set_property ("id", id().to_s ());
2532 node->add_child_nocopy (Tabbable::get_state());
2534 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2535 node->set_property("notebook-shrunk", _notebook_shrunk);
2536 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2538 maybe_add_mixer_strip_width (*node);
2540 node->set_property ("zoom-focus", zoom_focus);
2542 node->set_property ("zoom", samples_per_pixel);
2543 node->set_property ("snap-to", _snap_type);
2544 node->set_property ("snap-mode", _snap_mode);
2545 node->set_property ("internal-snap-to", internal_snap_type);
2546 node->set_property ("internal-snap-mode", internal_snap_mode);
2547 node->set_property ("pre-internal-snap-to", pre_internal_snap_type);
2548 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2549 node->set_property ("edit-point", _edit_point);
2550 node->set_property ("visible-track-count", _visible_track_count);
2552 node->set_property ("playhead", playhead_cursor->current_frame ());
2553 node->set_property ("left-frame", leftmost_frame);
2554 node->set_property ("y-origin", vertical_adjustment.get_value ());
2556 node->set_property ("show-measures", _show_measures);
2557 node->set_property ("maximised", _maximised);
2558 node->set_property ("follow-playhead", _follow_playhead);
2559 node->set_property ("stationary-playhead", _stationary_playhead);
2560 node->set_property ("region-list-sort-type", _regions->sort_type ());
2561 node->set_property ("mouse-mode", mouse_mode);
2562 node->set_property ("join-object-range", smart_mode_action->get_active ());
2564 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2566 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2567 node->set_property (X_("show-editor-mixer"), tact->get_active());
2570 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2572 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2573 node->set_property (X_("show-editor-list"), tact->get_active());
2576 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2578 if (button_bindings) {
2579 XMLNode* bb = new XMLNode (X_("Buttons"));
2580 button_bindings->save (*bb);
2581 node->add_child_nocopy (*bb);
2584 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2586 node->add_child_nocopy (selection->get_state ());
2587 node->add_child_nocopy (_regions->get_state ());
2589 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2591 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2592 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2593 node->add_child_nocopy (_locations->get_state ());
2598 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2599 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2601 * @return pair: TimeAxisView that y is over, layer index.
2603 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2604 * in stacked or expanded region display mode, otherwise 0.
2606 std::pair<TimeAxisView *, double>
2607 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2609 if (!trackview_relative_offset) {
2610 y -= _trackview_group->canvas_origin().y;
2614 return std::make_pair ( (TimeAxisView *) 0, 0);
2617 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2619 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2626 return std::make_pair ( (TimeAxisView *) 0, 0);
2629 /** Snap a position to the grid, if appropriate, taking into account current
2630 * grid settings and also the state of any snap modifier keys that may be pressed.
2631 * @param start Position to snap.
2632 * @param event Event to get current key modifier information from, or 0.
2635 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2637 if (!_session || !event) {
2641 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2642 if (_snap_mode == SnapOff) {
2643 snap_to_internal (start, direction, for_mark);
2645 start.set (start.frame, 0);
2648 if (_snap_mode != SnapOff) {
2649 snap_to_internal (start, direction, for_mark);
2650 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2651 /* SnapOff, but we pressed the snap_delta modifier */
2652 snap_to_internal (start, direction, for_mark);
2654 start.set (start.frame, 0);
2660 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2662 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2663 start.set (start.frame, 0);
2667 snap_to_internal (start, direction, for_mark, ensure_snap);
2671 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2673 framepos_t start = pos.frame;
2674 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2675 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2677 switch (_snap_type) {
2678 case SnapToTimecodeFrame:
2679 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2680 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2681 /* start is already on a whole timecode frame, do nothing */
2682 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2683 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2685 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2689 case SnapToTimecodeSeconds:
2690 if (_session->config.get_timecode_offset_negative()) {
2691 start += _session->config.get_timecode_offset ();
2693 start -= _session->config.get_timecode_offset ();
2695 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2696 (start % one_timecode_second == 0)) {
2697 /* start is already on a whole second, do nothing */
2698 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2699 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2701 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2704 if (_session->config.get_timecode_offset_negative()) {
2705 start -= _session->config.get_timecode_offset ();
2707 start += _session->config.get_timecode_offset ();
2711 case SnapToTimecodeMinutes:
2712 if (_session->config.get_timecode_offset_negative()) {
2713 start += _session->config.get_timecode_offset ();
2715 start -= _session->config.get_timecode_offset ();
2717 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2718 (start % one_timecode_minute == 0)) {
2719 /* start is already on a whole minute, do nothing */
2720 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2721 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2723 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2725 if (_session->config.get_timecode_offset_negative()) {
2726 start -= _session->config.get_timecode_offset ();
2728 start += _session->config.get_timecode_offset ();
2732 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2733 abort(); /*NOTREACHED*/
2740 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2742 const framepos_t one_second = _session->frame_rate();
2743 const framepos_t one_minute = _session->frame_rate() * 60;
2744 framepos_t presnap = start.frame;
2748 switch (_snap_type) {
2749 case SnapToTimecodeFrame:
2750 case SnapToTimecodeSeconds:
2751 case SnapToTimecodeMinutes:
2752 return timecode_snap_to_internal (start, direction, for_mark);
2755 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2756 start.frame % (one_second/75) == 0) {
2757 /* start is already on a whole CD frame, do nothing */
2758 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2759 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2761 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2764 start.set (start.frame, 0);
2769 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2770 start.frame % one_second == 0) {
2771 /* start is already on a whole second, do nothing */
2772 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2773 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2775 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2778 start.set (start.frame, 0);
2783 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2784 start.frame % one_minute == 0) {
2785 /* start is already on a whole minute, do nothing */
2786 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2787 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2789 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2792 start.set (start.frame, 0);
2797 start = _session->tempo_map().round_to_bar (start.frame, direction);
2801 start = _session->tempo_map().round_to_beat (start.frame, direction);
2804 case SnapToBeatDiv128:
2805 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2807 case SnapToBeatDiv64:
2808 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2810 case SnapToBeatDiv32:
2811 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2813 case SnapToBeatDiv28:
2814 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2816 case SnapToBeatDiv24:
2817 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2819 case SnapToBeatDiv20:
2820 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2822 case SnapToBeatDiv16:
2823 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2825 case SnapToBeatDiv14:
2826 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2828 case SnapToBeatDiv12:
2829 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2831 case SnapToBeatDiv10:
2832 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2834 case SnapToBeatDiv8:
2835 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2837 case SnapToBeatDiv7:
2838 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2840 case SnapToBeatDiv6:
2841 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2843 case SnapToBeatDiv5:
2844 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2846 case SnapToBeatDiv4:
2847 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2849 case SnapToBeatDiv3:
2850 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2852 case SnapToBeatDiv2:
2853 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2861 _session->locations()->marks_either_side (start.frame, before, after);
2863 if (before == max_framepos && after == max_framepos) {
2864 /* No marks to snap to, so just don't snap */
2866 } else if (before == max_framepos) {
2867 start.frame = after;
2868 } else if (after == max_framepos) {
2869 start.frame = before;
2870 } else if (before != max_framepos && after != max_framepos) {
2871 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2872 start.frame = after;
2873 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2874 start.frame = before;
2875 else if (direction == 0 ) {
2876 if ((start.frame - before) < (after - start.frame)) {
2877 start.frame = before;
2879 start.frame = after;
2884 start.set (start.frame, 0);
2888 case SnapToRegionStart:
2889 case SnapToRegionEnd:
2890 case SnapToRegionSync:
2891 case SnapToRegionBoundary:
2892 if (!region_boundary_cache.empty()) {
2894 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2895 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2897 if (direction > 0) {
2898 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2900 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2903 if (next != region_boundary_cache.begin ()) {
2908 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2909 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2911 if (start.frame > (p + n) / 2) {
2918 start.set (start.frame, 0);
2923 switch (_snap_mode) {
2933 if (presnap > start.frame) {
2934 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
2935 start.set (presnap, 0);
2938 } else if (presnap < start.frame) {
2939 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
2940 start.set (presnap, 0);
2945 /* handled at entry */
2952 Editor::setup_toolbar ()
2954 HBox* mode_box = manage(new HBox);
2955 mode_box->set_border_width (2);
2956 mode_box->set_spacing(2);
2958 HBox* mouse_mode_box = manage (new HBox);
2959 HBox* mouse_mode_hbox = manage (new HBox);
2960 VBox* mouse_mode_vbox = manage (new VBox);
2961 Alignment* mouse_mode_align = manage (new Alignment);
2963 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2964 mouse_mode_size_group->add_widget (smart_mode_button);
2965 mouse_mode_size_group->add_widget (mouse_move_button);
2966 mouse_mode_size_group->add_widget (mouse_cut_button);
2967 mouse_mode_size_group->add_widget (mouse_select_button);
2968 mouse_mode_size_group->add_widget (mouse_timefx_button);
2969 mouse_mode_size_group->add_widget (mouse_audition_button);
2970 mouse_mode_size_group->add_widget (mouse_draw_button);
2971 mouse_mode_size_group->add_widget (mouse_content_button);
2973 if (!Profile->get_mixbus()) {
2974 mouse_mode_size_group->add_widget (zoom_in_button);
2975 mouse_mode_size_group->add_widget (zoom_out_button);
2976 mouse_mode_size_group->add_widget (zoom_out_full_button);
2977 mouse_mode_size_group->add_widget (zoom_focus_selector);
2978 mouse_mode_size_group->add_widget (tav_shrink_button);
2979 mouse_mode_size_group->add_widget (tav_expand_button);
2981 mouse_mode_size_group->add_widget (zoom_preset_selector);
2982 mouse_mode_size_group->add_widget (visible_tracks_selector);
2985 mouse_mode_size_group->add_widget (snap_type_selector);
2986 mouse_mode_size_group->add_widget (snap_mode_selector);
2988 mouse_mode_size_group->add_widget (edit_point_selector);
2989 mouse_mode_size_group->add_widget (edit_mode_selector);
2991 mouse_mode_size_group->add_widget (*nudge_clock);
2992 mouse_mode_size_group->add_widget (nudge_forward_button);
2993 mouse_mode_size_group->add_widget (nudge_backward_button);
2995 mouse_mode_hbox->set_spacing (2);
2997 if (!ARDOUR::Profile->get_trx()) {
2998 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3001 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3002 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3004 if (!ARDOUR::Profile->get_mixbus()) {
3005 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3008 if (!ARDOUR::Profile->get_trx()) {
3009 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3010 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3011 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3012 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3015 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3017 mouse_mode_align->add (*mouse_mode_vbox);
3018 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3020 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3022 edit_mode_selector.set_name ("mouse mode button");
3024 if (!ARDOUR::Profile->get_trx()) {
3025 mode_box->pack_start (edit_mode_selector, false, false);
3028 mode_box->pack_start (*mouse_mode_box, false, false);
3032 _zoom_box.set_spacing (2);
3033 _zoom_box.set_border_width (2);
3037 zoom_preset_selector.set_name ("zoom button");
3038 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3040 zoom_in_button.set_name ("zoom button");
3041 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3042 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3043 zoom_in_button.set_related_action (act);
3045 zoom_out_button.set_name ("zoom button");
3046 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3047 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3048 zoom_out_button.set_related_action (act);
3050 zoom_out_full_button.set_name ("zoom button");
3051 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3052 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3053 zoom_out_full_button.set_related_action (act);
3055 zoom_focus_selector.set_name ("zoom button");
3057 if (ARDOUR::Profile->get_mixbus()) {
3058 _zoom_box.pack_start (zoom_preset_selector, false, false);
3059 } else if (ARDOUR::Profile->get_trx()) {
3060 mode_box->pack_start (zoom_out_button, false, false);
3061 mode_box->pack_start (zoom_in_button, false, false);
3063 _zoom_box.pack_start (zoom_out_button, false, false);
3064 _zoom_box.pack_start (zoom_in_button, false, false);
3065 _zoom_box.pack_start (zoom_out_full_button, false, false);
3066 _zoom_box.pack_start (zoom_focus_selector, false, false);
3069 /* Track zoom buttons */
3070 _track_box.set_spacing (2);
3071 _track_box.set_border_width (2);
3073 visible_tracks_selector.set_name ("zoom button");
3074 if (Profile->get_mixbus()) {
3075 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3077 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3080 tav_expand_button.set_name ("zoom button");
3081 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3082 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3083 tav_expand_button.set_related_action (act);
3085 tav_shrink_button.set_name ("zoom button");
3086 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3087 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3088 tav_shrink_button.set_related_action (act);
3090 if (ARDOUR::Profile->get_mixbus()) {
3091 _track_box.pack_start (visible_tracks_selector);
3092 } else if (ARDOUR::Profile->get_trx()) {
3093 _track_box.pack_start (tav_shrink_button);
3094 _track_box.pack_start (tav_expand_button);
3096 _track_box.pack_start (visible_tracks_selector);
3097 _track_box.pack_start (tav_shrink_button);
3098 _track_box.pack_start (tav_expand_button);
3101 snap_box.set_spacing (2);
3102 snap_box.set_border_width (2);
3104 snap_type_selector.set_name ("mouse mode button");
3106 snap_mode_selector.set_name ("mouse mode button");
3108 edit_point_selector.set_name ("mouse mode button");
3110 snap_box.pack_start (snap_mode_selector, false, false);
3111 snap_box.pack_start (snap_type_selector, false, false);
3114 HBox *ep_box = manage (new HBox);
3115 ep_box->set_spacing (2);
3116 ep_box->set_border_width (2);
3118 ep_box->pack_start (edit_point_selector, false, false);
3122 HBox *nudge_box = manage (new HBox);
3123 nudge_box->set_spacing (2);
3124 nudge_box->set_border_width (2);
3126 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3127 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3129 nudge_box->pack_start (nudge_backward_button, false, false);
3130 nudge_box->pack_start (nudge_forward_button, false, false);
3131 nudge_box->pack_start (*nudge_clock, false, false);
3134 /* Pack everything in... */
3136 toolbar_hbox.set_spacing (2);
3137 toolbar_hbox.set_border_width (2);
3139 toolbar_hbox.pack_start (*mode_box, false, false);
3141 if (!ARDOUR::Profile->get_trx()) {
3143 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3145 toolbar_hbox.pack_start (_zoom_box, false, false);
3147 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3149 toolbar_hbox.pack_start (_track_box, false, false);
3151 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3153 toolbar_hbox.pack_start (snap_box, false, false);
3155 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3157 toolbar_hbox.pack_start (*ep_box, false, false);
3159 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3161 toolbar_hbox.pack_start (*nudge_box, false, false);
3164 toolbar_hbox.show_all ();
3168 Editor::build_edit_point_menu ()
3170 using namespace Menu_Helpers;
3172 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3173 if(!Profile->get_mixbus())
3174 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3175 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3177 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3181 Editor::build_edit_mode_menu ()
3183 using namespace Menu_Helpers;
3185 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3186 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3187 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3188 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3190 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3194 Editor::build_snap_mode_menu ()
3196 using namespace Menu_Helpers;
3198 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3199 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3200 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3202 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3206 Editor::build_snap_type_menu ()
3208 using namespace Menu_Helpers;
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3241 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3246 Editor::setup_tooltips ()
3248 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3249 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3250 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3251 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3252 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3253 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3254 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3255 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3256 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3257 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3258 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3259 set_tooltip (zoom_in_button, _("Zoom In"));
3260 set_tooltip (zoom_out_button, _("Zoom Out"));
3261 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3262 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3263 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3264 set_tooltip (tav_expand_button, _("Expand Tracks"));
3265 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3266 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3267 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3268 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3269 set_tooltip (edit_point_selector, _("Edit Point"));
3270 set_tooltip (edit_mode_selector, _("Edit Mode"));
3271 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3275 Editor::convert_drop_to_paths (
3276 vector<string>& paths,
3277 const RefPtr<Gdk::DragContext>& /*context*/,
3280 const SelectionData& data,
3284 if (_session == 0) {
3288 vector<string> uris = data.get_uris();
3292 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3293 are actually URI lists. So do it by hand.
3296 if (data.get_target() != "text/plain") {
3300 /* Parse the "uri-list" format that Nautilus provides,
3301 where each pathname is delimited by \r\n.
3303 THERE MAY BE NO NULL TERMINATING CHAR!!!
3306 string txt = data.get_text();
3310 p = (char *) malloc (txt.length() + 1);
3311 txt.copy (p, txt.length(), 0);
3312 p[txt.length()] = '\0';
3318 while (g_ascii_isspace (*p))
3322 while (*q && (*q != '\n') && (*q != '\r')) {
3329 while (q > p && g_ascii_isspace (*q))
3334 uris.push_back (string (p, q - p + 1));
3338 p = strchr (p, '\n');
3350 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3351 if ((*i).substr (0,7) == "file://") {
3352 paths.push_back (Glib::filename_from_uri (*i));
3360 Editor::new_tempo_section ()
3365 Editor::map_transport_state ()
3367 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3369 if (_session && _session->transport_stopped()) {
3370 have_pending_keyboard_selection = false;
3373 update_loop_range_view ();
3377 Editor::transport_looped ()
3379 /* reset Playhead position interpolation.
3380 * see Editor::super_rapid_screen_update
3382 _last_update_time = 0;
3388 Editor::begin_selection_op_history ()
3390 selection_op_cmd_depth = 0;
3391 selection_op_history_it = 0;
3393 while(!selection_op_history.empty()) {
3394 delete selection_op_history.front();
3395 selection_op_history.pop_front();
3398 selection_undo_action->set_sensitive (false);
3399 selection_redo_action->set_sensitive (false);
3400 selection_op_history.push_front (&_selection_memento->get_state ());
3404 Editor::begin_reversible_selection_op (string name)
3407 //cerr << name << endl;
3408 /* begin/commit pairs can be nested */
3409 selection_op_cmd_depth++;
3414 Editor::commit_reversible_selection_op ()
3417 if (selection_op_cmd_depth == 1) {
3419 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3421 The user has undone some selection ops and then made a new one,
3422 making anything earlier in the list invalid.
3425 list<XMLNode *>::iterator it = selection_op_history.begin();
3426 list<XMLNode *>::iterator e_it = it;
3427 advance (e_it, selection_op_history_it);
3429 for ( ; it != e_it; ++it) {
3432 selection_op_history.erase (selection_op_history.begin(), e_it);
3435 selection_op_history.push_front (&_selection_memento->get_state ());
3436 selection_op_history_it = 0;
3438 selection_undo_action->set_sensitive (true);
3439 selection_redo_action->set_sensitive (false);
3442 if (selection_op_cmd_depth > 0) {
3443 selection_op_cmd_depth--;
3449 Editor::undo_selection_op ()
3452 selection_op_history_it++;
3454 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3455 if (n == selection_op_history_it) {
3456 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3457 selection_redo_action->set_sensitive (true);
3461 /* is there an earlier entry? */
3462 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3463 selection_undo_action->set_sensitive (false);
3469 Editor::redo_selection_op ()
3472 if (selection_op_history_it > 0) {
3473 selection_op_history_it--;
3476 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3477 if (n == selection_op_history_it) {
3478 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3479 selection_undo_action->set_sensitive (true);
3484 if (selection_op_history_it == 0) {
3485 selection_redo_action->set_sensitive (false);
3491 Editor::begin_reversible_command (string name)
3494 before.push_back (&_selection_memento->get_state ());
3495 _session->begin_reversible_command (name);
3500 Editor::begin_reversible_command (GQuark q)
3503 before.push_back (&_selection_memento->get_state ());
3504 _session->begin_reversible_command (q);
3509 Editor::abort_reversible_command ()
3512 while(!before.empty()) {
3513 delete before.front();
3516 _session->abort_reversible_command ();
3521 Editor::commit_reversible_command ()
3524 if (before.size() == 1) {
3525 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3526 redo_action->set_sensitive(false);
3527 undo_action->set_sensitive(true);
3528 begin_selection_op_history ();
3531 if (before.empty()) {
3532 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3537 _session->commit_reversible_command ();
3542 Editor::history_changed ()
3546 if (undo_action && _session) {
3547 if (_session->undo_depth() == 0) {
3548 label = S_("Command|Undo");
3550 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3552 undo_action->property_label() = label;
3555 if (redo_action && _session) {
3556 if (_session->redo_depth() == 0) {
3558 redo_action->set_sensitive (false);
3560 label = string_compose(_("Redo (%1)"), _session->next_redo());
3561 redo_action->set_sensitive (true);
3563 redo_action->property_label() = label;
3568 Editor::duplicate_range (bool with_dialog)
3572 RegionSelection rs = get_regions_from_selection_and_entered ();
3574 if ( selection->time.length() == 0 && rs.empty()) {
3580 ArdourDialog win (_("Duplicate"));
3581 Label label (_("Number of duplications:"));
3582 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3583 SpinButton spinner (adjustment, 0.0, 1);
3586 win.get_vbox()->set_spacing (12);
3587 win.get_vbox()->pack_start (hbox);
3588 hbox.set_border_width (6);
3589 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3591 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3592 place, visually. so do this by hand.
3595 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3596 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3597 spinner.grab_focus();
3603 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3604 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3605 win.set_default_response (RESPONSE_ACCEPT);
3607 spinner.grab_focus ();
3609 switch (win.run ()) {
3610 case RESPONSE_ACCEPT:
3616 times = adjustment.get_value();
3619 if ((current_mouse_mode() == Editing::MouseRange)) {
3620 if (selection->time.length()) {
3621 duplicate_selection (times);
3623 } else if (get_smart_mode()) {
3624 if (selection->time.length()) {
3625 duplicate_selection (times);
3627 duplicate_some_regions (rs, times);
3629 duplicate_some_regions (rs, times);
3634 Editor::set_edit_mode (EditMode m)
3636 Config->set_edit_mode (m);
3640 Editor::cycle_edit_mode ()
3642 switch (Config->get_edit_mode()) {
3644 Config->set_edit_mode (Ripple);
3648 Config->set_edit_mode (Lock);
3651 Config->set_edit_mode (Slide);
3657 Editor::edit_mode_selection_done ( EditMode m )
3659 Config->set_edit_mode ( m );
3663 Editor::snap_type_selection_done (SnapType snaptype)
3665 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3667 ract->set_active ();
3672 Editor::snap_mode_selection_done (SnapMode mode)
3674 RefPtr<RadioAction> ract = snap_mode_action (mode);
3677 ract->set_active (true);
3682 Editor::cycle_edit_point (bool with_marker)
3684 if(Profile->get_mixbus())
3685 with_marker = false;
3687 switch (_edit_point) {
3689 set_edit_point_preference (EditAtPlayhead);
3691 case EditAtPlayhead:
3693 set_edit_point_preference (EditAtSelectedMarker);
3695 set_edit_point_preference (EditAtMouse);
3698 case EditAtSelectedMarker:
3699 set_edit_point_preference (EditAtMouse);
3705 Editor::edit_point_selection_done (EditPoint ep)
3707 set_edit_point_preference ( ep );
3711 Editor::build_zoom_focus_menu ()
3713 using namespace Menu_Helpers;
3715 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3716 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3717 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3718 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3719 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3720 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3722 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3726 Editor::zoom_focus_selection_done ( ZoomFocus f )
3728 RefPtr<RadioAction> ract = zoom_focus_action (f);
3730 ract->set_active ();
3735 Editor::build_track_count_menu ()
3737 using namespace Menu_Helpers;
3739 if (!Profile->get_mixbus()) {
3740 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3744 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3745 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3746 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3747 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3748 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3749 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3750 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3751 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3752 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3754 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3755 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3756 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3757 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3758 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3759 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3760 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3763 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3765 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3766 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3767 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3768 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3769 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3770 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3771 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3772 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3773 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3774 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3775 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3780 Editor::set_zoom_preset (int64_t ms)
3783 temporal_zoom_session();
3787 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3788 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3792 Editor::set_visible_track_count (int32_t n)
3794 _visible_track_count = n;
3796 /* if the canvas hasn't really been allocated any size yet, just
3797 record the desired number of visible tracks and return. when canvas
3798 allocation happens, we will get called again and then we can do the
3802 if (_visible_canvas_height <= 1) {
3808 DisplaySuspender ds;
3810 if (_visible_track_count > 0) {
3811 h = trackviews_height() / _visible_track_count;
3812 std::ostringstream s;
3813 s << _visible_track_count;
3815 } else if (_visible_track_count == 0) {
3817 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3818 if ((*i)->marked_for_display()) {
3820 TimeAxisView::Children cl ((*i)->get_child_list ());
3821 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3822 if ((*j)->marked_for_display()) {
3829 visible_tracks_selector.set_text (X_("*"));
3832 h = trackviews_height() / n;
3835 /* negative value means that the visible track count has
3836 been overridden by explicit track height changes.
3838 visible_tracks_selector.set_text (X_("*"));
3842 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3843 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3846 if (str != visible_tracks_selector.get_text()) {
3847 visible_tracks_selector.set_text (str);
3852 Editor::override_visible_track_count ()
3854 _visible_track_count = -1;
3855 visible_tracks_selector.set_text ( _("*") );
3859 Editor::edit_controls_button_release (GdkEventButton* ev)
3861 if (Keyboard::is_context_menu_event (ev)) {
3862 ARDOUR_UI::instance()->add_route ();
3863 } else if (ev->button == 1) {
3864 selection->clear_tracks ();
3871 Editor::mouse_select_button_release (GdkEventButton* ev)
3873 /* this handles just right-clicks */
3875 if (ev->button != 3) {
3883 Editor::set_zoom_focus (ZoomFocus f)
3885 string str = zoom_focus_strings[(int)f];
3887 if (str != zoom_focus_selector.get_text()) {
3888 zoom_focus_selector.set_text (str);
3891 if (zoom_focus != f) {
3898 Editor::cycle_zoom_focus ()
3900 switch (zoom_focus) {
3902 set_zoom_focus (ZoomFocusRight);
3904 case ZoomFocusRight:
3905 set_zoom_focus (ZoomFocusCenter);
3907 case ZoomFocusCenter:
3908 set_zoom_focus (ZoomFocusPlayhead);
3910 case ZoomFocusPlayhead:
3911 set_zoom_focus (ZoomFocusMouse);
3913 case ZoomFocusMouse:
3914 set_zoom_focus (ZoomFocusEdit);
3917 set_zoom_focus (ZoomFocusLeft);
3923 Editor::set_show_measures (bool yn)
3925 if (_show_measures != yn) {
3928 if ((_show_measures = yn) == true) {
3930 tempo_lines->show();
3933 std::vector<TempoMap::BBTPoint> grid;
3934 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3935 draw_measures (grid);
3943 Editor::toggle_follow_playhead ()
3945 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3947 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3948 set_follow_playhead (tact->get_active());
3952 /** @param yn true to follow playhead, otherwise false.
3953 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3956 Editor::set_follow_playhead (bool yn, bool catch_up)
3958 if (_follow_playhead != yn) {
3959 if ((_follow_playhead = yn) == true && catch_up) {
3961 reset_x_origin_to_follow_playhead ();
3968 Editor::toggle_stationary_playhead ()
3970 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3972 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3973 set_stationary_playhead (tact->get_active());
3978 Editor::set_stationary_playhead (bool yn)
3980 if (_stationary_playhead != yn) {
3981 if ((_stationary_playhead = yn) == true) {
3983 // FIXME need a 3.0 equivalent of this 2.X call
3984 // update_current_screen ();
3991 Editor::playlist_selector () const
3993 return *_playlist_selector;
3997 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3999 if (paste_count == 0) {
4000 /* don't bother calculating an offset that will be zero anyway */
4004 /* calculate basic unsnapped multi-paste offset */
4005 framecnt_t offset = paste_count * duration;
4007 /* snap offset so pos + offset is aligned to the grid */
4008 MusicFrame offset_pos (pos + offset, 0);
4009 snap_to(offset_pos, RoundUpMaybe);
4010 offset = offset_pos.frame - pos;
4016 Editor::get_grid_beat_divisions(framepos_t position)
4018 switch (_snap_type) {
4019 case SnapToBeatDiv128: return 128;
4020 case SnapToBeatDiv64: return 64;
4021 case SnapToBeatDiv32: return 32;
4022 case SnapToBeatDiv28: return 28;
4023 case SnapToBeatDiv24: return 24;
4024 case SnapToBeatDiv20: return 20;
4025 case SnapToBeatDiv16: return 16;
4026 case SnapToBeatDiv14: return 14;
4027 case SnapToBeatDiv12: return 12;
4028 case SnapToBeatDiv10: return 10;
4029 case SnapToBeatDiv8: return 8;
4030 case SnapToBeatDiv7: return 7;
4031 case SnapToBeatDiv6: return 6;
4032 case SnapToBeatDiv5: return 5;
4033 case SnapToBeatDiv4: return 4;
4034 case SnapToBeatDiv3: return 3;
4035 case SnapToBeatDiv2: return 2;
4041 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4042 if the grid is non-musical, returns 0.
4043 if the grid is snapped to bars, returns -1.
4044 @param event_state the current keyboard modifier mask.
4047 Editor::get_grid_music_divisions (uint32_t event_state)
4049 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4053 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4057 switch (_snap_type) {
4058 case SnapToBeatDiv128: return 128;
4059 case SnapToBeatDiv64: return 64;
4060 case SnapToBeatDiv32: return 32;
4061 case SnapToBeatDiv28: return 28;
4062 case SnapToBeatDiv24: return 24;
4063 case SnapToBeatDiv20: return 20;
4064 case SnapToBeatDiv16: return 16;
4065 case SnapToBeatDiv14: return 14;
4066 case SnapToBeatDiv12: return 12;
4067 case SnapToBeatDiv10: return 10;
4068 case SnapToBeatDiv8: return 8;
4069 case SnapToBeatDiv7: return 7;
4070 case SnapToBeatDiv6: return 6;
4071 case SnapToBeatDiv5: return 5;
4072 case SnapToBeatDiv4: return 4;
4073 case SnapToBeatDiv3: return 3;
4074 case SnapToBeatDiv2: return 2;
4075 case SnapToBeat: return 1;
4076 case SnapToBar : return -1;
4083 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4087 const unsigned divisions = get_grid_beat_divisions(position);
4089 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4092 switch (_snap_type) {
4094 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4097 const Meter& m = _session->tempo_map().meter_at_frame (position);
4098 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4106 return Evoral::Beats();
4110 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4114 ret = nudge_clock->current_duration (pos);
4115 next = ret + 1; /* XXXX fix me */
4121 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4123 ArdourDialog dialog (_("Playlist Deletion"));
4124 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4125 "If it is kept, its audio files will not be cleaned.\n"
4126 "If it is deleted, audio files used by it alone will be cleaned."),
4129 dialog.set_position (WIN_POS_CENTER);
4130 dialog.get_vbox()->pack_start (label);
4134 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4135 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4136 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4137 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4138 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4140 // by default gtk uses the left most button
4141 keep->grab_focus ();
4143 switch (dialog.run ()) {
4145 /* keep this and all remaining ones */
4150 /* delete this and all others */
4154 case RESPONSE_ACCEPT:
4155 /* delete the playlist */
4159 case RESPONSE_REJECT:
4160 /* keep the playlist */
4172 Editor::audio_region_selection_covers (framepos_t where)
4174 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4175 if ((*a)->region()->covers (where)) {
4184 Editor::prepare_for_cleanup ()
4186 cut_buffer->clear_regions ();
4187 cut_buffer->clear_playlists ();
4189 selection->clear_regions ();
4190 selection->clear_playlists ();
4192 _regions->suspend_redisplay ();
4196 Editor::finish_cleanup ()
4198 _regions->resume_redisplay ();
4202 Editor::transport_loop_location()
4205 return _session->locations()->auto_loop_location();
4212 Editor::transport_punch_location()
4215 return _session->locations()->auto_punch_location();
4222 Editor::control_layout_scroll (GdkEventScroll* ev)
4224 /* Just forward to the normal canvas scroll method. The coordinate
4225 systems are different but since the canvas is always larger than the
4226 track headers, and aligned with the trackview area, this will work.
4228 In the not too distant future this layout is going away anyway and
4229 headers will be on the canvas.
4231 return canvas_scroll_event (ev, false);
4235 Editor::session_state_saved (string)
4238 _snapshots->redisplay ();
4242 Editor::maximise_editing_space ()
4248 Gtk::Window* toplevel = current_toplevel();
4251 toplevel->fullscreen ();
4257 Editor::restore_editing_space ()
4263 Gtk::Window* toplevel = current_toplevel();
4266 toplevel->unfullscreen();
4272 * Make new playlists for a given track and also any others that belong
4273 * to the same active route group with the `select' property.
4278 Editor::new_playlists (TimeAxisView* v)
4280 begin_reversible_command (_("new playlists"));
4281 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4282 _session->playlists->get (playlists);
4283 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4284 commit_reversible_command ();
4288 * Use a copy of the current playlist for a given track and also any others that belong
4289 * to the same active route group with the `select' property.
4294 Editor::copy_playlists (TimeAxisView* v)
4296 begin_reversible_command (_("copy playlists"));
4297 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4298 _session->playlists->get (playlists);
4299 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4300 commit_reversible_command ();
4303 /** Clear the current playlist for a given track and also any others that belong
4304 * to the same active route group with the `select' property.
4309 Editor::clear_playlists (TimeAxisView* v)
4311 begin_reversible_command (_("clear playlists"));
4312 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4313 _session->playlists->get (playlists);
4314 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4315 commit_reversible_command ();
4319 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4321 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4325 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4327 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4331 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4333 atv.clear_playlist ();
4337 Editor::get_y_origin () const
4339 return vertical_adjustment.get_value ();
4342 /** Queue up a change to the viewport x origin.
4343 * @param frame New x origin.
4346 Editor::reset_x_origin (framepos_t frame)
4348 pending_visual_change.add (VisualChange::TimeOrigin);
4349 pending_visual_change.time_origin = frame;
4350 ensure_visual_change_idle_handler ();
4354 Editor::reset_y_origin (double y)
4356 pending_visual_change.add (VisualChange::YOrigin);
4357 pending_visual_change.y_origin = y;
4358 ensure_visual_change_idle_handler ();
4362 Editor::reset_zoom (framecnt_t spp)
4364 if (spp == samples_per_pixel) {
4368 pending_visual_change.add (VisualChange::ZoomLevel);
4369 pending_visual_change.samples_per_pixel = spp;
4370 ensure_visual_change_idle_handler ();
4374 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4376 reset_x_origin (frame);
4379 if (!no_save_visual) {
4380 undo_visual_stack.push_back (current_visual_state(false));
4384 Editor::VisualState::VisualState (bool with_tracks)
4385 : gui_state (with_tracks ? new GUIObjectState : 0)
4389 Editor::VisualState::~VisualState ()
4394 Editor::VisualState*
4395 Editor::current_visual_state (bool with_tracks)
4397 VisualState* vs = new VisualState (with_tracks);
4398 vs->y_position = vertical_adjustment.get_value();
4399 vs->samples_per_pixel = samples_per_pixel;
4400 vs->leftmost_frame = leftmost_frame;
4401 vs->zoom_focus = zoom_focus;
4404 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4411 Editor::undo_visual_state ()
4413 if (undo_visual_stack.empty()) {
4417 VisualState* vs = undo_visual_stack.back();
4418 undo_visual_stack.pop_back();
4421 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4424 use_visual_state (*vs);
4429 Editor::redo_visual_state ()
4431 if (redo_visual_stack.empty()) {
4435 VisualState* vs = redo_visual_stack.back();
4436 redo_visual_stack.pop_back();
4438 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4439 // why do we check here?
4440 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4443 use_visual_state (*vs);
4448 Editor::swap_visual_state ()
4450 if (undo_visual_stack.empty()) {
4451 redo_visual_state ();
4453 undo_visual_state ();
4458 Editor::use_visual_state (VisualState& vs)
4460 PBD::Unwinder<bool> nsv (no_save_visual, true);
4461 DisplaySuspender ds;
4463 vertical_adjustment.set_value (vs.y_position);
4465 set_zoom_focus (vs.zoom_focus);
4466 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4469 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4471 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4472 (*i)->clear_property_cache();
4473 (*i)->reset_visual_state ();
4477 _routes->update_visibility ();
4480 /** This is the core function that controls the zoom level of the canvas. It is called
4481 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4482 * @param spp new number of samples per pixel
4485 Editor::set_samples_per_pixel (framecnt_t spp)
4491 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4492 const framecnt_t lots_of_pixels = 4000;
4494 /* if the zoom level is greater than what you'd get trying to display 3
4495 * days of audio on a really big screen, then it's too big.
4498 if (spp * lots_of_pixels > three_days) {
4502 samples_per_pixel = spp;
4506 Editor::on_samples_per_pixel_changed ()
4509 tempo_lines->tempo_map_changed(_session->tempo_map().music_origin());
4512 bool const showing_time_selection = selection->time.length() > 0;
4514 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4515 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4516 (*i)->reshow_selection (selection->time);
4520 ZoomChanged (); /* EMIT_SIGNAL */
4522 ArdourCanvas::GtkCanvasViewport* c;
4524 c = get_track_canvas();
4526 c->canvas()->zoomed ();
4529 if (playhead_cursor) {
4530 playhead_cursor->set_position (playhead_cursor->current_frame ());
4533 refresh_location_display();
4534 _summary->set_overlays_dirty ();
4536 update_marker_labels ();
4542 Editor::playhead_cursor_sample () const
4544 return playhead_cursor->current_frame();
4548 Editor::queue_visual_videotimeline_update ()
4550 pending_visual_change.add (VisualChange::VideoTimeline);
4551 ensure_visual_change_idle_handler ();
4555 Editor::ensure_visual_change_idle_handler ()
4557 if (pending_visual_change.idle_handler_id < 0) {
4558 // see comment in add_to_idle_resize above.
4559 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4560 pending_visual_change.being_handled = false;
4565 Editor::_idle_visual_changer (void* arg)
4567 return static_cast<Editor*>(arg)->idle_visual_changer ();
4571 Editor::pre_render ()
4573 visual_change_queued = false;
4575 if (pending_visual_change.pending != 0) {
4576 ensure_visual_change_idle_handler();
4581 Editor::idle_visual_changer ()
4583 pending_visual_change.idle_handler_id = -1;
4585 if (pending_visual_change.pending == 0) {
4589 /* set_horizontal_position() below (and maybe other calls) call
4590 gtk_main_iteration(), so it's possible that a signal will be handled
4591 half-way through this method. If this signal wants an
4592 idle_visual_changer we must schedule another one after this one, so
4593 mark the idle_handler_id as -1 here to allow that. Also make a note
4594 that we are doing the visual change, so that changes in response to
4595 super-rapid-screen-update can be dropped if we are still processing
4599 if (visual_change_queued) {
4603 pending_visual_change.being_handled = true;
4605 VisualChange vc = pending_visual_change;
4607 pending_visual_change.pending = (VisualChange::Type) 0;
4609 visual_changer (vc);
4611 pending_visual_change.being_handled = false;
4613 visual_change_queued = true;
4615 return 0; /* this is always a one-shot call */
4619 Editor::visual_changer (const VisualChange& vc)
4622 * Changed first so the correct horizontal canvas position is calculated in
4623 * Editor::set_horizontal_position
4625 if (vc.pending & VisualChange::ZoomLevel) {
4626 set_samples_per_pixel (vc.samples_per_pixel);
4629 if (vc.pending & VisualChange::TimeOrigin) {
4630 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4631 set_horizontal_position (new_time_origin);
4634 if (vc.pending & VisualChange::YOrigin) {
4635 vertical_adjustment.set_value (vc.y_origin);
4639 * Now the canvas is in the final state before render the canvas items that
4640 * support the Item::prepare_for_render interface can calculate the correct
4641 * item to visible canvas intersection.
4643 if (vc.pending & VisualChange::ZoomLevel) {
4644 on_samples_per_pixel_changed ();
4646 compute_fixed_ruler_scale ();
4648 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4649 update_tempo_based_rulers ();
4652 if (!(vc.pending & VisualChange::ZoomLevel)) {
4654 * If the canvas is not being zoomed then the canvas items will not change
4655 * and cause Item::prepare_for_render to be called so do it here manually.
4657 * Not ideal, but I can't think of a better solution atm.
4659 _track_canvas->prepare_for_render();
4662 // If we are only scrolling vertically there is no need to update these
4663 if (vc.pending != VisualChange::YOrigin) {
4664 update_fixed_rulers ();
4665 redisplay_tempo (true);
4667 /* video frames & position need to be updated for zoom, horiz-scroll
4668 * and (explicitly) VisualChange::VideoTimeline.
4670 update_video_timeline();
4673 _summary->set_overlays_dirty ();
4676 struct EditorOrderTimeAxisSorter {
4677 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4678 return a->order () < b->order ();
4683 Editor::sort_track_selection (TrackViewList& sel)
4685 EditorOrderTimeAxisSorter cmp;
4690 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4693 framepos_t where = 0;
4694 EditPoint ep = _edit_point;
4696 if (Profile->get_mixbus()) {
4697 if (ep == EditAtSelectedMarker) {
4698 ep = EditAtPlayhead;
4702 if (from_outside_canvas && (ep == EditAtMouse)) {
4703 ep = EditAtPlayhead;
4704 } else if (from_context_menu && (ep == EditAtMouse)) {
4705 return canvas_event_sample (&context_click_event, 0, 0);
4708 if (entered_marker) {
4709 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4710 return entered_marker->position();
4713 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4714 ep = EditAtSelectedMarker;
4717 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4718 ep = EditAtPlayhead;
4721 MusicFrame snap_mf (0, 0);
4724 case EditAtPlayhead:
4725 if (_dragging_playhead && _control_scroll_target) {
4726 where = *_control_scroll_target;
4728 where = _session->audible_frame();
4730 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4733 case EditAtSelectedMarker:
4734 if (!selection->markers.empty()) {
4736 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4739 where = loc->start();
4743 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4751 if (!mouse_frame (where, ignored)) {
4752 /* XXX not right but what can we do ? */
4755 snap_mf.frame = where;
4757 where = snap_mf.frame;
4758 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4766 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4768 if (!_session) return;
4770 begin_reversible_command (cmd);
4774 if ((tll = transport_loop_location()) == 0) {
4775 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4776 XMLNode &before = _session->locations()->get_state();
4777 _session->locations()->add (loc, true);
4778 _session->set_auto_loop_location (loc);
4779 XMLNode &after = _session->locations()->get_state();
4780 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4782 XMLNode &before = tll->get_state();
4783 tll->set_hidden (false, this);
4784 tll->set (start, end);
4785 XMLNode &after = tll->get_state();
4786 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4789 commit_reversible_command ();
4793 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4795 if (!_session) return;
4797 begin_reversible_command (cmd);
4801 if ((tpl = transport_punch_location()) == 0) {
4802 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4803 XMLNode &before = _session->locations()->get_state();
4804 _session->locations()->add (loc, true);
4805 _session->set_auto_punch_location (loc);
4806 XMLNode &after = _session->locations()->get_state();
4807 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4809 XMLNode &before = tpl->get_state();
4810 tpl->set_hidden (false, this);
4811 tpl->set (start, end);
4812 XMLNode &after = tpl->get_state();
4813 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4816 commit_reversible_command ();
4819 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4820 * @param rs List to which found regions are added.
4821 * @param where Time to look at.
4822 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4825 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4827 const TrackViewList* tracks;
4830 tracks = &track_views;
4835 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4837 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4840 boost::shared_ptr<Track> tr;
4841 boost::shared_ptr<Playlist> pl;
4843 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4845 boost::shared_ptr<RegionList> regions = pl->regions_at (
4846 (framepos_t) floor ( (double) where * tr->speed()));
4848 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4849 RegionView* rv = rtv->view()->find_view (*i);
4860 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4862 const TrackViewList* tracks;
4865 tracks = &track_views;
4870 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4871 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4873 boost::shared_ptr<Track> tr;
4874 boost::shared_ptr<Playlist> pl;
4876 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4878 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4879 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4881 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4883 RegionView* rv = rtv->view()->find_view (*i);
4894 /** Get regions using the following method:
4896 * Make a region list using:
4897 * (a) any selected regions
4898 * (b) the intersection of any selected tracks and the edit point(*)
4899 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4901 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4903 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4907 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4909 RegionSelection regions;
4911 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4912 regions.add (entered_regionview);
4914 regions = selection->regions;
4917 if ( regions.empty() ) {
4918 TrackViewList tracks = selection->tracks;
4920 if (!tracks.empty()) {
4921 /* no region selected or entered, but some selected tracks:
4922 * act on all regions on the selected tracks at the edit point
4924 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4925 get_regions_at(regions, where, tracks);
4932 /** Get regions using the following method:
4934 * Make a region list using:
4935 * (a) any selected regions
4936 * (b) the intersection of any selected tracks and the edit point(*)
4937 * (c) if neither exists, then whatever region is under the mouse
4939 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4941 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4944 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4946 RegionSelection regions;
4948 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4949 regions.add (entered_regionview);
4951 regions = selection->regions;
4954 if ( regions.empty() ) {
4955 TrackViewList tracks = selection->tracks;
4957 if (!tracks.empty()) {
4958 /* no region selected or entered, but some selected tracks:
4959 * act on all regions on the selected tracks at the edit point
4961 get_regions_at(regions, pos, tracks);
4968 /** Start with regions that are selected, or the entered regionview if none are selected.
4969 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4970 * of the regions that we started with.
4974 Editor::get_regions_from_selection_and_entered () const
4976 RegionSelection regions = selection->regions;
4978 if (regions.empty() && entered_regionview) {
4979 regions.add (entered_regionview);
4986 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4988 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4989 RouteTimeAxisView* rtav;
4991 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4992 boost::shared_ptr<Playlist> pl;
4993 std::vector<boost::shared_ptr<Region> > results;
4994 boost::shared_ptr<Track> tr;
4996 if ((tr = rtav->track()) == 0) {
5001 if ((pl = (tr->playlist())) != 0) {
5002 boost::shared_ptr<Region> r = pl->region_by_id (id);
5004 RegionView* rv = rtav->view()->find_view (r);
5006 regions.push_back (rv);
5015 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5018 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5019 MidiTimeAxisView* mtav;
5021 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5023 mtav->get_per_region_note_selection (selection);
5030 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5032 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5034 RouteTimeAxisView* tatv;
5036 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5038 boost::shared_ptr<Playlist> pl;
5039 vector<boost::shared_ptr<Region> > results;
5041 boost::shared_ptr<Track> tr;
5043 if ((tr = tatv->track()) == 0) {
5048 if ((pl = (tr->playlist())) != 0) {
5049 if (src_comparison) {
5050 pl->get_source_equivalent_regions (region, results);
5052 pl->get_region_list_equivalent_regions (region, results);
5056 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5057 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5058 regions.push_back (marv);
5067 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5069 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5070 RouteTimeAxisView* tatv;
5071 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5072 if (!tatv->track()) {
5075 RegionView* marv = tatv->view()->find_view (region);
5085 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5087 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5088 RouteTimeAxisView* rtav;
5089 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5090 if (rtav->route() == route) {
5099 Editor::show_rhythm_ferret ()
5101 if (rhythm_ferret == 0) {
5102 rhythm_ferret = new RhythmFerret(*this);
5105 rhythm_ferret->set_session (_session);
5106 rhythm_ferret->show ();
5107 rhythm_ferret->present ();
5111 Editor::first_idle ()
5113 MessageDialog* dialog = 0;
5115 if (track_views.size() > 1) {
5116 Timers::TimerSuspender t;
5117 dialog = new MessageDialog (
5118 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5122 ARDOUR_UI::instance()->flush_pending (60);
5125 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5129 /* now that all regionviews should exist, setup region selection */
5133 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5134 /* this is cumulative: rs is NOT cleared each time */
5135 get_regionviews_by_id (*pr, rs);
5138 selection->set (rs);
5140 // first idle adds route children (automation tracks), so we need to redisplay here
5141 _routes->redisplay ();
5145 if (_session->undo_depth() == 0) {
5146 undo_action->set_sensitive(false);
5148 redo_action->set_sensitive(false);
5149 begin_selection_op_history ();
5155 Editor::_idle_resize (gpointer arg)
5157 return ((Editor*)arg)->idle_resize ();
5161 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5163 if (resize_idle_id < 0) {
5164 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5165 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5166 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5168 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5169 _pending_resize_amount = 0;
5172 /* make a note of the smallest resulting height, so that we can clamp the
5173 lower limit at TimeAxisView::hSmall */
5175 int32_t min_resulting = INT32_MAX;
5177 _pending_resize_amount += h;
5178 _pending_resize_view = view;
5180 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5182 if (selection->tracks.contains (_pending_resize_view)) {
5183 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5184 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5188 if (min_resulting < 0) {
5193 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5194 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5198 /** Handle pending resizing of tracks */
5200 Editor::idle_resize ()
5202 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5204 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5205 selection->tracks.contains (_pending_resize_view)) {
5207 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5208 if (*i != _pending_resize_view) {
5209 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5214 _pending_resize_amount = 0;
5215 _group_tabs->set_dirty ();
5216 resize_idle_id = -1;
5224 ENSURE_GUI_THREAD (*this, &Editor::located);
5227 playhead_cursor->set_position (_session->audible_frame ());
5228 if (_follow_playhead && !_pending_initial_locate) {
5229 reset_x_origin_to_follow_playhead ();
5233 _pending_locate_request = false;
5234 _pending_initial_locate = false;
5235 _last_update_time = 0;
5239 Editor::region_view_added (RegionView * rv)
5241 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5243 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5244 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5245 if (rv->region()->id () == (*rnote).first) {
5246 mrv->select_notes ((*rnote).second);
5247 selection->pending_midi_note_selection.erase(rnote);
5253 _summary->set_background_dirty ();
5257 Editor::region_view_removed ()
5259 _summary->set_background_dirty ();
5263 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5265 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5266 if ((*j)->stripable() == s) {
5275 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5277 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5278 if ((*j)->control() == c) {
5282 TimeAxisView::Children kids = (*j)->get_child_list ();
5284 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5285 if ((*k)->control() == c) {
5295 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5299 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5300 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5310 Editor::suspend_route_redisplay ()
5313 _routes->suspend_redisplay();
5318 Editor::resume_route_redisplay ()
5321 _routes->redisplay(); // queue redisplay
5322 _routes->resume_redisplay();
5327 Editor::add_vcas (VCAList& vlist)
5331 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5332 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5335 add_stripables (sl);
5339 Editor::add_routes (RouteList& rlist)
5343 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5347 add_stripables (sl);
5351 Editor::add_stripables (StripableList& sl)
5353 list<TimeAxisView*> new_views;
5354 boost::shared_ptr<VCA> v;
5355 boost::shared_ptr<Route> r;
5356 TrackViewList new_selection;
5357 bool from_scratch = (track_views.size() == 0);
5359 sl.sort (Stripable::Sorter());
5361 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5363 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5365 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5367 new_views.push_back (vtv);
5369 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5371 if (r->is_auditioner() || r->is_monitor()) {
5375 RouteTimeAxisView* rtv;
5376 DataType dt = r->input()->default_type();
5378 if (dt == ARDOUR::DataType::AUDIO) {
5379 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5381 } else if (dt == ARDOUR::DataType::MIDI) {
5382 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5385 throw unknown_type();
5388 new_views.push_back (rtv);
5389 track_views.push_back (rtv);
5390 new_selection.push_back (rtv);
5392 rtv->effective_gain_display ();
5394 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5395 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5399 if (new_views.size() > 0) {
5400 _routes->time_axis_views_added (new_views);
5401 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5404 /* note: !new_selection.empty() means that we got some routes rather
5408 if (!from_scratch && !new_selection.empty()) {
5409 selection->set (new_selection);
5410 begin_selection_op_history();
5413 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5414 show_editor_mixer (true);
5417 editor_list_button.set_sensitive (true);
5421 Editor::timeaxisview_deleted (TimeAxisView *tv)
5423 if (tv == entered_track) {
5427 if (_session && _session->deletion_in_progress()) {
5428 /* the situation is under control */
5432 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5434 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5436 _routes->route_removed (tv);
5438 TimeAxisView::Children c = tv->get_child_list ();
5439 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5440 if (entered_track == i->get()) {
5445 /* remove it from the list of track views */
5447 TrackViewList::iterator i;
5449 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5450 i = track_views.erase (i);
5453 /* update whatever the current mixer strip is displaying, if revelant */
5455 boost::shared_ptr<Route> route;
5458 route = rtav->route ();
5461 if (current_mixer_strip && current_mixer_strip->route() == route) {
5463 TimeAxisView* next_tv;
5465 if (track_views.empty()) {
5467 } else if (i == track_views.end()) {
5468 next_tv = track_views.front();
5473 // skip VCAs (cannot be selected, n/a in editor-mixer)
5474 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5475 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5476 next_tv = track_views.front();
5478 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5479 /* just in case: no master, only a VCA remains */
5485 set_selected_mixer_strip (*next_tv);
5487 /* make the editor mixer strip go away setting the
5488 * button to inactive (which also unticks the menu option)
5491 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5497 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5502 if (apply_to_selection) {
5503 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5505 TrackSelection::iterator j = i;
5508 hide_track_in_display (*i, false);
5513 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5515 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5516 // this will hide the mixer strip
5517 set_selected_mixer_strip (*tv);
5520 _routes->hide_track_in_display (*tv);
5525 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5530 _routes->show_track_in_display (*tv);
5531 if (move_into_view) {
5532 ensure_time_axis_view_is_visible (*tv, false);
5537 Editor::sync_track_view_list_and_routes ()
5539 track_views = TrackViewList (_routes->views ());
5541 _summary->set_background_dirty();
5542 _group_tabs->set_dirty ();
5544 return false; // do not call again (until needed)
5548 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5550 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5555 /** Find a RouteTimeAxisView by the ID of its route */
5557 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5559 RouteTimeAxisView* v;
5561 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5562 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5563 if(v->route()->id() == id) {
5573 Editor::fit_route_group (RouteGroup *g)
5575 TrackViewList ts = axis_views_from_routes (g->route_list ());
5580 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5582 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5585 _session->cancel_audition ();
5589 if (_session->is_auditioning()) {
5590 _session->cancel_audition ();
5591 if (r == last_audition_region) {
5596 _session->audition_region (r);
5597 last_audition_region = r;
5602 Editor::hide_a_region (boost::shared_ptr<Region> r)
5604 r->set_hidden (true);
5608 Editor::show_a_region (boost::shared_ptr<Region> r)
5610 r->set_hidden (false);
5614 Editor::audition_region_from_region_list ()
5616 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5620 Editor::hide_region_from_region_list ()
5622 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5626 Editor::show_region_in_region_list ()
5628 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5632 Editor::step_edit_status_change (bool yn)
5635 start_step_editing ();
5637 stop_step_editing ();
5642 Editor::start_step_editing ()
5644 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5648 Editor::stop_step_editing ()
5650 step_edit_connection.disconnect ();
5654 Editor::check_step_edit ()
5656 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5657 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5659 mtv->check_step_edit ();
5663 return true; // do it again, till we stop
5667 Editor::scroll_press (Direction dir)
5669 ++_scroll_callbacks;
5671 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5672 /* delay the first auto-repeat */
5678 scroll_backward (1);
5686 scroll_up_one_track ();
5690 scroll_down_one_track ();
5694 /* do hacky auto-repeat */
5695 if (!_scroll_connection.connected ()) {
5697 _scroll_connection = Glib::signal_timeout().connect (
5698 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5701 _scroll_callbacks = 0;
5708 Editor::scroll_release ()
5710 _scroll_connection.disconnect ();
5713 /** Queue a change for the Editor viewport x origin to follow the playhead */
5715 Editor::reset_x_origin_to_follow_playhead ()
5717 framepos_t const frame = playhead_cursor->current_frame ();
5719 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5721 if (_session->transport_speed() < 0) {
5723 if (frame > (current_page_samples() / 2)) {
5724 center_screen (frame-(current_page_samples()/2));
5726 center_screen (current_page_samples()/2);
5733 if (frame < leftmost_frame) {
5735 if (_session->transport_rolling()) {
5736 /* rolling; end up with the playhead at the right of the page */
5737 l = frame - current_page_samples ();
5739 /* not rolling: end up with the playhead 1/4 of the way along the page */
5740 l = frame - current_page_samples() / 4;
5744 if (_session->transport_rolling()) {
5745 /* rolling: end up with the playhead on the left of the page */
5748 /* not rolling: end up with the playhead 3/4 of the way along the page */
5749 l = frame - 3 * current_page_samples() / 4;
5757 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5763 Editor::super_rapid_screen_update ()
5765 if (!_session || !_session->engine().running()) {
5769 /* METERING / MIXER STRIPS */
5771 /* update track meters, if required */
5772 if (contents().is_mapped() && meters_running) {
5773 RouteTimeAxisView* rtv;
5774 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5775 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5776 rtv->fast_update ();
5781 /* and any current mixer strip */
5782 if (current_mixer_strip) {
5783 current_mixer_strip->fast_update ();
5786 /* PLAYHEAD AND VIEWPORT */
5788 /* There are a few reasons why we might not update the playhead / viewport stuff:
5790 * 1. we don't update things when there's a pending locate request, otherwise
5791 * when the editor requests a locate there is a chance that this method
5792 * will move the playhead before the locate request is processed, causing
5794 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5795 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5797 if (_pending_locate_request || !_session->transport_rolling ()) {
5798 _last_update_time = 0;
5802 if (_dragging_playhead) {
5803 _last_update_time = 0;
5807 bool latent_locate = false;
5808 framepos_t frame = _session->audible_frame (&latent_locate);
5809 const int64_t now = g_get_monotonic_time ();
5812 if (_session->exporting ()) {
5813 /* freewheel/export may be faster or slower than transport_speed() / SR.
5814 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5816 _last_update_time = 0;
5819 if (_last_update_time > 0) {
5820 /* interpolate and smoothen playhead position */
5821 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6;
5822 framepos_t guess = playhead_cursor->current_frame () + rint (ds);
5823 err = frame - guess;
5825 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5826 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5829 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5831 err, _err_screen_engine);
5836 _err_screen_engine = 0;
5839 if (err > 8192 || latent_locate) {
5840 // in case of x-runs or freewheeling
5841 _last_update_time = 0;
5842 frame = _session->audible_frame ();
5844 _last_update_time = now;
5847 if (playhead_cursor->current_frame () == frame) {
5851 playhead_cursor->set_position (frame);
5853 if (_session->requested_return_frame() >= 0) {
5854 _last_update_time = 0;
5858 if (!_follow_playhead || pending_visual_change.being_handled) {
5859 /* We only do this if we aren't already
5860 * handling a visual change (ie if
5861 * pending_visual_change.being_handled is
5862 * false) so that these requests don't stack
5863 * up there are too many of them to handle in
5869 if (!_stationary_playhead) {
5870 reset_x_origin_to_follow_playhead ();
5872 framepos_t const frame = playhead_cursor->current_frame ();
5873 double target = ((double)frame - (double)current_page_samples() / 2.0);
5874 if (target <= 0.0) {
5877 // compare to EditorCursor::set_position()
5878 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5879 double const new_pos = sample_to_pixel_unrounded (target);
5880 if (rint (new_pos) != rint (old_pos)) {
5881 reset_x_origin (pixel_to_sample (new_pos));
5888 Editor::session_going_away ()
5890 _have_idled = false;
5892 _session_connections.drop_connections ();
5894 super_rapid_screen_update_connection.disconnect ();
5896 selection->clear ();
5897 cut_buffer->clear ();
5899 clicked_regionview = 0;
5900 clicked_axisview = 0;
5901 clicked_routeview = 0;
5902 entered_regionview = 0;
5904 _last_update_time = 0;
5907 playhead_cursor->hide ();
5909 /* rip everything out of the list displays */
5913 _route_groups->clear ();
5915 /* do this first so that deleting a track doesn't reset cms to null
5916 and thus cause a leak.
5919 if (current_mixer_strip) {
5920 if (current_mixer_strip->get_parent() != 0) {
5921 global_hpacker.remove (*current_mixer_strip);
5923 delete current_mixer_strip;
5924 current_mixer_strip = 0;
5927 /* delete all trackviews */
5929 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5932 track_views.clear ();
5934 nudge_clock->set_session (0);
5936 editor_list_button.set_active(false);
5937 editor_list_button.set_sensitive(false);
5939 /* clear tempo/meter rulers */
5940 remove_metric_marks ();
5942 clear_marker_display ();
5947 stop_step_editing ();
5951 /* get rid of any existing editor mixer strip */
5953 WindowTitle title(Glib::get_application_name());
5954 title += _("Editor");
5956 own_window()->set_title (title.get_string());
5959 SessionHandlePtr::session_going_away ();
5963 Editor::trigger_script (int i)
5965 LuaInstance::instance()-> call_action (i);
5969 Editor::show_editor_list (bool yn)
5972 _editor_list_vbox.show ();
5974 _editor_list_vbox.hide ();
5979 Editor::change_region_layering_order (bool from_context_menu)
5981 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5983 if (!clicked_routeview) {
5984 if (layering_order_editor) {
5985 layering_order_editor->hide ();
5990 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5996 boost::shared_ptr<Playlist> pl = track->playlist();
6002 if (layering_order_editor == 0) {
6003 layering_order_editor = new RegionLayeringOrderEditor (*this);
6006 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6007 layering_order_editor->maybe_present ();
6011 Editor::update_region_layering_order_editor ()
6013 if (layering_order_editor && layering_order_editor->is_visible ()) {
6014 change_region_layering_order (true);
6019 Editor::setup_fade_images ()
6021 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6022 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6023 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6024 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6025 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6027 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6028 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6029 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6030 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6031 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6035 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6037 Editor::action_menu_item (std::string const & name)
6039 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6042 return *manage (a->create_menu_item ());
6046 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6048 EventBox* b = manage (new EventBox);
6049 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6050 Label* l = manage (new Label (name));
6054 _the_notebook.append_page (widget, *b);
6058 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6060 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6061 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6064 if (ev->type == GDK_2BUTTON_PRESS) {
6066 /* double-click on a notebook tab shrinks or expands the notebook */
6068 if (_notebook_shrunk) {
6069 if (pre_notebook_shrink_pane_width) {
6070 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6072 _notebook_shrunk = false;
6074 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6076 /* this expands the LHS of the edit pane to cover the notebook
6077 PAGE but leaves the tabs visible.
6079 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6080 _notebook_shrunk = true;
6088 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6090 using namespace Menu_Helpers;
6092 MenuList& items = _control_point_context_menu.items ();
6095 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6096 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6097 if (!can_remove_control_point (item)) {
6098 items.back().set_sensitive (false);
6101 _control_point_context_menu.popup (event->button.button, event->button.time);
6105 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6107 using namespace Menu_Helpers;
6109 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6114 /* We need to get the selection here and pass it to the operations, since
6115 popping up the menu will cause a region leave event which clears
6116 entered_regionview. */
6118 MidiRegionView& mrv = note->region_view();
6119 const RegionSelection rs = get_regions_from_selection_and_entered ();
6120 const uint32_t sel_size = mrv.selection_size ();
6122 MenuList& items = _note_context_menu.items();
6126 items.push_back(MenuElem(_("Delete"),
6127 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6130 items.push_back(MenuElem(_("Edit..."),
6131 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6132 if (sel_size != 1) {
6133 items.back().set_sensitive (false);
6136 items.push_back(MenuElem(_("Transpose..."),
6137 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6140 items.push_back(MenuElem(_("Legatize"),
6141 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6143 items.back().set_sensitive (false);
6146 items.push_back(MenuElem(_("Quantize..."),
6147 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6149 items.push_back(MenuElem(_("Remove Overlap"),
6150 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6152 items.back().set_sensitive (false);
6155 items.push_back(MenuElem(_("Transform..."),
6156 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6158 _note_context_menu.popup (event->button.button, event->button.time);
6162 Editor::zoom_vertical_modifier_released()
6164 _stepping_axis_view = 0;
6168 Editor::ui_parameter_changed (string parameter)
6170 if (parameter == "icon-set") {
6171 while (!_cursor_stack.empty()) {
6172 _cursor_stack.pop_back();
6174 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6175 _cursor_stack.push_back(_cursors->grabber);
6176 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6177 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6179 } else if (parameter == "draggable-playhead") {
6180 if (_verbose_cursor) {
6181 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6187 Editor::use_own_window (bool and_fill_it)
6189 bool new_window = !own_window();
6191 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6193 if (win && new_window) {
6194 win->set_name ("EditorWindow");
6196 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6198 // win->signal_realize().connect (*this, &Editor::on_realize);
6199 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6200 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6201 win->set_data ("ardour-bindings", bindings);
6206 DisplaySuspender ds;
6207 contents().show_all ();
6209 /* XXX: this is a bit unfortunate; it would probably
6210 be nicer if we could just call show () above rather
6211 than needing the show_all ()
6214 /* re-hide stuff if necessary */
6215 editor_list_button_toggled ();
6216 parameter_changed ("show-summary");
6217 parameter_changed ("show-group-tabs");
6218 parameter_changed ("show-zoom-tools");
6220 /* now reset all audio_time_axis heights, because widgets might need
6226 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6227 tv = (static_cast<TimeAxisView*>(*i));
6228 tv->reset_height ();
6231 if (current_mixer_strip) {
6232 current_mixer_strip->hide_things ();
6233 current_mixer_strip->parameter_changed ("mixer-element-visibility");