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 (const std::string& action_group, const 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::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1154 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1158 Editor::on_realize ()
1162 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1163 start_lock_event_timing ();
1168 Editor::start_lock_event_timing ()
1170 /* check if we should lock the GUI every 30 seconds */
1172 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1176 Editor::generic_event_handler (GdkEvent* ev)
1179 case GDK_BUTTON_PRESS:
1180 case GDK_BUTTON_RELEASE:
1181 case GDK_MOTION_NOTIFY:
1183 case GDK_KEY_RELEASE:
1184 if (contents().is_mapped()) {
1185 gettimeofday (&last_event_time, 0);
1189 case GDK_LEAVE_NOTIFY:
1190 switch (ev->crossing.detail) {
1191 case GDK_NOTIFY_UNKNOWN:
1192 case GDK_NOTIFY_INFERIOR:
1193 case GDK_NOTIFY_ANCESTOR:
1195 case GDK_NOTIFY_VIRTUAL:
1196 case GDK_NOTIFY_NONLINEAR:
1197 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1198 /* leaving window, so reset focus, thus ending any and
1199 all text entry operations.
1201 ARDOUR_UI::instance()->reset_focus (&contents());
1214 Editor::lock_timeout_callback ()
1216 struct timeval now, delta;
1218 gettimeofday (&now, 0);
1220 timersub (&now, &last_event_time, &delta);
1222 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1224 /* don't call again. Returning false will effectively
1225 disconnect us from the timer callback.
1227 unlock() will call start_lock_event_timing() to get things
1237 Editor::map_position_change (framepos_t frame)
1239 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1241 if (_session == 0) {
1245 if (_follow_playhead) {
1246 center_screen (frame);
1249 playhead_cursor->set_position (frame);
1253 Editor::center_screen (framepos_t frame)
1255 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1257 /* if we're off the page, then scroll.
1260 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1261 center_screen_internal (frame, page);
1266 Editor::center_screen_internal (framepos_t frame, float page)
1271 frame -= (framepos_t) page;
1276 reset_x_origin (frame);
1281 Editor::update_title ()
1283 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1285 if (!own_window()) {
1290 bool dirty = _session->dirty();
1292 string session_name;
1294 if (_session->snap_name() != _session->name()) {
1295 session_name = _session->snap_name();
1297 session_name = _session->name();
1301 session_name = "*" + session_name;
1304 WindowTitle title(session_name);
1305 title += S_("Window|Editor");
1306 title += Glib::get_application_name();
1307 own_window()->set_title (title.get_string());
1309 /* ::session_going_away() will have taken care of it */
1314 Editor::set_session (Session *t)
1316 SessionHandlePtr::set_session (t);
1322 _playlist_selector->set_session (_session);
1323 nudge_clock->set_session (_session);
1324 _summary->set_session (_session);
1325 _group_tabs->set_session (_session);
1326 _route_groups->set_session (_session);
1327 _regions->set_session (_session);
1328 _snapshots->set_session (_session);
1329 _routes->set_session (_session);
1330 _locations->set_session (_session);
1331 _time_info_box->set_session (_session);
1333 if (rhythm_ferret) {
1334 rhythm_ferret->set_session (_session);
1337 if (analysis_window) {
1338 analysis_window->set_session (_session);
1342 sfbrowser->set_session (_session);
1345 compute_fixed_ruler_scale ();
1347 /* Make sure we have auto loop and auto punch ranges */
1349 Location* loc = _session->locations()->auto_loop_location();
1351 loc->set_name (_("Loop"));
1354 loc = _session->locations()->auto_punch_location();
1357 loc->set_name (_("Punch"));
1360 refresh_location_display ();
1362 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1363 the selected Marker; this needs the LocationMarker list to be available.
1365 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1366 set_state (*node, Stateful::loading_state_version);
1368 /* catch up on selection state, etc. */
1371 sc.add (Properties::selected);
1372 presentation_info_changed (sc);
1374 /* catch up with the playhead */
1376 _session->request_locate (playhead_cursor->current_frame ());
1377 _pending_initial_locate = true;
1381 /* These signals can all be emitted by a non-GUI thread. Therefore the
1382 handlers for them must not attempt to directly interact with the GUI,
1383 but use PBD::Signal<T>::connect() which accepts an event loop
1384 ("context") where the handler will be asked to run.
1387 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1388 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1389 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1390 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1391 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1392 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1393 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1394 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1395 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1396 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1397 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1398 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1399 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1400 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1401 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1402 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1404 playhead_cursor->show ();
1406 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1407 Config->map_parameters (pc);
1408 _session->config.map_parameters (pc);
1410 restore_ruler_visibility ();
1411 //tempo_map_changed (PropertyChange (0));
1412 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1414 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1415 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1418 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1419 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1422 switch (_snap_type) {
1423 case SnapToRegionStart:
1424 case SnapToRegionEnd:
1425 case SnapToRegionSync:
1426 case SnapToRegionBoundary:
1427 build_region_boundary_cache ();
1434 /* register for undo history */
1435 _session->register_with_memento_command_factory(id(), this);
1436 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1438 LuaInstance::instance()->set_session(_session);
1440 start_updating_meters ();
1444 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1446 using namespace Menu_Helpers;
1448 void (Editor::*emf)(FadeShape);
1449 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1452 images = &_xfade_in_images;
1453 emf = &Editor::set_fade_in_shape;
1455 images = &_xfade_out_images;
1456 emf = &Editor::set_fade_out_shape;
1461 _("Linear (for highly correlated material)"),
1462 *(*images)[FadeLinear],
1463 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1467 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1471 _("Constant power"),
1472 *(*images)[FadeConstantPower],
1473 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1476 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1481 *(*images)[FadeSymmetric],
1482 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 *(*images)[FadeSlow],
1492 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1495 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1500 *(*images)[FadeFast],
1501 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1504 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1507 /** Pop up a context menu for when the user clicks on a start crossfade */
1509 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1511 using namespace Menu_Helpers;
1512 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1517 MenuList& items (xfade_in_context_menu.items());
1520 if (arv->audio_region()->fade_in_active()) {
1521 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1523 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1526 items.push_back (SeparatorElem());
1527 fill_xfade_menu (items, true);
1529 xfade_in_context_menu.popup (button, time);
1532 /** Pop up a context menu for when the user clicks on an end crossfade */
1534 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1536 using namespace Menu_Helpers;
1537 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1542 MenuList& items (xfade_out_context_menu.items());
1545 if (arv->audio_region()->fade_out_active()) {
1546 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1548 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1551 items.push_back (SeparatorElem());
1552 fill_xfade_menu (items, false);
1554 xfade_out_context_menu.popup (button, time);
1558 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1560 using namespace Menu_Helpers;
1561 Menu* (Editor::*build_menu_function)();
1564 switch (item_type) {
1566 case RegionViewName:
1567 case RegionViewNameHighlight:
1568 case LeftFrameHandle:
1569 case RightFrameHandle:
1570 if (with_selection) {
1571 build_menu_function = &Editor::build_track_selection_context_menu;
1573 build_menu_function = &Editor::build_track_region_context_menu;
1578 if (with_selection) {
1579 build_menu_function = &Editor::build_track_selection_context_menu;
1581 build_menu_function = &Editor::build_track_context_menu;
1586 if (clicked_routeview->track()) {
1587 build_menu_function = &Editor::build_track_context_menu;
1589 build_menu_function = &Editor::build_track_bus_context_menu;
1594 /* probably shouldn't happen but if it does, we don't care */
1598 menu = (this->*build_menu_function)();
1599 menu->set_name ("ArdourContextMenu");
1601 /* now handle specific situations */
1603 switch (item_type) {
1605 case RegionViewName:
1606 case RegionViewNameHighlight:
1607 case LeftFrameHandle:
1608 case RightFrameHandle:
1609 if (!with_selection) {
1610 if (region_edit_menu_split_item) {
1611 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1612 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1614 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1617 if (region_edit_menu_split_multichannel_item) {
1618 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1619 region_edit_menu_split_multichannel_item->set_sensitive (true);
1621 region_edit_menu_split_multichannel_item->set_sensitive (false);
1634 /* probably shouldn't happen but if it does, we don't care */
1638 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1640 /* Bounce to disk */
1642 using namespace Menu_Helpers;
1643 MenuList& edit_items = menu->items();
1645 edit_items.push_back (SeparatorElem());
1647 switch (clicked_routeview->audio_track()->freeze_state()) {
1648 case AudioTrack::NoFreeze:
1649 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1652 case AudioTrack::Frozen:
1653 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1656 case AudioTrack::UnFrozen:
1657 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1663 if (item_type == StreamItem && clicked_routeview) {
1664 clicked_routeview->build_underlay_menu(menu);
1667 /* When the region menu is opened, we setup the actions so that they look right
1670 sensitize_the_right_region_actions (false);
1671 _last_region_menu_was_main = false;
1673 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1674 menu->popup (button, time);
1678 Editor::build_track_context_menu ()
1680 using namespace Menu_Helpers;
1682 MenuList& edit_items = track_context_menu.items();
1685 add_dstream_context_items (edit_items);
1686 return &track_context_menu;
1690 Editor::build_track_bus_context_menu ()
1692 using namespace Menu_Helpers;
1694 MenuList& edit_items = track_context_menu.items();
1697 add_bus_context_items (edit_items);
1698 return &track_context_menu;
1702 Editor::build_track_region_context_menu ()
1704 using namespace Menu_Helpers;
1705 MenuList& edit_items = track_region_context_menu.items();
1708 /* we've just cleared the track region context menu, so the menu that these
1709 two items were on will have disappeared; stop them dangling.
1711 region_edit_menu_split_item = 0;
1712 region_edit_menu_split_multichannel_item = 0;
1714 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1717 boost::shared_ptr<Track> tr;
1718 boost::shared_ptr<Playlist> pl;
1720 if ((tr = rtv->track())) {
1721 add_region_context_items (edit_items, tr);
1725 add_dstream_context_items (edit_items);
1727 return &track_region_context_menu;
1731 Editor::loudness_analyze_region_selection ()
1736 Selection& s (PublicEditor::instance ().get_selection ());
1737 RegionSelection ars = s.regions;
1738 ARDOUR::AnalysisGraph ag (_session);
1739 framecnt_t total_work = 0;
1741 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1742 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1746 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1749 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1750 total_work += arv->region ()->length ();
1753 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1755 ag.set_total_frames (total_work);
1756 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1759 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1760 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1764 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1768 ag.analyze_region (ar);
1771 if (!ag.canceled ()) {
1772 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1778 Editor::loudness_analyze_range_selection ()
1783 Selection& s (PublicEditor::instance ().get_selection ());
1784 TimeSelection ts = s.time;
1785 ARDOUR::AnalysisGraph ag (_session);
1786 framecnt_t total_work = 0;
1788 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1789 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1793 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1797 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1798 total_work += j->length ();
1802 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1804 ag.set_total_frames (total_work);
1805 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1808 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1809 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1813 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1817 ag.analyze_range (rui->route (), pl, ts);
1820 if (!ag.canceled ()) {
1821 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1827 Editor::spectral_analyze_region_selection ()
1829 if (analysis_window == 0) {
1830 analysis_window = new AnalysisWindow();
1833 analysis_window->set_session(_session);
1835 analysis_window->show_all();
1838 analysis_window->set_regionmode();
1839 analysis_window->analyze();
1841 analysis_window->present();
1845 Editor::spectral_analyze_range_selection()
1847 if (analysis_window == 0) {
1848 analysis_window = new AnalysisWindow();
1851 analysis_window->set_session(_session);
1853 analysis_window->show_all();
1856 analysis_window->set_rangemode();
1857 analysis_window->analyze();
1859 analysis_window->present();
1863 Editor::build_track_selection_context_menu ()
1865 using namespace Menu_Helpers;
1866 MenuList& edit_items = track_selection_context_menu.items();
1867 edit_items.clear ();
1869 add_selection_context_items (edit_items);
1870 // edit_items.push_back (SeparatorElem());
1871 // add_dstream_context_items (edit_items);
1873 return &track_selection_context_menu;
1877 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1879 using namespace Menu_Helpers;
1881 /* OK, stick the region submenu at the top of the list, and then add
1885 RegionSelection rs = get_regions_from_selection_and_entered ();
1887 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1889 if (_popup_region_menu_item == 0) {
1890 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1891 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1892 _popup_region_menu_item->show ();
1894 _popup_region_menu_item->set_label (menu_item_name);
1897 /* No layering allowed in later is higher layering model */
1898 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1899 if (act && Config->get_layer_model() == LaterHigher) {
1900 act->set_sensitive (false);
1902 act->set_sensitive (true);
1905 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1907 edit_items.push_back (*_popup_region_menu_item);
1908 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1909 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1911 edit_items.push_back (SeparatorElem());
1914 /** Add context menu items relevant to selection ranges.
1915 * @param edit_items List to add the items to.
1918 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1920 using namespace Menu_Helpers;
1922 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1923 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1925 edit_items.push_back (SeparatorElem());
1926 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1928 edit_items.push_back (SeparatorElem());
1929 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1930 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1932 edit_items.push_back (SeparatorElem());
1934 edit_items.push_back (
1936 _("Move Range Start to Previous Region Boundary"),
1937 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1941 edit_items.push_back (
1943 _("Move Range Start to Next Region Boundary"),
1944 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1948 edit_items.push_back (
1950 _("Move Range End to Previous Region Boundary"),
1951 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1955 edit_items.push_back (
1957 _("Move Range End to Next Region Boundary"),
1958 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1962 edit_items.push_back (SeparatorElem());
1963 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1964 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1966 edit_items.push_back (SeparatorElem());
1967 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1969 edit_items.push_back (SeparatorElem());
1970 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1971 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1972 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1974 edit_items.push_back (SeparatorElem());
1975 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1977 edit_items.push_back (SeparatorElem());
1978 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1979 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1981 edit_items.push_back (SeparatorElem());
1982 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1983 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1984 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1985 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1986 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1987 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1988 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1994 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1996 using namespace Menu_Helpers;
2000 Menu *play_menu = manage (new Menu);
2001 MenuList& play_items = play_menu->items();
2002 play_menu->set_name ("ArdourContextMenu");
2004 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2005 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2006 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2007 play_items.push_back (SeparatorElem());
2008 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2010 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2014 Menu *select_menu = manage (new Menu);
2015 MenuList& select_items = select_menu->items();
2016 select_menu->set_name ("ArdourContextMenu");
2018 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2019 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2020 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2021 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2022 select_items.push_back (SeparatorElem());
2023 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2024 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2025 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2026 select_items.push_back (SeparatorElem());
2027 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2028 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2029 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2030 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2031 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2032 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2033 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2035 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2039 Menu *cutnpaste_menu = manage (new Menu);
2040 MenuList& cutnpaste_items = cutnpaste_menu->items();
2041 cutnpaste_menu->set_name ("ArdourContextMenu");
2043 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2044 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2045 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2047 cutnpaste_items.push_back (SeparatorElem());
2049 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2050 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2052 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2054 /* Adding new material */
2056 edit_items.push_back (SeparatorElem());
2057 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2058 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2062 Menu *nudge_menu = manage (new Menu());
2063 MenuList& nudge_items = nudge_menu->items();
2064 nudge_menu->set_name ("ArdourContextMenu");
2066 edit_items.push_back (SeparatorElem());
2067 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2068 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2069 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2070 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2072 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2076 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2078 using namespace Menu_Helpers;
2082 Menu *play_menu = manage (new Menu);
2083 MenuList& play_items = play_menu->items();
2084 play_menu->set_name ("ArdourContextMenu");
2086 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2087 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2088 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2092 Menu *select_menu = manage (new Menu);
2093 MenuList& select_items = select_menu->items();
2094 select_menu->set_name ("ArdourContextMenu");
2096 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2097 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2098 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2099 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2100 select_items.push_back (SeparatorElem());
2101 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2102 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2103 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2104 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2106 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2110 Menu *cutnpaste_menu = manage (new Menu);
2111 MenuList& cutnpaste_items = cutnpaste_menu->items();
2112 cutnpaste_menu->set_name ("ArdourContextMenu");
2114 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2115 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2116 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2118 Menu *nudge_menu = manage (new Menu());
2119 MenuList& nudge_items = nudge_menu->items();
2120 nudge_menu->set_name ("ArdourContextMenu");
2122 edit_items.push_back (SeparatorElem());
2123 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2124 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2125 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2126 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2128 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2132 Editor::snap_type() const
2138 Editor::snap_musical() const
2140 switch (_snap_type) {
2141 case SnapToBeatDiv128:
2142 case SnapToBeatDiv64:
2143 case SnapToBeatDiv32:
2144 case SnapToBeatDiv28:
2145 case SnapToBeatDiv24:
2146 case SnapToBeatDiv20:
2147 case SnapToBeatDiv16:
2148 case SnapToBeatDiv14:
2149 case SnapToBeatDiv12:
2150 case SnapToBeatDiv10:
2151 case SnapToBeatDiv8:
2152 case SnapToBeatDiv7:
2153 case SnapToBeatDiv6:
2154 case SnapToBeatDiv5:
2155 case SnapToBeatDiv4:
2156 case SnapToBeatDiv3:
2157 case SnapToBeatDiv2:
2169 Editor::snap_mode() const
2175 Editor::set_snap_to (SnapType st)
2177 unsigned int snap_ind = (unsigned int)st;
2179 if (internal_editing()) {
2180 internal_snap_type = st;
2182 pre_internal_snap_type = st;
2187 if (snap_ind > snap_type_strings.size() - 1) {
2189 _snap_type = (SnapType)snap_ind;
2192 string str = snap_type_strings[snap_ind];
2194 if (str != snap_type_selector.get_text()) {
2195 snap_type_selector.set_text (str);
2200 switch (_snap_type) {
2201 case SnapToBeatDiv128:
2202 case SnapToBeatDiv64:
2203 case SnapToBeatDiv32:
2204 case SnapToBeatDiv28:
2205 case SnapToBeatDiv24:
2206 case SnapToBeatDiv20:
2207 case SnapToBeatDiv16:
2208 case SnapToBeatDiv14:
2209 case SnapToBeatDiv12:
2210 case SnapToBeatDiv10:
2211 case SnapToBeatDiv8:
2212 case SnapToBeatDiv7:
2213 case SnapToBeatDiv6:
2214 case SnapToBeatDiv5:
2215 case SnapToBeatDiv4:
2216 case SnapToBeatDiv3:
2217 case SnapToBeatDiv2: {
2218 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2219 update_tempo_based_rulers ();
2223 case SnapToRegionStart:
2224 case SnapToRegionEnd:
2225 case SnapToRegionSync:
2226 case SnapToRegionBoundary:
2227 build_region_boundary_cache ();
2235 redisplay_tempo (false);
2237 SnapChanged (); /* EMIT SIGNAL */
2241 Editor::set_snap_mode (SnapMode mode)
2243 string str = snap_mode_strings[(int)mode];
2245 if (internal_editing()) {
2246 internal_snap_mode = mode;
2248 pre_internal_snap_mode = mode;
2253 if (str != snap_mode_selector.get_text ()) {
2254 snap_mode_selector.set_text (str);
2261 Editor::set_edit_point_preference (EditPoint ep, bool force)
2263 bool changed = (_edit_point != ep);
2266 if (Profile->get_mixbus())
2267 if (ep == EditAtSelectedMarker)
2268 ep = EditAtPlayhead;
2270 string str = edit_point_strings[(int)ep];
2271 if (str != edit_point_selector.get_text ()) {
2272 edit_point_selector.set_text (str);
2275 update_all_enter_cursors();
2277 if (!force && !changed) {
2281 const char* action=NULL;
2283 switch (_edit_point) {
2284 case EditAtPlayhead:
2285 action = "edit-at-playhead";
2287 case EditAtSelectedMarker:
2288 action = "edit-at-marker";
2291 action = "edit-at-mouse";
2295 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2297 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2301 bool in_track_canvas;
2303 if (!mouse_frame (foo, in_track_canvas)) {
2304 in_track_canvas = false;
2307 reset_canvas_action_sensitivity (in_track_canvas);
2308 sensitize_the_right_region_actions (false);
2314 Editor::set_state (const XMLNode& node, int version)
2317 PBD::Unwinder<bool> nsi (no_save_instant, true);
2320 Tabbable::set_state (node, version);
2323 if (_session && node.get_property ("playhead", ph_pos)) {
2325 playhead_cursor->set_position (ph_pos);
2327 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2328 playhead_cursor->set_position (0);
2331 playhead_cursor->set_position (0);
2334 node.get_property ("mixer-width", editor_mixer_strip_width);
2336 node.get_property ("zoom-focus", zoom_focus);
2337 zoom_focus_selection_done (zoom_focus);
2340 if (node.get_property ("zoom", z)) {
2341 /* older versions of ardour used floating point samples_per_pixel */
2342 reset_zoom (llrintf (z));
2344 reset_zoom (samples_per_pixel);
2348 if (node.get_property ("visible-track-count", cnt)) {
2349 set_visible_track_count (cnt);
2353 if (!node.get_property ("snap-to", snap_type)) {
2354 snap_type = _snap_type;
2356 set_snap_to (snap_type);
2359 if (node.get_property ("snap-mode", sm)) {
2360 snap_mode_selection_done(sm);
2361 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2362 * snap_mode_selection_done() will only mark an already active item as active
2363 * which does not trigger set_text().
2367 set_snap_mode (_snap_mode);
2370 node.get_property ("internal-snap-to", internal_snap_type);
2371 node.get_property ("internal-snap-mode", internal_snap_mode);
2372 node.get_property ("pre-internal-snap-to", pre_internal_snap_type);
2373 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2376 if (node.get_property ("mouse-mode", mm_str)) {
2377 MouseMode m = str2mousemode(mm_str);
2378 set_mouse_mode (m, true);
2380 set_mouse_mode (MouseObject, true);
2384 if (node.get_property ("left-frame", lf_pos)) {
2388 reset_x_origin (lf_pos);
2392 if (node.get_property ("y-origin", y_origin)) {
2393 reset_y_origin (y_origin);
2396 if (node.get_property ("join-object-range", yn)) {
2397 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2399 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2400 tact->set_active (!yn);
2401 tact->set_active (yn);
2403 set_mouse_mode(mouse_mode, true);
2407 if (node.get_property ("edit-point", ep)) {
2408 set_edit_point_preference (ep, true);
2410 set_edit_point_preference (_edit_point);
2413 node.get_property ("show-measures", _show_measures);
2415 if (node.get_property ("follow-playhead", yn)) {
2416 set_follow_playhead (yn);
2419 if (node.get_property ("stationary-playhead", yn)) {
2420 set_stationary_playhead (yn);
2423 RegionListSortType sort_type;
2424 if (node.get_property ("region-list-sort-type", sort_type)) {
2425 _regions->reset_sort_type (sort_type, true);
2428 if (node.get_property ("show-editor-mixer", yn)) {
2430 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2433 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2435 /* do it twice to force the change */
2437 tact->set_active (!yn);
2438 tact->set_active (yn);
2441 if (node.get_property ("show-editor-list", yn)) {
2443 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2446 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2448 /* do it twice to force the change */
2450 tact->set_active (!yn);
2451 tact->set_active (yn);
2455 if (node.get_property (X_("editor-list-page"), el_page)) {
2456 _the_notebook.set_current_page (el_page);
2459 if (node.get_property (X_("show-marker-lines"), yn)) {
2460 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2462 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2464 tact->set_active (!yn);
2465 tact->set_active (yn);
2468 XMLNodeList children = node.children ();
2469 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2470 selection->set_state (**i, Stateful::current_state_version);
2471 _regions->set_state (**i);
2472 _locations->set_state (**i);
2475 if (node.get_property ("maximised", yn)) {
2476 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2478 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2479 bool fs = tact && tact->get_active();
2481 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2485 framepos_t nudge_clock_value;
2486 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2487 nudge_clock->set (nudge_clock_value);
2489 nudge_clock->set_mode (AudioClock::Timecode);
2490 nudge_clock->set (_session->frame_rate() * 5, true);
2495 * Not all properties may have been in XML, but
2496 * those that are linked to a private variable may need changing
2500 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2502 yn = _show_measures;
2503 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2504 /* do it twice to force the change */
2505 tact->set_active (!yn);
2506 tact->set_active (yn);
2509 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2510 yn = _follow_playhead;
2512 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2513 if (tact->get_active() != yn) {
2514 tact->set_active (yn);
2518 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2519 yn = _stationary_playhead;
2521 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2522 if (tact->get_active() != yn) {
2523 tact->set_active (yn);
2528 return LuaInstance::instance()->set_state(node);
2532 Editor::get_state ()
2534 XMLNode* node = new XMLNode (X_("Editor"));
2536 node->set_property ("id", id().to_s ());
2538 node->add_child_nocopy (Tabbable::get_state());
2540 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2541 node->set_property("notebook-shrunk", _notebook_shrunk);
2542 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2544 maybe_add_mixer_strip_width (*node);
2546 node->set_property ("zoom-focus", zoom_focus);
2548 node->set_property ("zoom", samples_per_pixel);
2549 node->set_property ("snap-to", _snap_type);
2550 node->set_property ("snap-mode", _snap_mode);
2551 node->set_property ("internal-snap-to", internal_snap_type);
2552 node->set_property ("internal-snap-mode", internal_snap_mode);
2553 node->set_property ("pre-internal-snap-to", pre_internal_snap_type);
2554 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2555 node->set_property ("edit-point", _edit_point);
2556 node->set_property ("visible-track-count", _visible_track_count);
2558 node->set_property ("playhead", playhead_cursor->current_frame ());
2559 node->set_property ("left-frame", leftmost_frame);
2560 node->set_property ("y-origin", vertical_adjustment.get_value ());
2562 node->set_property ("show-measures", _show_measures);
2563 node->set_property ("maximised", _maximised);
2564 node->set_property ("follow-playhead", _follow_playhead);
2565 node->set_property ("stationary-playhead", _stationary_playhead);
2566 node->set_property ("region-list-sort-type", _regions->sort_type ());
2567 node->set_property ("mouse-mode", mouse_mode);
2568 node->set_property ("join-object-range", smart_mode_action->get_active ());
2570 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2572 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2573 node->set_property (X_("show-editor-mixer"), tact->get_active());
2576 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2578 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2579 node->set_property (X_("show-editor-list"), tact->get_active());
2582 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2584 if (button_bindings) {
2585 XMLNode* bb = new XMLNode (X_("Buttons"));
2586 button_bindings->save (*bb);
2587 node->add_child_nocopy (*bb);
2590 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2592 node->add_child_nocopy (selection->get_state ());
2593 node->add_child_nocopy (_regions->get_state ());
2595 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2597 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2598 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2599 node->add_child_nocopy (_locations->get_state ());
2604 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2605 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2607 * @return pair: TimeAxisView that y is over, layer index.
2609 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2610 * in stacked or expanded region display mode, otherwise 0.
2612 std::pair<TimeAxisView *, double>
2613 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2615 if (!trackview_relative_offset) {
2616 y -= _trackview_group->canvas_origin().y;
2620 return std::make_pair ( (TimeAxisView *) 0, 0);
2623 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2625 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2632 return std::make_pair ( (TimeAxisView *) 0, 0);
2635 /** Snap a position to the grid, if appropriate, taking into account current
2636 * grid settings and also the state of any snap modifier keys that may be pressed.
2637 * @param start Position to snap.
2638 * @param event Event to get current key modifier information from, or 0.
2641 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2643 if (!_session || !event) {
2647 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2648 if (_snap_mode == SnapOff) {
2649 snap_to_internal (start, direction, for_mark);
2651 start.set (start.frame, 0);
2654 if (_snap_mode != SnapOff) {
2655 snap_to_internal (start, direction, for_mark);
2656 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2657 /* SnapOff, but we pressed the snap_delta modifier */
2658 snap_to_internal (start, direction, for_mark);
2660 start.set (start.frame, 0);
2666 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2668 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2669 start.set (start.frame, 0);
2673 snap_to_internal (start, direction, for_mark, ensure_snap);
2677 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2679 framepos_t start = pos.frame;
2680 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2681 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2683 switch (_snap_type) {
2684 case SnapToTimecodeFrame:
2685 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2686 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2687 /* start is already on a whole timecode frame, do nothing */
2688 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2689 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2691 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2695 case SnapToTimecodeSeconds:
2696 if (_session->config.get_timecode_offset_negative()) {
2697 start += _session->config.get_timecode_offset ();
2699 start -= _session->config.get_timecode_offset ();
2701 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2702 (start % one_timecode_second == 0)) {
2703 /* start is already on a whole second, do nothing */
2704 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2705 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2707 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2710 if (_session->config.get_timecode_offset_negative()) {
2711 start -= _session->config.get_timecode_offset ();
2713 start += _session->config.get_timecode_offset ();
2717 case SnapToTimecodeMinutes:
2718 if (_session->config.get_timecode_offset_negative()) {
2719 start += _session->config.get_timecode_offset ();
2721 start -= _session->config.get_timecode_offset ();
2723 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2724 (start % one_timecode_minute == 0)) {
2725 /* start is already on a whole minute, do nothing */
2726 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2727 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2729 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2731 if (_session->config.get_timecode_offset_negative()) {
2732 start -= _session->config.get_timecode_offset ();
2734 start += _session->config.get_timecode_offset ();
2738 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2739 abort(); /*NOTREACHED*/
2746 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2748 const framepos_t one_second = _session->frame_rate();
2749 const framepos_t one_minute = _session->frame_rate() * 60;
2750 framepos_t presnap = start.frame;
2754 switch (_snap_type) {
2755 case SnapToTimecodeFrame:
2756 case SnapToTimecodeSeconds:
2757 case SnapToTimecodeMinutes:
2758 return timecode_snap_to_internal (start, direction, for_mark);
2761 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2762 start.frame % (one_second/75) == 0) {
2763 /* start is already on a whole CD frame, do nothing */
2764 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2765 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2767 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2770 start.set (start.frame, 0);
2775 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2776 start.frame % one_second == 0) {
2777 /* start is already on a whole second, do nothing */
2778 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2779 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2781 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2784 start.set (start.frame, 0);
2789 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2790 start.frame % one_minute == 0) {
2791 /* start is already on a whole minute, do nothing */
2792 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2793 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2795 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2798 start.set (start.frame, 0);
2803 start = _session->tempo_map().round_to_bar (start.frame, direction);
2807 start = _session->tempo_map().round_to_beat (start.frame, direction);
2810 case SnapToBeatDiv128:
2811 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2813 case SnapToBeatDiv64:
2814 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2816 case SnapToBeatDiv32:
2817 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2819 case SnapToBeatDiv28:
2820 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2822 case SnapToBeatDiv24:
2823 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2825 case SnapToBeatDiv20:
2826 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2828 case SnapToBeatDiv16:
2829 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2831 case SnapToBeatDiv14:
2832 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2834 case SnapToBeatDiv12:
2835 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2837 case SnapToBeatDiv10:
2838 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2840 case SnapToBeatDiv8:
2841 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2843 case SnapToBeatDiv7:
2844 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2846 case SnapToBeatDiv6:
2847 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2849 case SnapToBeatDiv5:
2850 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2852 case SnapToBeatDiv4:
2853 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2855 case SnapToBeatDiv3:
2856 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2858 case SnapToBeatDiv2:
2859 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2867 _session->locations()->marks_either_side (start.frame, before, after);
2869 if (before == max_framepos && after == max_framepos) {
2870 /* No marks to snap to, so just don't snap */
2872 } else if (before == max_framepos) {
2873 start.frame = after;
2874 } else if (after == max_framepos) {
2875 start.frame = before;
2876 } else if (before != max_framepos && after != max_framepos) {
2877 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2878 start.frame = after;
2879 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2880 start.frame = before;
2881 else if (direction == 0 ) {
2882 if ((start.frame - before) < (after - start.frame)) {
2883 start.frame = before;
2885 start.frame = after;
2890 start.set (start.frame, 0);
2894 case SnapToRegionStart:
2895 case SnapToRegionEnd:
2896 case SnapToRegionSync:
2897 case SnapToRegionBoundary:
2898 if (!region_boundary_cache.empty()) {
2900 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2901 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2903 if (direction > 0) {
2904 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2906 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2909 if (next != region_boundary_cache.begin ()) {
2914 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2915 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2917 if (start.frame > (p + n) / 2) {
2924 start.set (start.frame, 0);
2929 switch (_snap_mode) {
2939 if (presnap > start.frame) {
2940 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
2941 start.set (presnap, 0);
2944 } else if (presnap < start.frame) {
2945 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
2946 start.set (presnap, 0);
2951 /* handled at entry */
2958 Editor::setup_toolbar ()
2960 HBox* mode_box = manage(new HBox);
2961 mode_box->set_border_width (2);
2962 mode_box->set_spacing(2);
2964 HBox* mouse_mode_box = manage (new HBox);
2965 HBox* mouse_mode_hbox = manage (new HBox);
2966 VBox* mouse_mode_vbox = manage (new VBox);
2967 Alignment* mouse_mode_align = manage (new Alignment);
2969 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2970 mouse_mode_size_group->add_widget (smart_mode_button);
2971 mouse_mode_size_group->add_widget (mouse_move_button);
2972 mouse_mode_size_group->add_widget (mouse_cut_button);
2973 mouse_mode_size_group->add_widget (mouse_select_button);
2974 mouse_mode_size_group->add_widget (mouse_timefx_button);
2975 mouse_mode_size_group->add_widget (mouse_audition_button);
2976 mouse_mode_size_group->add_widget (mouse_draw_button);
2977 mouse_mode_size_group->add_widget (mouse_content_button);
2979 if (!Profile->get_mixbus()) {
2980 mouse_mode_size_group->add_widget (zoom_in_button);
2981 mouse_mode_size_group->add_widget (zoom_out_button);
2982 mouse_mode_size_group->add_widget (zoom_out_full_button);
2983 mouse_mode_size_group->add_widget (zoom_focus_selector);
2984 mouse_mode_size_group->add_widget (tav_shrink_button);
2985 mouse_mode_size_group->add_widget (tav_expand_button);
2987 mouse_mode_size_group->add_widget (zoom_preset_selector);
2988 mouse_mode_size_group->add_widget (visible_tracks_selector);
2991 mouse_mode_size_group->add_widget (snap_type_selector);
2992 mouse_mode_size_group->add_widget (snap_mode_selector);
2994 mouse_mode_size_group->add_widget (edit_point_selector);
2995 mouse_mode_size_group->add_widget (edit_mode_selector);
2997 mouse_mode_size_group->add_widget (*nudge_clock);
2998 mouse_mode_size_group->add_widget (nudge_forward_button);
2999 mouse_mode_size_group->add_widget (nudge_backward_button);
3001 mouse_mode_hbox->set_spacing (2);
3003 if (!ARDOUR::Profile->get_trx()) {
3004 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3007 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3008 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3010 if (!ARDOUR::Profile->get_mixbus()) {
3011 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3014 if (!ARDOUR::Profile->get_trx()) {
3015 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3016 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3017 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3018 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3021 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3023 mouse_mode_align->add (*mouse_mode_vbox);
3024 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3026 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3028 edit_mode_selector.set_name ("mouse mode button");
3030 if (!ARDOUR::Profile->get_trx()) {
3031 mode_box->pack_start (edit_mode_selector, false, false);
3034 mode_box->pack_start (*mouse_mode_box, false, false);
3038 _zoom_box.set_spacing (2);
3039 _zoom_box.set_border_width (2);
3043 zoom_preset_selector.set_name ("zoom button");
3044 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3046 zoom_in_button.set_name ("zoom button");
3047 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3048 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3049 zoom_in_button.set_related_action (act);
3051 zoom_out_button.set_name ("zoom button");
3052 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3053 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3054 zoom_out_button.set_related_action (act);
3056 zoom_out_full_button.set_name ("zoom button");
3057 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3058 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3059 zoom_out_full_button.set_related_action (act);
3061 zoom_focus_selector.set_name ("zoom button");
3063 if (ARDOUR::Profile->get_mixbus()) {
3064 _zoom_box.pack_start (zoom_preset_selector, false, false);
3065 } else if (ARDOUR::Profile->get_trx()) {
3066 mode_box->pack_start (zoom_out_button, false, false);
3067 mode_box->pack_start (zoom_in_button, false, false);
3069 _zoom_box.pack_start (zoom_out_button, false, false);
3070 _zoom_box.pack_start (zoom_in_button, false, false);
3071 _zoom_box.pack_start (zoom_out_full_button, false, false);
3072 _zoom_box.pack_start (zoom_focus_selector, false, false);
3075 /* Track zoom buttons */
3076 _track_box.set_spacing (2);
3077 _track_box.set_border_width (2);
3079 visible_tracks_selector.set_name ("zoom button");
3080 if (Profile->get_mixbus()) {
3081 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3083 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3086 tav_expand_button.set_name ("zoom button");
3087 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3088 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3089 tav_expand_button.set_related_action (act);
3091 tav_shrink_button.set_name ("zoom button");
3092 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3093 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3094 tav_shrink_button.set_related_action (act);
3096 if (ARDOUR::Profile->get_mixbus()) {
3097 _track_box.pack_start (visible_tracks_selector);
3098 } else if (ARDOUR::Profile->get_trx()) {
3099 _track_box.pack_start (tav_shrink_button);
3100 _track_box.pack_start (tav_expand_button);
3102 _track_box.pack_start (visible_tracks_selector);
3103 _track_box.pack_start (tav_shrink_button);
3104 _track_box.pack_start (tav_expand_button);
3107 snap_box.set_spacing (2);
3108 snap_box.set_border_width (2);
3110 snap_type_selector.set_name ("mouse mode button");
3112 snap_mode_selector.set_name ("mouse mode button");
3114 edit_point_selector.set_name ("mouse mode button");
3116 snap_box.pack_start (snap_mode_selector, false, false);
3117 snap_box.pack_start (snap_type_selector, false, false);
3120 HBox *ep_box = manage (new HBox);
3121 ep_box->set_spacing (2);
3122 ep_box->set_border_width (2);
3124 ep_box->pack_start (edit_point_selector, false, false);
3128 HBox *nudge_box = manage (new HBox);
3129 nudge_box->set_spacing (2);
3130 nudge_box->set_border_width (2);
3132 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3133 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3135 nudge_box->pack_start (nudge_backward_button, false, false);
3136 nudge_box->pack_start (nudge_forward_button, false, false);
3137 nudge_box->pack_start (*nudge_clock, false, false);
3140 /* Pack everything in... */
3142 toolbar_hbox.set_spacing (2);
3143 toolbar_hbox.set_border_width (2);
3145 toolbar_hbox.pack_start (*mode_box, false, false);
3147 if (!ARDOUR::Profile->get_trx()) {
3149 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3151 toolbar_hbox.pack_start (_zoom_box, false, false);
3153 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3155 toolbar_hbox.pack_start (_track_box, false, false);
3157 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3159 toolbar_hbox.pack_start (snap_box, false, false);
3161 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3163 toolbar_hbox.pack_start (*ep_box, false, false);
3165 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3167 toolbar_hbox.pack_start (*nudge_box, false, false);
3170 toolbar_hbox.show_all ();
3174 Editor::build_edit_point_menu ()
3176 using namespace Menu_Helpers;
3178 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3179 if(!Profile->get_mixbus())
3180 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3181 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3183 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3187 Editor::build_edit_mode_menu ()
3189 using namespace Menu_Helpers;
3191 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3192 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3193 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3194 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3196 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3200 Editor::build_snap_mode_menu ()
3202 using namespace Menu_Helpers;
3204 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3205 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3206 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3208 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3212 Editor::build_snap_type_menu ()
3214 using namespace Menu_Helpers;
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3247 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3252 Editor::setup_tooltips ()
3254 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3255 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3256 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3257 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3258 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3259 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3260 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3261 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3262 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3263 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3264 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3265 set_tooltip (zoom_in_button, _("Zoom In"));
3266 set_tooltip (zoom_out_button, _("Zoom Out"));
3267 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3268 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3269 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3270 set_tooltip (tav_expand_button, _("Expand Tracks"));
3271 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3272 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3273 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3274 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3275 set_tooltip (edit_point_selector, _("Edit Point"));
3276 set_tooltip (edit_mode_selector, _("Edit Mode"));
3277 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3281 Editor::convert_drop_to_paths (
3282 vector<string>& paths,
3283 const RefPtr<Gdk::DragContext>& /*context*/,
3286 const SelectionData& data,
3290 if (_session == 0) {
3294 vector<string> uris = data.get_uris();
3298 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3299 are actually URI lists. So do it by hand.
3302 if (data.get_target() != "text/plain") {
3306 /* Parse the "uri-list" format that Nautilus provides,
3307 where each pathname is delimited by \r\n.
3309 THERE MAY BE NO NULL TERMINATING CHAR!!!
3312 string txt = data.get_text();
3316 p = (char *) malloc (txt.length() + 1);
3317 txt.copy (p, txt.length(), 0);
3318 p[txt.length()] = '\0';
3324 while (g_ascii_isspace (*p))
3328 while (*q && (*q != '\n') && (*q != '\r')) {
3335 while (q > p && g_ascii_isspace (*q))
3340 uris.push_back (string (p, q - p + 1));
3344 p = strchr (p, '\n');
3356 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3357 if ((*i).substr (0,7) == "file://") {
3358 paths.push_back (Glib::filename_from_uri (*i));
3366 Editor::new_tempo_section ()
3371 Editor::map_transport_state ()
3373 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3375 if (_session && _session->transport_stopped()) {
3376 have_pending_keyboard_selection = false;
3379 update_loop_range_view ();
3383 Editor::transport_looped ()
3385 /* reset Playhead position interpolation.
3386 * see Editor::super_rapid_screen_update
3388 _last_update_time = 0;
3394 Editor::begin_selection_op_history ()
3396 selection_op_cmd_depth = 0;
3397 selection_op_history_it = 0;
3399 while(!selection_op_history.empty()) {
3400 delete selection_op_history.front();
3401 selection_op_history.pop_front();
3404 selection_undo_action->set_sensitive (false);
3405 selection_redo_action->set_sensitive (false);
3406 selection_op_history.push_front (&_selection_memento->get_state ());
3410 Editor::begin_reversible_selection_op (string name)
3413 //cerr << name << endl;
3414 /* begin/commit pairs can be nested */
3415 selection_op_cmd_depth++;
3420 Editor::commit_reversible_selection_op ()
3423 if (selection_op_cmd_depth == 1) {
3425 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3427 The user has undone some selection ops and then made a new one,
3428 making anything earlier in the list invalid.
3431 list<XMLNode *>::iterator it = selection_op_history.begin();
3432 list<XMLNode *>::iterator e_it = it;
3433 advance (e_it, selection_op_history_it);
3435 for ( ; it != e_it; ++it) {
3438 selection_op_history.erase (selection_op_history.begin(), e_it);
3441 selection_op_history.push_front (&_selection_memento->get_state ());
3442 selection_op_history_it = 0;
3444 selection_undo_action->set_sensitive (true);
3445 selection_redo_action->set_sensitive (false);
3448 if (selection_op_cmd_depth > 0) {
3449 selection_op_cmd_depth--;
3455 Editor::undo_selection_op ()
3458 selection_op_history_it++;
3460 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3461 if (n == selection_op_history_it) {
3462 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3463 selection_redo_action->set_sensitive (true);
3467 /* is there an earlier entry? */
3468 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3469 selection_undo_action->set_sensitive (false);
3475 Editor::redo_selection_op ()
3478 if (selection_op_history_it > 0) {
3479 selection_op_history_it--;
3482 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3483 if (n == selection_op_history_it) {
3484 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3485 selection_undo_action->set_sensitive (true);
3490 if (selection_op_history_it == 0) {
3491 selection_redo_action->set_sensitive (false);
3497 Editor::begin_reversible_command (string name)
3500 before.push_back (&_selection_memento->get_state ());
3501 _session->begin_reversible_command (name);
3506 Editor::begin_reversible_command (GQuark q)
3509 before.push_back (&_selection_memento->get_state ());
3510 _session->begin_reversible_command (q);
3515 Editor::abort_reversible_command ()
3518 while(!before.empty()) {
3519 delete before.front();
3522 _session->abort_reversible_command ();
3527 Editor::commit_reversible_command ()
3530 if (before.size() == 1) {
3531 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3532 redo_action->set_sensitive(false);
3533 undo_action->set_sensitive(true);
3534 begin_selection_op_history ();
3537 if (before.empty()) {
3538 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3543 _session->commit_reversible_command ();
3548 Editor::history_changed ()
3552 if (undo_action && _session) {
3553 if (_session->undo_depth() == 0) {
3554 label = S_("Command|Undo");
3556 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3558 undo_action->property_label() = label;
3561 if (redo_action && _session) {
3562 if (_session->redo_depth() == 0) {
3564 redo_action->set_sensitive (false);
3566 label = string_compose(_("Redo (%1)"), _session->next_redo());
3567 redo_action->set_sensitive (true);
3569 redo_action->property_label() = label;
3574 Editor::duplicate_range (bool with_dialog)
3578 RegionSelection rs = get_regions_from_selection_and_entered ();
3580 if ( selection->time.length() == 0 && rs.empty()) {
3586 ArdourDialog win (_("Duplicate"));
3587 Label label (_("Number of duplications:"));
3588 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3589 SpinButton spinner (adjustment, 0.0, 1);
3592 win.get_vbox()->set_spacing (12);
3593 win.get_vbox()->pack_start (hbox);
3594 hbox.set_border_width (6);
3595 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3597 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3598 place, visually. so do this by hand.
3601 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3602 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3603 spinner.grab_focus();
3609 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3610 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3611 win.set_default_response (RESPONSE_ACCEPT);
3613 spinner.grab_focus ();
3615 switch (win.run ()) {
3616 case RESPONSE_ACCEPT:
3622 times = adjustment.get_value();
3625 if ((current_mouse_mode() == Editing::MouseRange)) {
3626 if (selection->time.length()) {
3627 duplicate_selection (times);
3629 } else if (get_smart_mode()) {
3630 if (selection->time.length()) {
3631 duplicate_selection (times);
3633 duplicate_some_regions (rs, times);
3635 duplicate_some_regions (rs, times);
3640 Editor::set_edit_mode (EditMode m)
3642 Config->set_edit_mode (m);
3646 Editor::cycle_edit_mode ()
3648 switch (Config->get_edit_mode()) {
3650 Config->set_edit_mode (Ripple);
3654 Config->set_edit_mode (Lock);
3657 Config->set_edit_mode (Slide);
3663 Editor::edit_mode_selection_done ( EditMode m )
3665 Config->set_edit_mode ( m );
3669 Editor::snap_type_selection_done (SnapType snaptype)
3671 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3673 ract->set_active ();
3678 Editor::snap_mode_selection_done (SnapMode mode)
3680 RefPtr<RadioAction> ract = snap_mode_action (mode);
3683 ract->set_active (true);
3688 Editor::cycle_edit_point (bool with_marker)
3690 if(Profile->get_mixbus())
3691 with_marker = false;
3693 switch (_edit_point) {
3695 set_edit_point_preference (EditAtPlayhead);
3697 case EditAtPlayhead:
3699 set_edit_point_preference (EditAtSelectedMarker);
3701 set_edit_point_preference (EditAtMouse);
3704 case EditAtSelectedMarker:
3705 set_edit_point_preference (EditAtMouse);
3711 Editor::edit_point_selection_done (EditPoint ep)
3713 set_edit_point_preference ( ep );
3717 Editor::build_zoom_focus_menu ()
3719 using namespace Menu_Helpers;
3721 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3722 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3723 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3724 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3725 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3726 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3728 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3732 Editor::zoom_focus_selection_done ( ZoomFocus f )
3734 RefPtr<RadioAction> ract = zoom_focus_action (f);
3736 ract->set_active ();
3741 Editor::build_track_count_menu ()
3743 using namespace Menu_Helpers;
3745 if (!Profile->get_mixbus()) {
3746 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3747 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3748 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3749 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3750 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3751 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3752 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3753 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3754 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3755 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3756 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3757 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3758 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3760 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3763 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3764 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3771 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3772 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3773 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3774 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3775 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3776 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3777 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3778 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3779 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3780 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3781 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3786 Editor::set_zoom_preset (int64_t ms)
3789 temporal_zoom_session();
3793 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3794 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3798 Editor::set_visible_track_count (int32_t n)
3800 _visible_track_count = n;
3802 /* if the canvas hasn't really been allocated any size yet, just
3803 record the desired number of visible tracks and return. when canvas
3804 allocation happens, we will get called again and then we can do the
3808 if (_visible_canvas_height <= 1) {
3814 DisplaySuspender ds;
3816 if (_visible_track_count > 0) {
3817 h = trackviews_height() / _visible_track_count;
3818 std::ostringstream s;
3819 s << _visible_track_count;
3821 } else if (_visible_track_count == 0) {
3823 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3824 if ((*i)->marked_for_display()) {
3826 TimeAxisView::Children cl ((*i)->get_child_list ());
3827 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3828 if ((*j)->marked_for_display()) {
3835 visible_tracks_selector.set_text (X_("*"));
3838 h = trackviews_height() / n;
3841 /* negative value means that the visible track count has
3842 been overridden by explicit track height changes.
3844 visible_tracks_selector.set_text (X_("*"));
3848 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3849 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3852 if (str != visible_tracks_selector.get_text()) {
3853 visible_tracks_selector.set_text (str);
3858 Editor::override_visible_track_count ()
3860 _visible_track_count = -1;
3861 visible_tracks_selector.set_text ( _("*") );
3865 Editor::edit_controls_button_release (GdkEventButton* ev)
3867 if (Keyboard::is_context_menu_event (ev)) {
3868 ARDOUR_UI::instance()->add_route ();
3869 } else if (ev->button == 1) {
3870 selection->clear_tracks ();
3877 Editor::mouse_select_button_release (GdkEventButton* ev)
3879 /* this handles just right-clicks */
3881 if (ev->button != 3) {
3889 Editor::set_zoom_focus (ZoomFocus f)
3891 string str = zoom_focus_strings[(int)f];
3893 if (str != zoom_focus_selector.get_text()) {
3894 zoom_focus_selector.set_text (str);
3897 if (zoom_focus != f) {
3904 Editor::cycle_zoom_focus ()
3906 switch (zoom_focus) {
3908 set_zoom_focus (ZoomFocusRight);
3910 case ZoomFocusRight:
3911 set_zoom_focus (ZoomFocusCenter);
3913 case ZoomFocusCenter:
3914 set_zoom_focus (ZoomFocusPlayhead);
3916 case ZoomFocusPlayhead:
3917 set_zoom_focus (ZoomFocusMouse);
3919 case ZoomFocusMouse:
3920 set_zoom_focus (ZoomFocusEdit);
3923 set_zoom_focus (ZoomFocusLeft);
3929 Editor::set_show_measures (bool yn)
3931 if (_show_measures != yn) {
3934 if ((_show_measures = yn) == true) {
3936 tempo_lines->show();
3939 std::vector<TempoMap::BBTPoint> grid;
3940 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3941 draw_measures (grid);
3949 Editor::toggle_follow_playhead ()
3951 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3953 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3954 set_follow_playhead (tact->get_active());
3958 /** @param yn true to follow playhead, otherwise false.
3959 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3962 Editor::set_follow_playhead (bool yn, bool catch_up)
3964 if (_follow_playhead != yn) {
3965 if ((_follow_playhead = yn) == true && catch_up) {
3967 reset_x_origin_to_follow_playhead ();
3974 Editor::toggle_stationary_playhead ()
3976 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3978 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3979 set_stationary_playhead (tact->get_active());
3984 Editor::set_stationary_playhead (bool yn)
3986 if (_stationary_playhead != yn) {
3987 if ((_stationary_playhead = yn) == true) {
3989 // FIXME need a 3.0 equivalent of this 2.X call
3990 // update_current_screen ();
3997 Editor::playlist_selector () const
3999 return *_playlist_selector;
4003 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4005 if (paste_count == 0) {
4006 /* don't bother calculating an offset that will be zero anyway */
4010 /* calculate basic unsnapped multi-paste offset */
4011 framecnt_t offset = paste_count * duration;
4013 /* snap offset so pos + offset is aligned to the grid */
4014 MusicFrame offset_pos (pos + offset, 0);
4015 snap_to(offset_pos, RoundUpMaybe);
4016 offset = offset_pos.frame - pos;
4022 Editor::get_grid_beat_divisions(framepos_t position)
4024 switch (_snap_type) {
4025 case SnapToBeatDiv128: return 128;
4026 case SnapToBeatDiv64: return 64;
4027 case SnapToBeatDiv32: return 32;
4028 case SnapToBeatDiv28: return 28;
4029 case SnapToBeatDiv24: return 24;
4030 case SnapToBeatDiv20: return 20;
4031 case SnapToBeatDiv16: return 16;
4032 case SnapToBeatDiv14: return 14;
4033 case SnapToBeatDiv12: return 12;
4034 case SnapToBeatDiv10: return 10;
4035 case SnapToBeatDiv8: return 8;
4036 case SnapToBeatDiv7: return 7;
4037 case SnapToBeatDiv6: return 6;
4038 case SnapToBeatDiv5: return 5;
4039 case SnapToBeatDiv4: return 4;
4040 case SnapToBeatDiv3: return 3;
4041 case SnapToBeatDiv2: return 2;
4047 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4048 if the grid is non-musical, returns 0.
4049 if the grid is snapped to bars, returns -1.
4050 @param event_state the current keyboard modifier mask.
4053 Editor::get_grid_music_divisions (uint32_t event_state)
4055 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4059 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4063 switch (_snap_type) {
4064 case SnapToBeatDiv128: return 128;
4065 case SnapToBeatDiv64: return 64;
4066 case SnapToBeatDiv32: return 32;
4067 case SnapToBeatDiv28: return 28;
4068 case SnapToBeatDiv24: return 24;
4069 case SnapToBeatDiv20: return 20;
4070 case SnapToBeatDiv16: return 16;
4071 case SnapToBeatDiv14: return 14;
4072 case SnapToBeatDiv12: return 12;
4073 case SnapToBeatDiv10: return 10;
4074 case SnapToBeatDiv8: return 8;
4075 case SnapToBeatDiv7: return 7;
4076 case SnapToBeatDiv6: return 6;
4077 case SnapToBeatDiv5: return 5;
4078 case SnapToBeatDiv4: return 4;
4079 case SnapToBeatDiv3: return 3;
4080 case SnapToBeatDiv2: return 2;
4081 case SnapToBeat: return 1;
4082 case SnapToBar : return -1;
4089 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4093 const unsigned divisions = get_grid_beat_divisions(position);
4095 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4098 switch (_snap_type) {
4100 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4103 const Meter& m = _session->tempo_map().meter_at_frame (position);
4104 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4112 return Evoral::Beats();
4116 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4120 ret = nudge_clock->current_duration (pos);
4121 next = ret + 1; /* XXXX fix me */
4127 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4129 ArdourDialog dialog (_("Playlist Deletion"));
4130 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4131 "If it is kept, its audio files will not be cleaned.\n"
4132 "If it is deleted, audio files used by it alone will be cleaned."),
4135 dialog.set_position (WIN_POS_CENTER);
4136 dialog.get_vbox()->pack_start (label);
4140 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4141 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4142 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4143 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4144 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4146 // by default gtk uses the left most button
4147 keep->grab_focus ();
4149 switch (dialog.run ()) {
4151 /* keep this and all remaining ones */
4156 /* delete this and all others */
4160 case RESPONSE_ACCEPT:
4161 /* delete the playlist */
4165 case RESPONSE_REJECT:
4166 /* keep the playlist */
4178 Editor::audio_region_selection_covers (framepos_t where)
4180 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4181 if ((*a)->region()->covers (where)) {
4190 Editor::prepare_for_cleanup ()
4192 cut_buffer->clear_regions ();
4193 cut_buffer->clear_playlists ();
4195 selection->clear_regions ();
4196 selection->clear_playlists ();
4198 _regions->suspend_redisplay ();
4202 Editor::finish_cleanup ()
4204 _regions->resume_redisplay ();
4208 Editor::transport_loop_location()
4211 return _session->locations()->auto_loop_location();
4218 Editor::transport_punch_location()
4221 return _session->locations()->auto_punch_location();
4228 Editor::control_layout_scroll (GdkEventScroll* ev)
4230 /* Just forward to the normal canvas scroll method. The coordinate
4231 systems are different but since the canvas is always larger than the
4232 track headers, and aligned with the trackview area, this will work.
4234 In the not too distant future this layout is going away anyway and
4235 headers will be on the canvas.
4237 return canvas_scroll_event (ev, false);
4241 Editor::session_state_saved (string)
4244 _snapshots->redisplay ();
4248 Editor::maximise_editing_space ()
4254 Gtk::Window* toplevel = current_toplevel();
4257 toplevel->fullscreen ();
4263 Editor::restore_editing_space ()
4269 Gtk::Window* toplevel = current_toplevel();
4272 toplevel->unfullscreen();
4278 * Make new playlists for a given track and also any others that belong
4279 * to the same active route group with the `select' property.
4284 Editor::new_playlists (TimeAxisView* v)
4286 begin_reversible_command (_("new playlists"));
4287 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4288 _session->playlists->get (playlists);
4289 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4290 commit_reversible_command ();
4294 * Use a copy of the current playlist for a given track and also any others that belong
4295 * to the same active route group with the `select' property.
4300 Editor::copy_playlists (TimeAxisView* v)
4302 begin_reversible_command (_("copy playlists"));
4303 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4304 _session->playlists->get (playlists);
4305 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4306 commit_reversible_command ();
4309 /** Clear the current playlist for a given track and also any others that belong
4310 * to the same active route group with the `select' property.
4315 Editor::clear_playlists (TimeAxisView* v)
4317 begin_reversible_command (_("clear playlists"));
4318 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4319 _session->playlists->get (playlists);
4320 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4321 commit_reversible_command ();
4325 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4327 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4331 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4333 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4337 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4339 atv.clear_playlist ();
4343 Editor::get_y_origin () const
4345 return vertical_adjustment.get_value ();
4348 /** Queue up a change to the viewport x origin.
4349 * @param frame New x origin.
4352 Editor::reset_x_origin (framepos_t frame)
4354 pending_visual_change.add (VisualChange::TimeOrigin);
4355 pending_visual_change.time_origin = frame;
4356 ensure_visual_change_idle_handler ();
4360 Editor::reset_y_origin (double y)
4362 pending_visual_change.add (VisualChange::YOrigin);
4363 pending_visual_change.y_origin = y;
4364 ensure_visual_change_idle_handler ();
4368 Editor::reset_zoom (framecnt_t spp)
4370 if (spp == samples_per_pixel) {
4374 pending_visual_change.add (VisualChange::ZoomLevel);
4375 pending_visual_change.samples_per_pixel = spp;
4376 ensure_visual_change_idle_handler ();
4380 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4382 reset_x_origin (frame);
4385 if (!no_save_visual) {
4386 undo_visual_stack.push_back (current_visual_state(false));
4390 Editor::VisualState::VisualState (bool with_tracks)
4391 : gui_state (with_tracks ? new GUIObjectState : 0)
4395 Editor::VisualState::~VisualState ()
4400 Editor::VisualState*
4401 Editor::current_visual_state (bool with_tracks)
4403 VisualState* vs = new VisualState (with_tracks);
4404 vs->y_position = vertical_adjustment.get_value();
4405 vs->samples_per_pixel = samples_per_pixel;
4406 vs->leftmost_frame = leftmost_frame;
4407 vs->zoom_focus = zoom_focus;
4410 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4417 Editor::undo_visual_state ()
4419 if (undo_visual_stack.empty()) {
4423 VisualState* vs = undo_visual_stack.back();
4424 undo_visual_stack.pop_back();
4427 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4430 use_visual_state (*vs);
4435 Editor::redo_visual_state ()
4437 if (redo_visual_stack.empty()) {
4441 VisualState* vs = redo_visual_stack.back();
4442 redo_visual_stack.pop_back();
4444 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4445 // why do we check here?
4446 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4449 use_visual_state (*vs);
4454 Editor::swap_visual_state ()
4456 if (undo_visual_stack.empty()) {
4457 redo_visual_state ();
4459 undo_visual_state ();
4464 Editor::use_visual_state (VisualState& vs)
4466 PBD::Unwinder<bool> nsv (no_save_visual, true);
4467 DisplaySuspender ds;
4469 vertical_adjustment.set_value (vs.y_position);
4471 set_zoom_focus (vs.zoom_focus);
4472 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4475 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4477 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4478 (*i)->clear_property_cache();
4479 (*i)->reset_visual_state ();
4483 _routes->update_visibility ();
4486 /** This is the core function that controls the zoom level of the canvas. It is called
4487 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4488 * @param spp new number of samples per pixel
4491 Editor::set_samples_per_pixel (framecnt_t spp)
4497 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4498 const framecnt_t lots_of_pixels = 4000;
4500 /* if the zoom level is greater than what you'd get trying to display 3
4501 * days of audio on a really big screen, then it's too big.
4504 if (spp * lots_of_pixels > three_days) {
4508 samples_per_pixel = spp;
4512 Editor::on_samples_per_pixel_changed ()
4515 tempo_lines->tempo_map_changed(_session->tempo_map().music_origin());
4518 bool const showing_time_selection = selection->time.length() > 0;
4520 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4521 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4522 (*i)->reshow_selection (selection->time);
4526 ZoomChanged (); /* EMIT_SIGNAL */
4528 ArdourCanvas::GtkCanvasViewport* c;
4530 c = get_track_canvas();
4532 c->canvas()->zoomed ();
4535 if (playhead_cursor) {
4536 playhead_cursor->set_position (playhead_cursor->current_frame ());
4539 refresh_location_display();
4540 _summary->set_overlays_dirty ();
4542 update_marker_labels ();
4548 Editor::playhead_cursor_sample () const
4550 return playhead_cursor->current_frame();
4554 Editor::queue_visual_videotimeline_update ()
4556 pending_visual_change.add (VisualChange::VideoTimeline);
4557 ensure_visual_change_idle_handler ();
4561 Editor::ensure_visual_change_idle_handler ()
4563 if (pending_visual_change.idle_handler_id < 0) {
4564 // see comment in add_to_idle_resize above.
4565 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4566 pending_visual_change.being_handled = false;
4571 Editor::_idle_visual_changer (void* arg)
4573 return static_cast<Editor*>(arg)->idle_visual_changer ();
4577 Editor::pre_render ()
4579 visual_change_queued = false;
4581 if (pending_visual_change.pending != 0) {
4582 ensure_visual_change_idle_handler();
4587 Editor::idle_visual_changer ()
4589 pending_visual_change.idle_handler_id = -1;
4591 if (pending_visual_change.pending == 0) {
4595 /* set_horizontal_position() below (and maybe other calls) call
4596 gtk_main_iteration(), so it's possible that a signal will be handled
4597 half-way through this method. If this signal wants an
4598 idle_visual_changer we must schedule another one after this one, so
4599 mark the idle_handler_id as -1 here to allow that. Also make a note
4600 that we are doing the visual change, so that changes in response to
4601 super-rapid-screen-update can be dropped if we are still processing
4605 if (visual_change_queued) {
4609 pending_visual_change.being_handled = true;
4611 VisualChange vc = pending_visual_change;
4613 pending_visual_change.pending = (VisualChange::Type) 0;
4615 visual_changer (vc);
4617 pending_visual_change.being_handled = false;
4619 visual_change_queued = true;
4621 return 0; /* this is always a one-shot call */
4625 Editor::visual_changer (const VisualChange& vc)
4628 * Changed first so the correct horizontal canvas position is calculated in
4629 * Editor::set_horizontal_position
4631 if (vc.pending & VisualChange::ZoomLevel) {
4632 set_samples_per_pixel (vc.samples_per_pixel);
4635 if (vc.pending & VisualChange::TimeOrigin) {
4636 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4637 set_horizontal_position (new_time_origin);
4640 if (vc.pending & VisualChange::YOrigin) {
4641 vertical_adjustment.set_value (vc.y_origin);
4645 * Now the canvas is in the final state before render the canvas items that
4646 * support the Item::prepare_for_render interface can calculate the correct
4647 * item to visible canvas intersection.
4649 if (vc.pending & VisualChange::ZoomLevel) {
4650 on_samples_per_pixel_changed ();
4652 compute_fixed_ruler_scale ();
4654 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4655 update_tempo_based_rulers ();
4658 if (!(vc.pending & VisualChange::ZoomLevel)) {
4660 * If the canvas is not being zoomed then the canvas items will not change
4661 * and cause Item::prepare_for_render to be called so do it here manually.
4663 * Not ideal, but I can't think of a better solution atm.
4665 _track_canvas->prepare_for_render();
4668 // If we are only scrolling vertically there is no need to update these
4669 if (vc.pending != VisualChange::YOrigin) {
4670 update_fixed_rulers ();
4671 redisplay_tempo (true);
4673 /* video frames & position need to be updated for zoom, horiz-scroll
4674 * and (explicitly) VisualChange::VideoTimeline.
4676 update_video_timeline();
4679 _summary->set_overlays_dirty ();
4682 struct EditorOrderTimeAxisSorter {
4683 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4684 return a->order () < b->order ();
4689 Editor::sort_track_selection (TrackViewList& sel)
4691 EditorOrderTimeAxisSorter cmp;
4696 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4699 framepos_t where = 0;
4700 EditPoint ep = _edit_point;
4702 if (Profile->get_mixbus()) {
4703 if (ep == EditAtSelectedMarker) {
4704 ep = EditAtPlayhead;
4708 if (from_outside_canvas && (ep == EditAtMouse)) {
4709 ep = EditAtPlayhead;
4710 } else if (from_context_menu && (ep == EditAtMouse)) {
4711 return canvas_event_sample (&context_click_event, 0, 0);
4714 if (entered_marker) {
4715 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4716 return entered_marker->position();
4719 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4720 ep = EditAtSelectedMarker;
4723 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4724 ep = EditAtPlayhead;
4727 MusicFrame snap_mf (0, 0);
4730 case EditAtPlayhead:
4731 if (_dragging_playhead && _control_scroll_target) {
4732 where = *_control_scroll_target;
4734 where = _session->audible_frame();
4736 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4739 case EditAtSelectedMarker:
4740 if (!selection->markers.empty()) {
4742 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4745 where = loc->start();
4749 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4757 if (!mouse_frame (where, ignored)) {
4758 /* XXX not right but what can we do ? */
4761 snap_mf.frame = where;
4763 where = snap_mf.frame;
4764 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4772 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4774 if (!_session) return;
4776 begin_reversible_command (cmd);
4780 if ((tll = transport_loop_location()) == 0) {
4781 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4782 XMLNode &before = _session->locations()->get_state();
4783 _session->locations()->add (loc, true);
4784 _session->set_auto_loop_location (loc);
4785 XMLNode &after = _session->locations()->get_state();
4786 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4788 XMLNode &before = tll->get_state();
4789 tll->set_hidden (false, this);
4790 tll->set (start, end);
4791 XMLNode &after = tll->get_state();
4792 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4795 commit_reversible_command ();
4799 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4801 if (!_session) return;
4803 begin_reversible_command (cmd);
4807 if ((tpl = transport_punch_location()) == 0) {
4808 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4809 XMLNode &before = _session->locations()->get_state();
4810 _session->locations()->add (loc, true);
4811 _session->set_auto_punch_location (loc);
4812 XMLNode &after = _session->locations()->get_state();
4813 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4815 XMLNode &before = tpl->get_state();
4816 tpl->set_hidden (false, this);
4817 tpl->set (start, end);
4818 XMLNode &after = tpl->get_state();
4819 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4822 commit_reversible_command ();
4825 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4826 * @param rs List to which found regions are added.
4827 * @param where Time to look at.
4828 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4831 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4833 const TrackViewList* tracks;
4836 tracks = &track_views;
4841 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4843 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4846 boost::shared_ptr<Track> tr;
4847 boost::shared_ptr<Playlist> pl;
4849 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4851 boost::shared_ptr<RegionList> regions = pl->regions_at (
4852 (framepos_t) floor ( (double) where * tr->speed()));
4854 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4855 RegionView* rv = rtv->view()->find_view (*i);
4866 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4868 const TrackViewList* tracks;
4871 tracks = &track_views;
4876 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4877 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4879 boost::shared_ptr<Track> tr;
4880 boost::shared_ptr<Playlist> pl;
4882 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4884 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4885 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4887 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4889 RegionView* rv = rtv->view()->find_view (*i);
4900 /** Get regions using the following method:
4902 * Make a region list using:
4903 * (a) any selected regions
4904 * (b) the intersection of any selected tracks and the edit point(*)
4905 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4907 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4909 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4913 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4915 RegionSelection regions;
4917 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4918 regions.add (entered_regionview);
4920 regions = selection->regions;
4923 if ( regions.empty() ) {
4924 TrackViewList tracks = selection->tracks;
4926 if (!tracks.empty()) {
4927 /* no region selected or entered, but some selected tracks:
4928 * act on all regions on the selected tracks at the edit point
4930 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4931 get_regions_at(regions, where, tracks);
4938 /** Get regions using the following method:
4940 * Make a region list using:
4941 * (a) any selected regions
4942 * (b) the intersection of any selected tracks and the edit point(*)
4943 * (c) if neither exists, then whatever region is under the mouse
4945 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4947 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4950 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4952 RegionSelection regions;
4954 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4955 regions.add (entered_regionview);
4957 regions = selection->regions;
4960 if ( regions.empty() ) {
4961 TrackViewList tracks = selection->tracks;
4963 if (!tracks.empty()) {
4964 /* no region selected or entered, but some selected tracks:
4965 * act on all regions on the selected tracks at the edit point
4967 get_regions_at(regions, pos, tracks);
4974 /** Start with regions that are selected, or the entered regionview if none are selected.
4975 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4976 * of the regions that we started with.
4980 Editor::get_regions_from_selection_and_entered () const
4982 RegionSelection regions = selection->regions;
4984 if (regions.empty() && entered_regionview) {
4985 regions.add (entered_regionview);
4992 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4994 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4995 RouteTimeAxisView* rtav;
4997 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4998 boost::shared_ptr<Playlist> pl;
4999 std::vector<boost::shared_ptr<Region> > results;
5000 boost::shared_ptr<Track> tr;
5002 if ((tr = rtav->track()) == 0) {
5007 if ((pl = (tr->playlist())) != 0) {
5008 boost::shared_ptr<Region> r = pl->region_by_id (id);
5010 RegionView* rv = rtav->view()->find_view (r);
5012 regions.push_back (rv);
5021 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5024 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5025 MidiTimeAxisView* mtav;
5027 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5029 mtav->get_per_region_note_selection (selection);
5036 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5038 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5040 RouteTimeAxisView* tatv;
5042 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5044 boost::shared_ptr<Playlist> pl;
5045 vector<boost::shared_ptr<Region> > results;
5047 boost::shared_ptr<Track> tr;
5049 if ((tr = tatv->track()) == 0) {
5054 if ((pl = (tr->playlist())) != 0) {
5055 if (src_comparison) {
5056 pl->get_source_equivalent_regions (region, results);
5058 pl->get_region_list_equivalent_regions (region, results);
5062 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5063 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5064 regions.push_back (marv);
5073 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5075 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5076 RouteTimeAxisView* tatv;
5077 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5078 if (!tatv->track()) {
5081 RegionView* marv = tatv->view()->find_view (region);
5091 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5093 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5094 RouteTimeAxisView* rtav;
5095 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5096 if (rtav->route() == route) {
5105 Editor::show_rhythm_ferret ()
5107 if (rhythm_ferret == 0) {
5108 rhythm_ferret = new RhythmFerret(*this);
5111 rhythm_ferret->set_session (_session);
5112 rhythm_ferret->show ();
5113 rhythm_ferret->present ();
5117 Editor::first_idle ()
5119 MessageDialog* dialog = 0;
5121 if (track_views.size() > 1) {
5122 Timers::TimerSuspender t;
5123 dialog = new MessageDialog (
5124 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5128 ARDOUR_UI::instance()->flush_pending (60);
5131 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5135 /* now that all regionviews should exist, setup region selection */
5139 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5140 /* this is cumulative: rs is NOT cleared each time */
5141 get_regionviews_by_id (*pr, rs);
5144 selection->set (rs);
5146 // first idle adds route children (automation tracks), so we need to redisplay here
5147 _routes->redisplay ();
5151 if (_session->undo_depth() == 0) {
5152 undo_action->set_sensitive(false);
5154 redo_action->set_sensitive(false);
5155 begin_selection_op_history ();
5161 Editor::_idle_resize (gpointer arg)
5163 return ((Editor*)arg)->idle_resize ();
5167 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5169 if (resize_idle_id < 0) {
5170 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5171 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5172 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5174 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5175 _pending_resize_amount = 0;
5178 /* make a note of the smallest resulting height, so that we can clamp the
5179 lower limit at TimeAxisView::hSmall */
5181 int32_t min_resulting = INT32_MAX;
5183 _pending_resize_amount += h;
5184 _pending_resize_view = view;
5186 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5188 if (selection->tracks.contains (_pending_resize_view)) {
5189 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5190 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5194 if (min_resulting < 0) {
5199 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5200 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5204 /** Handle pending resizing of tracks */
5206 Editor::idle_resize ()
5208 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5210 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5211 selection->tracks.contains (_pending_resize_view)) {
5213 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5214 if (*i != _pending_resize_view) {
5215 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5220 _pending_resize_amount = 0;
5221 _group_tabs->set_dirty ();
5222 resize_idle_id = -1;
5230 ENSURE_GUI_THREAD (*this, &Editor::located);
5233 playhead_cursor->set_position (_session->audible_frame ());
5234 if (_follow_playhead && !_pending_initial_locate) {
5235 reset_x_origin_to_follow_playhead ();
5239 _pending_locate_request = false;
5240 _pending_initial_locate = false;
5241 _last_update_time = 0;
5245 Editor::region_view_added (RegionView * rv)
5247 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5249 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5250 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5251 if (rv->region()->id () == (*rnote).first) {
5252 mrv->select_notes ((*rnote).second);
5253 selection->pending_midi_note_selection.erase(rnote);
5259 _summary->set_background_dirty ();
5263 Editor::region_view_removed ()
5265 _summary->set_background_dirty ();
5269 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5271 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5272 if ((*j)->stripable() == s) {
5281 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5283 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5284 if ((*j)->control() == c) {
5288 TimeAxisView::Children kids = (*j)->get_child_list ();
5290 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5291 if ((*k)->control() == c) {
5301 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5305 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5306 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5316 Editor::suspend_route_redisplay ()
5319 _routes->suspend_redisplay();
5324 Editor::resume_route_redisplay ()
5327 _routes->redisplay(); // queue redisplay
5328 _routes->resume_redisplay();
5333 Editor::add_vcas (VCAList& vlist)
5337 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5338 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5341 add_stripables (sl);
5345 Editor::add_routes (RouteList& rlist)
5349 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5353 add_stripables (sl);
5357 Editor::add_stripables (StripableList& sl)
5359 list<TimeAxisView*> new_views;
5360 boost::shared_ptr<VCA> v;
5361 boost::shared_ptr<Route> r;
5362 TrackViewList new_selection;
5363 bool from_scratch = (track_views.size() == 0);
5365 sl.sort (Stripable::Sorter());
5367 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5369 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5371 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5373 new_views.push_back (vtv);
5375 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5377 if (r->is_auditioner() || r->is_monitor()) {
5381 RouteTimeAxisView* rtv;
5382 DataType dt = r->input()->default_type();
5384 if (dt == ARDOUR::DataType::AUDIO) {
5385 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5387 } else if (dt == ARDOUR::DataType::MIDI) {
5388 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5391 throw unknown_type();
5394 new_views.push_back (rtv);
5395 track_views.push_back (rtv);
5396 new_selection.push_back (rtv);
5398 rtv->effective_gain_display ();
5400 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5401 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5405 if (new_views.size() > 0) {
5406 _routes->time_axis_views_added (new_views);
5407 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5410 /* note: !new_selection.empty() means that we got some routes rather
5414 if (!from_scratch && !new_selection.empty()) {
5415 selection->set (new_selection);
5416 begin_selection_op_history();
5419 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5420 show_editor_mixer (true);
5423 editor_list_button.set_sensitive (true);
5427 Editor::timeaxisview_deleted (TimeAxisView *tv)
5429 if (tv == entered_track) {
5433 if (_session && _session->deletion_in_progress()) {
5434 /* the situation is under control */
5438 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5440 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5442 _routes->route_removed (tv);
5444 TimeAxisView::Children c = tv->get_child_list ();
5445 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5446 if (entered_track == i->get()) {
5451 /* remove it from the list of track views */
5453 TrackViewList::iterator i;
5455 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5456 i = track_views.erase (i);
5459 /* update whatever the current mixer strip is displaying, if revelant */
5461 boost::shared_ptr<Route> route;
5464 route = rtav->route ();
5467 if (current_mixer_strip && current_mixer_strip->route() == route) {
5469 TimeAxisView* next_tv;
5471 if (track_views.empty()) {
5473 } else if (i == track_views.end()) {
5474 next_tv = track_views.front();
5479 // skip VCAs (cannot be selected, n/a in editor-mixer)
5480 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5481 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5482 next_tv = track_views.front();
5484 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5485 /* just in case: no master, only a VCA remains */
5491 set_selected_mixer_strip (*next_tv);
5493 /* make the editor mixer strip go away setting the
5494 * button to inactive (which also unticks the menu option)
5497 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5503 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5508 if (apply_to_selection) {
5509 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5511 TrackSelection::iterator j = i;
5514 hide_track_in_display (*i, false);
5519 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5521 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5522 // this will hide the mixer strip
5523 set_selected_mixer_strip (*tv);
5526 _routes->hide_track_in_display (*tv);
5531 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5536 _routes->show_track_in_display (*tv);
5537 if (move_into_view) {
5538 ensure_time_axis_view_is_visible (*tv, false);
5543 Editor::sync_track_view_list_and_routes ()
5545 track_views = TrackViewList (_routes->views ());
5547 _summary->set_background_dirty();
5548 _group_tabs->set_dirty ();
5550 return false; // do not call again (until needed)
5554 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5556 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5561 /** Find a StripableTimeAxisView by the ID of its stripable */
5562 StripableTimeAxisView*
5563 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5565 StripableTimeAxisView* v;
5567 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5568 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5569 if(v->stripable()->id() == id) {
5579 Editor::fit_route_group (RouteGroup *g)
5581 TrackViewList ts = axis_views_from_routes (g->route_list ());
5586 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5588 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5591 _session->cancel_audition ();
5595 if (_session->is_auditioning()) {
5596 _session->cancel_audition ();
5597 if (r == last_audition_region) {
5602 _session->audition_region (r);
5603 last_audition_region = r;
5608 Editor::hide_a_region (boost::shared_ptr<Region> r)
5610 r->set_hidden (true);
5614 Editor::show_a_region (boost::shared_ptr<Region> r)
5616 r->set_hidden (false);
5620 Editor::audition_region_from_region_list ()
5622 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5626 Editor::hide_region_from_region_list ()
5628 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5632 Editor::show_region_in_region_list ()
5634 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5638 Editor::step_edit_status_change (bool yn)
5641 start_step_editing ();
5643 stop_step_editing ();
5648 Editor::start_step_editing ()
5650 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5654 Editor::stop_step_editing ()
5656 step_edit_connection.disconnect ();
5660 Editor::check_step_edit ()
5662 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5663 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5665 mtv->check_step_edit ();
5669 return true; // do it again, till we stop
5673 Editor::scroll_press (Direction dir)
5675 ++_scroll_callbacks;
5677 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5678 /* delay the first auto-repeat */
5684 scroll_backward (1);
5692 scroll_up_one_track ();
5696 scroll_down_one_track ();
5700 /* do hacky auto-repeat */
5701 if (!_scroll_connection.connected ()) {
5703 _scroll_connection = Glib::signal_timeout().connect (
5704 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5707 _scroll_callbacks = 0;
5714 Editor::scroll_release ()
5716 _scroll_connection.disconnect ();
5719 /** Queue a change for the Editor viewport x origin to follow the playhead */
5721 Editor::reset_x_origin_to_follow_playhead ()
5723 framepos_t const frame = playhead_cursor->current_frame ();
5725 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5727 if (_session->transport_speed() < 0) {
5729 if (frame > (current_page_samples() / 2)) {
5730 center_screen (frame-(current_page_samples()/2));
5732 center_screen (current_page_samples()/2);
5739 if (frame < leftmost_frame) {
5741 if (_session->transport_rolling()) {
5742 /* rolling; end up with the playhead at the right of the page */
5743 l = frame - current_page_samples ();
5745 /* not rolling: end up with the playhead 1/4 of the way along the page */
5746 l = frame - current_page_samples() / 4;
5750 if (_session->transport_rolling()) {
5751 /* rolling: end up with the playhead on the left of the page */
5754 /* not rolling: end up with the playhead 3/4 of the way along the page */
5755 l = frame - 3 * current_page_samples() / 4;
5763 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5769 Editor::super_rapid_screen_update ()
5771 if (!_session || !_session->engine().running()) {
5775 /* METERING / MIXER STRIPS */
5777 /* update track meters, if required */
5778 if (contents().is_mapped() && meters_running) {
5779 RouteTimeAxisView* rtv;
5780 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5781 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5782 rtv->fast_update ();
5787 /* and any current mixer strip */
5788 if (current_mixer_strip) {
5789 current_mixer_strip->fast_update ();
5792 /* PLAYHEAD AND VIEWPORT */
5794 /* There are a few reasons why we might not update the playhead / viewport stuff:
5796 * 1. we don't update things when there's a pending locate request, otherwise
5797 * when the editor requests a locate there is a chance that this method
5798 * will move the playhead before the locate request is processed, causing
5800 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5801 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5803 if (_pending_locate_request || !_session->transport_rolling ()) {
5804 _last_update_time = 0;
5808 if (_dragging_playhead) {
5809 _last_update_time = 0;
5813 bool latent_locate = false;
5814 framepos_t frame = _session->audible_frame (&latent_locate);
5815 const int64_t now = g_get_monotonic_time ();
5818 if (_session->exporting ()) {
5819 /* freewheel/export may be faster or slower than transport_speed() / SR.
5820 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5822 _last_update_time = 0;
5825 if (_last_update_time > 0) {
5826 /* interpolate and smoothen playhead position */
5827 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6;
5828 framepos_t guess = playhead_cursor->current_frame () + rint (ds);
5829 err = frame - guess;
5831 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5832 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5835 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5837 err, _err_screen_engine);
5842 _err_screen_engine = 0;
5845 if (err > 8192 || latent_locate) {
5846 // in case of x-runs or freewheeling
5847 _last_update_time = 0;
5848 frame = _session->audible_frame ();
5850 _last_update_time = now;
5853 if (playhead_cursor->current_frame () == frame) {
5857 playhead_cursor->set_position (frame);
5859 if (_session->requested_return_frame() >= 0) {
5860 _last_update_time = 0;
5864 if (!_follow_playhead || pending_visual_change.being_handled) {
5865 /* We only do this if we aren't already
5866 * handling a visual change (ie if
5867 * pending_visual_change.being_handled is
5868 * false) so that these requests don't stack
5869 * up there are too many of them to handle in
5875 if (!_stationary_playhead) {
5876 reset_x_origin_to_follow_playhead ();
5878 framepos_t const frame = playhead_cursor->current_frame ();
5879 double target = ((double)frame - (double)current_page_samples() / 2.0);
5880 if (target <= 0.0) {
5883 // compare to EditorCursor::set_position()
5884 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5885 double const new_pos = sample_to_pixel_unrounded (target);
5886 if (rint (new_pos) != rint (old_pos)) {
5887 reset_x_origin (pixel_to_sample (new_pos));
5894 Editor::session_going_away ()
5896 _have_idled = false;
5898 _session_connections.drop_connections ();
5900 super_rapid_screen_update_connection.disconnect ();
5902 selection->clear ();
5903 cut_buffer->clear ();
5905 clicked_regionview = 0;
5906 clicked_axisview = 0;
5907 clicked_routeview = 0;
5908 entered_regionview = 0;
5910 _last_update_time = 0;
5913 playhead_cursor->hide ();
5915 /* rip everything out of the list displays */
5919 _route_groups->clear ();
5921 /* do this first so that deleting a track doesn't reset cms to null
5922 and thus cause a leak.
5925 if (current_mixer_strip) {
5926 if (current_mixer_strip->get_parent() != 0) {
5927 global_hpacker.remove (*current_mixer_strip);
5929 delete current_mixer_strip;
5930 current_mixer_strip = 0;
5933 /* delete all trackviews */
5935 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5938 track_views.clear ();
5940 nudge_clock->set_session (0);
5942 editor_list_button.set_active(false);
5943 editor_list_button.set_sensitive(false);
5945 /* clear tempo/meter rulers */
5946 remove_metric_marks ();
5948 clear_marker_display ();
5953 stop_step_editing ();
5957 /* get rid of any existing editor mixer strip */
5959 WindowTitle title(Glib::get_application_name());
5960 title += _("Editor");
5962 own_window()->set_title (title.get_string());
5965 SessionHandlePtr::session_going_away ();
5969 Editor::trigger_script (int i)
5971 LuaInstance::instance()-> call_action (i);
5975 Editor::show_editor_list (bool yn)
5978 _editor_list_vbox.show ();
5980 _editor_list_vbox.hide ();
5985 Editor::change_region_layering_order (bool from_context_menu)
5987 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5989 if (!clicked_routeview) {
5990 if (layering_order_editor) {
5991 layering_order_editor->hide ();
5996 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6002 boost::shared_ptr<Playlist> pl = track->playlist();
6008 if (layering_order_editor == 0) {
6009 layering_order_editor = new RegionLayeringOrderEditor (*this);
6012 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6013 layering_order_editor->maybe_present ();
6017 Editor::update_region_layering_order_editor ()
6019 if (layering_order_editor && layering_order_editor->is_visible ()) {
6020 change_region_layering_order (true);
6025 Editor::setup_fade_images ()
6027 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6028 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6029 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6030 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6031 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6033 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6034 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6035 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6036 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6037 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6041 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6043 Editor::action_menu_item (std::string const & name)
6045 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6048 return *manage (a->create_menu_item ());
6052 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6054 EventBox* b = manage (new EventBox);
6055 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6056 Label* l = manage (new Label (name));
6060 _the_notebook.append_page (widget, *b);
6064 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6066 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6067 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6070 if (ev->type == GDK_2BUTTON_PRESS) {
6072 /* double-click on a notebook tab shrinks or expands the notebook */
6074 if (_notebook_shrunk) {
6075 if (pre_notebook_shrink_pane_width) {
6076 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6078 _notebook_shrunk = false;
6080 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6082 /* this expands the LHS of the edit pane to cover the notebook
6083 PAGE but leaves the tabs visible.
6085 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6086 _notebook_shrunk = true;
6094 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6096 using namespace Menu_Helpers;
6098 MenuList& items = _control_point_context_menu.items ();
6101 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6102 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6103 if (!can_remove_control_point (item)) {
6104 items.back().set_sensitive (false);
6107 _control_point_context_menu.popup (event->button.button, event->button.time);
6111 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6113 using namespace Menu_Helpers;
6115 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6120 /* We need to get the selection here and pass it to the operations, since
6121 popping up the menu will cause a region leave event which clears
6122 entered_regionview. */
6124 MidiRegionView& mrv = note->region_view();
6125 const RegionSelection rs = get_regions_from_selection_and_entered ();
6126 const uint32_t sel_size = mrv.selection_size ();
6128 MenuList& items = _note_context_menu.items();
6132 items.push_back(MenuElem(_("Delete"),
6133 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6136 items.push_back(MenuElem(_("Edit..."),
6137 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6138 if (sel_size != 1) {
6139 items.back().set_sensitive (false);
6142 items.push_back(MenuElem(_("Transpose..."),
6143 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6146 items.push_back(MenuElem(_("Legatize"),
6147 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6149 items.back().set_sensitive (false);
6152 items.push_back(MenuElem(_("Quantize..."),
6153 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6155 items.push_back(MenuElem(_("Remove Overlap"),
6156 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6158 items.back().set_sensitive (false);
6161 items.push_back(MenuElem(_("Transform..."),
6162 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6164 _note_context_menu.popup (event->button.button, event->button.time);
6168 Editor::zoom_vertical_modifier_released()
6170 _stepping_axis_view = 0;
6174 Editor::ui_parameter_changed (string parameter)
6176 if (parameter == "icon-set") {
6177 while (!_cursor_stack.empty()) {
6178 _cursor_stack.pop_back();
6180 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6181 _cursor_stack.push_back(_cursors->grabber);
6182 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6183 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6185 } else if (parameter == "draggable-playhead") {
6186 if (_verbose_cursor) {
6187 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6193 Editor::use_own_window (bool and_fill_it)
6195 bool new_window = !own_window();
6197 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6199 if (win && new_window) {
6200 win->set_name ("EditorWindow");
6202 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6204 // win->signal_realize().connect (*this, &Editor::on_realize);
6205 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6206 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6207 win->set_data ("ardour-bindings", bindings);
6212 DisplaySuspender ds;
6213 contents().show_all ();
6215 /* XXX: this is a bit unfortunate; it would probably
6216 be nicer if we could just call show () above rather
6217 than needing the show_all ()
6220 /* re-hide stuff if necessary */
6221 editor_list_button_toggled ();
6222 parameter_changed ("show-summary");
6223 parameter_changed ("show-group-tabs");
6224 parameter_changed ("show-zoom-tools");
6226 /* now reset all audio_time_axis heights, because widgets might need
6232 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6233 tv = (static_cast<TimeAxisView*>(*i));
6234 tv->reset_height ();
6237 if (current_mixer_strip) {
6238 current_mixer_strip->hide_things ();
6239 current_mixer_strip->parameter_changed ("mixer-element-visibility");