2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
86 #include "control_protocol/control_protocol.h"
89 #include "analysis_window.h"
90 #include "ardour_spacer.h"
91 #include "audio_clock.h"
92 #include "audio_region_view.h"
93 #include "audio_streamview.h"
94 #include "audio_time_axis.h"
95 #include "automation_time_axis.h"
96 #include "bundle_manager.h"
97 #include "crossfade_edit.h"
101 #include "editor_cursors.h"
102 #include "editor_drag.h"
103 #include "editor_group_tabs.h"
104 #include "editor_locations.h"
105 #include "editor_regions.h"
106 #include "editor_route_groups.h"
107 #include "editor_routes.h"
108 #include "editor_snapshots.h"
109 #include "editor_summary.h"
110 #include "export_report.h"
111 #include "global_port_matrix.h"
112 #include "gui_object.h"
113 #include "gui_thread.h"
114 #include "keyboard.h"
115 #include "keyeditor.h"
116 #include "luainstance.h"
118 #include "midi_region_view.h"
119 #include "midi_time_axis.h"
120 #include "mixer_strip.h"
121 #include "mixer_ui.h"
122 #include "mouse_cursors.h"
123 #include "note_base.h"
124 #include "playlist_selector.h"
125 #include "public_editor.h"
126 #include "quantize_dialog.h"
127 #include "region_layering_order_editor.h"
128 #include "rgb_macros.h"
129 #include "rhythm_ferret.h"
130 #include "route_sorter.h"
131 #include "selection.h"
132 #include "simple_progress_dialog.h"
134 #include "tempo_lines.h"
135 #include "time_axis_view.h"
136 #include "time_info_box.h"
138 #include "tooltips.h"
139 #include "ui_config.h"
141 #include "vca_time_axis.h"
142 #include "verbose_cursor.h"
144 #include "pbd/i18n.h"
147 using namespace ARDOUR;
148 using namespace ARDOUR_UI_UTILS;
151 using namespace Glib;
152 using namespace Gtkmm2ext;
153 using namespace Editing;
155 using PBD::internationalize;
157 using Gtkmm2ext::Keyboard;
159 double Editor::timebar_height = 15.0;
161 static const gchar *_snap_type_strings[] = {
195 static const gchar *_snap_mode_strings[] = {
202 static const gchar *_edit_point_strings[] = {
209 static const gchar *_edit_mode_strings[] = {
217 static const gchar *_zoom_focus_strings[] = {
227 #ifdef USE_RUBBERBAND
228 static const gchar *_rb_opt_strings[] = {
231 N_("Balanced multitimbral mixture"),
232 N_("Unpitched percussion with stable notes"),
233 N_("Crisp monophonic instrumental"),
234 N_("Unpitched solo percussion"),
235 N_("Resample without preserving pitch"),
240 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
243 : PublicEditor (global_hpacker)
244 , editor_mixer_strip_width (Wide)
245 , constructed (false)
246 , _playlist_selector (0)
248 , no_save_visual (false)
250 , samples_per_pixel (2048)
251 , zoom_focus (ZoomFocusPlayhead)
252 , mouse_mode (MouseObject)
253 , pre_internal_snap_type (SnapToBeat)
254 , pre_internal_snap_mode (SnapOff)
255 , internal_snap_type (SnapToBeat)
256 , internal_snap_mode (SnapOff)
257 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
258 , _notebook_shrunk (false)
259 , location_marker_color (0)
260 , location_range_color (0)
261 , location_loop_color (0)
262 , location_punch_color (0)
263 , location_cd_marker_color (0)
265 , _show_marker_lines (false)
266 , clicked_axisview (0)
267 , clicked_routeview (0)
268 , clicked_regionview (0)
269 , clicked_selection (0)
270 , clicked_control_point (0)
271 , button_release_can_deselect (true)
272 , _mouse_changed_selection (false)
273 , region_edit_menu_split_item (0)
274 , region_edit_menu_split_multichannel_item (0)
275 , track_region_edit_playlist_menu (0)
276 , track_edit_playlist_submenu (0)
277 , track_selection_edit_playlist_submenu (0)
278 , _popup_region_menu_item (0)
280 , _track_canvas_viewport (0)
281 , within_track_canvas (false)
282 , _verbose_cursor (0)
286 , range_marker_group (0)
287 , transport_marker_group (0)
288 , cd_marker_group (0)
289 , _time_markers_group (0)
290 , hv_scroll_group (0)
292 , cursor_scroll_group (0)
293 , no_scroll_group (0)
294 , _trackview_group (0)
295 , _drag_motion_group (0)
296 , _canvas_drop_zone (0)
297 , no_ruler_shown_update (false)
298 , ruler_grabbed_widget (0)
300 , minsec_mark_interval (0)
301 , minsec_mark_modulo (0)
303 , timecode_mark_modulo (0)
304 , timecode_nmarks (0)
305 , _samples_ruler_interval (0)
308 , bbt_bar_helper_on (0)
309 , bbt_accent_modulo (0)
314 , visible_timebars (0)
315 , editor_ruler_menu (0)
319 , range_marker_bar (0)
320 , transport_marker_bar (0)
322 , minsec_label (_("Mins:Secs"))
323 , bbt_label (_("Bars:Beats"))
324 , timecode_label (_("Timecode"))
325 , samples_label (_("Samples"))
326 , tempo_label (_("Tempo"))
327 , meter_label (_("Meter"))
328 , mark_label (_("Location Markers"))
329 , range_mark_label (_("Range Markers"))
330 , transport_mark_label (_("Loop/Punch Ranges"))
331 , cd_mark_label (_("CD Markers"))
332 , videotl_label (_("Video Timeline"))
334 , playhead_cursor (0)
335 , edit_packer (4, 4, true)
336 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
337 , horizontal_adjustment (0.0, 0.0, 1e16)
338 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
339 , controls_layout (unused_adjustment, vertical_adjustment)
340 , _scroll_callbacks (0)
341 , _visible_canvas_width (0)
342 , _visible_canvas_height (0)
343 , _full_canvas_height (0)
344 , edit_controls_left_menu (0)
345 , edit_controls_right_menu (0)
346 , last_update_frame (0)
347 , cut_buffer_start (0)
348 , cut_buffer_length (0)
349 , button_bindings (0)
353 , current_interthread_info (0)
354 , analysis_window (0)
355 , select_new_marker (false)
357 , scrubbing_direction (0)
358 , scrub_reversals (0)
359 , scrub_reverse_distance (0)
360 , have_pending_keyboard_selection (false)
361 , pending_keyboard_selection_start (0)
362 , _snap_type (SnapToBeat)
363 , _snap_mode (SnapOff)
364 , snap_threshold (5.0)
365 , ignore_gui_changes (false)
366 , _drags (new DragManager (this))
368 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
369 , _dragging_playhead (false)
370 , _dragging_edit_point (false)
371 , _show_measures (true)
372 , _follow_playhead (true)
373 , _stationary_playhead (false)
376 , global_rect_group (0)
377 , time_line_group (0)
378 , tempo_marker_menu (0)
379 , meter_marker_menu (0)
381 , range_marker_menu (0)
382 , transport_marker_menu (0)
383 , new_transport_marker_menu (0)
385 , marker_menu_item (0)
386 , bbt_beat_subdivision (4)
387 , _visible_track_count (-1)
388 , toolbar_selection_clock_table (2,3)
389 , automation_mode_button (_("mode"))
390 , selection (new Selection (this))
391 , cut_buffer (new Selection (this))
392 , _selection_memento (new SelectionMemento())
393 , _all_region_actions_sensitized (false)
394 , _ignore_region_action (false)
395 , _last_region_menu_was_main (false)
396 , cd_marker_bar_drag_rect (0)
397 , range_bar_drag_rect (0)
398 , transport_bar_drag_rect (0)
399 , transport_bar_range_rect (0)
400 , transport_bar_preroll_rect (0)
401 , transport_bar_postroll_rect (0)
402 , transport_loop_range_rect (0)
403 , transport_punch_range_rect (0)
404 , transport_punchin_line (0)
405 , transport_punchout_line (0)
406 , transport_preroll_rect (0)
407 , transport_postroll_rect (0)
409 , rubberband_rect (0)
415 , autoscroll_horizontal_allowed (false)
416 , autoscroll_vertical_allowed (false)
418 , autoscroll_widget (0)
419 , show_gain_after_trim (false)
420 , selection_op_cmd_depth (0)
421 , selection_op_history_it (0)
422 , no_save_instant (false)
424 , current_mixer_strip (0)
425 , show_editor_mixer_when_tracks_arrive (false)
426 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
427 , current_stepping_trackview (0)
428 , last_track_height_step_timestamp (0)
430 , entered_regionview (0)
431 , clear_entered_track (false)
432 , _edit_point (EditAtMouse)
433 , meters_running (false)
435 , _have_idled (false)
436 , resize_idle_id (-1)
437 , _pending_resize_amount (0)
438 , _pending_resize_view (0)
439 , _pending_locate_request (false)
440 , _pending_initial_locate (false)
444 , layering_order_editor (0)
445 , _last_cut_copy_source_track (0)
446 , _region_selection_change_updates_region_list (true)
448 , _following_mixer_selection (false)
449 , _control_point_toggled_on_press (false)
450 , _stepping_axis_view (0)
451 , quantize_dialog (0)
452 , _main_menu_disabler (0)
453 , myactions (X_("editor"))
455 /* we are a singleton */
457 PublicEditor::_instance = this;
461 last_event_time.tv_sec = 0;
462 last_event_time.tv_usec = 0;
464 selection_op_history.clear();
467 snap_type_strings = I18N (_snap_type_strings);
468 snap_mode_strings = I18N (_snap_mode_strings);
469 zoom_focus_strings = I18N (_zoom_focus_strings);
470 edit_mode_strings = I18N (_edit_mode_strings);
471 edit_point_strings = I18N (_edit_point_strings);
472 #ifdef USE_RUBBERBAND
473 rb_opt_strings = I18N (_rb_opt_strings);
477 build_edit_mode_menu();
478 build_zoom_focus_menu();
479 build_track_count_menu();
480 build_snap_mode_menu();
481 build_snap_type_menu();
482 build_edit_point_menu();
484 location_marker_color = UIConfiguration::instance().color ("location marker");
485 location_range_color = UIConfiguration::instance().color ("location range");
486 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
487 location_loop_color = UIConfiguration::instance().color ("location loop");
488 location_punch_color = UIConfiguration::instance().color ("location punch");
490 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
492 TimeAxisView::setup_sizes ();
493 ArdourMarker::setup_sizes (timebar_height);
494 TempoCurve::setup_sizes (timebar_height);
496 bbt_label.set_name ("EditorRulerLabel");
497 bbt_label.set_size_request (-1, (int)timebar_height);
498 bbt_label.set_alignment (1.0, 0.5);
499 bbt_label.set_padding (5,0);
501 bbt_label.set_no_show_all();
502 minsec_label.set_name ("EditorRulerLabel");
503 minsec_label.set_size_request (-1, (int)timebar_height);
504 minsec_label.set_alignment (1.0, 0.5);
505 minsec_label.set_padding (5,0);
506 minsec_label.hide ();
507 minsec_label.set_no_show_all();
508 timecode_label.set_name ("EditorRulerLabel");
509 timecode_label.set_size_request (-1, (int)timebar_height);
510 timecode_label.set_alignment (1.0, 0.5);
511 timecode_label.set_padding (5,0);
512 timecode_label.hide ();
513 timecode_label.set_no_show_all();
514 samples_label.set_name ("EditorRulerLabel");
515 samples_label.set_size_request (-1, (int)timebar_height);
516 samples_label.set_alignment (1.0, 0.5);
517 samples_label.set_padding (5,0);
518 samples_label.hide ();
519 samples_label.set_no_show_all();
521 tempo_label.set_name ("EditorRulerLabel");
522 tempo_label.set_size_request (-1, (int)timebar_height);
523 tempo_label.set_alignment (1.0, 0.5);
524 tempo_label.set_padding (5,0);
526 tempo_label.set_no_show_all();
528 meter_label.set_name ("EditorRulerLabel");
529 meter_label.set_size_request (-1, (int)timebar_height);
530 meter_label.set_alignment (1.0, 0.5);
531 meter_label.set_padding (5,0);
533 meter_label.set_no_show_all();
535 if (Profile->get_trx()) {
536 mark_label.set_text (_("Markers"));
538 mark_label.set_name ("EditorRulerLabel");
539 mark_label.set_size_request (-1, (int)timebar_height);
540 mark_label.set_alignment (1.0, 0.5);
541 mark_label.set_padding (5,0);
543 mark_label.set_no_show_all();
545 cd_mark_label.set_name ("EditorRulerLabel");
546 cd_mark_label.set_size_request (-1, (int)timebar_height);
547 cd_mark_label.set_alignment (1.0, 0.5);
548 cd_mark_label.set_padding (5,0);
549 cd_mark_label.hide();
550 cd_mark_label.set_no_show_all();
552 videotl_bar_height = 4;
553 videotl_label.set_name ("EditorRulerLabel");
554 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
555 videotl_label.set_alignment (1.0, 0.5);
556 videotl_label.set_padding (5,0);
557 videotl_label.hide();
558 videotl_label.set_no_show_all();
560 range_mark_label.set_name ("EditorRulerLabel");
561 range_mark_label.set_size_request (-1, (int)timebar_height);
562 range_mark_label.set_alignment (1.0, 0.5);
563 range_mark_label.set_padding (5,0);
564 range_mark_label.hide();
565 range_mark_label.set_no_show_all();
567 transport_mark_label.set_name ("EditorRulerLabel");
568 transport_mark_label.set_size_request (-1, (int)timebar_height);
569 transport_mark_label.set_alignment (1.0, 0.5);
570 transport_mark_label.set_padding (5,0);
571 transport_mark_label.hide();
572 transport_mark_label.set_no_show_all();
574 initialize_canvas ();
576 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
578 _summary = new EditorSummary (this);
580 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
582 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
584 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
585 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
587 edit_controls_vbox.set_spacing (0);
588 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
589 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
591 HBox* h = manage (new HBox);
592 _group_tabs = new EditorGroupTabs (this);
593 if (!ARDOUR::Profile->get_trx()) {
594 h->pack_start (*_group_tabs, PACK_SHRINK);
596 h->pack_start (edit_controls_vbox);
597 controls_layout.add (*h);
599 controls_layout.set_name ("EditControlsBase");
600 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
601 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
602 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
604 _cursors = new MouseCursors;
605 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
606 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
608 /* Push default cursor to ever-present bottom of cursor stack. */
609 push_canvas_cursor(_cursors->grabber);
611 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
613 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
614 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
615 pad_line_1->set_outline_color (0xFF0000FF);
621 edit_packer.set_col_spacings (0);
622 edit_packer.set_row_spacings (0);
623 edit_packer.set_homogeneous (false);
624 edit_packer.set_border_width (0);
625 edit_packer.set_name ("EditorWindow");
627 time_bars_event_box.add (time_bars_vbox);
628 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
629 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
631 /* labels for the time bars */
632 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
634 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
636 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
638 bottom_hbox.set_border_width (2);
639 bottom_hbox.set_spacing (3);
641 _route_groups = new EditorRouteGroups (this);
642 _routes = new EditorRoutes (this);
643 _regions = new EditorRegions (this);
644 _snapshots = new EditorSnapshots (this);
645 _locations = new EditorLocations (this);
646 _time_info_box = new TimeInfoBox (true);
648 /* these are static location signals */
650 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
651 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
654 add_notebook_page (_("Regions"), _regions->widget ());
655 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
656 add_notebook_page (_("Snapshots"), _snapshots->widget ());
657 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
658 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
660 _the_notebook.set_show_tabs (true);
661 _the_notebook.set_scrollable (true);
662 _the_notebook.popup_disable ();
663 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
664 _the_notebook.show_all ();
666 _notebook_shrunk = false;
669 /* Pick up some settings we need to cache, early */
671 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
674 if (settings && (prop = settings->property ("notebook-shrunk"))) {
675 _notebook_shrunk = string_is_affirmative (prop->value ());
678 editor_summary_pane.set_check_divider_position (true);
679 editor_summary_pane.add (edit_packer);
681 Button* summary_arrows_left_left = manage (new Button);
682 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
683 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
684 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
686 Button* summary_arrows_left_right = manage (new Button);
687 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
688 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
689 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 VBox* summary_arrows_left = manage (new VBox);
692 summary_arrows_left->pack_start (*summary_arrows_left_left);
693 summary_arrows_left->pack_start (*summary_arrows_left_right);
695 Button* summary_arrows_right_up = manage (new Button);
696 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
697 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
698 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 Button* summary_arrows_right_down = manage (new Button);
701 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
702 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
703 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 VBox* summary_arrows_right = manage (new VBox);
706 summary_arrows_right->pack_start (*summary_arrows_right_up);
707 summary_arrows_right->pack_start (*summary_arrows_right_down);
709 Frame* summary_frame = manage (new Frame);
710 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
712 summary_frame->add (*_summary);
713 summary_frame->show ();
715 _summary_hbox.pack_start (*summary_arrows_left, false, false);
716 _summary_hbox.pack_start (*summary_frame, true, true);
717 _summary_hbox.pack_start (*summary_arrows_right, false, false);
719 if (!ARDOUR::Profile->get_trx()) {
720 editor_summary_pane.add (_summary_hbox);
723 edit_pane.set_check_divider_position (true);
724 edit_pane.add (editor_summary_pane);
725 if (!ARDOUR::Profile->get_trx()) {
726 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
727 _editor_list_vbox.pack_start (_the_notebook);
728 edit_pane.add (_editor_list_vbox);
729 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
732 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
733 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
740 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
741 /* initial allocation is 90% to canvas, 10% to notebook */
742 edit_pane.set_divider (0, 0.90);
744 edit_pane.set_divider (0, fract);
747 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
748 /* initial allocation is 90% to canvas, 10% to summary */
749 editor_summary_pane.set_divider (0, 0.90);
752 editor_summary_pane.set_divider (0, fract);
756 global_vpacker.set_spacing (2);
757 global_vpacker.set_border_width (0);
759 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
761 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
762 ebox->set_name("EditorWindow");
763 ebox->add (toolbar_hbox);
765 Gtk::EventBox* epane_box = manage (new Gtk::EventBox); //a themeable box
766 epane_box->set_name("EditorWindow");
767 epane_box->add (edit_pane);
769 Gtk::EventBox* epane_box2 = manage (new Gtk::EventBox); //a themeable box
770 epane_box2->set_name("EditorWindow");
771 epane_box2->add (global_vpacker);
773 global_vpacker.pack_start (*ebox, false, false);
774 global_vpacker.pack_start (*epane_box, true, true);
775 global_hpacker.pack_start (*epane_box2, true, true);
777 /* need to show the "contents" widget so that notebook will show if tab is switched to
780 global_hpacker.show ();
782 /* register actions now so that set_state() can find them and set toggles/checks etc */
789 _playlist_selector = new PlaylistSelector();
790 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
792 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
796 nudge_forward_button.set_name ("nudge button");
797 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
799 nudge_backward_button.set_name ("nudge button");
800 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
802 fade_context_menu.set_name ("ArdourContextMenu");
804 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
806 /* allow external control surfaces/protocols to do various things */
808 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
809 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
810 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
811 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
812 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
813 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
814 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
815 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
816 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
817 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
818 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
819 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
820 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
821 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
823 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
824 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
825 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
826 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
827 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
829 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
831 PresentationInfo::Change.connect (*this, invalidator (*this), boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
835 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
837 /* problematic: has to return a value and thus cannot be x-thread */
839 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
841 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
842 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
844 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
846 _ignore_region_action = false;
847 _last_region_menu_was_main = false;
848 _popup_region_menu_item = 0;
850 _show_marker_lines = false;
852 /* Button bindings */
854 button_bindings = new Bindings ("editor-mouse");
856 XMLNode* node = button_settings();
858 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
859 button_bindings->load_operation (**i);
865 /* grab current parameter state */
866 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
867 UIConfiguration::instance().map_parameters (pc);
869 setup_fade_images ();
871 LuaInstance::instance(); // instantiate
872 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
879 delete button_bindings;
881 delete _route_groups;
882 delete _track_canvas_viewport;
885 delete _verbose_cursor;
886 delete quantize_dialog;
892 delete _playlist_selector;
893 delete _time_info_box;
898 LuaInstance::destroy_instance ();
900 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
903 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
906 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
912 Editor::presentation_info_changed (PropertyChange const & what_changed)
914 if (what_changed.contains (Properties::selected)) {
915 track_selection_changed ();
920 Editor::button_settings () const
922 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
923 XMLNode* node = find_named_node (*settings, X_("Buttons"));
926 node = new XMLNode (X_("Buttons"));
933 Editor::get_smart_mode () const
935 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
939 Editor::catch_vanishing_regionview (RegionView *rv)
941 /* note: the selection will take care of the vanishing
942 audioregionview by itself.
945 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
949 if (clicked_regionview == rv) {
950 clicked_regionview = 0;
953 if (entered_regionview == rv) {
954 set_entered_regionview (0);
957 if (!_all_region_actions_sensitized) {
958 sensitize_all_region_actions (true);
963 Editor::set_entered_regionview (RegionView* rv)
965 if (rv == entered_regionview) {
969 if (entered_regionview) {
970 entered_regionview->exited ();
973 entered_regionview = rv;
975 if (entered_regionview != 0) {
976 entered_regionview->entered ();
979 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
980 /* This RegionView entry might have changed what region actions
981 are allowed, so sensitize them all in case a key is pressed.
983 sensitize_all_region_actions (true);
988 Editor::set_entered_track (TimeAxisView* tav)
991 entered_track->exited ();
997 entered_track->entered ();
1002 Editor::instant_save ()
1004 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
1009 _session->add_instant_xml(get_state());
1011 Config->add_instant_xml(get_state());
1016 Editor::control_vertical_zoom_in_all ()
1018 tav_zoom_smooth (false, true);
1022 Editor::control_vertical_zoom_out_all ()
1024 tav_zoom_smooth (true, true);
1028 Editor::control_vertical_zoom_in_selected ()
1030 tav_zoom_smooth (false, false);
1034 Editor::control_vertical_zoom_out_selected ()
1036 tav_zoom_smooth (true, false);
1040 Editor::control_view (uint32_t view)
1042 goto_visual_state (view);
1046 Editor::control_unselect ()
1048 selection->clear_tracks ();
1052 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1054 TimeAxisView* tav = axis_view_from_stripable (s);
1058 case Selection::Add:
1059 selection->add (tav);
1061 case Selection::Toggle:
1062 selection->toggle (tav);
1064 case Selection::Extend:
1066 case Selection::Set:
1067 selection->set (tav);
1071 selection->clear_tracks ();
1076 Editor::control_step_tracks_up ()
1078 scroll_tracks_up_line ();
1082 Editor::control_step_tracks_down ()
1084 scroll_tracks_down_line ();
1088 Editor::control_scroll (float fraction)
1090 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1096 double step = fraction * current_page_samples();
1099 _control_scroll_target is an optional<T>
1101 it acts like a pointer to an framepos_t, with
1102 a operator conversion to boolean to check
1103 that it has a value could possibly use
1104 playhead_cursor->current_frame to store the
1105 value and a boolean in the class to know
1106 when it's out of date
1109 if (!_control_scroll_target) {
1110 _control_scroll_target = _session->transport_frame();
1111 _dragging_playhead = true;
1114 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1115 *_control_scroll_target = 0;
1116 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1117 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1119 *_control_scroll_target += (framepos_t) trunc (step);
1122 /* move visuals, we'll catch up with it later */
1124 playhead_cursor->set_position (*_control_scroll_target);
1125 UpdateAllTransportClocks (*_control_scroll_target);
1127 if (*_control_scroll_target > (current_page_samples() / 2)) {
1128 /* try to center PH in window */
1129 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1135 Now we do a timeout to actually bring the session to the right place
1136 according to the playhead. This is to avoid reading disk buffers on every
1137 call to control_scroll, which is driven by ScrollTimeline and therefore
1138 probably by a control surface wheel which can generate lots of events.
1140 /* cancel the existing timeout */
1142 control_scroll_connection.disconnect ();
1144 /* add the next timeout */
1146 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1150 Editor::deferred_control_scroll (framepos_t /*target*/)
1152 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1153 // reset for next stream
1154 _control_scroll_target = boost::none;
1155 _dragging_playhead = false;
1160 Editor::access_action (std::string action_group, std::string action_item)
1166 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1169 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1177 Editor::on_realize ()
1181 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1182 start_lock_event_timing ();
1187 Editor::start_lock_event_timing ()
1189 /* check if we should lock the GUI every 30 seconds */
1191 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1195 Editor::generic_event_handler (GdkEvent* ev)
1198 case GDK_BUTTON_PRESS:
1199 case GDK_BUTTON_RELEASE:
1200 case GDK_MOTION_NOTIFY:
1202 case GDK_KEY_RELEASE:
1203 if (contents().is_mapped()) {
1204 gettimeofday (&last_event_time, 0);
1208 case GDK_LEAVE_NOTIFY:
1209 switch (ev->crossing.detail) {
1210 case GDK_NOTIFY_UNKNOWN:
1211 case GDK_NOTIFY_INFERIOR:
1212 case GDK_NOTIFY_ANCESTOR:
1214 case GDK_NOTIFY_VIRTUAL:
1215 case GDK_NOTIFY_NONLINEAR:
1216 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1217 /* leaving window, so reset focus, thus ending any and
1218 all text entry operations.
1220 ARDOUR_UI::instance()->reset_focus (&contents());
1233 Editor::lock_timeout_callback ()
1235 struct timeval now, delta;
1237 gettimeofday (&now, 0);
1239 timersub (&now, &last_event_time, &delta);
1241 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1243 /* don't call again. Returning false will effectively
1244 disconnect us from the timer callback.
1246 unlock() will call start_lock_event_timing() to get things
1256 Editor::map_position_change (framepos_t frame)
1258 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1260 if (_session == 0) {
1264 if (_follow_playhead) {
1265 center_screen (frame);
1268 playhead_cursor->set_position (frame);
1272 Editor::center_screen (framepos_t frame)
1274 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1276 /* if we're off the page, then scroll.
1279 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1280 center_screen_internal (frame, page);
1285 Editor::center_screen_internal (framepos_t frame, float page)
1290 frame -= (framepos_t) page;
1295 reset_x_origin (frame);
1300 Editor::update_title ()
1302 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1304 if (!own_window()) {
1309 bool dirty = _session->dirty();
1311 string session_name;
1313 if (_session->snap_name() != _session->name()) {
1314 session_name = _session->snap_name();
1316 session_name = _session->name();
1320 session_name = "*" + session_name;
1323 WindowTitle title(session_name);
1324 title += S_("Window|Editor");
1325 title += Glib::get_application_name();
1326 own_window()->set_title (title.get_string());
1328 /* ::session_going_away() will have taken care of it */
1333 Editor::set_session (Session *t)
1335 SessionHandlePtr::set_session (t);
1341 _playlist_selector->set_session (_session);
1342 nudge_clock->set_session (_session);
1343 _summary->set_session (_session);
1344 _group_tabs->set_session (_session);
1345 _route_groups->set_session (_session);
1346 _regions->set_session (_session);
1347 _snapshots->set_session (_session);
1348 _routes->set_session (_session);
1349 _locations->set_session (_session);
1350 _time_info_box->set_session (_session);
1352 if (rhythm_ferret) {
1353 rhythm_ferret->set_session (_session);
1356 if (analysis_window) {
1357 analysis_window->set_session (_session);
1361 sfbrowser->set_session (_session);
1364 compute_fixed_ruler_scale ();
1366 /* Make sure we have auto loop and auto punch ranges */
1368 Location* loc = _session->locations()->auto_loop_location();
1370 loc->set_name (_("Loop"));
1373 loc = _session->locations()->auto_punch_location();
1376 loc->set_name (_("Punch"));
1379 refresh_location_display ();
1381 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1382 the selected Marker; this needs the LocationMarker list to be available.
1384 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1385 set_state (*node, Stateful::loading_state_version);
1387 /* catch up with the playhead */
1389 _session->request_locate (playhead_cursor->current_frame ());
1390 _pending_initial_locate = true;
1394 /* These signals can all be emitted by a non-GUI thread. Therefore the
1395 handlers for them must not attempt to directly interact with the GUI,
1396 but use PBD::Signal<T>::connect() which accepts an event loop
1397 ("context") where the handler will be asked to run.
1400 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1401 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1402 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1403 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1404 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1405 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1406 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1407 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1408 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1409 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1410 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1411 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1412 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1413 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1414 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1416 playhead_cursor->show ();
1418 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1419 Config->map_parameters (pc);
1420 _session->config.map_parameters (pc);
1422 restore_ruler_visibility ();
1423 //tempo_map_changed (PropertyChange (0));
1424 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1426 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1427 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1430 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1431 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1434 switch (_snap_type) {
1435 case SnapToRegionStart:
1436 case SnapToRegionEnd:
1437 case SnapToRegionSync:
1438 case SnapToRegionBoundary:
1439 build_region_boundary_cache ();
1446 /* catch up on selection of stripables (other selection state is lost
1447 * when a session is closed
1452 _session->get_stripables (sl);
1453 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1454 if ((*s)->presentation_info().selected()) {
1455 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1457 tl.push_back (rtav);
1462 selection->set (tl);
1465 /* register for undo history */
1466 _session->register_with_memento_command_factory(id(), this);
1467 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1469 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1471 LuaInstance::instance()->set_session(_session);
1473 start_updating_meters ();
1477 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1479 if (a->get_name() == "RegionMenu") {
1480 /* When the main menu's region menu is opened, we setup the actions so that they look right
1481 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1482 so we resensitize all region actions when the entered regionview or the region selection
1483 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1484 happens after the region context menu is opened. So we set a flag here, too.
1488 sensitize_the_right_region_actions ();
1489 _last_region_menu_was_main = true;
1494 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1496 using namespace Menu_Helpers;
1498 void (Editor::*emf)(FadeShape);
1499 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1502 images = &_xfade_in_images;
1503 emf = &Editor::set_fade_in_shape;
1505 images = &_xfade_out_images;
1506 emf = &Editor::set_fade_out_shape;
1511 _("Linear (for highly correlated material)"),
1512 *(*images)[FadeLinear],
1513 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1517 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1521 _("Constant power"),
1522 *(*images)[FadeConstantPower],
1523 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1526 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1531 *(*images)[FadeSymmetric],
1532 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1536 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1541 *(*images)[FadeSlow],
1542 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1545 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1550 *(*images)[FadeFast],
1551 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1554 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1557 /** Pop up a context menu for when the user clicks on a start crossfade */
1559 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1561 using namespace Menu_Helpers;
1562 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1567 MenuList& items (xfade_in_context_menu.items());
1570 if (arv->audio_region()->fade_in_active()) {
1571 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1573 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1576 items.push_back (SeparatorElem());
1577 fill_xfade_menu (items, true);
1579 xfade_in_context_menu.popup (button, time);
1582 /** Pop up a context menu for when the user clicks on an end crossfade */
1584 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1586 using namespace Menu_Helpers;
1587 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1592 MenuList& items (xfade_out_context_menu.items());
1595 if (arv->audio_region()->fade_out_active()) {
1596 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1598 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1601 items.push_back (SeparatorElem());
1602 fill_xfade_menu (items, false);
1604 xfade_out_context_menu.popup (button, time);
1608 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1610 using namespace Menu_Helpers;
1611 Menu* (Editor::*build_menu_function)();
1614 switch (item_type) {
1616 case RegionViewName:
1617 case RegionViewNameHighlight:
1618 case LeftFrameHandle:
1619 case RightFrameHandle:
1620 if (with_selection) {
1621 build_menu_function = &Editor::build_track_selection_context_menu;
1623 build_menu_function = &Editor::build_track_region_context_menu;
1628 if (with_selection) {
1629 build_menu_function = &Editor::build_track_selection_context_menu;
1631 build_menu_function = &Editor::build_track_context_menu;
1636 if (clicked_routeview->track()) {
1637 build_menu_function = &Editor::build_track_context_menu;
1639 build_menu_function = &Editor::build_track_bus_context_menu;
1644 /* probably shouldn't happen but if it does, we don't care */
1648 menu = (this->*build_menu_function)();
1649 menu->set_name ("ArdourContextMenu");
1651 /* now handle specific situations */
1653 switch (item_type) {
1655 case RegionViewName:
1656 case RegionViewNameHighlight:
1657 case LeftFrameHandle:
1658 case RightFrameHandle:
1659 if (!with_selection) {
1660 if (region_edit_menu_split_item) {
1661 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1662 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1664 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1667 if (region_edit_menu_split_multichannel_item) {
1668 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1669 region_edit_menu_split_multichannel_item->set_sensitive (true);
1671 region_edit_menu_split_multichannel_item->set_sensitive (false);
1684 /* probably shouldn't happen but if it does, we don't care */
1688 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1690 /* Bounce to disk */
1692 using namespace Menu_Helpers;
1693 MenuList& edit_items = menu->items();
1695 edit_items.push_back (SeparatorElem());
1697 switch (clicked_routeview->audio_track()->freeze_state()) {
1698 case AudioTrack::NoFreeze:
1699 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1702 case AudioTrack::Frozen:
1703 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1706 case AudioTrack::UnFrozen:
1707 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1713 if (item_type == StreamItem && clicked_routeview) {
1714 clicked_routeview->build_underlay_menu(menu);
1717 /* When the region menu is opened, we setup the actions so that they look right
1720 sensitize_the_right_region_actions ();
1721 _last_region_menu_was_main = false;
1723 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1724 menu->popup (button, time);
1728 Editor::build_track_context_menu ()
1730 using namespace Menu_Helpers;
1732 MenuList& edit_items = track_context_menu.items();
1735 add_dstream_context_items (edit_items);
1736 return &track_context_menu;
1740 Editor::build_track_bus_context_menu ()
1742 using namespace Menu_Helpers;
1744 MenuList& edit_items = track_context_menu.items();
1747 add_bus_context_items (edit_items);
1748 return &track_context_menu;
1752 Editor::build_track_region_context_menu ()
1754 using namespace Menu_Helpers;
1755 MenuList& edit_items = track_region_context_menu.items();
1758 /* we've just cleared the track region context menu, so the menu that these
1759 two items were on will have disappeared; stop them dangling.
1761 region_edit_menu_split_item = 0;
1762 region_edit_menu_split_multichannel_item = 0;
1764 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1767 boost::shared_ptr<Track> tr;
1768 boost::shared_ptr<Playlist> pl;
1770 if ((tr = rtv->track())) {
1771 add_region_context_items (edit_items, tr);
1775 add_dstream_context_items (edit_items);
1777 return &track_region_context_menu;
1781 Editor::loudness_analyze_region_selection ()
1786 Selection& s (PublicEditor::instance ().get_selection ());
1787 RegionSelection ars = s.regions;
1788 ARDOUR::AnalysisGraph ag (_session);
1789 framecnt_t total_work = 0;
1791 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1792 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1796 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1799 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1800 total_work += arv->region ()->length ();
1803 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1805 ag.set_total_frames (total_work);
1806 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1809 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1810 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1814 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1818 ag.analyze_region (ar);
1821 if (!ag.canceled ()) {
1822 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1828 Editor::loudness_analyze_range_selection ()
1833 Selection& s (PublicEditor::instance ().get_selection ());
1834 TimeSelection ts = s.time;
1835 ARDOUR::AnalysisGraph ag (_session);
1836 framecnt_t total_work = 0;
1838 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1839 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1843 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1847 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1848 total_work += j->length ();
1852 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1854 ag.set_total_frames (total_work);
1855 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1858 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1859 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1863 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1867 ag.analyze_range (rui->route (), pl, ts);
1870 if (!ag.canceled ()) {
1871 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1877 Editor::spectral_analyze_region_selection ()
1879 if (analysis_window == 0) {
1880 analysis_window = new AnalysisWindow();
1883 analysis_window->set_session(_session);
1885 analysis_window->show_all();
1888 analysis_window->set_regionmode();
1889 analysis_window->analyze();
1891 analysis_window->present();
1895 Editor::spectral_analyze_range_selection()
1897 if (analysis_window == 0) {
1898 analysis_window = new AnalysisWindow();
1901 analysis_window->set_session(_session);
1903 analysis_window->show_all();
1906 analysis_window->set_rangemode();
1907 analysis_window->analyze();
1909 analysis_window->present();
1913 Editor::build_track_selection_context_menu ()
1915 using namespace Menu_Helpers;
1916 MenuList& edit_items = track_selection_context_menu.items();
1917 edit_items.clear ();
1919 add_selection_context_items (edit_items);
1920 // edit_items.push_back (SeparatorElem());
1921 // add_dstream_context_items (edit_items);
1923 return &track_selection_context_menu;
1927 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1929 using namespace Menu_Helpers;
1931 /* OK, stick the region submenu at the top of the list, and then add
1935 RegionSelection rs = get_regions_from_selection_and_entered ();
1937 string::size_type pos = 0;
1938 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1940 /* we have to hack up the region name because "_" has a special
1941 meaning for menu titles.
1944 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1945 menu_item_name.replace (pos, 1, "__");
1949 if (_popup_region_menu_item == 0) {
1950 _popup_region_menu_item = new MenuItem (menu_item_name);
1951 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1952 _popup_region_menu_item->show ();
1954 _popup_region_menu_item->set_label (menu_item_name);
1957 /* No latering allowed in later is higher layering model */
1958 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1959 if (act && Config->get_layer_model() == LaterHigher) {
1960 act->set_sensitive (false);
1962 act->set_sensitive (true);
1965 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1967 edit_items.push_back (*_popup_region_menu_item);
1968 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1969 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1971 edit_items.push_back (SeparatorElem());
1974 /** Add context menu items relevant to selection ranges.
1975 * @param edit_items List to add the items to.
1978 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1980 using namespace Menu_Helpers;
1982 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1983 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1985 edit_items.push_back (SeparatorElem());
1986 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1988 edit_items.push_back (SeparatorElem());
1989 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1990 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1992 edit_items.push_back (SeparatorElem());
1994 edit_items.push_back (
1996 _("Move Range Start to Previous Region Boundary"),
1997 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
2001 edit_items.push_back (
2003 _("Move Range Start to Next Region Boundary"),
2004 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
2008 edit_items.push_back (
2010 _("Move Range End to Previous Region Boundary"),
2011 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
2015 edit_items.push_back (
2017 _("Move Range End to Next Region Boundary"),
2018 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
2022 edit_items.push_back (SeparatorElem());
2023 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
2024 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
2026 edit_items.push_back (SeparatorElem());
2027 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2029 edit_items.push_back (SeparatorElem());
2030 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2031 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2032 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2034 edit_items.push_back (SeparatorElem());
2035 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2037 edit_items.push_back (SeparatorElem());
2038 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2039 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2041 edit_items.push_back (SeparatorElem());
2042 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2043 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2044 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2045 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2046 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2047 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2048 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2054 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2056 using namespace Menu_Helpers;
2060 Menu *play_menu = manage (new Menu);
2061 MenuList& play_items = play_menu->items();
2062 play_menu->set_name ("ArdourContextMenu");
2064 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2065 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2066 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2067 play_items.push_back (SeparatorElem());
2068 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2070 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2074 Menu *select_menu = manage (new Menu);
2075 MenuList& select_items = select_menu->items();
2076 select_menu->set_name ("ArdourContextMenu");
2078 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2079 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2080 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2081 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2082 select_items.push_back (SeparatorElem());
2083 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2084 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2085 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2086 select_items.push_back (SeparatorElem());
2087 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2088 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2089 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2090 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2091 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2092 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2093 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2095 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2099 Menu *cutnpaste_menu = manage (new Menu);
2100 MenuList& cutnpaste_items = cutnpaste_menu->items();
2101 cutnpaste_menu->set_name ("ArdourContextMenu");
2103 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2104 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2105 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2107 cutnpaste_items.push_back (SeparatorElem());
2109 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2110 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2112 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2114 /* Adding new material */
2116 edit_items.push_back (SeparatorElem());
2117 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2118 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2122 Menu *nudge_menu = manage (new Menu());
2123 MenuList& nudge_items = nudge_menu->items();
2124 nudge_menu->set_name ("ArdourContextMenu");
2126 edit_items.push_back (SeparatorElem());
2127 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2128 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2129 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2130 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2132 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2136 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2138 using namespace Menu_Helpers;
2142 Menu *play_menu = manage (new Menu);
2143 MenuList& play_items = play_menu->items();
2144 play_menu->set_name ("ArdourContextMenu");
2146 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2147 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2148 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2152 Menu *select_menu = manage (new Menu);
2153 MenuList& select_items = select_menu->items();
2154 select_menu->set_name ("ArdourContextMenu");
2156 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2157 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2158 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2159 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2160 select_items.push_back (SeparatorElem());
2161 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2162 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2163 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2164 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2166 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2170 Menu *cutnpaste_menu = manage (new Menu);
2171 MenuList& cutnpaste_items = cutnpaste_menu->items();
2172 cutnpaste_menu->set_name ("ArdourContextMenu");
2174 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2175 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2176 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2178 Menu *nudge_menu = manage (new Menu());
2179 MenuList& nudge_items = nudge_menu->items();
2180 nudge_menu->set_name ("ArdourContextMenu");
2182 edit_items.push_back (SeparatorElem());
2183 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2184 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2185 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2186 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2188 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2192 Editor::snap_type() const
2198 Editor::snap_musical() const
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:
2229 Editor::snap_mode() const
2235 Editor::set_snap_to (SnapType st)
2237 unsigned int snap_ind = (unsigned int)st;
2239 if (internal_editing()) {
2240 internal_snap_type = st;
2242 pre_internal_snap_type = st;
2247 if (snap_ind > snap_type_strings.size() - 1) {
2249 _snap_type = (SnapType)snap_ind;
2252 string str = snap_type_strings[snap_ind];
2254 if (str != snap_type_selector.get_text()) {
2255 snap_type_selector.set_text (str);
2260 switch (_snap_type) {
2261 case SnapToBeatDiv128:
2262 case SnapToBeatDiv64:
2263 case SnapToBeatDiv32:
2264 case SnapToBeatDiv28:
2265 case SnapToBeatDiv24:
2266 case SnapToBeatDiv20:
2267 case SnapToBeatDiv16:
2268 case SnapToBeatDiv14:
2269 case SnapToBeatDiv12:
2270 case SnapToBeatDiv10:
2271 case SnapToBeatDiv8:
2272 case SnapToBeatDiv7:
2273 case SnapToBeatDiv6:
2274 case SnapToBeatDiv5:
2275 case SnapToBeatDiv4:
2276 case SnapToBeatDiv3:
2277 case SnapToBeatDiv2: {
2278 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2279 update_tempo_based_rulers ();
2283 case SnapToRegionStart:
2284 case SnapToRegionEnd:
2285 case SnapToRegionSync:
2286 case SnapToRegionBoundary:
2287 build_region_boundary_cache ();
2295 redisplay_tempo (false);
2297 SnapChanged (); /* EMIT SIGNAL */
2301 Editor::set_snap_mode (SnapMode mode)
2303 string str = snap_mode_strings[(int)mode];
2305 if (internal_editing()) {
2306 internal_snap_mode = mode;
2308 pre_internal_snap_mode = mode;
2313 if (str != snap_mode_selector.get_text ()) {
2314 snap_mode_selector.set_text (str);
2321 Editor::set_edit_point_preference (EditPoint ep, bool force)
2323 bool changed = (_edit_point != ep);
2326 if (Profile->get_mixbus())
2327 if (ep == EditAtSelectedMarker)
2328 ep = EditAtPlayhead;
2330 string str = edit_point_strings[(int)ep];
2331 if (str != edit_point_selector.get_text ()) {
2332 edit_point_selector.set_text (str);
2335 update_all_enter_cursors();
2337 if (!force && !changed) {
2341 const char* action=NULL;
2343 switch (_edit_point) {
2344 case EditAtPlayhead:
2345 action = "edit-at-playhead";
2347 case EditAtSelectedMarker:
2348 action = "edit-at-marker";
2351 action = "edit-at-mouse";
2355 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2357 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2361 bool in_track_canvas;
2363 if (!mouse_frame (foo, in_track_canvas)) {
2364 in_track_canvas = false;
2367 reset_canvas_action_sensitivity (in_track_canvas);
2373 Editor::set_state (const XMLNode& node, int version)
2375 XMLProperty const * prop;
2377 PBD::Unwinder<bool> nsi (no_save_instant, true);
2380 Tabbable::set_state (node, version);
2382 if (_session && (prop = node.property ("playhead"))) {
2384 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2386 playhead_cursor->set_position (pos);
2388 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2389 playhead_cursor->set_position (0);
2392 playhead_cursor->set_position (0);
2395 if ((prop = node.property ("mixer-width"))) {
2396 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2399 if ((prop = node.property ("zoom-focus"))) {
2400 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2402 zoom_focus_selection_done (zoom_focus);
2405 if ((prop = node.property ("zoom"))) {
2406 /* older versions of ardour used floating point samples_per_pixel */
2407 double f = PBD::atof (prop->value());
2408 reset_zoom (llrintf (f));
2410 reset_zoom (samples_per_pixel);
2413 if ((prop = node.property ("visible-track-count"))) {
2414 set_visible_track_count (PBD::atoi (prop->value()));
2417 if ((prop = node.property ("snap-to"))) {
2418 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2419 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2421 set_snap_to (_snap_type);
2424 if ((prop = node.property ("snap-mode"))) {
2425 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2426 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2427 * snap_mode_selection_done() will only mark an already active item as active
2428 * which does not trigger set_text().
2430 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2432 set_snap_mode (_snap_mode);
2435 if ((prop = node.property ("internal-snap-to"))) {
2436 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2439 if ((prop = node.property ("internal-snap-mode"))) {
2440 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2443 if ((prop = node.property ("pre-internal-snap-to"))) {
2444 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2447 if ((prop = node.property ("pre-internal-snap-mode"))) {
2448 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2451 if ((prop = node.property ("mouse-mode"))) {
2452 MouseMode m = str2mousemode(prop->value());
2453 set_mouse_mode (m, true);
2455 set_mouse_mode (MouseObject, true);
2458 if ((prop = node.property ("left-frame")) != 0) {
2460 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2464 reset_x_origin (pos);
2468 if ((prop = node.property ("y-origin")) != 0) {
2469 reset_y_origin (atof (prop->value ()));
2472 if ((prop = node.property ("join-object-range"))) {
2473 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2474 bool yn = string_is_affirmative (prop->value());
2476 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2477 tact->set_active (!yn);
2478 tact->set_active (yn);
2480 set_mouse_mode(mouse_mode, true);
2483 if ((prop = node.property ("edit-point"))) {
2484 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2486 set_edit_point_preference (_edit_point);
2489 if ((prop = node.property ("show-measures"))) {
2490 bool yn = string_is_affirmative (prop->value());
2491 _show_measures = yn;
2494 if ((prop = node.property ("follow-playhead"))) {
2495 bool yn = string_is_affirmative (prop->value());
2496 set_follow_playhead (yn);
2499 if ((prop = node.property ("stationary-playhead"))) {
2500 bool yn = string_is_affirmative (prop->value());
2501 set_stationary_playhead (yn);
2504 if ((prop = node.property ("region-list-sort-type"))) {
2505 RegionListSortType st;
2506 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2509 if ((prop = node.property ("show-editor-mixer"))) {
2511 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2514 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2515 bool yn = string_is_affirmative (prop->value());
2517 /* do it twice to force the change */
2519 tact->set_active (!yn);
2520 tact->set_active (yn);
2523 if ((prop = node.property ("show-editor-list"))) {
2525 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2528 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2529 bool yn = string_is_affirmative (prop->value());
2531 /* do it twice to force the change */
2533 tact->set_active (!yn);
2534 tact->set_active (yn);
2537 if ((prop = node.property (X_("editor-list-page")))) {
2538 _the_notebook.set_current_page (atoi (prop->value ()));
2541 if ((prop = node.property (X_("show-marker-lines")))) {
2542 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2544 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2545 bool yn = string_is_affirmative (prop->value ());
2547 tact->set_active (!yn);
2548 tact->set_active (yn);
2551 XMLNodeList children = node.children ();
2552 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2553 selection->set_state (**i, Stateful::current_state_version);
2554 _regions->set_state (**i);
2555 _locations->set_state (**i);
2558 if ((prop = node.property ("maximised"))) {
2559 bool yn = string_is_affirmative (prop->value());
2560 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2562 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2563 bool fs = tact && tact->get_active();
2565 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2569 if ((prop = node.property ("nudge-clock-value"))) {
2571 sscanf (prop->value().c_str(), "%" PRId64, &f);
2572 nudge_clock->set (f);
2574 nudge_clock->set_mode (AudioClock::Timecode);
2575 nudge_clock->set (_session->frame_rate() * 5, true);
2580 * Not all properties may have been in XML, but
2581 * those that are linked to a private variable may need changing
2586 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2588 yn = _show_measures;
2589 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2590 /* do it twice to force the change */
2591 tact->set_active (!yn);
2592 tact->set_active (yn);
2595 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2596 yn = _follow_playhead;
2598 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2599 if (tact->get_active() != yn) {
2600 tact->set_active (yn);
2604 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2605 yn = _stationary_playhead;
2607 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2608 if (tact->get_active() != yn) {
2609 tact->set_active (yn);
2614 return LuaInstance::instance()->set_state(node);
2618 Editor::get_state ()
2620 XMLNode* node = new XMLNode (X_("Editor"));
2624 id().print (buf, sizeof (buf));
2625 node->add_property ("id", buf);
2627 node->add_child_nocopy (Tabbable::get_state());
2629 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2630 node->add_property("edit-horizontal-pane-pos", string(buf));
2631 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2632 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2633 node->add_property("edit-vertical-pane-pos", string(buf));
2635 maybe_add_mixer_strip_width (*node);
2637 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2639 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2640 node->add_property ("zoom", buf);
2641 node->add_property ("snap-to", enum_2_string (_snap_type));
2642 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2643 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2644 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2645 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2646 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2647 node->add_property ("edit-point", enum_2_string (_edit_point));
2648 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2649 node->add_property ("visible-track-count", buf);
2651 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2652 node->add_property ("playhead", buf);
2653 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2654 node->add_property ("left-frame", buf);
2655 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2656 node->add_property ("y-origin", buf);
2658 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2659 node->add_property ("maximised", _maximised ? "yes" : "no");
2660 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2661 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2662 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2663 node->add_property ("mouse-mode", enum2str(mouse_mode));
2664 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2666 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2668 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2669 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2672 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2674 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2675 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2678 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2679 node->add_property (X_("editor-list-page"), buf);
2681 if (button_bindings) {
2682 XMLNode* bb = new XMLNode (X_("Buttons"));
2683 button_bindings->save (*bb);
2684 node->add_child_nocopy (*bb);
2687 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2689 node->add_child_nocopy (selection->get_state ());
2690 node->add_child_nocopy (_regions->get_state ());
2692 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2693 node->add_property ("nudge-clock-value", buf);
2695 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2696 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2697 node->add_child_nocopy (_locations->get_state ());
2702 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2703 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2705 * @return pair: TimeAxisView that y is over, layer index.
2707 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2708 * in stacked or expanded region display mode, otherwise 0.
2710 std::pair<TimeAxisView *, double>
2711 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2713 if (!trackview_relative_offset) {
2714 y -= _trackview_group->canvas_origin().y;
2718 return std::make_pair ( (TimeAxisView *) 0, 0);
2721 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2723 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2730 return std::make_pair ( (TimeAxisView *) 0, 0);
2733 /** Snap a position to the grid, if appropriate, taking into account current
2734 * grid settings and also the state of any snap modifier keys that may be pressed.
2735 * @param start Position to snap.
2736 * @param event Event to get current key modifier information from, or 0.
2739 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2741 if (!_session || !event) {
2745 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2746 if (_snap_mode == SnapOff) {
2747 snap_to_internal (start, direction, for_mark);
2749 start.set (start.frame, 0);
2752 if (_snap_mode != SnapOff) {
2753 snap_to_internal (start, direction, for_mark);
2754 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2755 /* SnapOff, but we pressed the snap_delta modifier */
2756 snap_to_internal (start, direction, for_mark);
2758 start.set (start.frame, 0);
2764 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2766 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2767 start.set (start.frame, 0);
2771 snap_to_internal (start, direction, for_mark, ensure_snap);
2775 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2777 framepos_t start = pos.frame;
2778 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2779 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2781 switch (_snap_type) {
2782 case SnapToTimecodeFrame:
2783 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2784 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2785 /* start is already on a whole timecode frame, do nothing */
2786 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2787 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2789 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2793 case SnapToTimecodeSeconds:
2794 if (_session->config.get_timecode_offset_negative()) {
2795 start += _session->config.get_timecode_offset ();
2797 start -= _session->config.get_timecode_offset ();
2799 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2800 (start % one_timecode_second == 0)) {
2801 /* start is already on a whole second, do nothing */
2802 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2803 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2805 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2808 if (_session->config.get_timecode_offset_negative()) {
2809 start -= _session->config.get_timecode_offset ();
2811 start += _session->config.get_timecode_offset ();
2815 case SnapToTimecodeMinutes:
2816 if (_session->config.get_timecode_offset_negative()) {
2817 start += _session->config.get_timecode_offset ();
2819 start -= _session->config.get_timecode_offset ();
2821 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2822 (start % one_timecode_minute == 0)) {
2823 /* start is already on a whole minute, do nothing */
2824 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2825 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2827 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2829 if (_session->config.get_timecode_offset_negative()) {
2830 start -= _session->config.get_timecode_offset ();
2832 start += _session->config.get_timecode_offset ();
2836 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2837 abort(); /*NOTREACHED*/
2844 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2846 const framepos_t one_second = _session->frame_rate();
2847 const framepos_t one_minute = _session->frame_rate() * 60;
2848 framepos_t presnap = start.frame;
2852 switch (_snap_type) {
2853 case SnapToTimecodeFrame:
2854 case SnapToTimecodeSeconds:
2855 case SnapToTimecodeMinutes:
2856 return timecode_snap_to_internal (start, direction, for_mark);
2859 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2860 start.frame % (one_second/75) == 0) {
2861 /* start is already on a whole CD frame, do nothing */
2862 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2863 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2865 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2868 start.set (start.frame, 0);
2873 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2874 start.frame % one_second == 0) {
2875 /* start is already on a whole second, do nothing */
2876 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2877 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2879 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2882 start.set (start.frame, 0);
2887 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2888 start.frame % one_minute == 0) {
2889 /* start is already on a whole minute, do nothing */
2890 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2891 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2893 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2896 start.set (start.frame, 0);
2901 start = _session->tempo_map().round_to_bar (start.frame, direction);
2905 start = _session->tempo_map().round_to_beat (start.frame, direction);
2908 case SnapToBeatDiv128:
2909 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2911 case SnapToBeatDiv64:
2912 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2914 case SnapToBeatDiv32:
2915 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2917 case SnapToBeatDiv28:
2918 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2920 case SnapToBeatDiv24:
2921 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2923 case SnapToBeatDiv20:
2924 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2926 case SnapToBeatDiv16:
2927 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2929 case SnapToBeatDiv14:
2930 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2932 case SnapToBeatDiv12:
2933 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2935 case SnapToBeatDiv10:
2936 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2938 case SnapToBeatDiv8:
2939 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2941 case SnapToBeatDiv7:
2942 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2944 case SnapToBeatDiv6:
2945 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2947 case SnapToBeatDiv5:
2948 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2950 case SnapToBeatDiv4:
2951 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2953 case SnapToBeatDiv3:
2954 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2956 case SnapToBeatDiv2:
2957 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2965 _session->locations()->marks_either_side (start.frame, before, after);
2967 if (before == max_framepos && after == max_framepos) {
2968 /* No marks to snap to, so just don't snap */
2970 } else if (before == max_framepos) {
2971 start.frame = after;
2972 } else if (after == max_framepos) {
2973 start.frame = before;
2974 } else if (before != max_framepos && after != max_framepos) {
2975 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2976 start.frame = after;
2977 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2978 start.frame = before;
2979 else if (direction == 0 ) {
2980 if ((start.frame - before) < (after - start.frame)) {
2981 start.frame = before;
2983 start.frame = after;
2988 start.set (start.frame, 0);
2992 case SnapToRegionStart:
2993 case SnapToRegionEnd:
2994 case SnapToRegionSync:
2995 case SnapToRegionBoundary:
2996 if (!region_boundary_cache.empty()) {
2998 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2999 vector<framepos_t>::iterator next = region_boundary_cache.end ();
3001 if (direction > 0) {
3002 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
3004 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
3007 if (next != region_boundary_cache.begin ()) {
3012 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
3013 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
3015 if (start.frame > (p + n) / 2) {
3022 start.set (start.frame, 0);
3027 switch (_snap_mode) {
3037 if (presnap > start.frame) {
3038 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
3039 start.set (presnap, 0);
3042 } else if (presnap < start.frame) {
3043 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
3044 start.set (presnap, 0);
3049 /* handled at entry */
3056 Editor::setup_toolbar ()
3058 HBox* mode_box = manage(new HBox);
3059 mode_box->set_border_width (2);
3060 mode_box->set_spacing(2);
3062 HBox* mouse_mode_box = manage (new HBox);
3063 HBox* mouse_mode_hbox = manage (new HBox);
3064 VBox* mouse_mode_vbox = manage (new VBox);
3065 Alignment* mouse_mode_align = manage (new Alignment);
3067 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3068 mouse_mode_size_group->add_widget (smart_mode_button);
3069 mouse_mode_size_group->add_widget (mouse_move_button);
3070 mouse_mode_size_group->add_widget (mouse_cut_button);
3071 mouse_mode_size_group->add_widget (mouse_select_button);
3072 mouse_mode_size_group->add_widget (mouse_timefx_button);
3073 mouse_mode_size_group->add_widget (mouse_audition_button);
3074 mouse_mode_size_group->add_widget (mouse_draw_button);
3075 mouse_mode_size_group->add_widget (mouse_content_button);
3077 if (!Profile->get_mixbus()) {
3078 mouse_mode_size_group->add_widget (zoom_in_button);
3079 mouse_mode_size_group->add_widget (zoom_out_button);
3080 mouse_mode_size_group->add_widget (zoom_out_full_button);
3081 mouse_mode_size_group->add_widget (zoom_focus_selector);
3082 mouse_mode_size_group->add_widget (tav_shrink_button);
3083 mouse_mode_size_group->add_widget (tav_expand_button);
3085 mouse_mode_size_group->add_widget (zoom_preset_selector);
3086 mouse_mode_size_group->add_widget (visible_tracks_selector);
3089 mouse_mode_size_group->add_widget (snap_type_selector);
3090 mouse_mode_size_group->add_widget (snap_mode_selector);
3092 mouse_mode_size_group->add_widget (edit_point_selector);
3093 mouse_mode_size_group->add_widget (edit_mode_selector);
3095 mouse_mode_size_group->add_widget (*nudge_clock);
3096 mouse_mode_size_group->add_widget (nudge_forward_button);
3097 mouse_mode_size_group->add_widget (nudge_backward_button);
3099 mouse_mode_hbox->set_spacing (2);
3101 if (!ARDOUR::Profile->get_trx()) {
3102 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3105 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3106 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3108 if (!ARDOUR::Profile->get_mixbus()) {
3109 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3112 if (!ARDOUR::Profile->get_trx()) {
3113 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3114 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3115 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3116 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3119 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3121 mouse_mode_align->add (*mouse_mode_vbox);
3122 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3124 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3126 edit_mode_selector.set_name ("mouse mode button");
3128 if (!ARDOUR::Profile->get_trx()) {
3129 mode_box->pack_start (edit_mode_selector, false, false);
3132 mode_box->pack_start (*mouse_mode_box, false, false);
3136 _zoom_box.set_spacing (2);
3137 _zoom_box.set_border_width (2);
3141 zoom_preset_selector.set_name ("zoom button");
3142 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3144 zoom_in_button.set_name ("zoom button");
3145 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3146 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3147 zoom_in_button.set_related_action (act);
3149 zoom_out_button.set_name ("zoom button");
3150 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3151 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3152 zoom_out_button.set_related_action (act);
3154 zoom_out_full_button.set_name ("zoom button");
3155 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3156 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3157 zoom_out_full_button.set_related_action (act);
3159 zoom_focus_selector.set_name ("zoom button");
3161 if (ARDOUR::Profile->get_mixbus()) {
3162 _zoom_box.pack_start (zoom_preset_selector, false, false);
3163 } else if (ARDOUR::Profile->get_trx()) {
3164 mode_box->pack_start (zoom_out_button, false, false);
3165 mode_box->pack_start (zoom_in_button, false, false);
3167 _zoom_box.pack_start (zoom_out_button, false, false);
3168 _zoom_box.pack_start (zoom_in_button, false, false);
3169 _zoom_box.pack_start (zoom_out_full_button, false, false);
3170 _zoom_box.pack_start (zoom_focus_selector, false, false);
3173 /* Track zoom buttons */
3174 _track_box.set_spacing (2);
3175 _track_box.set_border_width (2);
3177 visible_tracks_selector.set_name ("zoom button");
3178 if (Profile->get_mixbus()) {
3179 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3181 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3184 tav_expand_button.set_name ("zoom button");
3185 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3186 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3187 tav_expand_button.set_related_action (act);
3189 tav_shrink_button.set_name ("zoom button");
3190 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3191 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3192 tav_shrink_button.set_related_action (act);
3194 if (ARDOUR::Profile->get_mixbus()) {
3195 _track_box.pack_start (visible_tracks_selector);
3196 } else if (ARDOUR::Profile->get_trx()) {
3197 _track_box.pack_start (tav_shrink_button);
3198 _track_box.pack_start (tav_expand_button);
3200 _track_box.pack_start (visible_tracks_selector);
3201 _track_box.pack_start (tav_shrink_button);
3202 _track_box.pack_start (tav_expand_button);
3205 snap_box.set_spacing (2);
3206 snap_box.set_border_width (2);
3208 snap_type_selector.set_name ("mouse mode button");
3210 snap_mode_selector.set_name ("mouse mode button");
3212 edit_point_selector.set_name ("mouse mode button");
3214 snap_box.pack_start (snap_mode_selector, false, false);
3215 snap_box.pack_start (snap_type_selector, false, false);
3218 HBox *ep_box = manage (new HBox);
3219 ep_box->set_spacing (2);
3220 ep_box->set_border_width (2);
3222 ep_box->pack_start (edit_point_selector, false, false);
3226 HBox *nudge_box = manage (new HBox);
3227 nudge_box->set_spacing (2);
3228 nudge_box->set_border_width (2);
3230 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3231 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3233 nudge_box->pack_start (nudge_backward_button, false, false);
3234 nudge_box->pack_start (nudge_forward_button, false, false);
3235 nudge_box->pack_start (*nudge_clock, false, false);
3238 /* Pack everything in... */
3240 toolbar_hbox.set_spacing (2);
3241 toolbar_hbox.set_border_width (2);
3243 toolbar_hbox.pack_start (*mode_box, false, false);
3245 if (!ARDOUR::Profile->get_trx()) {
3247 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3249 toolbar_hbox.pack_start (_zoom_box, false, false);
3251 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3253 toolbar_hbox.pack_start (_track_box, false, false);
3255 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3257 toolbar_hbox.pack_start (snap_box, false, false);
3259 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3261 toolbar_hbox.pack_start (*ep_box, false, false);
3263 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3265 toolbar_hbox.pack_start (*nudge_box, false, false);
3268 toolbar_hbox.show_all ();
3272 Editor::build_edit_point_menu ()
3274 using namespace Menu_Helpers;
3276 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3277 if(!Profile->get_mixbus())
3278 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3279 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3281 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3285 Editor::build_edit_mode_menu ()
3287 using namespace Menu_Helpers;
3289 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3290 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3291 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3292 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3294 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3298 Editor::build_snap_mode_menu ()
3300 using namespace Menu_Helpers;
3302 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3303 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3304 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3306 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3310 Editor::build_snap_type_menu ()
3312 using namespace Menu_Helpers;
3314 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3315 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3316 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3317 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3318 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3319 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3320 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3321 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3322 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3323 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3324 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3325 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3326 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3327 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3328 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3329 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3330 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3331 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3332 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3333 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3334 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3335 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3336 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3337 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3338 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3339 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3340 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3341 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3342 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3343 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3345 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3350 Editor::setup_tooltips ()
3352 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3353 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3354 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3355 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3356 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3357 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3358 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3359 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3360 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3361 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3362 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3363 set_tooltip (zoom_in_button, _("Zoom In"));
3364 set_tooltip (zoom_out_button, _("Zoom Out"));
3365 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3366 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3367 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3368 set_tooltip (tav_expand_button, _("Expand Tracks"));
3369 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3370 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3371 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3372 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3373 set_tooltip (edit_point_selector, _("Edit Point"));
3374 set_tooltip (edit_mode_selector, _("Edit Mode"));
3375 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3379 Editor::convert_drop_to_paths (
3380 vector<string>& paths,
3381 const RefPtr<Gdk::DragContext>& /*context*/,
3384 const SelectionData& data,
3388 if (_session == 0) {
3392 vector<string> uris = data.get_uris();
3396 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3397 are actually URI lists. So do it by hand.
3400 if (data.get_target() != "text/plain") {
3404 /* Parse the "uri-list" format that Nautilus provides,
3405 where each pathname is delimited by \r\n.
3407 THERE MAY BE NO NULL TERMINATING CHAR!!!
3410 string txt = data.get_text();
3414 p = (char *) malloc (txt.length() + 1);
3415 txt.copy (p, txt.length(), 0);
3416 p[txt.length()] = '\0';
3422 while (g_ascii_isspace (*p))
3426 while (*q && (*q != '\n') && (*q != '\r')) {
3433 while (q > p && g_ascii_isspace (*q))
3438 uris.push_back (string (p, q - p + 1));
3442 p = strchr (p, '\n');
3454 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3455 if ((*i).substr (0,7) == "file://") {
3456 paths.push_back (Glib::filename_from_uri (*i));
3464 Editor::new_tempo_section ()
3469 Editor::map_transport_state ()
3471 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3473 if (_session && _session->transport_stopped()) {
3474 have_pending_keyboard_selection = false;
3477 update_loop_range_view ();
3483 Editor::begin_selection_op_history ()
3485 selection_op_cmd_depth = 0;
3486 selection_op_history_it = 0;
3488 while(!selection_op_history.empty()) {
3489 delete selection_op_history.front();
3490 selection_op_history.pop_front();
3493 selection_undo_action->set_sensitive (false);
3494 selection_redo_action->set_sensitive (false);
3495 selection_op_history.push_front (&_selection_memento->get_state ());
3499 Editor::begin_reversible_selection_op (string name)
3502 //cerr << name << endl;
3503 /* begin/commit pairs can be nested */
3504 selection_op_cmd_depth++;
3509 Editor::commit_reversible_selection_op ()
3512 if (selection_op_cmd_depth == 1) {
3514 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3516 The user has undone some selection ops and then made a new one,
3517 making anything earlier in the list invalid.
3520 list<XMLNode *>::iterator it = selection_op_history.begin();
3521 list<XMLNode *>::iterator e_it = it;
3522 advance (e_it, selection_op_history_it);
3524 for ( ; it != e_it; ++it) {
3527 selection_op_history.erase (selection_op_history.begin(), e_it);
3530 selection_op_history.push_front (&_selection_memento->get_state ());
3531 selection_op_history_it = 0;
3533 selection_undo_action->set_sensitive (true);
3534 selection_redo_action->set_sensitive (false);
3537 if (selection_op_cmd_depth > 0) {
3538 selection_op_cmd_depth--;
3544 Editor::undo_selection_op ()
3547 selection_op_history_it++;
3549 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3550 if (n == selection_op_history_it) {
3551 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3552 selection_redo_action->set_sensitive (true);
3556 /* is there an earlier entry? */
3557 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3558 selection_undo_action->set_sensitive (false);
3564 Editor::redo_selection_op ()
3567 if (selection_op_history_it > 0) {
3568 selection_op_history_it--;
3571 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3572 if (n == selection_op_history_it) {
3573 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3574 selection_undo_action->set_sensitive (true);
3579 if (selection_op_history_it == 0) {
3580 selection_redo_action->set_sensitive (false);
3586 Editor::begin_reversible_command (string name)
3589 before.push_back (&_selection_memento->get_state ());
3590 _session->begin_reversible_command (name);
3595 Editor::begin_reversible_command (GQuark q)
3598 before.push_back (&_selection_memento->get_state ());
3599 _session->begin_reversible_command (q);
3604 Editor::abort_reversible_command ()
3607 while(!before.empty()) {
3608 delete before.front();
3611 _session->abort_reversible_command ();
3616 Editor::commit_reversible_command ()
3619 if (before.size() == 1) {
3620 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3621 redo_action->set_sensitive(false);
3622 undo_action->set_sensitive(true);
3623 begin_selection_op_history ();
3626 if (before.empty()) {
3627 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3632 _session->commit_reversible_command ();
3637 Editor::history_changed ()
3641 if (undo_action && _session) {
3642 if (_session->undo_depth() == 0) {
3643 label = S_("Command|Undo");
3645 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3647 undo_action->property_label() = label;
3650 if (redo_action && _session) {
3651 if (_session->redo_depth() == 0) {
3653 redo_action->set_sensitive (false);
3655 label = string_compose(_("Redo (%1)"), _session->next_redo());
3656 redo_action->set_sensitive (true);
3658 redo_action->property_label() = label;
3663 Editor::duplicate_range (bool with_dialog)
3667 RegionSelection rs = get_regions_from_selection_and_entered ();
3669 if ( selection->time.length() == 0 && rs.empty()) {
3675 ArdourDialog win (_("Duplicate"));
3676 Label label (_("Number of duplications:"));
3677 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3678 SpinButton spinner (adjustment, 0.0, 1);
3681 win.get_vbox()->set_spacing (12);
3682 win.get_vbox()->pack_start (hbox);
3683 hbox.set_border_width (6);
3684 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3686 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3687 place, visually. so do this by hand.
3690 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3691 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3692 spinner.grab_focus();
3698 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3699 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3700 win.set_default_response (RESPONSE_ACCEPT);
3702 spinner.grab_focus ();
3704 switch (win.run ()) {
3705 case RESPONSE_ACCEPT:
3711 times = adjustment.get_value();
3714 if ((current_mouse_mode() == Editing::MouseRange)) {
3715 if (selection->time.length()) {
3716 duplicate_selection (times);
3718 } else if (get_smart_mode()) {
3719 if (selection->time.length()) {
3720 duplicate_selection (times);
3722 duplicate_some_regions (rs, times);
3724 duplicate_some_regions (rs, times);
3729 Editor::set_edit_mode (EditMode m)
3731 Config->set_edit_mode (m);
3735 Editor::cycle_edit_mode ()
3737 switch (Config->get_edit_mode()) {
3739 Config->set_edit_mode (Ripple);
3743 Config->set_edit_mode (Lock);
3746 Config->set_edit_mode (Slide);
3752 Editor::edit_mode_selection_done ( EditMode m )
3754 Config->set_edit_mode ( m );
3758 Editor::snap_type_selection_done (SnapType snaptype)
3760 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3762 ract->set_active ();
3767 Editor::snap_mode_selection_done (SnapMode mode)
3769 RefPtr<RadioAction> ract = snap_mode_action (mode);
3772 ract->set_active (true);
3777 Editor::cycle_edit_point (bool with_marker)
3779 if(Profile->get_mixbus())
3780 with_marker = false;
3782 switch (_edit_point) {
3784 set_edit_point_preference (EditAtPlayhead);
3786 case EditAtPlayhead:
3788 set_edit_point_preference (EditAtSelectedMarker);
3790 set_edit_point_preference (EditAtMouse);
3793 case EditAtSelectedMarker:
3794 set_edit_point_preference (EditAtMouse);
3800 Editor::edit_point_selection_done (EditPoint ep)
3802 set_edit_point_preference ( ep );
3806 Editor::build_zoom_focus_menu ()
3808 using namespace Menu_Helpers;
3810 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3811 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3812 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3813 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3814 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3815 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3817 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3821 Editor::zoom_focus_selection_done ( ZoomFocus f )
3823 RefPtr<RadioAction> ract = zoom_focus_action (f);
3825 ract->set_active ();
3830 Editor::build_track_count_menu ()
3832 using namespace Menu_Helpers;
3834 if (!Profile->get_mixbus()) {
3835 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3836 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3837 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3838 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3839 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3840 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3841 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3842 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3843 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3844 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3845 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3846 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3847 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3849 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3850 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3851 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3852 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3853 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3854 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3855 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3856 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3857 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3858 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3860 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3861 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3862 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3863 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3864 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3865 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3866 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3867 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3868 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3869 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3870 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3875 Editor::set_zoom_preset (int64_t ms)
3878 temporal_zoom_session();
3882 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3883 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3887 Editor::set_visible_track_count (int32_t n)
3889 _visible_track_count = n;
3891 /* if the canvas hasn't really been allocated any size yet, just
3892 record the desired number of visible tracks and return. when canvas
3893 allocation happens, we will get called again and then we can do the
3897 if (_visible_canvas_height <= 1) {
3903 DisplaySuspender ds;
3905 if (_visible_track_count > 0) {
3906 h = trackviews_height() / _visible_track_count;
3907 std::ostringstream s;
3908 s << _visible_track_count;
3910 } else if (_visible_track_count == 0) {
3912 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3913 if ((*i)->marked_for_display()) {
3917 h = trackviews_height() / n;
3920 /* negative value means that the visible track count has
3921 been overridden by explicit track height changes.
3923 visible_tracks_selector.set_text (X_("*"));
3927 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3928 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3931 if (str != visible_tracks_selector.get_text()) {
3932 visible_tracks_selector.set_text (str);
3937 Editor::override_visible_track_count ()
3939 _visible_track_count = -1;
3940 visible_tracks_selector.set_text ( _("*") );
3944 Editor::edit_controls_button_release (GdkEventButton* ev)
3946 if (Keyboard::is_context_menu_event (ev)) {
3947 ARDOUR_UI::instance()->add_route ();
3948 } else if (ev->button == 1) {
3949 selection->clear_tracks ();
3956 Editor::mouse_select_button_release (GdkEventButton* ev)
3958 /* this handles just right-clicks */
3960 if (ev->button != 3) {
3968 Editor::set_zoom_focus (ZoomFocus f)
3970 string str = zoom_focus_strings[(int)f];
3972 if (str != zoom_focus_selector.get_text()) {
3973 zoom_focus_selector.set_text (str);
3976 if (zoom_focus != f) {
3983 Editor::cycle_zoom_focus ()
3985 switch (zoom_focus) {
3987 set_zoom_focus (ZoomFocusRight);
3989 case ZoomFocusRight:
3990 set_zoom_focus (ZoomFocusCenter);
3992 case ZoomFocusCenter:
3993 set_zoom_focus (ZoomFocusPlayhead);
3995 case ZoomFocusPlayhead:
3996 set_zoom_focus (ZoomFocusMouse);
3998 case ZoomFocusMouse:
3999 set_zoom_focus (ZoomFocusEdit);
4002 set_zoom_focus (ZoomFocusLeft);
4008 Editor::set_show_measures (bool yn)
4010 if (_show_measures != yn) {
4013 if ((_show_measures = yn) == true) {
4015 tempo_lines->show();
4018 std::vector<TempoMap::BBTPoint> grid;
4019 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
4020 draw_measures (grid);
4028 Editor::toggle_follow_playhead ()
4030 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4032 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4033 set_follow_playhead (tact->get_active());
4037 /** @param yn true to follow playhead, otherwise false.
4038 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4041 Editor::set_follow_playhead (bool yn, bool catch_up)
4043 if (_follow_playhead != yn) {
4044 if ((_follow_playhead = yn) == true && catch_up) {
4046 reset_x_origin_to_follow_playhead ();
4053 Editor::toggle_stationary_playhead ()
4055 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4057 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4058 set_stationary_playhead (tact->get_active());
4063 Editor::set_stationary_playhead (bool yn)
4065 if (_stationary_playhead != yn) {
4066 if ((_stationary_playhead = yn) == true) {
4068 // FIXME need a 3.0 equivalent of this 2.X call
4069 // update_current_screen ();
4076 Editor::playlist_selector () const
4078 return *_playlist_selector;
4082 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4084 if (paste_count == 0) {
4085 /* don't bother calculating an offset that will be zero anyway */
4089 /* calculate basic unsnapped multi-paste offset */
4090 framecnt_t offset = paste_count * duration;
4092 /* snap offset so pos + offset is aligned to the grid */
4093 MusicFrame offset_pos (pos + offset, 0);
4094 snap_to(offset_pos, RoundUpMaybe);
4095 offset = offset_pos.frame - pos;
4101 Editor::get_grid_beat_divisions(framepos_t position)
4103 switch (_snap_type) {
4104 case SnapToBeatDiv128: return 128;
4105 case SnapToBeatDiv64: return 64;
4106 case SnapToBeatDiv32: return 32;
4107 case SnapToBeatDiv28: return 28;
4108 case SnapToBeatDiv24: return 24;
4109 case SnapToBeatDiv20: return 20;
4110 case SnapToBeatDiv16: return 16;
4111 case SnapToBeatDiv14: return 14;
4112 case SnapToBeatDiv12: return 12;
4113 case SnapToBeatDiv10: return 10;
4114 case SnapToBeatDiv8: return 8;
4115 case SnapToBeatDiv7: return 7;
4116 case SnapToBeatDiv6: return 6;
4117 case SnapToBeatDiv5: return 5;
4118 case SnapToBeatDiv4: return 4;
4119 case SnapToBeatDiv3: return 3;
4120 case SnapToBeatDiv2: return 2;
4126 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4127 if the grid is non-musical, returns 0.
4128 if the grid is snapped to bars, returns -1.
4129 @param event_state the current keyboard modifier mask.
4132 Editor::get_grid_music_divisions (uint32_t event_state)
4134 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4138 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4142 switch (_snap_type) {
4143 case SnapToBeatDiv128: return 128;
4144 case SnapToBeatDiv64: return 64;
4145 case SnapToBeatDiv32: return 32;
4146 case SnapToBeatDiv28: return 28;
4147 case SnapToBeatDiv24: return 24;
4148 case SnapToBeatDiv20: return 20;
4149 case SnapToBeatDiv16: return 16;
4150 case SnapToBeatDiv14: return 14;
4151 case SnapToBeatDiv12: return 12;
4152 case SnapToBeatDiv10: return 10;
4153 case SnapToBeatDiv8: return 8;
4154 case SnapToBeatDiv7: return 7;
4155 case SnapToBeatDiv6: return 6;
4156 case SnapToBeatDiv5: return 5;
4157 case SnapToBeatDiv4: return 4;
4158 case SnapToBeatDiv3: return 3;
4159 case SnapToBeatDiv2: return 2;
4160 case SnapToBeat: return 1;
4161 case SnapToBar : return -1;
4168 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4172 const unsigned divisions = get_grid_beat_divisions(position);
4174 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4177 switch (_snap_type) {
4179 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4182 const Meter& m = _session->tempo_map().meter_at_frame (position);
4183 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4191 return Evoral::Beats();
4195 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4199 ret = nudge_clock->current_duration (pos);
4200 next = ret + 1; /* XXXX fix me */
4206 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4208 ArdourDialog dialog (_("Playlist Deletion"));
4209 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4210 "If it is kept, its audio files will not be cleaned.\n"
4211 "If it is deleted, audio files used by it alone will be cleaned."),
4214 dialog.set_position (WIN_POS_CENTER);
4215 dialog.get_vbox()->pack_start (label);
4219 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4220 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4221 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4222 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4223 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4225 // by default gtk uses the left most button
4226 keep->grab_focus ();
4228 switch (dialog.run ()) {
4230 /* keep this and all remaining ones */
4235 /* delete this and all others */
4239 case RESPONSE_ACCEPT:
4240 /* delete the playlist */
4244 case RESPONSE_REJECT:
4245 /* keep the playlist */
4257 Editor::audio_region_selection_covers (framepos_t where)
4259 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4260 if ((*a)->region()->covers (where)) {
4269 Editor::prepare_for_cleanup ()
4271 cut_buffer->clear_regions ();
4272 cut_buffer->clear_playlists ();
4274 selection->clear_regions ();
4275 selection->clear_playlists ();
4277 _regions->suspend_redisplay ();
4281 Editor::finish_cleanup ()
4283 _regions->resume_redisplay ();
4287 Editor::transport_loop_location()
4290 return _session->locations()->auto_loop_location();
4297 Editor::transport_punch_location()
4300 return _session->locations()->auto_punch_location();
4307 Editor::control_layout_scroll (GdkEventScroll* ev)
4309 /* Just forward to the normal canvas scroll method. The coordinate
4310 systems are different but since the canvas is always larger than the
4311 track headers, and aligned with the trackview area, this will work.
4313 In the not too distant future this layout is going away anyway and
4314 headers will be on the canvas.
4316 return canvas_scroll_event (ev, false);
4320 Editor::session_state_saved (string)
4323 _snapshots->redisplay ();
4327 Editor::maximise_editing_space ()
4333 Gtk::Window* toplevel = current_toplevel();
4336 toplevel->fullscreen ();
4342 Editor::restore_editing_space ()
4348 Gtk::Window* toplevel = current_toplevel();
4351 toplevel->unfullscreen();
4357 * Make new playlists for a given track and also any others that belong
4358 * to the same active route group with the `select' property.
4363 Editor::new_playlists (TimeAxisView* v)
4365 begin_reversible_command (_("new playlists"));
4366 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4367 _session->playlists->get (playlists);
4368 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4369 commit_reversible_command ();
4373 * Use a copy of the current playlist for a given track and also any others that belong
4374 * to the same active route group with the `select' property.
4379 Editor::copy_playlists (TimeAxisView* v)
4381 begin_reversible_command (_("copy playlists"));
4382 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4383 _session->playlists->get (playlists);
4384 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4385 commit_reversible_command ();
4388 /** Clear the current playlist for a given track and also any others that belong
4389 * to the same active route group with the `select' property.
4394 Editor::clear_playlists (TimeAxisView* v)
4396 begin_reversible_command (_("clear playlists"));
4397 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4398 _session->playlists->get (playlists);
4399 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4400 commit_reversible_command ();
4404 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4406 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4410 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4412 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4416 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4418 atv.clear_playlist ();
4422 Editor::get_y_origin () const
4424 return vertical_adjustment.get_value ();
4427 /** Queue up a change to the viewport x origin.
4428 * @param frame New x origin.
4431 Editor::reset_x_origin (framepos_t frame)
4433 pending_visual_change.add (VisualChange::TimeOrigin);
4434 pending_visual_change.time_origin = frame;
4435 ensure_visual_change_idle_handler ();
4439 Editor::reset_y_origin (double y)
4441 pending_visual_change.add (VisualChange::YOrigin);
4442 pending_visual_change.y_origin = y;
4443 ensure_visual_change_idle_handler ();
4447 Editor::reset_zoom (framecnt_t spp)
4449 if (spp == samples_per_pixel) {
4453 pending_visual_change.add (VisualChange::ZoomLevel);
4454 pending_visual_change.samples_per_pixel = spp;
4455 ensure_visual_change_idle_handler ();
4459 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4461 reset_x_origin (frame);
4464 if (!no_save_visual) {
4465 undo_visual_stack.push_back (current_visual_state(false));
4469 Editor::VisualState::VisualState (bool with_tracks)
4470 : gui_state (with_tracks ? new GUIObjectState : 0)
4474 Editor::VisualState::~VisualState ()
4479 Editor::VisualState*
4480 Editor::current_visual_state (bool with_tracks)
4482 VisualState* vs = new VisualState (with_tracks);
4483 vs->y_position = vertical_adjustment.get_value();
4484 vs->samples_per_pixel = samples_per_pixel;
4485 vs->leftmost_frame = leftmost_frame;
4486 vs->zoom_focus = zoom_focus;
4489 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4496 Editor::undo_visual_state ()
4498 if (undo_visual_stack.empty()) {
4502 VisualState* vs = undo_visual_stack.back();
4503 undo_visual_stack.pop_back();
4506 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4509 use_visual_state (*vs);
4514 Editor::redo_visual_state ()
4516 if (redo_visual_stack.empty()) {
4520 VisualState* vs = redo_visual_stack.back();
4521 redo_visual_stack.pop_back();
4523 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4524 // why do we check here?
4525 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4528 use_visual_state (*vs);
4533 Editor::swap_visual_state ()
4535 if (undo_visual_stack.empty()) {
4536 redo_visual_state ();
4538 undo_visual_state ();
4543 Editor::use_visual_state (VisualState& vs)
4545 PBD::Unwinder<bool> nsv (no_save_visual, true);
4546 DisplaySuspender ds;
4548 vertical_adjustment.set_value (vs.y_position);
4550 set_zoom_focus (vs.zoom_focus);
4551 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4554 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4556 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4557 (*i)->clear_property_cache();
4558 (*i)->reset_visual_state ();
4562 _routes->update_visibility ();
4565 /** This is the core function that controls the zoom level of the canvas. It is called
4566 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4567 * @param spp new number of samples per pixel
4570 Editor::set_samples_per_pixel (framecnt_t spp)
4576 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4577 const framecnt_t lots_of_pixels = 4000;
4579 /* if the zoom level is greater than what you'd get trying to display 3
4580 * days of audio on a really big screen, then it's too big.
4583 if (spp * lots_of_pixels > three_days) {
4587 samples_per_pixel = spp;
4590 tempo_lines->tempo_map_changed();
4593 bool const showing_time_selection = selection->time.length() > 0;
4595 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4596 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4597 (*i)->reshow_selection (selection->time);
4601 ZoomChanged (); /* EMIT_SIGNAL */
4603 ArdourCanvas::GtkCanvasViewport* c;
4605 c = get_track_canvas();
4607 c->canvas()->zoomed ();
4610 if (playhead_cursor) {
4611 playhead_cursor->set_position (playhead_cursor->current_frame ());
4614 refresh_location_display();
4615 _summary->set_overlays_dirty ();
4617 update_marker_labels ();
4623 Editor::playhead_cursor_sample () const
4625 return playhead_cursor->current_frame();
4629 Editor::queue_visual_videotimeline_update ()
4632 * pending_visual_change.add (VisualChange::VideoTimeline);
4633 * or maybe even more specific: which videotimeline-image
4634 * currently it calls update_video_timeline() to update
4635 * _all outdated_ images on the video-timeline.
4636 * see 'exposeimg()' in video_image_frame.cc
4638 ensure_visual_change_idle_handler ();
4642 Editor::ensure_visual_change_idle_handler ()
4644 if (pending_visual_change.idle_handler_id < 0) {
4645 // see comment in add_to_idle_resize above.
4646 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4647 pending_visual_change.being_handled = false;
4652 Editor::_idle_visual_changer (void* arg)
4654 return static_cast<Editor*>(arg)->idle_visual_changer ();
4658 Editor::idle_visual_changer ()
4660 /* set_horizontal_position() below (and maybe other calls) call
4661 gtk_main_iteration(), so it's possible that a signal will be handled
4662 half-way through this method. If this signal wants an
4663 idle_visual_changer we must schedule another one after this one, so
4664 mark the idle_handler_id as -1 here to allow that. Also make a note
4665 that we are doing the visual change, so that changes in response to
4666 super-rapid-screen-update can be dropped if we are still processing
4670 pending_visual_change.idle_handler_id = -1;
4671 pending_visual_change.being_handled = true;
4673 VisualChange vc = pending_visual_change;
4675 pending_visual_change.pending = (VisualChange::Type) 0;
4677 visual_changer (vc);
4679 pending_visual_change.being_handled = false;
4681 return 0; /* this is always a one-shot call */
4685 Editor::visual_changer (const VisualChange& vc)
4687 double const last_time_origin = horizontal_position ();
4689 if (vc.pending & VisualChange::ZoomLevel) {
4690 set_samples_per_pixel (vc.samples_per_pixel);
4692 compute_fixed_ruler_scale ();
4694 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4695 update_tempo_based_rulers ();
4697 update_video_timeline();
4700 if (vc.pending & VisualChange::TimeOrigin) {
4701 set_horizontal_position (vc.time_origin / samples_per_pixel);
4704 if (vc.pending & VisualChange::YOrigin) {
4705 vertical_adjustment.set_value (vc.y_origin);
4708 if (last_time_origin == horizontal_position ()) {
4709 /* changed signal not emitted */
4710 update_fixed_rulers ();
4711 redisplay_tempo (true);
4714 if (!(vc.pending & VisualChange::ZoomLevel)) {
4715 update_video_timeline();
4718 _summary->set_overlays_dirty ();
4721 struct EditorOrderTimeAxisSorter {
4722 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4723 return a->order () < b->order ();
4728 Editor::sort_track_selection (TrackViewList& sel)
4730 EditorOrderTimeAxisSorter cmp;
4735 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4738 framepos_t where = 0;
4739 EditPoint ep = _edit_point;
4741 if (Profile->get_mixbus()) {
4742 if (ep == EditAtSelectedMarker) {
4743 ep = EditAtPlayhead;
4747 if (from_outside_canvas && (ep == EditAtMouse)) {
4748 ep = EditAtPlayhead;
4749 } else if (from_context_menu && (ep == EditAtMouse)) {
4750 return canvas_event_sample (&context_click_event, 0, 0);
4753 if (entered_marker) {
4754 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4755 return entered_marker->position();
4758 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4759 ep = EditAtSelectedMarker;
4762 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4763 ep = EditAtPlayhead;
4766 MusicFrame snap_mf (0, 0);
4769 case EditAtPlayhead:
4770 if (_dragging_playhead) {
4771 where = *_control_scroll_target;
4773 where = _session->audible_frame();
4775 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4778 case EditAtSelectedMarker:
4779 if (!selection->markers.empty()) {
4781 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4784 where = loc->start();
4788 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4796 if (!mouse_frame (where, ignored)) {
4797 /* XXX not right but what can we do ? */
4800 snap_mf.frame = where;
4802 where = snap_mf.frame;
4803 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4811 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4813 if (!_session) return;
4815 begin_reversible_command (cmd);
4819 if ((tll = transport_loop_location()) == 0) {
4820 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4821 XMLNode &before = _session->locations()->get_state();
4822 _session->locations()->add (loc, true);
4823 _session->set_auto_loop_location (loc);
4824 XMLNode &after = _session->locations()->get_state();
4825 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4827 XMLNode &before = tll->get_state();
4828 tll->set_hidden (false, this);
4829 tll->set (start, end);
4830 XMLNode &after = tll->get_state();
4831 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4834 commit_reversible_command ();
4838 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4840 if (!_session) return;
4842 begin_reversible_command (cmd);
4846 if ((tpl = transport_punch_location()) == 0) {
4847 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4848 XMLNode &before = _session->locations()->get_state();
4849 _session->locations()->add (loc, true);
4850 _session->set_auto_punch_location (loc);
4851 XMLNode &after = _session->locations()->get_state();
4852 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4854 XMLNode &before = tpl->get_state();
4855 tpl->set_hidden (false, this);
4856 tpl->set (start, end);
4857 XMLNode &after = tpl->get_state();
4858 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4861 commit_reversible_command ();
4864 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4865 * @param rs List to which found regions are added.
4866 * @param where Time to look at.
4867 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4870 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4872 const TrackViewList* tracks;
4875 tracks = &track_views;
4880 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4882 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4885 boost::shared_ptr<Track> tr;
4886 boost::shared_ptr<Playlist> pl;
4888 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4890 boost::shared_ptr<RegionList> regions = pl->regions_at (
4891 (framepos_t) floor ( (double) where * tr->speed()));
4893 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4894 RegionView* rv = rtv->view()->find_view (*i);
4905 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4907 const TrackViewList* tracks;
4910 tracks = &track_views;
4915 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4916 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4918 boost::shared_ptr<Track> tr;
4919 boost::shared_ptr<Playlist> pl;
4921 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4923 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4924 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4926 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4928 RegionView* rv = rtv->view()->find_view (*i);
4939 /** Get regions using the following method:
4941 * Make a region list using:
4942 * (a) any selected regions
4943 * (b) the intersection of any selected tracks and the edit point(*)
4944 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4946 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4948 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4952 Editor::get_regions_from_selection_and_edit_point ()
4954 RegionSelection regions;
4956 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4957 regions.add (entered_regionview);
4959 regions = selection->regions;
4962 if ( regions.empty() ) {
4963 TrackViewList tracks = selection->tracks;
4965 if (!tracks.empty()) {
4966 /* no region selected or entered, but some selected tracks:
4967 * act on all regions on the selected tracks at the edit point
4969 framepos_t const where = get_preferred_edit_position ();
4970 get_regions_at(regions, where, tracks);
4977 /** Get regions using the following method:
4979 * Make a region list using:
4980 * (a) any selected regions
4981 * (b) the intersection of any selected tracks and the edit point(*)
4982 * (c) if neither exists, then whatever region is under the mouse
4984 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4986 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4989 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4991 RegionSelection regions;
4993 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4994 regions.add (entered_regionview);
4996 regions = selection->regions;
4999 if ( regions.empty() ) {
5000 TrackViewList tracks = selection->tracks;
5002 if (!tracks.empty()) {
5003 /* no region selected or entered, but some selected tracks:
5004 * act on all regions on the selected tracks at the edit point
5006 get_regions_at(regions, pos, tracks);
5013 /** Start with regions that are selected, or the entered regionview if none are selected.
5014 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5015 * of the regions that we started with.
5019 Editor::get_regions_from_selection_and_entered () const
5021 RegionSelection regions = selection->regions;
5023 if (regions.empty() && entered_regionview) {
5024 regions.add (entered_regionview);
5031 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5033 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5034 RouteTimeAxisView* rtav;
5036 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5037 boost::shared_ptr<Playlist> pl;
5038 std::vector<boost::shared_ptr<Region> > results;
5039 boost::shared_ptr<Track> tr;
5041 if ((tr = rtav->track()) == 0) {
5046 if ((pl = (tr->playlist())) != 0) {
5047 boost::shared_ptr<Region> r = pl->region_by_id (id);
5049 RegionView* rv = rtav->view()->find_view (r);
5051 regions.push_back (rv);
5060 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5063 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5064 MidiTimeAxisView* mtav;
5066 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5068 mtav->get_per_region_note_selection (selection);
5075 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5077 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5079 RouteTimeAxisView* tatv;
5081 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5083 boost::shared_ptr<Playlist> pl;
5084 vector<boost::shared_ptr<Region> > results;
5086 boost::shared_ptr<Track> tr;
5088 if ((tr = tatv->track()) == 0) {
5093 if ((pl = (tr->playlist())) != 0) {
5094 if (src_comparison) {
5095 pl->get_source_equivalent_regions (region, results);
5097 pl->get_region_list_equivalent_regions (region, results);
5101 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5102 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5103 regions.push_back (marv);
5112 Editor::show_rhythm_ferret ()
5114 if (rhythm_ferret == 0) {
5115 rhythm_ferret = new RhythmFerret(*this);
5118 rhythm_ferret->set_session (_session);
5119 rhythm_ferret->show ();
5120 rhythm_ferret->present ();
5124 Editor::first_idle ()
5126 MessageDialog* dialog = 0;
5128 if (track_views.size() > 1) {
5129 Timers::TimerSuspender t;
5130 dialog = new MessageDialog (
5131 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5135 ARDOUR_UI::instance()->flush_pending (60);
5138 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5142 // first idle adds route children (automation tracks), so we need to redisplay here
5143 _routes->redisplay ();
5147 if (_session->undo_depth() == 0) {
5148 undo_action->set_sensitive(false);
5150 redo_action->set_sensitive(false);
5151 begin_selection_op_history ();
5157 Editor::_idle_resize (gpointer arg)
5159 return ((Editor*)arg)->idle_resize ();
5163 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5165 if (resize_idle_id < 0) {
5166 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5167 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5168 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5170 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5171 _pending_resize_amount = 0;
5174 /* make a note of the smallest resulting height, so that we can clamp the
5175 lower limit at TimeAxisView::hSmall */
5177 int32_t min_resulting = INT32_MAX;
5179 _pending_resize_amount += h;
5180 _pending_resize_view = view;
5182 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5184 if (selection->tracks.contains (_pending_resize_view)) {
5185 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5186 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5190 if (min_resulting < 0) {
5195 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5196 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5200 /** Handle pending resizing of tracks */
5202 Editor::idle_resize ()
5204 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5206 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5207 selection->tracks.contains (_pending_resize_view)) {
5209 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5210 if (*i != _pending_resize_view) {
5211 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5216 _pending_resize_amount = 0;
5217 _group_tabs->set_dirty ();
5218 resize_idle_id = -1;
5226 ENSURE_GUI_THREAD (*this, &Editor::located);
5229 playhead_cursor->set_position (_session->audible_frame ());
5230 if (_follow_playhead && !_pending_initial_locate) {
5231 reset_x_origin_to_follow_playhead ();
5235 _pending_locate_request = false;
5236 _pending_initial_locate = false;
5240 Editor::region_view_added (RegionView * rv)
5242 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5243 if (rv->region ()->id () == (*pr)) {
5244 selection->add (rv);
5245 selection->regions.pending.erase (pr);
5250 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5252 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5253 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5254 if (rv->region()->id () == (*rnote).first) {
5255 mrv->select_notes ((*rnote).second);
5256 selection->pending_midi_note_selection.erase(rnote);
5262 _summary->set_background_dirty ();
5266 Editor::region_view_removed ()
5268 _summary->set_background_dirty ();
5272 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5274 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5275 if ((*j)->stripable() == s) {
5285 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5289 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5290 TimeAxisView* tv = axis_view_from_stripable (*i);
5300 Editor::suspend_route_redisplay ()
5303 _routes->suspend_redisplay();
5308 Editor::resume_route_redisplay ()
5311 _routes->redisplay(); // queue redisplay
5312 _routes->resume_redisplay();
5317 Editor::add_vcas (VCAList& vlist)
5321 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5322 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5325 add_stripables (sl);
5329 Editor::add_routes (RouteList& rlist)
5333 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5337 add_stripables (sl);
5341 Editor::add_stripables (StripableList& sl)
5343 list<TimeAxisView*> new_views;
5344 boost::shared_ptr<VCA> v;
5345 boost::shared_ptr<Route> r;
5346 TrackViewList new_selection;
5347 bool from_scratch = (track_views.size() == 0);
5349 sl.sort (StripablePresentationInfoSorter());
5351 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5353 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5355 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5357 new_views.push_back (vtv);
5359 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5361 if (r->is_auditioner() || r->is_monitor()) {
5365 RouteTimeAxisView* rtv;
5366 DataType dt = r->input()->default_type();
5368 if (dt == ARDOUR::DataType::AUDIO) {
5369 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5371 } else if (dt == ARDOUR::DataType::MIDI) {
5372 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5375 throw unknown_type();
5378 new_views.push_back (rtv);
5379 track_views.push_back (rtv);
5380 new_selection.push_back (rtv);
5382 rtv->effective_gain_display ();
5384 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5385 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5389 if (new_views.size() > 0) {
5390 _routes->time_axis_views_added (new_views);
5391 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5394 /* note: !new_selection.empty() means that we got some routes rather
5398 if (!from_scratch && !new_selection.empty()) {
5399 selection->tracks.clear();
5400 selection->add (new_selection);
5401 begin_selection_op_history();
5404 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5405 show_editor_mixer (true);
5408 editor_list_button.set_sensitive (true);
5412 Editor::timeaxisview_deleted (TimeAxisView *tv)
5414 if (tv == entered_track) {
5418 if (_session && _session->deletion_in_progress()) {
5419 /* the situation is under control */
5423 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5425 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5427 _routes->route_removed (tv);
5429 TimeAxisView::Children c = tv->get_child_list ();
5430 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5431 if (entered_track == i->get()) {
5436 /* remove it from the list of track views */
5438 TrackViewList::iterator i;
5440 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5441 i = track_views.erase (i);
5444 /* update whatever the current mixer strip is displaying, if revelant */
5446 boost::shared_ptr<Route> route;
5449 route = rtav->route ();
5452 if (current_mixer_strip && current_mixer_strip->route() == route) {
5454 TimeAxisView* next_tv;
5456 if (track_views.empty()) {
5458 } else if (i == track_views.end()) {
5459 next_tv = track_views.front();
5464 // skip VCAs (cannot be selected, n/a in editor-mixer)
5465 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5466 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5467 next_tv = track_views.front();
5469 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5470 /* just in case: no master, only a VCA remains */
5476 set_selected_mixer_strip (*next_tv);
5478 /* make the editor mixer strip go away setting the
5479 * button to inactive (which also unticks the menu option)
5482 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5488 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5490 if (apply_to_selection) {
5491 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5493 TrackSelection::iterator j = i;
5496 hide_track_in_display (*i, false);
5501 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5503 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5504 // this will hide the mixer strip
5505 set_selected_mixer_strip (*tv);
5508 _routes->hide_track_in_display (*tv);
5513 Editor::sync_track_view_list_and_routes ()
5515 track_views = TrackViewList (_routes->views ());
5517 _summary->set_background_dirty();
5518 _group_tabs->set_dirty ();
5520 return false; // do not call again (until needed)
5524 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5526 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5531 /** Find a RouteTimeAxisView by the ID of its route */
5533 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5535 RouteTimeAxisView* v;
5537 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5538 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5539 if(v->route()->id() == id) {
5549 Editor::fit_route_group (RouteGroup *g)
5551 TrackViewList ts = axis_views_from_routes (g->route_list ());
5556 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5558 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5561 _session->cancel_audition ();
5565 if (_session->is_auditioning()) {
5566 _session->cancel_audition ();
5567 if (r == last_audition_region) {
5572 _session->audition_region (r);
5573 last_audition_region = r;
5578 Editor::hide_a_region (boost::shared_ptr<Region> r)
5580 r->set_hidden (true);
5584 Editor::show_a_region (boost::shared_ptr<Region> r)
5586 r->set_hidden (false);
5590 Editor::audition_region_from_region_list ()
5592 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5596 Editor::hide_region_from_region_list ()
5598 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5602 Editor::show_region_in_region_list ()
5604 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5608 Editor::step_edit_status_change (bool yn)
5611 start_step_editing ();
5613 stop_step_editing ();
5618 Editor::start_step_editing ()
5620 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5624 Editor::stop_step_editing ()
5626 step_edit_connection.disconnect ();
5630 Editor::check_step_edit ()
5632 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5633 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5635 mtv->check_step_edit ();
5639 return true; // do it again, till we stop
5643 Editor::scroll_press (Direction dir)
5645 ++_scroll_callbacks;
5647 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5648 /* delay the first auto-repeat */
5654 scroll_backward (1);
5662 scroll_up_one_track ();
5666 scroll_down_one_track ();
5670 /* do hacky auto-repeat */
5671 if (!_scroll_connection.connected ()) {
5673 _scroll_connection = Glib::signal_timeout().connect (
5674 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5677 _scroll_callbacks = 0;
5684 Editor::scroll_release ()
5686 _scroll_connection.disconnect ();
5689 /** Queue a change for the Editor viewport x origin to follow the playhead */
5691 Editor::reset_x_origin_to_follow_playhead ()
5693 framepos_t const frame = playhead_cursor->current_frame ();
5695 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5697 if (_session->transport_speed() < 0) {
5699 if (frame > (current_page_samples() / 2)) {
5700 center_screen (frame-(current_page_samples()/2));
5702 center_screen (current_page_samples()/2);
5709 if (frame < leftmost_frame) {
5711 if (_session->transport_rolling()) {
5712 /* rolling; end up with the playhead at the right of the page */
5713 l = frame - current_page_samples ();
5715 /* not rolling: end up with the playhead 1/4 of the way along the page */
5716 l = frame - current_page_samples() / 4;
5720 if (_session->transport_rolling()) {
5721 /* rolling: end up with the playhead on the left of the page */
5724 /* not rolling: end up with the playhead 3/4 of the way along the page */
5725 l = frame - 3 * current_page_samples() / 4;
5733 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5739 Editor::super_rapid_screen_update ()
5741 if (!_session || !_session->engine().running()) {
5745 /* METERING / MIXER STRIPS */
5747 /* update track meters, if required */
5748 if (contents().is_mapped() && meters_running) {
5749 RouteTimeAxisView* rtv;
5750 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5751 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5752 rtv->fast_update ();
5757 /* and any current mixer strip */
5758 if (current_mixer_strip) {
5759 current_mixer_strip->fast_update ();
5762 /* PLAYHEAD AND VIEWPORT */
5764 framepos_t const frame = _session->audible_frame();
5766 /* There are a few reasons why we might not update the playhead / viewport stuff:
5768 * 1. we don't update things when there's a pending locate request, otherwise
5769 * when the editor requests a locate there is a chance that this method
5770 * will move the playhead before the locate request is processed, causing
5772 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5773 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5776 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5778 last_update_frame = frame;
5780 if (!_dragging_playhead) {
5781 playhead_cursor->set_position (frame);
5784 if (!_stationary_playhead) {
5786 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5787 /* We only do this if we aren't already
5788 handling a visual change (ie if
5789 pending_visual_change.being_handled is
5790 false) so that these requests don't stack
5791 up there are too many of them to handle in
5794 reset_x_origin_to_follow_playhead ();
5799 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5800 framepos_t const frame = playhead_cursor->current_frame ();
5801 double target = ((double)frame - (double)current_page_samples()/2.0);
5802 if (target <= 0.0) {
5805 // compare to EditorCursor::set_position()
5806 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5807 double const new_pos = sample_to_pixel_unrounded (target);
5808 if (rint (new_pos) != rint (old_pos)) {
5809 reset_x_origin (pixel_to_sample (floor (new_pos)));
5820 Editor::session_going_away ()
5822 _have_idled = false;
5824 _session_connections.drop_connections ();
5826 super_rapid_screen_update_connection.disconnect ();
5828 selection->clear ();
5829 cut_buffer->clear ();
5831 clicked_regionview = 0;
5832 clicked_axisview = 0;
5833 clicked_routeview = 0;
5834 entered_regionview = 0;
5836 last_update_frame = 0;
5839 playhead_cursor->hide ();
5841 /* rip everything out of the list displays */
5845 _route_groups->clear ();
5847 /* do this first so that deleting a track doesn't reset cms to null
5848 and thus cause a leak.
5851 if (current_mixer_strip) {
5852 if (current_mixer_strip->get_parent() != 0) {
5853 global_hpacker.remove (*current_mixer_strip);
5855 delete current_mixer_strip;
5856 current_mixer_strip = 0;
5859 /* delete all trackviews */
5861 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5864 track_views.clear ();
5866 nudge_clock->set_session (0);
5868 editor_list_button.set_active(false);
5869 editor_list_button.set_sensitive(false);
5871 /* clear tempo/meter rulers */
5872 remove_metric_marks ();
5874 clear_marker_display ();
5876 stop_step_editing ();
5880 /* get rid of any existing editor mixer strip */
5882 WindowTitle title(Glib::get_application_name());
5883 title += _("Editor");
5885 own_window()->set_title (title.get_string());
5888 SessionHandlePtr::session_going_away ();
5892 Editor::trigger_script (int i)
5894 LuaInstance::instance()-> call_action (i);
5898 Editor::set_script_action_name (int i, const std::string& n)
5900 string const a = string_compose (X_("script-action-%1"), i + 1);
5901 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5904 act->set_label (string_compose (_("Unset #%1"), i + 1));
5905 act->set_tooltip (_("no action bound"));
5906 act->set_sensitive (false);
5909 act->set_tooltip (n);
5910 act->set_sensitive (true);
5912 KeyEditor::UpdateBindings ();
5916 Editor::show_editor_list (bool yn)
5919 _editor_list_vbox.show ();
5921 _editor_list_vbox.hide ();
5926 Editor::change_region_layering_order (bool from_context_menu)
5928 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5930 if (!clicked_routeview) {
5931 if (layering_order_editor) {
5932 layering_order_editor->hide ();
5937 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5943 boost::shared_ptr<Playlist> pl = track->playlist();
5949 if (layering_order_editor == 0) {
5950 layering_order_editor = new RegionLayeringOrderEditor (*this);
5953 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5954 layering_order_editor->maybe_present ();
5958 Editor::update_region_layering_order_editor ()
5960 if (layering_order_editor && layering_order_editor->is_visible ()) {
5961 change_region_layering_order (true);
5966 Editor::setup_fade_images ()
5968 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5969 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5970 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5971 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5972 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5974 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5975 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5976 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5977 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5978 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5982 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5984 Editor::action_menu_item (std::string const & name)
5986 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5989 return *manage (a->create_menu_item ());
5993 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5995 EventBox* b = manage (new EventBox);
5996 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5997 Label* l = manage (new Label (name));
6001 _the_notebook.append_page (widget, *b);
6005 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6007 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6008 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6011 if (ev->type == GDK_2BUTTON_PRESS) {
6013 /* double-click on a notebook tab shrinks or expands the notebook */
6015 if (_notebook_shrunk) {
6016 if (pre_notebook_shrink_pane_width) {
6017 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6019 _notebook_shrunk = false;
6021 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6023 /* this expands the LHS of the edit pane to cover the notebook
6024 PAGE but leaves the tabs visible.
6026 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6027 _notebook_shrunk = true;
6035 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6037 using namespace Menu_Helpers;
6039 MenuList& items = _control_point_context_menu.items ();
6042 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6043 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6044 if (!can_remove_control_point (item)) {
6045 items.back().set_sensitive (false);
6048 _control_point_context_menu.popup (event->button.button, event->button.time);
6052 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6054 using namespace Menu_Helpers;
6056 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6061 /* We need to get the selection here and pass it to the operations, since
6062 popping up the menu will cause a region leave event which clears
6063 entered_regionview. */
6065 MidiRegionView& mrv = note->region_view();
6066 const RegionSelection rs = get_regions_from_selection_and_entered ();
6067 const uint32_t sel_size = mrv.selection_size ();
6069 MenuList& items = _note_context_menu.items();
6073 items.push_back(MenuElem(_("Delete"),
6074 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6077 items.push_back(MenuElem(_("Edit..."),
6078 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6079 if (sel_size != 1) {
6080 items.back().set_sensitive (false);
6083 items.push_back(MenuElem(_("Transpose..."),
6084 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6087 items.push_back(MenuElem(_("Legatize"),
6088 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6090 items.back().set_sensitive (false);
6093 items.push_back(MenuElem(_("Quantize..."),
6094 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6096 items.push_back(MenuElem(_("Remove Overlap"),
6097 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6099 items.back().set_sensitive (false);
6102 items.push_back(MenuElem(_("Transform..."),
6103 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6105 _note_context_menu.popup (event->button.button, event->button.time);
6109 Editor::zoom_vertical_modifier_released()
6111 _stepping_axis_view = 0;
6115 Editor::ui_parameter_changed (string parameter)
6117 if (parameter == "icon-set") {
6118 while (!_cursor_stack.empty()) {
6119 _cursor_stack.pop_back();
6121 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6122 _cursor_stack.push_back(_cursors->grabber);
6123 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6124 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6126 } else if (parameter == "draggable-playhead") {
6127 if (_verbose_cursor) {
6128 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6134 Editor::use_own_window (bool and_fill_it)
6136 bool new_window = !own_window();
6138 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6140 if (win && new_window) {
6141 win->set_name ("EditorWindow");
6143 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6145 // win->signal_realize().connect (*this, &Editor::on_realize);
6146 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6147 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6148 win->set_data ("ardour-bindings", bindings);
6153 DisplaySuspender ds;
6154 contents().show_all ();
6156 /* XXX: this is a bit unfortunate; it would probably
6157 be nicer if we could just call show () above rather
6158 than needing the show_all ()
6161 /* re-hide stuff if necessary */
6162 editor_list_button_toggled ();
6163 parameter_changed ("show-summary");
6164 parameter_changed ("show-group-tabs");
6165 parameter_changed ("show-zoom-tools");
6167 /* now reset all audio_time_axis heights, because widgets might need
6173 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6174 tv = (static_cast<TimeAxisView*>(*i));
6175 tv->reset_height ();
6178 if (current_mixer_strip) {
6179 current_mixer_strip->hide_things ();
6180 current_mixer_strip->parameter_changed ("mixer-element-visibility");