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));
581 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
583 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
585 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
586 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
588 edit_controls_vbox.set_spacing (0);
589 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
590 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
592 HBox* h = manage (new HBox);
593 _group_tabs = new EditorGroupTabs (this);
594 if (!ARDOUR::Profile->get_trx()) {
595 h->pack_start (*_group_tabs, PACK_SHRINK);
597 h->pack_start (edit_controls_vbox);
598 controls_layout.add (*h);
600 controls_layout.set_name ("EditControlsBase");
601 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
602 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
603 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
605 _cursors = new MouseCursors;
606 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
607 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
609 /* Push default cursor to ever-present bottom of cursor stack. */
610 push_canvas_cursor(_cursors->grabber);
612 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
614 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
615 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
616 pad_line_1->set_outline_color (0xFF0000FF);
622 edit_packer.set_col_spacings (0);
623 edit_packer.set_row_spacings (0);
624 edit_packer.set_homogeneous (false);
625 edit_packer.set_border_width (0);
626 edit_packer.set_name ("EditorWindow");
628 time_bars_event_box.add (time_bars_vbox);
629 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
630 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
632 /* labels for the time bars */
633 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
635 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
637 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
639 bottom_hbox.set_border_width (2);
640 bottom_hbox.set_spacing (3);
642 _route_groups = new EditorRouteGroups (this);
643 _routes = new EditorRoutes (this);
644 _regions = new EditorRegions (this);
645 _snapshots = new EditorSnapshots (this);
646 _locations = new EditorLocations (this);
647 _time_info_box = new TimeInfoBox (true);
649 /* these are static location signals */
651 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
655 add_notebook_page (_("Regions"), _regions->widget ());
656 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
657 add_notebook_page (_("Snapshots"), _snapshots->widget ());
658 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
659 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
661 _the_notebook.set_show_tabs (true);
662 _the_notebook.set_scrollable (true);
663 _the_notebook.popup_disable ();
664 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
665 _the_notebook.show_all ();
667 _notebook_shrunk = false;
670 /* Pick up some settings we need to cache, early */
672 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
675 if (settings && (prop = settings->property ("notebook-shrunk"))) {
676 _notebook_shrunk = string_is_affirmative (prop->value ());
679 editor_summary_pane.set_check_divider_position (true);
680 editor_summary_pane.add (edit_packer);
682 Button* summary_arrows_left_left = manage (new Button);
683 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
684 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
685 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
687 Button* summary_arrows_left_right = manage (new Button);
688 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
689 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
690 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
692 VBox* summary_arrows_left = manage (new VBox);
693 summary_arrows_left->pack_start (*summary_arrows_left_left);
694 summary_arrows_left->pack_start (*summary_arrows_left_right);
696 Button* summary_arrows_right_up = manage (new Button);
697 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
698 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
699 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
701 Button* summary_arrows_right_down = manage (new Button);
702 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
703 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
704 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
706 VBox* summary_arrows_right = manage (new VBox);
707 summary_arrows_right->pack_start (*summary_arrows_right_up);
708 summary_arrows_right->pack_start (*summary_arrows_right_down);
710 Frame* summary_frame = manage (new Frame);
711 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
713 summary_frame->add (*_summary);
714 summary_frame->show ();
716 _summary_hbox.pack_start (*summary_arrows_left, false, false);
717 _summary_hbox.pack_start (*summary_frame, true, true);
718 _summary_hbox.pack_start (*summary_arrows_right, false, false);
720 if (!ARDOUR::Profile->get_trx()) {
721 editor_summary_pane.add (_summary_hbox);
724 edit_pane.set_check_divider_position (true);
725 edit_pane.add (editor_summary_pane);
726 if (!ARDOUR::Profile->get_trx()) {
727 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
728 _editor_list_vbox.pack_start (_the_notebook);
729 edit_pane.add (_editor_list_vbox);
730 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
733 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
734 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
741 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
742 /* initial allocation is 90% to canvas, 10% to notebook */
743 edit_pane.set_divider (0, 0.90);
745 edit_pane.set_divider (0, fract);
748 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
749 /* initial allocation is 90% to canvas, 10% to summary */
750 editor_summary_pane.set_divider (0, 0.90);
753 editor_summary_pane.set_divider (0, fract);
757 global_vpacker.set_spacing (2);
758 global_vpacker.set_border_width (0);
760 global_vpacker.pack_start (toolbar_hbox, false, false);
761 global_vpacker.pack_start (edit_pane, true, true);
762 global_hpacker.pack_start (global_vpacker, true, true);
764 /* need to show the "contents" widget so that notebook will show if tab is switched to
767 global_hpacker.show ();
769 /* register actions now so that set_state() can find them and set toggles/checks etc */
776 _playlist_selector = new PlaylistSelector();
777 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
779 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
783 nudge_forward_button.set_name ("nudge button");
784 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
786 nudge_backward_button.set_name ("nudge button");
787 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
789 fade_context_menu.set_name ("ArdourContextMenu");
791 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
793 /* allow external control surfaces/protocols to do various things */
795 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
796 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
797 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
798 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
799 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
800 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
801 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
802 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
803 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
804 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
805 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
806 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
807 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
808 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
810 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
811 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
812 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
813 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
814 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
816 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
820 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
822 /* problematic: has to return a value and thus cannot be x-thread */
824 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
826 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
827 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
829 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
831 _ignore_region_action = false;
832 _last_region_menu_was_main = false;
833 _popup_region_menu_item = 0;
835 _show_marker_lines = false;
837 /* Button bindings */
839 button_bindings = new Bindings ("editor-mouse");
841 XMLNode* node = button_settings();
843 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
844 button_bindings->load_operation (**i);
850 /* grab current parameter state */
851 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
852 UIConfiguration::instance().map_parameters (pc);
854 setup_fade_images ();
856 LuaInstance::instance(); // instantiate
857 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
864 delete button_bindings;
866 delete _route_groups;
867 delete _track_canvas_viewport;
870 delete _verbose_cursor;
871 delete quantize_dialog;
877 delete _playlist_selector;
878 delete _time_info_box;
880 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
886 Editor::button_settings () const
888 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
889 XMLNode* node = find_named_node (*settings, X_("Buttons"));
892 node = new XMLNode (X_("Buttons"));
899 Editor::get_smart_mode () const
901 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
905 Editor::catch_vanishing_regionview (RegionView *rv)
907 /* note: the selection will take care of the vanishing
908 audioregionview by itself.
911 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
915 if (clicked_regionview == rv) {
916 clicked_regionview = 0;
919 if (entered_regionview == rv) {
920 set_entered_regionview (0);
923 if (!_all_region_actions_sensitized) {
924 sensitize_all_region_actions (true);
929 Editor::set_entered_regionview (RegionView* rv)
931 if (rv == entered_regionview) {
935 if (entered_regionview) {
936 entered_regionview->exited ();
939 entered_regionview = rv;
941 if (entered_regionview != 0) {
942 entered_regionview->entered ();
945 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
946 /* This RegionView entry might have changed what region actions
947 are allowed, so sensitize them all in case a key is pressed.
949 sensitize_all_region_actions (true);
954 Editor::set_entered_track (TimeAxisView* tav)
957 entered_track->exited ();
963 entered_track->entered ();
968 Editor::instant_save ()
970 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
975 _session->add_instant_xml(get_state());
977 Config->add_instant_xml(get_state());
982 Editor::control_vertical_zoom_in_all ()
984 tav_zoom_smooth (false, true);
988 Editor::control_vertical_zoom_out_all ()
990 tav_zoom_smooth (true, true);
994 Editor::control_vertical_zoom_in_selected ()
996 tav_zoom_smooth (false, false);
1000 Editor::control_vertical_zoom_out_selected ()
1002 tav_zoom_smooth (true, false);
1006 Editor::control_view (uint32_t view)
1008 goto_visual_state (view);
1012 Editor::control_unselect ()
1014 selection->clear_tracks ();
1018 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1020 TimeAxisView* tav = axis_view_from_stripable (s);
1024 case Selection::Add:
1025 selection->add (tav);
1027 case Selection::Toggle:
1028 selection->toggle (tav);
1030 case Selection::Extend:
1032 case Selection::Set:
1033 selection->set (tav);
1037 selection->clear_tracks ();
1042 Editor::control_step_tracks_up ()
1044 scroll_tracks_up_line ();
1048 Editor::control_step_tracks_down ()
1050 scroll_tracks_down_line ();
1054 Editor::control_scroll (float fraction)
1056 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1062 double step = fraction * current_page_samples();
1065 _control_scroll_target is an optional<T>
1067 it acts like a pointer to an framepos_t, with
1068 a operator conversion to boolean to check
1069 that it has a value could possibly use
1070 playhead_cursor->current_frame to store the
1071 value and a boolean in the class to know
1072 when it's out of date
1075 if (!_control_scroll_target) {
1076 _control_scroll_target = _session->transport_frame();
1077 _dragging_playhead = true;
1080 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1081 *_control_scroll_target = 0;
1082 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1083 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1085 *_control_scroll_target += (framepos_t) trunc (step);
1088 /* move visuals, we'll catch up with it later */
1090 playhead_cursor->set_position (*_control_scroll_target);
1091 UpdateAllTransportClocks (*_control_scroll_target);
1093 if (*_control_scroll_target > (current_page_samples() / 2)) {
1094 /* try to center PH in window */
1095 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1101 Now we do a timeout to actually bring the session to the right place
1102 according to the playhead. This is to avoid reading disk buffers on every
1103 call to control_scroll, which is driven by ScrollTimeline and therefore
1104 probably by a control surface wheel which can generate lots of events.
1106 /* cancel the existing timeout */
1108 control_scroll_connection.disconnect ();
1110 /* add the next timeout */
1112 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1116 Editor::deferred_control_scroll (framepos_t /*target*/)
1118 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1119 // reset for next stream
1120 _control_scroll_target = boost::none;
1121 _dragging_playhead = false;
1126 Editor::access_action (std::string action_group, std::string action_item)
1132 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1135 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1143 Editor::on_realize ()
1147 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1148 start_lock_event_timing ();
1153 Editor::start_lock_event_timing ()
1155 /* check if we should lock the GUI every 30 seconds */
1157 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1161 Editor::generic_event_handler (GdkEvent* ev)
1164 case GDK_BUTTON_PRESS:
1165 case GDK_BUTTON_RELEASE:
1166 case GDK_MOTION_NOTIFY:
1168 case GDK_KEY_RELEASE:
1169 if (contents().is_mapped()) {
1170 gettimeofday (&last_event_time, 0);
1174 case GDK_LEAVE_NOTIFY:
1175 switch (ev->crossing.detail) {
1176 case GDK_NOTIFY_UNKNOWN:
1177 case GDK_NOTIFY_INFERIOR:
1178 case GDK_NOTIFY_ANCESTOR:
1180 case GDK_NOTIFY_VIRTUAL:
1181 case GDK_NOTIFY_NONLINEAR:
1182 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1183 /* leaving window, so reset focus, thus ending any and
1184 all text entry operations.
1186 ARDOUR_UI::instance()->reset_focus (&contents());
1199 Editor::lock_timeout_callback ()
1201 struct timeval now, delta;
1203 gettimeofday (&now, 0);
1205 timersub (&now, &last_event_time, &delta);
1207 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1209 /* don't call again. Returning false will effectively
1210 disconnect us from the timer callback.
1212 unlock() will call start_lock_event_timing() to get things
1222 Editor::map_position_change (framepos_t frame)
1224 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1226 if (_session == 0) {
1230 if (_follow_playhead) {
1231 center_screen (frame);
1234 playhead_cursor->set_position (frame);
1238 Editor::center_screen (framepos_t frame)
1240 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1242 /* if we're off the page, then scroll.
1245 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1246 center_screen_internal (frame, page);
1251 Editor::center_screen_internal (framepos_t frame, float page)
1256 frame -= (framepos_t) page;
1261 reset_x_origin (frame);
1266 Editor::update_title ()
1268 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1270 if (!own_window()) {
1275 bool dirty = _session->dirty();
1277 string session_name;
1279 if (_session->snap_name() != _session->name()) {
1280 session_name = _session->snap_name();
1282 session_name = _session->name();
1286 session_name = "*" + session_name;
1289 WindowTitle title(session_name);
1290 title += S_("Window|Editor");
1291 title += Glib::get_application_name();
1292 own_window()->set_title (title.get_string());
1294 /* ::session_going_away() will have taken care of it */
1299 Editor::set_session (Session *t)
1301 SessionHandlePtr::set_session (t);
1307 _playlist_selector->set_session (_session);
1308 nudge_clock->set_session (_session);
1309 _summary->set_session (_session);
1310 _group_tabs->set_session (_session);
1311 _route_groups->set_session (_session);
1312 _regions->set_session (_session);
1313 _snapshots->set_session (_session);
1314 _routes->set_session (_session);
1315 _locations->set_session (_session);
1316 _time_info_box->set_session (_session);
1318 if (rhythm_ferret) {
1319 rhythm_ferret->set_session (_session);
1322 if (analysis_window) {
1323 analysis_window->set_session (_session);
1327 sfbrowser->set_session (_session);
1330 compute_fixed_ruler_scale ();
1332 /* Make sure we have auto loop and auto punch ranges */
1334 Location* loc = _session->locations()->auto_loop_location();
1336 loc->set_name (_("Loop"));
1339 loc = _session->locations()->auto_punch_location();
1342 loc->set_name (_("Punch"));
1345 refresh_location_display ();
1347 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1348 the selected Marker; this needs the LocationMarker list to be available.
1350 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1351 set_state (*node, Stateful::loading_state_version);
1353 /* catch up with the playhead */
1355 _session->request_locate (playhead_cursor->current_frame ());
1356 _pending_initial_locate = true;
1360 /* These signals can all be emitted by a non-GUI thread. Therefore the
1361 handlers for them must not attempt to directly interact with the GUI,
1362 but use PBD::Signal<T>::connect() which accepts an event loop
1363 ("context") where the handler will be asked to run.
1366 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1367 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1368 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1369 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1370 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1371 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1372 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1373 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1374 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1375 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1376 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1377 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1378 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1379 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1380 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1382 playhead_cursor->show ();
1384 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1385 Config->map_parameters (pc);
1386 _session->config.map_parameters (pc);
1388 restore_ruler_visibility ();
1389 //tempo_map_changed (PropertyChange (0));
1390 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1392 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1393 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1396 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1397 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1400 switch (_snap_type) {
1401 case SnapToRegionStart:
1402 case SnapToRegionEnd:
1403 case SnapToRegionSync:
1404 case SnapToRegionBoundary:
1405 build_region_boundary_cache ();
1412 /* catch up on selection of stripables (other selection state is lost
1413 * when a session is closed
1418 _session->get_stripables (sl);
1419 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1420 if ((*s)->presentation_info().selected()) {
1421 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1423 tl.push_back (rtav);
1428 selection->set (tl);
1431 /* register for undo history */
1432 _session->register_with_memento_command_factory(id(), this);
1433 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1435 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1437 LuaInstance::instance()->set_session(_session);
1439 start_updating_meters ();
1443 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1445 if (a->get_name() == "RegionMenu") {
1446 /* When the main menu's region menu is opened, we setup the actions so that they look right
1447 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1448 so we resensitize all region actions when the entered regionview or the region selection
1449 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1450 happens after the region context menu is opened. So we set a flag here, too.
1454 sensitize_the_right_region_actions ();
1455 _last_region_menu_was_main = true;
1460 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1462 using namespace Menu_Helpers;
1464 void (Editor::*emf)(FadeShape);
1465 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1468 images = &_xfade_in_images;
1469 emf = &Editor::set_fade_in_shape;
1471 images = &_xfade_out_images;
1472 emf = &Editor::set_fade_out_shape;
1477 _("Linear (for highly correlated material)"),
1478 *(*images)[FadeLinear],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 _("Constant power"),
1488 *(*images)[FadeConstantPower],
1489 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *(*images)[FadeSymmetric],
1498 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1502 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1507 *(*images)[FadeSlow],
1508 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1511 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1516 *(*images)[FadeFast],
1517 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1520 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1523 /** Pop up a context menu for when the user clicks on a start crossfade */
1525 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1527 using namespace Menu_Helpers;
1528 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1533 MenuList& items (xfade_in_context_menu.items());
1536 if (arv->audio_region()->fade_in_active()) {
1537 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1539 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1542 items.push_back (SeparatorElem());
1543 fill_xfade_menu (items, true);
1545 xfade_in_context_menu.popup (button, time);
1548 /** Pop up a context menu for when the user clicks on an end crossfade */
1550 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1552 using namespace Menu_Helpers;
1553 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1558 MenuList& items (xfade_out_context_menu.items());
1561 if (arv->audio_region()->fade_out_active()) {
1562 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1564 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1567 items.push_back (SeparatorElem());
1568 fill_xfade_menu (items, false);
1570 xfade_out_context_menu.popup (button, time);
1574 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1576 using namespace Menu_Helpers;
1577 Menu* (Editor::*build_menu_function)();
1580 switch (item_type) {
1582 case RegionViewName:
1583 case RegionViewNameHighlight:
1584 case LeftFrameHandle:
1585 case RightFrameHandle:
1586 if (with_selection) {
1587 build_menu_function = &Editor::build_track_selection_context_menu;
1589 build_menu_function = &Editor::build_track_region_context_menu;
1594 if (with_selection) {
1595 build_menu_function = &Editor::build_track_selection_context_menu;
1597 build_menu_function = &Editor::build_track_context_menu;
1602 if (clicked_routeview->track()) {
1603 build_menu_function = &Editor::build_track_context_menu;
1605 build_menu_function = &Editor::build_track_bus_context_menu;
1610 /* probably shouldn't happen but if it does, we don't care */
1614 menu = (this->*build_menu_function)();
1615 menu->set_name ("ArdourContextMenu");
1617 /* now handle specific situations */
1619 switch (item_type) {
1621 case RegionViewName:
1622 case RegionViewNameHighlight:
1623 case LeftFrameHandle:
1624 case RightFrameHandle:
1625 if (!with_selection) {
1626 if (region_edit_menu_split_item) {
1627 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1628 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1630 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1633 if (region_edit_menu_split_multichannel_item) {
1634 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1635 region_edit_menu_split_multichannel_item->set_sensitive (true);
1637 region_edit_menu_split_multichannel_item->set_sensitive (false);
1650 /* probably shouldn't happen but if it does, we don't care */
1654 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1656 /* Bounce to disk */
1658 using namespace Menu_Helpers;
1659 MenuList& edit_items = menu->items();
1661 edit_items.push_back (SeparatorElem());
1663 switch (clicked_routeview->audio_track()->freeze_state()) {
1664 case AudioTrack::NoFreeze:
1665 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1668 case AudioTrack::Frozen:
1669 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1672 case AudioTrack::UnFrozen:
1673 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1679 if (item_type == StreamItem && clicked_routeview) {
1680 clicked_routeview->build_underlay_menu(menu);
1683 /* When the region menu is opened, we setup the actions so that they look right
1686 sensitize_the_right_region_actions ();
1687 _last_region_menu_was_main = false;
1689 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1690 menu->popup (button, time);
1694 Editor::build_track_context_menu ()
1696 using namespace Menu_Helpers;
1698 MenuList& edit_items = track_context_menu.items();
1701 add_dstream_context_items (edit_items);
1702 return &track_context_menu;
1706 Editor::build_track_bus_context_menu ()
1708 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_context_menu.items();
1713 add_bus_context_items (edit_items);
1714 return &track_context_menu;
1718 Editor::build_track_region_context_menu ()
1720 using namespace Menu_Helpers;
1721 MenuList& edit_items = track_region_context_menu.items();
1724 /* we've just cleared the track region context menu, so the menu that these
1725 two items were on will have disappeared; stop them dangling.
1727 region_edit_menu_split_item = 0;
1728 region_edit_menu_split_multichannel_item = 0;
1730 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1733 boost::shared_ptr<Track> tr;
1734 boost::shared_ptr<Playlist> pl;
1736 if ((tr = rtv->track())) {
1737 add_region_context_items (edit_items, tr);
1741 add_dstream_context_items (edit_items);
1743 return &track_region_context_menu;
1747 Editor::loudness_analyze_region_selection ()
1752 Selection& s (PublicEditor::instance ().get_selection ());
1753 RegionSelection ars = s.regions;
1754 ARDOUR::AnalysisGraph ag (_session);
1755 framecnt_t total_work = 0;
1757 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1758 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1762 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1765 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1766 total_work += arv->region ()->length ();
1769 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1771 ag.set_total_frames (total_work);
1772 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1775 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1776 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1780 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1784 ag.analyze_region (ar);
1787 if (!ag.canceled ()) {
1788 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1794 Editor::loudness_analyze_range_selection ()
1799 Selection& s (PublicEditor::instance ().get_selection ());
1800 TimeSelection ts = s.time;
1801 ARDOUR::AnalysisGraph ag (_session);
1802 framecnt_t total_work = 0;
1804 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1805 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1809 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1813 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1814 total_work += j->length ();
1818 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1820 ag.set_total_frames (total_work);
1821 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1824 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1825 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1829 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1833 ag.analyze_range (rui->route (), pl, ts);
1836 if (!ag.canceled ()) {
1837 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1843 Editor::spectral_analyze_region_selection ()
1845 if (analysis_window == 0) {
1846 analysis_window = new AnalysisWindow();
1849 analysis_window->set_session(_session);
1851 analysis_window->show_all();
1854 analysis_window->set_regionmode();
1855 analysis_window->analyze();
1857 analysis_window->present();
1861 Editor::spectral_analyze_range_selection()
1863 if (analysis_window == 0) {
1864 analysis_window = new AnalysisWindow();
1867 analysis_window->set_session(_session);
1869 analysis_window->show_all();
1872 analysis_window->set_rangemode();
1873 analysis_window->analyze();
1875 analysis_window->present();
1879 Editor::build_track_selection_context_menu ()
1881 using namespace Menu_Helpers;
1882 MenuList& edit_items = track_selection_context_menu.items();
1883 edit_items.clear ();
1885 add_selection_context_items (edit_items);
1886 // edit_items.push_back (SeparatorElem());
1887 // add_dstream_context_items (edit_items);
1889 return &track_selection_context_menu;
1893 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1895 using namespace Menu_Helpers;
1897 /* OK, stick the region submenu at the top of the list, and then add
1901 RegionSelection rs = get_regions_from_selection_and_entered ();
1903 string::size_type pos = 0;
1904 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1906 /* we have to hack up the region name because "_" has a special
1907 meaning for menu titles.
1910 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1911 menu_item_name.replace (pos, 1, "__");
1915 if (_popup_region_menu_item == 0) {
1916 _popup_region_menu_item = new MenuItem (menu_item_name);
1917 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1918 _popup_region_menu_item->show ();
1920 _popup_region_menu_item->set_label (menu_item_name);
1923 /* No latering allowed in later is higher layering model */
1924 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1925 if (act && Config->get_layer_model() == LaterHigher) {
1926 act->set_sensitive (false);
1928 act->set_sensitive (true);
1931 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1933 edit_items.push_back (*_popup_region_menu_item);
1934 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1935 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1937 edit_items.push_back (SeparatorElem());
1940 /** Add context menu items relevant to selection ranges.
1941 * @param edit_items List to add the items to.
1944 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1946 using namespace Menu_Helpers;
1948 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1949 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1951 edit_items.push_back (SeparatorElem());
1952 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1954 edit_items.push_back (SeparatorElem());
1955 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1956 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1958 edit_items.push_back (SeparatorElem());
1960 edit_items.push_back (
1962 _("Move Range Start to Previous Region Boundary"),
1963 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1967 edit_items.push_back (
1969 _("Move Range Start to Next Region Boundary"),
1970 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1974 edit_items.push_back (
1976 _("Move Range End to Previous Region Boundary"),
1977 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1981 edit_items.push_back (
1983 _("Move Range End to Next Region Boundary"),
1984 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1988 edit_items.push_back (SeparatorElem());
1989 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1990 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1992 edit_items.push_back (SeparatorElem());
1993 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1995 edit_items.push_back (SeparatorElem());
1996 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1997 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1998 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2000 edit_items.push_back (SeparatorElem());
2001 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2003 edit_items.push_back (SeparatorElem());
2004 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2005 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2007 edit_items.push_back (SeparatorElem());
2008 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2009 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2010 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2011 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2012 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2013 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2014 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2020 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2022 using namespace Menu_Helpers;
2026 Menu *play_menu = manage (new Menu);
2027 MenuList& play_items = play_menu->items();
2028 play_menu->set_name ("ArdourContextMenu");
2030 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2031 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2032 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2033 play_items.push_back (SeparatorElem());
2034 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2036 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2040 Menu *select_menu = manage (new Menu);
2041 MenuList& select_items = select_menu->items();
2042 select_menu->set_name ("ArdourContextMenu");
2044 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2045 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2046 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2047 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2048 select_items.push_back (SeparatorElem());
2049 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2050 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2051 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2052 select_items.push_back (SeparatorElem());
2053 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2054 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2055 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2056 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2057 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2058 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2059 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2061 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2065 Menu *cutnpaste_menu = manage (new Menu);
2066 MenuList& cutnpaste_items = cutnpaste_menu->items();
2067 cutnpaste_menu->set_name ("ArdourContextMenu");
2069 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2070 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2071 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2073 cutnpaste_items.push_back (SeparatorElem());
2075 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2076 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2078 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2080 /* Adding new material */
2082 edit_items.push_back (SeparatorElem());
2083 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2084 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2088 Menu *nudge_menu = manage (new Menu());
2089 MenuList& nudge_items = nudge_menu->items();
2090 nudge_menu->set_name ("ArdourContextMenu");
2092 edit_items.push_back (SeparatorElem());
2093 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2094 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2095 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2096 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2098 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2102 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2104 using namespace Menu_Helpers;
2108 Menu *play_menu = manage (new Menu);
2109 MenuList& play_items = play_menu->items();
2110 play_menu->set_name ("ArdourContextMenu");
2112 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2113 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2114 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2118 Menu *select_menu = manage (new Menu);
2119 MenuList& select_items = select_menu->items();
2120 select_menu->set_name ("ArdourContextMenu");
2122 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2123 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2124 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2125 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2126 select_items.push_back (SeparatorElem());
2127 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2128 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2129 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2130 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2132 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2136 Menu *cutnpaste_menu = manage (new Menu);
2137 MenuList& cutnpaste_items = cutnpaste_menu->items();
2138 cutnpaste_menu->set_name ("ArdourContextMenu");
2140 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2141 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2142 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2144 Menu *nudge_menu = manage (new Menu());
2145 MenuList& nudge_items = nudge_menu->items();
2146 nudge_menu->set_name ("ArdourContextMenu");
2148 edit_items.push_back (SeparatorElem());
2149 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2150 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2151 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2152 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2154 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2158 Editor::snap_type() const
2164 Editor::snap_musical() const
2166 switch (_snap_type) {
2167 case SnapToBeatDiv128:
2168 case SnapToBeatDiv64:
2169 case SnapToBeatDiv32:
2170 case SnapToBeatDiv28:
2171 case SnapToBeatDiv24:
2172 case SnapToBeatDiv20:
2173 case SnapToBeatDiv16:
2174 case SnapToBeatDiv14:
2175 case SnapToBeatDiv12:
2176 case SnapToBeatDiv10:
2177 case SnapToBeatDiv8:
2178 case SnapToBeatDiv7:
2179 case SnapToBeatDiv6:
2180 case SnapToBeatDiv5:
2181 case SnapToBeatDiv4:
2182 case SnapToBeatDiv3:
2183 case SnapToBeatDiv2:
2195 Editor::snap_mode() const
2201 Editor::set_snap_to (SnapType st)
2203 unsigned int snap_ind = (unsigned int)st;
2205 if (internal_editing()) {
2206 internal_snap_type = st;
2208 pre_internal_snap_type = st;
2213 if (snap_ind > snap_type_strings.size() - 1) {
2215 _snap_type = (SnapType)snap_ind;
2218 string str = snap_type_strings[snap_ind];
2220 if (str != snap_type_selector.get_text()) {
2221 snap_type_selector.set_text (str);
2226 switch (_snap_type) {
2227 case SnapToBeatDiv128:
2228 case SnapToBeatDiv64:
2229 case SnapToBeatDiv32:
2230 case SnapToBeatDiv28:
2231 case SnapToBeatDiv24:
2232 case SnapToBeatDiv20:
2233 case SnapToBeatDiv16:
2234 case SnapToBeatDiv14:
2235 case SnapToBeatDiv12:
2236 case SnapToBeatDiv10:
2237 case SnapToBeatDiv8:
2238 case SnapToBeatDiv7:
2239 case SnapToBeatDiv6:
2240 case SnapToBeatDiv5:
2241 case SnapToBeatDiv4:
2242 case SnapToBeatDiv3:
2243 case SnapToBeatDiv2: {
2244 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2245 update_tempo_based_rulers ();
2249 case SnapToRegionStart:
2250 case SnapToRegionEnd:
2251 case SnapToRegionSync:
2252 case SnapToRegionBoundary:
2253 build_region_boundary_cache ();
2261 redisplay_tempo (false);
2263 SnapChanged (); /* EMIT SIGNAL */
2267 Editor::set_snap_mode (SnapMode mode)
2269 string str = snap_mode_strings[(int)mode];
2271 if (internal_editing()) {
2272 internal_snap_mode = mode;
2274 pre_internal_snap_mode = mode;
2279 if (str != snap_mode_selector.get_text ()) {
2280 snap_mode_selector.set_text (str);
2287 Editor::set_edit_point_preference (EditPoint ep, bool force)
2289 bool changed = (_edit_point != ep);
2292 if (Profile->get_mixbus())
2293 if (ep == EditAtSelectedMarker)
2294 ep = EditAtPlayhead;
2296 string str = edit_point_strings[(int)ep];
2297 if (str != edit_point_selector.get_text ()) {
2298 edit_point_selector.set_text (str);
2301 update_all_enter_cursors();
2303 if (!force && !changed) {
2307 const char* action=NULL;
2309 switch (_edit_point) {
2310 case EditAtPlayhead:
2311 action = "edit-at-playhead";
2313 case EditAtSelectedMarker:
2314 action = "edit-at-marker";
2317 action = "edit-at-mouse";
2321 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2323 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2327 bool in_track_canvas;
2329 if (!mouse_frame (foo, in_track_canvas)) {
2330 in_track_canvas = false;
2333 reset_canvas_action_sensitivity (in_track_canvas);
2339 Editor::set_state (const XMLNode& node, int version)
2341 XMLProperty const * prop;
2343 PBD::Unwinder<bool> nsi (no_save_instant, true);
2346 Tabbable::set_state (node, version);
2348 if (_session && (prop = node.property ("playhead"))) {
2350 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2352 playhead_cursor->set_position (pos);
2354 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2355 playhead_cursor->set_position (0);
2358 playhead_cursor->set_position (0);
2361 if ((prop = node.property ("mixer-width"))) {
2362 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2365 if ((prop = node.property ("zoom-focus"))) {
2366 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2368 zoom_focus_selection_done (zoom_focus);
2371 if ((prop = node.property ("zoom"))) {
2372 /* older versions of ardour used floating point samples_per_pixel */
2373 double f = PBD::atof (prop->value());
2374 reset_zoom (llrintf (f));
2376 reset_zoom (samples_per_pixel);
2379 if ((prop = node.property ("visible-track-count"))) {
2380 set_visible_track_count (PBD::atoi (prop->value()));
2383 if ((prop = node.property ("snap-to"))) {
2384 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2385 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2387 set_snap_to (_snap_type);
2390 if ((prop = node.property ("snap-mode"))) {
2391 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2392 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2393 * snap_mode_selection_done() will only mark an already active item as active
2394 * which does not trigger set_text().
2396 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2398 set_snap_mode (_snap_mode);
2401 if ((prop = node.property ("internal-snap-to"))) {
2402 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2405 if ((prop = node.property ("internal-snap-mode"))) {
2406 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2409 if ((prop = node.property ("pre-internal-snap-to"))) {
2410 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2413 if ((prop = node.property ("pre-internal-snap-mode"))) {
2414 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2417 if ((prop = node.property ("mouse-mode"))) {
2418 MouseMode m = str2mousemode(prop->value());
2419 set_mouse_mode (m, true);
2421 set_mouse_mode (MouseObject, true);
2424 if ((prop = node.property ("left-frame")) != 0) {
2426 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2430 reset_x_origin (pos);
2434 if ((prop = node.property ("y-origin")) != 0) {
2435 reset_y_origin (atof (prop->value ()));
2438 if ((prop = node.property ("join-object-range"))) {
2439 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2440 bool yn = string_is_affirmative (prop->value());
2442 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2443 tact->set_active (!yn);
2444 tact->set_active (yn);
2446 set_mouse_mode(mouse_mode, true);
2449 if ((prop = node.property ("edit-point"))) {
2450 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2452 set_edit_point_preference (_edit_point);
2455 if ((prop = node.property ("show-measures"))) {
2456 bool yn = string_is_affirmative (prop->value());
2457 _show_measures = yn;
2460 if ((prop = node.property ("follow-playhead"))) {
2461 bool yn = string_is_affirmative (prop->value());
2462 set_follow_playhead (yn);
2465 if ((prop = node.property ("stationary-playhead"))) {
2466 bool yn = string_is_affirmative (prop->value());
2467 set_stationary_playhead (yn);
2470 if ((prop = node.property ("region-list-sort-type"))) {
2471 RegionListSortType st;
2472 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2475 if ((prop = node.property ("show-editor-mixer"))) {
2477 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2480 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2481 bool yn = string_is_affirmative (prop->value());
2483 /* do it twice to force the change */
2485 tact->set_active (!yn);
2486 tact->set_active (yn);
2489 if ((prop = node.property ("show-editor-list"))) {
2491 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2494 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495 bool yn = string_is_affirmative (prop->value());
2497 /* do it twice to force the change */
2499 tact->set_active (!yn);
2500 tact->set_active (yn);
2503 if ((prop = node.property (X_("editor-list-page")))) {
2504 _the_notebook.set_current_page (atoi (prop->value ()));
2507 if ((prop = node.property (X_("show-marker-lines")))) {
2508 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2510 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2511 bool yn = string_is_affirmative (prop->value ());
2513 tact->set_active (!yn);
2514 tact->set_active (yn);
2517 XMLNodeList children = node.children ();
2518 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2519 selection->set_state (**i, Stateful::current_state_version);
2520 _regions->set_state (**i);
2523 if ((prop = node.property ("maximised"))) {
2524 bool yn = string_is_affirmative (prop->value());
2525 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2527 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2528 bool fs = tact && tact->get_active();
2530 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2534 if ((prop = node.property ("nudge-clock-value"))) {
2536 sscanf (prop->value().c_str(), "%" PRId64, &f);
2537 nudge_clock->set (f);
2539 nudge_clock->set_mode (AudioClock::Timecode);
2540 nudge_clock->set (_session->frame_rate() * 5, true);
2545 * Not all properties may have been in XML, but
2546 * those that are linked to a private variable may need changing
2551 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2553 yn = _show_measures;
2554 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2555 /* do it twice to force the change */
2556 tact->set_active (!yn);
2557 tact->set_active (yn);
2560 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2561 yn = _follow_playhead;
2563 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2564 if (tact->get_active() != yn) {
2565 tact->set_active (yn);
2569 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2570 yn = _stationary_playhead;
2572 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2573 if (tact->get_active() != yn) {
2574 tact->set_active (yn);
2579 return LuaInstance::instance()->set_state(node);
2583 Editor::get_state ()
2585 XMLNode* node = new XMLNode (X_("Editor"));
2589 id().print (buf, sizeof (buf));
2590 node->add_property ("id", buf);
2592 node->add_child_nocopy (Tabbable::get_state());
2594 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2595 node->add_property("edit-horizontal-pane-pos", string(buf));
2596 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2597 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2598 node->add_property("edit-vertical-pane-pos", string(buf));
2600 maybe_add_mixer_strip_width (*node);
2602 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2604 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2605 node->add_property ("zoom", buf);
2606 node->add_property ("snap-to", enum_2_string (_snap_type));
2607 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2608 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2609 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2610 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2611 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2612 node->add_property ("edit-point", enum_2_string (_edit_point));
2613 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2614 node->add_property ("visible-track-count", buf);
2616 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2617 node->add_property ("playhead", buf);
2618 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2619 node->add_property ("left-frame", buf);
2620 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2621 node->add_property ("y-origin", buf);
2623 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2624 node->add_property ("maximised", _maximised ? "yes" : "no");
2625 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2626 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2627 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2628 node->add_property ("mouse-mode", enum2str(mouse_mode));
2629 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2631 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2633 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2634 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2637 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2639 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2640 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2643 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2644 node->add_property (X_("editor-list-page"), buf);
2646 if (button_bindings) {
2647 XMLNode* bb = new XMLNode (X_("Buttons"));
2648 button_bindings->save (*bb);
2649 node->add_child_nocopy (*bb);
2652 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2654 node->add_child_nocopy (selection->get_state ());
2655 node->add_child_nocopy (_regions->get_state ());
2657 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2658 node->add_property ("nudge-clock-value", buf);
2660 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2661 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2666 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2667 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2669 * @return pair: TimeAxisView that y is over, layer index.
2671 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2672 * in stacked or expanded region display mode, otherwise 0.
2674 std::pair<TimeAxisView *, double>
2675 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2677 if (!trackview_relative_offset) {
2678 y -= _trackview_group->canvas_origin().y;
2682 return std::make_pair ( (TimeAxisView *) 0, 0);
2685 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2687 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2694 return std::make_pair ( (TimeAxisView *) 0, 0);
2697 /** Snap a position to the grid, if appropriate, taking into account current
2698 * grid settings and also the state of any snap modifier keys that may be pressed.
2699 * @param start Position to snap.
2700 * @param event Event to get current key modifier information from, or 0.
2703 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2705 if (!_session || !event) {
2709 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2710 if (_snap_mode == SnapOff) {
2711 snap_to_internal (start, direction, for_mark);
2714 if (_snap_mode != SnapOff) {
2715 snap_to_internal (start, direction, for_mark);
2716 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2717 /* SnapOff, but we pressed the snap_delta modifier */
2718 snap_to_internal (start, direction, for_mark);
2724 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2726 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2730 snap_to_internal (start, direction, for_mark, ensure_snap);
2734 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2736 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2737 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2739 switch (_snap_type) {
2740 case SnapToTimecodeFrame:
2741 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2742 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2743 /* start is already on a whole timecode frame, do nothing */
2744 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2745 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2747 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2751 case SnapToTimecodeSeconds:
2752 if (_session->config.get_timecode_offset_negative()) {
2753 start += _session->config.get_timecode_offset ();
2755 start -= _session->config.get_timecode_offset ();
2757 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2758 (start % one_timecode_second == 0)) {
2759 /* start is already on a whole second, do nothing */
2760 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2761 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2763 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2766 if (_session->config.get_timecode_offset_negative()) {
2767 start -= _session->config.get_timecode_offset ();
2769 start += _session->config.get_timecode_offset ();
2773 case SnapToTimecodeMinutes:
2774 if (_session->config.get_timecode_offset_negative()) {
2775 start += _session->config.get_timecode_offset ();
2777 start -= _session->config.get_timecode_offset ();
2779 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2780 (start % one_timecode_minute == 0)) {
2781 /* start is already on a whole minute, do nothing */
2782 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2783 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2785 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2787 if (_session->config.get_timecode_offset_negative()) {
2788 start -= _session->config.get_timecode_offset ();
2790 start += _session->config.get_timecode_offset ();
2794 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2795 abort(); /*NOTREACHED*/
2800 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2802 const framepos_t one_second = _session->frame_rate();
2803 const framepos_t one_minute = _session->frame_rate() * 60;
2804 framepos_t presnap = start;
2808 switch (_snap_type) {
2809 case SnapToTimecodeFrame:
2810 case SnapToTimecodeSeconds:
2811 case SnapToTimecodeMinutes:
2812 return timecode_snap_to_internal (start, direction, for_mark);
2815 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2816 start % (one_second/75) == 0) {
2817 /* start is already on a whole CD frame, do nothing */
2818 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2819 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2821 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2826 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2827 start % one_second == 0) {
2828 /* start is already on a whole second, do nothing */
2829 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2830 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2832 start = (framepos_t) floor ((double) start / one_second) * one_second;
2837 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2838 start % one_minute == 0) {
2839 /* start is already on a whole minute, do nothing */
2840 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2841 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2843 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2848 start = _session->tempo_map().round_to_bar (start, direction);
2852 start = _session->tempo_map().round_to_beat (start, direction);
2855 case SnapToBeatDiv128:
2856 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2858 case SnapToBeatDiv64:
2859 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2861 case SnapToBeatDiv32:
2862 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2864 case SnapToBeatDiv28:
2865 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2867 case SnapToBeatDiv24:
2868 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2870 case SnapToBeatDiv20:
2871 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2873 case SnapToBeatDiv16:
2874 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2876 case SnapToBeatDiv14:
2877 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2879 case SnapToBeatDiv12:
2880 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2882 case SnapToBeatDiv10:
2883 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2885 case SnapToBeatDiv8:
2886 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2888 case SnapToBeatDiv7:
2889 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2891 case SnapToBeatDiv6:
2892 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2894 case SnapToBeatDiv5:
2895 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2897 case SnapToBeatDiv4:
2898 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2900 case SnapToBeatDiv3:
2901 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2903 case SnapToBeatDiv2:
2904 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2912 _session->locations()->marks_either_side (start, before, after);
2914 if (before == max_framepos && after == max_framepos) {
2915 /* No marks to snap to, so just don't snap */
2917 } else if (before == max_framepos) {
2919 } else if (after == max_framepos) {
2921 } else if (before != max_framepos && after != max_framepos) {
2922 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2924 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2926 else if (direction == 0 ) {
2927 if ((start - before) < (after - start)) {
2937 case SnapToRegionStart:
2938 case SnapToRegionEnd:
2939 case SnapToRegionSync:
2940 case SnapToRegionBoundary:
2941 if (!region_boundary_cache.empty()) {
2943 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2944 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2946 if (direction > 0) {
2947 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2949 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2952 if (next != region_boundary_cache.begin ()) {
2957 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2958 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2960 if (start > (p + n) / 2) {
2969 switch (_snap_mode) {
2979 if (presnap > start) {
2980 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2984 } else if (presnap < start) {
2985 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2991 /* handled at entry */
2999 Editor::setup_toolbar ()
3001 HBox* mode_box = manage(new HBox);
3002 mode_box->set_border_width (2);
3003 mode_box->set_spacing(2);
3005 HBox* mouse_mode_box = manage (new HBox);
3006 HBox* mouse_mode_hbox = manage (new HBox);
3007 VBox* mouse_mode_vbox = manage (new VBox);
3008 Alignment* mouse_mode_align = manage (new Alignment);
3010 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3011 mouse_mode_size_group->add_widget (smart_mode_button);
3012 mouse_mode_size_group->add_widget (mouse_move_button);
3013 mouse_mode_size_group->add_widget (mouse_cut_button);
3014 mouse_mode_size_group->add_widget (mouse_select_button);
3015 mouse_mode_size_group->add_widget (mouse_timefx_button);
3016 mouse_mode_size_group->add_widget (mouse_audition_button);
3017 mouse_mode_size_group->add_widget (mouse_draw_button);
3018 mouse_mode_size_group->add_widget (mouse_content_button);
3020 if (!Profile->get_mixbus()) {
3021 mouse_mode_size_group->add_widget (zoom_in_button);
3022 mouse_mode_size_group->add_widget (zoom_out_button);
3023 mouse_mode_size_group->add_widget (zoom_out_full_button);
3024 mouse_mode_size_group->add_widget (zoom_focus_selector);
3025 mouse_mode_size_group->add_widget (tav_shrink_button);
3026 mouse_mode_size_group->add_widget (tav_expand_button);
3028 mouse_mode_size_group->add_widget (zoom_preset_selector);
3029 mouse_mode_size_group->add_widget (visible_tracks_selector);
3032 mouse_mode_size_group->add_widget (snap_type_selector);
3033 mouse_mode_size_group->add_widget (snap_mode_selector);
3035 mouse_mode_size_group->add_widget (edit_point_selector);
3036 mouse_mode_size_group->add_widget (edit_mode_selector);
3038 mouse_mode_size_group->add_widget (*nudge_clock);
3039 mouse_mode_size_group->add_widget (nudge_forward_button);
3040 mouse_mode_size_group->add_widget (nudge_backward_button);
3042 mouse_mode_hbox->set_spacing (2);
3044 if (!ARDOUR::Profile->get_trx()) {
3045 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3048 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3049 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3051 if (!ARDOUR::Profile->get_mixbus()) {
3052 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3055 if (!ARDOUR::Profile->get_trx()) {
3056 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3057 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3058 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3059 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3062 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3064 mouse_mode_align->add (*mouse_mode_vbox);
3065 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3067 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3069 edit_mode_selector.set_name ("mouse mode button");
3071 if (!ARDOUR::Profile->get_trx()) {
3072 mode_box->pack_start (edit_mode_selector, false, false);
3075 mode_box->pack_start (*mouse_mode_box, false, false);
3079 _zoom_box.set_spacing (2);
3080 _zoom_box.set_border_width (2);
3084 zoom_preset_selector.set_name ("zoom button");
3085 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3087 zoom_in_button.set_name ("zoom button");
3088 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3089 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3090 zoom_in_button.set_related_action (act);
3092 zoom_out_button.set_name ("zoom button");
3093 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3094 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3095 zoom_out_button.set_related_action (act);
3097 zoom_out_full_button.set_name ("zoom button");
3098 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3099 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3100 zoom_out_full_button.set_related_action (act);
3102 zoom_focus_selector.set_name ("zoom button");
3104 if (ARDOUR::Profile->get_mixbus()) {
3105 _zoom_box.pack_start (zoom_preset_selector, false, false);
3106 } else if (ARDOUR::Profile->get_trx()) {
3107 mode_box->pack_start (zoom_out_button, false, false);
3108 mode_box->pack_start (zoom_in_button, false, false);
3110 _zoom_box.pack_start (zoom_out_button, false, false);
3111 _zoom_box.pack_start (zoom_in_button, false, false);
3112 _zoom_box.pack_start (zoom_out_full_button, false, false);
3113 _zoom_box.pack_start (zoom_focus_selector, false, false);
3116 /* Track zoom buttons */
3117 _track_box.set_spacing (2);
3118 _track_box.set_border_width (2);
3120 visible_tracks_selector.set_name ("zoom button");
3121 if (Profile->get_mixbus()) {
3122 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3124 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3127 tav_expand_button.set_name ("zoom button");
3128 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3129 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3130 tav_expand_button.set_related_action (act);
3132 tav_shrink_button.set_name ("zoom button");
3133 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3134 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3135 tav_shrink_button.set_related_action (act);
3137 if (ARDOUR::Profile->get_mixbus()) {
3138 _track_box.pack_start (visible_tracks_selector);
3139 } else if (ARDOUR::Profile->get_trx()) {
3140 _track_box.pack_start (tav_shrink_button);
3141 _track_box.pack_start (tav_expand_button);
3143 _track_box.pack_start (visible_tracks_selector);
3144 _track_box.pack_start (tav_shrink_button);
3145 _track_box.pack_start (tav_expand_button);
3148 snap_box.set_spacing (2);
3149 snap_box.set_border_width (2);
3151 snap_type_selector.set_name ("mouse mode button");
3153 snap_mode_selector.set_name ("mouse mode button");
3155 edit_point_selector.set_name ("mouse mode button");
3157 snap_box.pack_start (snap_mode_selector, false, false);
3158 snap_box.pack_start (snap_type_selector, false, false);
3161 HBox *ep_box = manage (new HBox);
3162 ep_box->set_spacing (2);
3163 ep_box->set_border_width (2);
3165 ep_box->pack_start (edit_point_selector, false, false);
3169 HBox *nudge_box = manage (new HBox);
3170 nudge_box->set_spacing (2);
3171 nudge_box->set_border_width (2);
3173 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3174 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3176 nudge_box->pack_start (nudge_backward_button, false, false);
3177 nudge_box->pack_start (nudge_forward_button, false, false);
3178 nudge_box->pack_start (*nudge_clock, false, false);
3181 /* Pack everything in... */
3183 toolbar_hbox.set_spacing (2);
3184 toolbar_hbox.set_border_width (2);
3186 toolbar_hbox.pack_start (*mode_box, false, false);
3188 if (!ARDOUR::Profile->get_trx()) {
3190 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3192 toolbar_hbox.pack_start (_zoom_box, false, false);
3194 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3196 toolbar_hbox.pack_start (_track_box, false, false);
3198 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3200 toolbar_hbox.pack_start (snap_box, false, false);
3202 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3204 toolbar_hbox.pack_start (*ep_box, false, false);
3206 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3208 toolbar_hbox.pack_start (*nudge_box, false, false);
3211 toolbar_hbox.show_all ();
3215 Editor::build_edit_point_menu ()
3217 using namespace Menu_Helpers;
3219 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3220 if(!Profile->get_mixbus())
3221 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3222 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3224 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3228 Editor::build_edit_mode_menu ()
3230 using namespace Menu_Helpers;
3232 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3233 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3234 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3235 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3237 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3241 Editor::build_snap_mode_menu ()
3243 using namespace Menu_Helpers;
3245 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3246 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3247 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3249 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3253 Editor::build_snap_type_menu ()
3255 using namespace Menu_Helpers;
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3273 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3274 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3275 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3276 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3277 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3278 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3279 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3280 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3281 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3282 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3283 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3284 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3288 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3293 Editor::setup_tooltips ()
3295 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3296 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3297 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3298 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3299 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3300 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3301 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3302 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3303 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3304 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3305 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3306 set_tooltip (zoom_in_button, _("Zoom In"));
3307 set_tooltip (zoom_out_button, _("Zoom Out"));
3308 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3309 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3310 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3311 set_tooltip (tav_expand_button, _("Expand Tracks"));
3312 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3313 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3314 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3315 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3316 set_tooltip (edit_point_selector, _("Edit Point"));
3317 set_tooltip (edit_mode_selector, _("Edit Mode"));
3318 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3322 Editor::convert_drop_to_paths (
3323 vector<string>& paths,
3324 const RefPtr<Gdk::DragContext>& /*context*/,
3327 const SelectionData& data,
3331 if (_session == 0) {
3335 vector<string> uris = data.get_uris();
3339 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3340 are actually URI lists. So do it by hand.
3343 if (data.get_target() != "text/plain") {
3347 /* Parse the "uri-list" format that Nautilus provides,
3348 where each pathname is delimited by \r\n.
3350 THERE MAY BE NO NULL TERMINATING CHAR!!!
3353 string txt = data.get_text();
3357 p = (char *) malloc (txt.length() + 1);
3358 txt.copy (p, txt.length(), 0);
3359 p[txt.length()] = '\0';
3365 while (g_ascii_isspace (*p))
3369 while (*q && (*q != '\n') && (*q != '\r')) {
3376 while (q > p && g_ascii_isspace (*q))
3381 uris.push_back (string (p, q - p + 1));
3385 p = strchr (p, '\n');
3397 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3398 if ((*i).substr (0,7) == "file://") {
3399 paths.push_back (Glib::filename_from_uri (*i));
3407 Editor::new_tempo_section ()
3412 Editor::map_transport_state ()
3414 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3416 if (_session && _session->transport_stopped()) {
3417 have_pending_keyboard_selection = false;
3420 update_loop_range_view ();
3426 Editor::begin_selection_op_history ()
3428 selection_op_cmd_depth = 0;
3429 selection_op_history_it = 0;
3431 while(!selection_op_history.empty()) {
3432 delete selection_op_history.front();
3433 selection_op_history.pop_front();
3436 selection_undo_action->set_sensitive (false);
3437 selection_redo_action->set_sensitive (false);
3438 selection_op_history.push_front (&_selection_memento->get_state ());
3442 Editor::begin_reversible_selection_op (string name)
3445 //cerr << name << endl;
3446 /* begin/commit pairs can be nested */
3447 selection_op_cmd_depth++;
3452 Editor::commit_reversible_selection_op ()
3455 if (selection_op_cmd_depth == 1) {
3457 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3459 The user has undone some selection ops and then made a new one,
3460 making anything earlier in the list invalid.
3463 list<XMLNode *>::iterator it = selection_op_history.begin();
3464 list<XMLNode *>::iterator e_it = it;
3465 advance (e_it, selection_op_history_it);
3467 for ( ; it != e_it; ++it) {
3470 selection_op_history.erase (selection_op_history.begin(), e_it);
3473 selection_op_history.push_front (&_selection_memento->get_state ());
3474 selection_op_history_it = 0;
3476 selection_undo_action->set_sensitive (true);
3477 selection_redo_action->set_sensitive (false);
3480 if (selection_op_cmd_depth > 0) {
3481 selection_op_cmd_depth--;
3487 Editor::undo_selection_op ()
3490 selection_op_history_it++;
3492 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3493 if (n == selection_op_history_it) {
3494 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3495 selection_redo_action->set_sensitive (true);
3499 /* is there an earlier entry? */
3500 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3501 selection_undo_action->set_sensitive (false);
3507 Editor::redo_selection_op ()
3510 if (selection_op_history_it > 0) {
3511 selection_op_history_it--;
3514 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3515 if (n == selection_op_history_it) {
3516 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3517 selection_undo_action->set_sensitive (true);
3522 if (selection_op_history_it == 0) {
3523 selection_redo_action->set_sensitive (false);
3529 Editor::begin_reversible_command (string name)
3532 before.push_back (&_selection_memento->get_state ());
3533 _session->begin_reversible_command (name);
3538 Editor::begin_reversible_command (GQuark q)
3541 before.push_back (&_selection_memento->get_state ());
3542 _session->begin_reversible_command (q);
3547 Editor::abort_reversible_command ()
3550 while(!before.empty()) {
3551 delete before.front();
3554 _session->abort_reversible_command ();
3559 Editor::commit_reversible_command ()
3562 if (before.size() == 1) {
3563 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3564 redo_action->set_sensitive(false);
3565 undo_action->set_sensitive(true);
3566 begin_selection_op_history ();
3569 if (before.empty()) {
3570 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3575 _session->commit_reversible_command ();
3580 Editor::history_changed ()
3584 if (undo_action && _session) {
3585 if (_session->undo_depth() == 0) {
3586 label = S_("Command|Undo");
3588 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3590 undo_action->property_label() = label;
3593 if (redo_action && _session) {
3594 if (_session->redo_depth() == 0) {
3596 redo_action->set_sensitive (false);
3598 label = string_compose(_("Redo (%1)"), _session->next_redo());
3599 redo_action->set_sensitive (true);
3601 redo_action->property_label() = label;
3606 Editor::duplicate_range (bool with_dialog)
3610 RegionSelection rs = get_regions_from_selection_and_entered ();
3612 if ( selection->time.length() == 0 && rs.empty()) {
3618 ArdourDialog win (_("Duplicate"));
3619 Label label (_("Number of duplications:"));
3620 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3621 SpinButton spinner (adjustment, 0.0, 1);
3624 win.get_vbox()->set_spacing (12);
3625 win.get_vbox()->pack_start (hbox);
3626 hbox.set_border_width (6);
3627 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3629 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3630 place, visually. so do this by hand.
3633 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3634 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3635 spinner.grab_focus();
3641 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3642 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3643 win.set_default_response (RESPONSE_ACCEPT);
3645 spinner.grab_focus ();
3647 switch (win.run ()) {
3648 case RESPONSE_ACCEPT:
3654 times = adjustment.get_value();
3657 if ((current_mouse_mode() == Editing::MouseRange)) {
3658 if (selection->time.length()) {
3659 duplicate_selection (times);
3661 } else if (get_smart_mode()) {
3662 if (selection->time.length()) {
3663 duplicate_selection (times);
3665 duplicate_some_regions (rs, times);
3667 duplicate_some_regions (rs, times);
3672 Editor::set_edit_mode (EditMode m)
3674 Config->set_edit_mode (m);
3678 Editor::cycle_edit_mode ()
3680 switch (Config->get_edit_mode()) {
3682 Config->set_edit_mode (Ripple);
3686 Config->set_edit_mode (Lock);
3689 Config->set_edit_mode (Slide);
3695 Editor::edit_mode_selection_done ( EditMode m )
3697 Config->set_edit_mode ( m );
3701 Editor::snap_type_selection_done (SnapType snaptype)
3703 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3705 ract->set_active ();
3710 Editor::snap_mode_selection_done (SnapMode mode)
3712 RefPtr<RadioAction> ract = snap_mode_action (mode);
3715 ract->set_active (true);
3720 Editor::cycle_edit_point (bool with_marker)
3722 if(Profile->get_mixbus())
3723 with_marker = false;
3725 switch (_edit_point) {
3727 set_edit_point_preference (EditAtPlayhead);
3729 case EditAtPlayhead:
3731 set_edit_point_preference (EditAtSelectedMarker);
3733 set_edit_point_preference (EditAtMouse);
3736 case EditAtSelectedMarker:
3737 set_edit_point_preference (EditAtMouse);
3743 Editor::edit_point_selection_done (EditPoint ep)
3745 set_edit_point_preference ( ep );
3749 Editor::build_zoom_focus_menu ()
3751 using namespace Menu_Helpers;
3753 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3754 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3755 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3756 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3757 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3758 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3760 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3764 Editor::zoom_focus_selection_done ( ZoomFocus f )
3766 RefPtr<RadioAction> ract = zoom_focus_action (f);
3768 ract->set_active ();
3773 Editor::build_track_count_menu ()
3775 using namespace Menu_Helpers;
3777 if (!Profile->get_mixbus()) {
3778 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3790 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3792 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3793 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3794 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3795 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3796 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3797 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3798 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3799 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3800 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3801 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3803 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3804 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3805 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3806 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3807 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3808 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3809 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3810 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3811 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3812 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3813 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3818 Editor::set_zoom_preset (int64_t ms)
3821 temporal_zoom_session();
3825 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3826 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3830 Editor::set_visible_track_count (int32_t n)
3832 _visible_track_count = n;
3834 /* if the canvas hasn't really been allocated any size yet, just
3835 record the desired number of visible tracks and return. when canvas
3836 allocation happens, we will get called again and then we can do the
3840 if (_visible_canvas_height <= 1) {
3846 DisplaySuspender ds;
3848 if (_visible_track_count > 0) {
3849 h = trackviews_height() / _visible_track_count;
3850 std::ostringstream s;
3851 s << _visible_track_count;
3853 } else if (_visible_track_count == 0) {
3855 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3856 if ((*i)->marked_for_display()) {
3860 h = trackviews_height() / n;
3863 /* negative value means that the visible track count has
3864 been overridden by explicit track height changes.
3866 visible_tracks_selector.set_text (X_("*"));
3870 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3871 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3874 if (str != visible_tracks_selector.get_text()) {
3875 visible_tracks_selector.set_text (str);
3880 Editor::override_visible_track_count ()
3882 _visible_track_count = -1;
3883 visible_tracks_selector.set_text ( _("*") );
3887 Editor::edit_controls_button_release (GdkEventButton* ev)
3889 if (Keyboard::is_context_menu_event (ev)) {
3890 ARDOUR_UI::instance()->add_route ();
3891 } else if (ev->button == 1) {
3892 selection->clear_tracks ();
3899 Editor::mouse_select_button_release (GdkEventButton* ev)
3901 /* this handles just right-clicks */
3903 if (ev->button != 3) {
3911 Editor::set_zoom_focus (ZoomFocus f)
3913 string str = zoom_focus_strings[(int)f];
3915 if (str != zoom_focus_selector.get_text()) {
3916 zoom_focus_selector.set_text (str);
3919 if (zoom_focus != f) {
3926 Editor::cycle_zoom_focus ()
3928 switch (zoom_focus) {
3930 set_zoom_focus (ZoomFocusRight);
3932 case ZoomFocusRight:
3933 set_zoom_focus (ZoomFocusCenter);
3935 case ZoomFocusCenter:
3936 set_zoom_focus (ZoomFocusPlayhead);
3938 case ZoomFocusPlayhead:
3939 set_zoom_focus (ZoomFocusMouse);
3941 case ZoomFocusMouse:
3942 set_zoom_focus (ZoomFocusEdit);
3945 set_zoom_focus (ZoomFocusLeft);
3951 Editor::set_show_measures (bool yn)
3953 if (_show_measures != yn) {
3956 if ((_show_measures = yn) == true) {
3958 tempo_lines->show();
3961 std::vector<TempoMap::BBTPoint> grid;
3962 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3963 draw_measures (grid);
3971 Editor::toggle_follow_playhead ()
3973 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3975 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3976 set_follow_playhead (tact->get_active());
3980 /** @param yn true to follow playhead, otherwise false.
3981 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3984 Editor::set_follow_playhead (bool yn, bool catch_up)
3986 if (_follow_playhead != yn) {
3987 if ((_follow_playhead = yn) == true && catch_up) {
3989 reset_x_origin_to_follow_playhead ();
3996 Editor::toggle_stationary_playhead ()
3998 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4000 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4001 set_stationary_playhead (tact->get_active());
4006 Editor::set_stationary_playhead (bool yn)
4008 if (_stationary_playhead != yn) {
4009 if ((_stationary_playhead = yn) == true) {
4011 // FIXME need a 3.0 equivalent of this 2.X call
4012 // update_current_screen ();
4019 Editor::playlist_selector () const
4021 return *_playlist_selector;
4025 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4027 if (paste_count == 0) {
4028 /* don't bother calculating an offset that will be zero anyway */
4032 /* calculate basic unsnapped multi-paste offset */
4033 framecnt_t offset = paste_count * duration;
4035 /* snap offset so pos + offset is aligned to the grid */
4036 framepos_t offset_pos = pos + offset;
4037 snap_to(offset_pos, RoundUpMaybe);
4038 offset = offset_pos - pos;
4044 Editor::get_grid_beat_divisions(framepos_t position)
4046 switch (_snap_type) {
4047 case SnapToBeatDiv128: return 128;
4048 case SnapToBeatDiv64: return 64;
4049 case SnapToBeatDiv32: return 32;
4050 case SnapToBeatDiv28: return 28;
4051 case SnapToBeatDiv24: return 24;
4052 case SnapToBeatDiv20: return 20;
4053 case SnapToBeatDiv16: return 16;
4054 case SnapToBeatDiv14: return 14;
4055 case SnapToBeatDiv12: return 12;
4056 case SnapToBeatDiv10: return 10;
4057 case SnapToBeatDiv8: return 8;
4058 case SnapToBeatDiv7: return 7;
4059 case SnapToBeatDiv6: return 6;
4060 case SnapToBeatDiv5: return 5;
4061 case SnapToBeatDiv4: return 4;
4062 case SnapToBeatDiv3: return 3;
4063 case SnapToBeatDiv2: return 2;
4069 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4070 if the grid is non-musical, returns 0.
4071 if the grid is snapped to bars, returns -1.
4072 @param event_state the current keyboard modifier mask.
4075 Editor::get_grid_music_divisions (uint32_t event_state)
4077 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4081 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4085 switch (_snap_type) {
4086 case SnapToBeatDiv128: return 128;
4087 case SnapToBeatDiv64: return 64;
4088 case SnapToBeatDiv32: return 32;
4089 case SnapToBeatDiv28: return 28;
4090 case SnapToBeatDiv24: return 24;
4091 case SnapToBeatDiv20: return 20;
4092 case SnapToBeatDiv16: return 16;
4093 case SnapToBeatDiv14: return 14;
4094 case SnapToBeatDiv12: return 12;
4095 case SnapToBeatDiv10: return 10;
4096 case SnapToBeatDiv8: return 8;
4097 case SnapToBeatDiv7: return 7;
4098 case SnapToBeatDiv6: return 6;
4099 case SnapToBeatDiv5: return 5;
4100 case SnapToBeatDiv4: return 4;
4101 case SnapToBeatDiv3: return 3;
4102 case SnapToBeatDiv2: return 2;
4103 case SnapToBeat: return 1;
4104 case SnapToBar : return -1;
4111 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4115 const unsigned divisions = get_grid_beat_divisions(position);
4117 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4120 switch (_snap_type) {
4122 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4125 const Meter& m = _session->tempo_map().meter_at_frame (position);
4126 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4134 return Evoral::Beats();
4138 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4142 ret = nudge_clock->current_duration (pos);
4143 next = ret + 1; /* XXXX fix me */
4149 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4151 ArdourDialog dialog (_("Playlist Deletion"));
4152 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4153 "If it is kept, its audio files will not be cleaned.\n"
4154 "If it is deleted, audio files used by it alone will be cleaned."),
4157 dialog.set_position (WIN_POS_CENTER);
4158 dialog.get_vbox()->pack_start (label);
4162 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4163 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4164 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4165 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4166 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4168 // by default gtk uses the left most button
4169 keep->grab_focus ();
4171 switch (dialog.run ()) {
4173 /* keep this and all remaining ones */
4178 /* delete this and all others */
4182 case RESPONSE_ACCEPT:
4183 /* delete the playlist */
4187 case RESPONSE_REJECT:
4188 /* keep the playlist */
4200 Editor::audio_region_selection_covers (framepos_t where)
4202 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4203 if ((*a)->region()->covers (where)) {
4212 Editor::prepare_for_cleanup ()
4214 cut_buffer->clear_regions ();
4215 cut_buffer->clear_playlists ();
4217 selection->clear_regions ();
4218 selection->clear_playlists ();
4220 _regions->suspend_redisplay ();
4224 Editor::finish_cleanup ()
4226 _regions->resume_redisplay ();
4230 Editor::transport_loop_location()
4233 return _session->locations()->auto_loop_location();
4240 Editor::transport_punch_location()
4243 return _session->locations()->auto_punch_location();
4250 Editor::control_layout_scroll (GdkEventScroll* ev)
4252 /* Just forward to the normal canvas scroll method. The coordinate
4253 systems are different but since the canvas is always larger than the
4254 track headers, and aligned with the trackview area, this will work.
4256 In the not too distant future this layout is going away anyway and
4257 headers will be on the canvas.
4259 return canvas_scroll_event (ev, false);
4263 Editor::session_state_saved (string)
4266 _snapshots->redisplay ();
4270 Editor::maximise_editing_space ()
4276 Gtk::Window* toplevel = current_toplevel();
4279 toplevel->fullscreen ();
4285 Editor::restore_editing_space ()
4291 Gtk::Window* toplevel = current_toplevel();
4294 toplevel->unfullscreen();
4300 * Make new playlists for a given track and also any others that belong
4301 * to the same active route group with the `select' property.
4306 Editor::new_playlists (TimeAxisView* v)
4308 begin_reversible_command (_("new playlists"));
4309 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4310 _session->playlists->get (playlists);
4311 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4312 commit_reversible_command ();
4316 * Use a copy of the current playlist for a given track and also any others that belong
4317 * to the same active route group with the `select' property.
4322 Editor::copy_playlists (TimeAxisView* v)
4324 begin_reversible_command (_("copy playlists"));
4325 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4326 _session->playlists->get (playlists);
4327 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4328 commit_reversible_command ();
4331 /** Clear the current playlist for a given track and also any others that belong
4332 * to the same active route group with the `select' property.
4337 Editor::clear_playlists (TimeAxisView* v)
4339 begin_reversible_command (_("clear playlists"));
4340 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4341 _session->playlists->get (playlists);
4342 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4343 commit_reversible_command ();
4347 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4349 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4353 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4355 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4359 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4361 atv.clear_playlist ();
4365 Editor::get_y_origin () const
4367 return vertical_adjustment.get_value ();
4370 /** Queue up a change to the viewport x origin.
4371 * @param frame New x origin.
4374 Editor::reset_x_origin (framepos_t frame)
4376 pending_visual_change.add (VisualChange::TimeOrigin);
4377 pending_visual_change.time_origin = frame;
4378 ensure_visual_change_idle_handler ();
4382 Editor::reset_y_origin (double y)
4384 pending_visual_change.add (VisualChange::YOrigin);
4385 pending_visual_change.y_origin = y;
4386 ensure_visual_change_idle_handler ();
4390 Editor::reset_zoom (framecnt_t spp)
4392 if (spp == samples_per_pixel) {
4396 pending_visual_change.add (VisualChange::ZoomLevel);
4397 pending_visual_change.samples_per_pixel = spp;
4398 ensure_visual_change_idle_handler ();
4402 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4404 reset_x_origin (frame);
4407 if (!no_save_visual) {
4408 undo_visual_stack.push_back (current_visual_state(false));
4412 Editor::VisualState::VisualState (bool with_tracks)
4413 : gui_state (with_tracks ? new GUIObjectState : 0)
4417 Editor::VisualState::~VisualState ()
4422 Editor::VisualState*
4423 Editor::current_visual_state (bool with_tracks)
4425 VisualState* vs = new VisualState (with_tracks);
4426 vs->y_position = vertical_adjustment.get_value();
4427 vs->samples_per_pixel = samples_per_pixel;
4428 vs->leftmost_frame = leftmost_frame;
4429 vs->zoom_focus = zoom_focus;
4432 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4439 Editor::undo_visual_state ()
4441 if (undo_visual_stack.empty()) {
4445 VisualState* vs = undo_visual_stack.back();
4446 undo_visual_stack.pop_back();
4449 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4452 use_visual_state (*vs);
4457 Editor::redo_visual_state ()
4459 if (redo_visual_stack.empty()) {
4463 VisualState* vs = redo_visual_stack.back();
4464 redo_visual_stack.pop_back();
4466 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4467 // why do we check here?
4468 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4471 use_visual_state (*vs);
4476 Editor::swap_visual_state ()
4478 if (undo_visual_stack.empty()) {
4479 redo_visual_state ();
4481 undo_visual_state ();
4486 Editor::use_visual_state (VisualState& vs)
4488 PBD::Unwinder<bool> nsv (no_save_visual, true);
4489 DisplaySuspender ds;
4491 vertical_adjustment.set_value (vs.y_position);
4493 set_zoom_focus (vs.zoom_focus);
4494 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4497 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4499 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4500 (*i)->clear_property_cache();
4501 (*i)->reset_visual_state ();
4505 _routes->update_visibility ();
4508 /** This is the core function that controls the zoom level of the canvas. It is called
4509 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4510 * @param spp new number of samples per pixel
4513 Editor::set_samples_per_pixel (framecnt_t spp)
4519 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4520 const framecnt_t lots_of_pixels = 4000;
4522 /* if the zoom level is greater than what you'd get trying to display 3
4523 * days of audio on a really big screen, then it's too big.
4526 if (spp * lots_of_pixels > three_days) {
4530 samples_per_pixel = spp;
4533 tempo_lines->tempo_map_changed();
4536 bool const showing_time_selection = selection->time.length() > 0;
4538 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4539 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4540 (*i)->reshow_selection (selection->time);
4544 ZoomChanged (); /* EMIT_SIGNAL */
4546 ArdourCanvas::GtkCanvasViewport* c;
4548 c = get_track_canvas();
4550 c->canvas()->zoomed ();
4553 if (playhead_cursor) {
4554 playhead_cursor->set_position (playhead_cursor->current_frame ());
4557 refresh_location_display();
4558 _summary->set_overlays_dirty ();
4560 update_marker_labels ();
4566 Editor::playhead_cursor_sample () const
4568 return playhead_cursor->current_frame();
4572 Editor::queue_visual_videotimeline_update ()
4575 * pending_visual_change.add (VisualChange::VideoTimeline);
4576 * or maybe even more specific: which videotimeline-image
4577 * currently it calls update_video_timeline() to update
4578 * _all outdated_ images on the video-timeline.
4579 * see 'exposeimg()' in video_image_frame.cc
4581 ensure_visual_change_idle_handler ();
4585 Editor::ensure_visual_change_idle_handler ()
4587 if (pending_visual_change.idle_handler_id < 0) {
4588 // see comment in add_to_idle_resize above.
4589 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4590 pending_visual_change.being_handled = false;
4595 Editor::_idle_visual_changer (void* arg)
4597 return static_cast<Editor*>(arg)->idle_visual_changer ();
4601 Editor::idle_visual_changer ()
4603 /* set_horizontal_position() below (and maybe other calls) call
4604 gtk_main_iteration(), so it's possible that a signal will be handled
4605 half-way through this method. If this signal wants an
4606 idle_visual_changer we must schedule another one after this one, so
4607 mark the idle_handler_id as -1 here to allow that. Also make a note
4608 that we are doing the visual change, so that changes in response to
4609 super-rapid-screen-update can be dropped if we are still processing
4613 pending_visual_change.idle_handler_id = -1;
4614 pending_visual_change.being_handled = true;
4616 VisualChange vc = pending_visual_change;
4618 pending_visual_change.pending = (VisualChange::Type) 0;
4620 visual_changer (vc);
4622 pending_visual_change.being_handled = false;
4624 return 0; /* this is always a one-shot call */
4628 Editor::visual_changer (const VisualChange& vc)
4630 double const last_time_origin = horizontal_position ();
4632 if (vc.pending & VisualChange::ZoomLevel) {
4633 set_samples_per_pixel (vc.samples_per_pixel);
4635 compute_fixed_ruler_scale ();
4637 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4638 update_tempo_based_rulers ();
4640 update_video_timeline();
4643 if (vc.pending & VisualChange::TimeOrigin) {
4644 set_horizontal_position (vc.time_origin / samples_per_pixel);
4647 if (vc.pending & VisualChange::YOrigin) {
4648 vertical_adjustment.set_value (vc.y_origin);
4651 if (last_time_origin == horizontal_position ()) {
4652 /* changed signal not emitted */
4653 update_fixed_rulers ();
4654 redisplay_tempo (true);
4657 if (!(vc.pending & VisualChange::ZoomLevel)) {
4658 update_video_timeline();
4661 _summary->set_overlays_dirty ();
4664 struct EditorOrderTimeAxisSorter {
4665 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4666 return a->order () < b->order ();
4671 Editor::sort_track_selection (TrackViewList& sel)
4673 EditorOrderTimeAxisSorter cmp;
4678 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4681 framepos_t where = 0;
4682 EditPoint ep = _edit_point;
4684 if (Profile->get_mixbus()) {
4685 if (ep == EditAtSelectedMarker) {
4686 ep = EditAtPlayhead;
4690 if (from_outside_canvas && (ep == EditAtMouse)) {
4691 ep = EditAtPlayhead;
4692 } else if (from_context_menu && (ep == EditAtMouse)) {
4693 return canvas_event_sample (&context_click_event, 0, 0);
4696 if (entered_marker) {
4697 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4698 return entered_marker->position();
4701 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4702 ep = EditAtSelectedMarker;
4705 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4706 ep = EditAtPlayhead;
4710 case EditAtPlayhead:
4711 if (_dragging_playhead) {
4712 where = *_control_scroll_target;
4714 where = _session->audible_frame();
4716 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4719 case EditAtSelectedMarker:
4720 if (!selection->markers.empty()) {
4722 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4725 where = loc->start();
4729 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4737 if (!mouse_frame (where, ignored)) {
4738 /* XXX not right but what can we do ? */
4742 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4750 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4752 if (!_session) return;
4754 begin_reversible_command (cmd);
4758 if ((tll = transport_loop_location()) == 0) {
4759 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4760 XMLNode &before = _session->locations()->get_state();
4761 _session->locations()->add (loc, true);
4762 _session->set_auto_loop_location (loc);
4763 XMLNode &after = _session->locations()->get_state();
4764 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4766 XMLNode &before = tll->get_state();
4767 tll->set_hidden (false, this);
4768 tll->set (start, end);
4769 XMLNode &after = tll->get_state();
4770 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4773 commit_reversible_command ();
4777 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4779 if (!_session) return;
4781 begin_reversible_command (cmd);
4785 if ((tpl = transport_punch_location()) == 0) {
4786 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4787 XMLNode &before = _session->locations()->get_state();
4788 _session->locations()->add (loc, true);
4789 _session->set_auto_punch_location (loc);
4790 XMLNode &after = _session->locations()->get_state();
4791 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4793 XMLNode &before = tpl->get_state();
4794 tpl->set_hidden (false, this);
4795 tpl->set (start, end);
4796 XMLNode &after = tpl->get_state();
4797 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4800 commit_reversible_command ();
4803 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4804 * @param rs List to which found regions are added.
4805 * @param where Time to look at.
4806 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4809 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4811 const TrackViewList* tracks;
4814 tracks = &track_views;
4819 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4821 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4824 boost::shared_ptr<Track> tr;
4825 boost::shared_ptr<Playlist> pl;
4827 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4829 boost::shared_ptr<RegionList> regions = pl->regions_at (
4830 (framepos_t) floor ( (double) where * tr->speed()));
4832 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4833 RegionView* rv = rtv->view()->find_view (*i);
4844 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4846 const TrackViewList* tracks;
4849 tracks = &track_views;
4854 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4855 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4857 boost::shared_ptr<Track> tr;
4858 boost::shared_ptr<Playlist> pl;
4860 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4862 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4863 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4865 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4867 RegionView* rv = rtv->view()->find_view (*i);
4878 /** Get regions using the following method:
4880 * Make a region list using:
4881 * (a) any selected regions
4882 * (b) the intersection of any selected tracks and the edit point(*)
4883 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4885 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4887 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4891 Editor::get_regions_from_selection_and_edit_point ()
4893 RegionSelection regions;
4895 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4896 regions.add (entered_regionview);
4898 regions = selection->regions;
4901 if ( regions.empty() ) {
4902 TrackViewList tracks = selection->tracks;
4904 if (!tracks.empty()) {
4905 /* no region selected or entered, but some selected tracks:
4906 * act on all regions on the selected tracks at the edit point
4908 framepos_t const where = get_preferred_edit_position ();
4909 get_regions_at(regions, where, tracks);
4916 /** Get regions using the following method:
4918 * Make a region list using:
4919 * (a) any selected regions
4920 * (b) the intersection of any selected tracks and the edit point(*)
4921 * (c) if neither exists, then whatever region is under the mouse
4923 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4925 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4928 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4930 RegionSelection regions;
4932 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4933 regions.add (entered_regionview);
4935 regions = selection->regions;
4938 if ( regions.empty() ) {
4939 TrackViewList tracks = selection->tracks;
4941 if (!tracks.empty()) {
4942 /* no region selected or entered, but some selected tracks:
4943 * act on all regions on the selected tracks at the edit point
4945 get_regions_at(regions, pos, tracks);
4952 /** Start with regions that are selected, or the entered regionview if none are selected.
4953 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4954 * of the regions that we started with.
4958 Editor::get_regions_from_selection_and_entered () const
4960 RegionSelection regions = selection->regions;
4962 if (regions.empty() && entered_regionview) {
4963 regions.add (entered_regionview);
4970 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4972 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4973 RouteTimeAxisView* rtav;
4975 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4976 boost::shared_ptr<Playlist> pl;
4977 std::vector<boost::shared_ptr<Region> > results;
4978 boost::shared_ptr<Track> tr;
4980 if ((tr = rtav->track()) == 0) {
4985 if ((pl = (tr->playlist())) != 0) {
4986 boost::shared_ptr<Region> r = pl->region_by_id (id);
4988 RegionView* rv = rtav->view()->find_view (r);
4990 regions.push_back (rv);
4999 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5002 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5003 MidiTimeAxisView* mtav;
5005 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5007 mtav->get_per_region_note_selection (selection);
5014 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5016 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5018 RouteTimeAxisView* tatv;
5020 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5022 boost::shared_ptr<Playlist> pl;
5023 vector<boost::shared_ptr<Region> > results;
5025 boost::shared_ptr<Track> tr;
5027 if ((tr = tatv->track()) == 0) {
5032 if ((pl = (tr->playlist())) != 0) {
5033 if (src_comparison) {
5034 pl->get_source_equivalent_regions (region, results);
5036 pl->get_region_list_equivalent_regions (region, results);
5040 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5041 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5042 regions.push_back (marv);
5051 Editor::show_rhythm_ferret ()
5053 if (rhythm_ferret == 0) {
5054 rhythm_ferret = new RhythmFerret(*this);
5057 rhythm_ferret->set_session (_session);
5058 rhythm_ferret->show ();
5059 rhythm_ferret->present ();
5063 Editor::first_idle ()
5065 MessageDialog* dialog = 0;
5067 if (track_views.size() > 1) {
5068 Timers::TimerSuspender t;
5069 dialog = new MessageDialog (
5070 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5074 ARDOUR_UI::instance()->flush_pending (60);
5077 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5081 // first idle adds route children (automation tracks), so we need to redisplay here
5082 _routes->redisplay ();
5086 if (_session->undo_depth() == 0) {
5087 undo_action->set_sensitive(false);
5089 redo_action->set_sensitive(false);
5090 begin_selection_op_history ();
5096 Editor::_idle_resize (gpointer arg)
5098 return ((Editor*)arg)->idle_resize ();
5102 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5104 if (resize_idle_id < 0) {
5105 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5106 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5107 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5109 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5110 _pending_resize_amount = 0;
5113 /* make a note of the smallest resulting height, so that we can clamp the
5114 lower limit at TimeAxisView::hSmall */
5116 int32_t min_resulting = INT32_MAX;
5118 _pending_resize_amount += h;
5119 _pending_resize_view = view;
5121 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5123 if (selection->tracks.contains (_pending_resize_view)) {
5124 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5125 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5129 if (min_resulting < 0) {
5134 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5135 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5139 /** Handle pending resizing of tracks */
5141 Editor::idle_resize ()
5143 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5145 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5146 selection->tracks.contains (_pending_resize_view)) {
5148 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5149 if (*i != _pending_resize_view) {
5150 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5155 _pending_resize_amount = 0;
5156 _group_tabs->set_dirty ();
5157 resize_idle_id = -1;
5165 ENSURE_GUI_THREAD (*this, &Editor::located);
5168 playhead_cursor->set_position (_session->audible_frame ());
5169 if (_follow_playhead && !_pending_initial_locate) {
5170 reset_x_origin_to_follow_playhead ();
5174 _pending_locate_request = false;
5175 _pending_initial_locate = false;
5179 Editor::region_view_added (RegionView * rv)
5181 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5182 if (rv->region ()->id () == (*pr)) {
5183 selection->add (rv);
5184 selection->regions.pending.erase (pr);
5189 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5191 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5192 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5193 if (rv->region()->id () == (*rnote).first) {
5194 mrv->select_notes ((*rnote).second);
5195 selection->pending_midi_note_selection.erase(rnote);
5201 _summary->set_background_dirty ();
5205 Editor::region_view_removed ()
5207 _summary->set_background_dirty ();
5211 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5213 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5214 if ((*j)->stripable() == s) {
5224 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5228 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5229 TimeAxisView* tv = axis_view_from_stripable (*i);
5239 Editor::suspend_route_redisplay ()
5242 _routes->suspend_redisplay();
5247 Editor::resume_route_redisplay ()
5250 _routes->redisplay(); // queue redisplay
5251 _routes->resume_redisplay();
5256 Editor::add_vcas (VCAList& vlist)
5260 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5261 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5264 add_stripables (sl);
5268 Editor::add_routes (RouteList& rlist)
5272 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5276 add_stripables (sl);
5280 Editor::add_stripables (StripableList& sl)
5282 list<TimeAxisView*> new_views;
5283 boost::shared_ptr<VCA> v;
5284 boost::shared_ptr<Route> r;
5285 TrackViewList new_selection;
5286 bool from_scratch = (track_views.size() == 0);
5288 sl.sort (StripablePresentationInfoSorter());
5290 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5292 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5294 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5296 new_views.push_back (vtv);
5298 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5300 if (r->is_auditioner() || r->is_monitor()) {
5304 RouteTimeAxisView* rtv;
5305 DataType dt = r->input()->default_type();
5307 if (dt == ARDOUR::DataType::AUDIO) {
5308 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5310 } else if (dt == ARDOUR::DataType::MIDI) {
5311 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5314 throw unknown_type();
5317 new_views.push_back (rtv);
5318 track_views.push_back (rtv);
5319 new_selection.push_back (rtv);
5321 rtv->effective_gain_display ();
5323 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5324 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5328 if (new_views.size() > 0) {
5329 _routes->time_axis_views_added (new_views);
5330 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5333 /* note: !new_selection.empty() means that we got some routes rather
5337 if (!from_scratch && !new_selection.empty()) {
5338 selection->tracks.clear();
5339 selection->add (new_selection);
5340 begin_selection_op_history();
5343 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5344 show_editor_mixer (true);
5347 editor_list_button.set_sensitive (true);
5351 Editor::timeaxisview_deleted (TimeAxisView *tv)
5353 if (tv == entered_track) {
5357 if (_session && _session->deletion_in_progress()) {
5358 /* the situation is under control */
5362 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5364 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5366 _routes->route_removed (tv);
5368 TimeAxisView::Children c = tv->get_child_list ();
5369 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5370 if (entered_track == i->get()) {
5375 /* remove it from the list of track views */
5377 TrackViewList::iterator i;
5379 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5380 i = track_views.erase (i);
5383 /* update whatever the current mixer strip is displaying, if revelant */
5385 boost::shared_ptr<Route> route;
5388 route = rtav->route ();
5391 if (current_mixer_strip && current_mixer_strip->route() == route) {
5393 TimeAxisView* next_tv;
5395 if (track_views.empty()) {
5397 } else if (i == track_views.end()) {
5398 next_tv = track_views.front();
5405 set_selected_mixer_strip (*next_tv);
5407 /* make the editor mixer strip go away setting the
5408 * button to inactive (which also unticks the menu option)
5411 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5417 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5419 if (apply_to_selection) {
5420 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5422 TrackSelection::iterator j = i;
5425 hide_track_in_display (*i, false);
5430 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5432 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5433 // this will hide the mixer strip
5434 set_selected_mixer_strip (*tv);
5437 _routes->hide_track_in_display (*tv);
5442 Editor::sync_track_view_list_and_routes ()
5444 track_views = TrackViewList (_routes->views ());
5446 _summary->set_background_dirty();
5447 _group_tabs->set_dirty ();
5449 return false; // do not call again (until needed)
5453 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5455 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5460 /** Find a RouteTimeAxisView by the ID of its route */
5462 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5464 RouteTimeAxisView* v;
5466 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5467 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5468 if(v->route()->id() == id) {
5478 Editor::fit_route_group (RouteGroup *g)
5480 TrackViewList ts = axis_views_from_routes (g->route_list ());
5485 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5487 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5490 _session->cancel_audition ();
5494 if (_session->is_auditioning()) {
5495 _session->cancel_audition ();
5496 if (r == last_audition_region) {
5501 _session->audition_region (r);
5502 last_audition_region = r;
5507 Editor::hide_a_region (boost::shared_ptr<Region> r)
5509 r->set_hidden (true);
5513 Editor::show_a_region (boost::shared_ptr<Region> r)
5515 r->set_hidden (false);
5519 Editor::audition_region_from_region_list ()
5521 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5525 Editor::hide_region_from_region_list ()
5527 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5531 Editor::show_region_in_region_list ()
5533 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5537 Editor::step_edit_status_change (bool yn)
5540 start_step_editing ();
5542 stop_step_editing ();
5547 Editor::start_step_editing ()
5549 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5553 Editor::stop_step_editing ()
5555 step_edit_connection.disconnect ();
5559 Editor::check_step_edit ()
5561 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5562 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5564 mtv->check_step_edit ();
5568 return true; // do it again, till we stop
5572 Editor::scroll_press (Direction dir)
5574 ++_scroll_callbacks;
5576 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5577 /* delay the first auto-repeat */
5583 scroll_backward (1);
5591 scroll_up_one_track ();
5595 scroll_down_one_track ();
5599 /* do hacky auto-repeat */
5600 if (!_scroll_connection.connected ()) {
5602 _scroll_connection = Glib::signal_timeout().connect (
5603 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5606 _scroll_callbacks = 0;
5613 Editor::scroll_release ()
5615 _scroll_connection.disconnect ();
5618 /** Queue a change for the Editor viewport x origin to follow the playhead */
5620 Editor::reset_x_origin_to_follow_playhead ()
5622 framepos_t const frame = playhead_cursor->current_frame ();
5624 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5626 if (_session->transport_speed() < 0) {
5628 if (frame > (current_page_samples() / 2)) {
5629 center_screen (frame-(current_page_samples()/2));
5631 center_screen (current_page_samples()/2);
5638 if (frame < leftmost_frame) {
5640 if (_session->transport_rolling()) {
5641 /* rolling; end up with the playhead at the right of the page */
5642 l = frame - current_page_samples ();
5644 /* not rolling: end up with the playhead 1/4 of the way along the page */
5645 l = frame - current_page_samples() / 4;
5649 if (_session->transport_rolling()) {
5650 /* rolling: end up with the playhead on the left of the page */
5653 /* not rolling: end up with the playhead 3/4 of the way along the page */
5654 l = frame - 3 * current_page_samples() / 4;
5662 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5668 Editor::super_rapid_screen_update ()
5670 if (!_session || !_session->engine().running()) {
5674 /* METERING / MIXER STRIPS */
5676 /* update track meters, if required */
5677 if (contents().is_mapped() && meters_running) {
5678 RouteTimeAxisView* rtv;
5679 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5680 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5681 rtv->fast_update ();
5686 /* and any current mixer strip */
5687 if (current_mixer_strip) {
5688 current_mixer_strip->fast_update ();
5691 /* PLAYHEAD AND VIEWPORT */
5693 framepos_t const frame = _session->audible_frame();
5695 /* There are a few reasons why we might not update the playhead / viewport stuff:
5697 * 1. we don't update things when there's a pending locate request, otherwise
5698 * when the editor requests a locate there is a chance that this method
5699 * will move the playhead before the locate request is processed, causing
5701 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5702 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5705 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5707 last_update_frame = frame;
5709 if (!_dragging_playhead) {
5710 playhead_cursor->set_position (frame);
5713 if (!_stationary_playhead) {
5715 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5716 /* We only do this if we aren't already
5717 handling a visual change (ie if
5718 pending_visual_change.being_handled is
5719 false) so that these requests don't stack
5720 up there are too many of them to handle in
5723 reset_x_origin_to_follow_playhead ();
5728 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5729 framepos_t const frame = playhead_cursor->current_frame ();
5730 double target = ((double)frame - (double)current_page_samples()/2.0);
5731 if (target <= 0.0) {
5734 // compare to EditorCursor::set_position()
5735 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5736 double const new_pos = sample_to_pixel_unrounded (target);
5737 if (rint (new_pos) != rint (old_pos)) {
5738 reset_x_origin (pixel_to_sample (floor (new_pos)));
5749 Editor::session_going_away ()
5751 _have_idled = false;
5753 _session_connections.drop_connections ();
5755 super_rapid_screen_update_connection.disconnect ();
5757 selection->clear ();
5758 cut_buffer->clear ();
5760 clicked_regionview = 0;
5761 clicked_axisview = 0;
5762 clicked_routeview = 0;
5763 entered_regionview = 0;
5765 last_update_frame = 0;
5768 playhead_cursor->hide ();
5770 /* rip everything out of the list displays */
5774 _route_groups->clear ();
5776 /* do this first so that deleting a track doesn't reset cms to null
5777 and thus cause a leak.
5780 if (current_mixer_strip) {
5781 if (current_mixer_strip->get_parent() != 0) {
5782 global_hpacker.remove (*current_mixer_strip);
5784 delete current_mixer_strip;
5785 current_mixer_strip = 0;
5788 /* delete all trackviews */
5790 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5793 track_views.clear ();
5795 nudge_clock->set_session (0);
5797 editor_list_button.set_active(false);
5798 editor_list_button.set_sensitive(false);
5800 /* clear tempo/meter rulers */
5801 remove_metric_marks ();
5803 clear_marker_display ();
5805 stop_step_editing ();
5809 /* get rid of any existing editor mixer strip */
5811 WindowTitle title(Glib::get_application_name());
5812 title += _("Editor");
5814 own_window()->set_title (title.get_string());
5817 SessionHandlePtr::session_going_away ();
5821 Editor::trigger_script (int i)
5823 LuaInstance::instance()-> call_action (i);
5827 Editor::set_script_action_name (int i, const std::string& n)
5829 string const a = string_compose (X_("script-action-%1"), i + 1);
5830 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5833 act->set_label (string_compose (_("Unset #%1"), i + 1));
5834 act->set_tooltip (_("no action bound"));
5835 act->set_sensitive (false);
5838 act->set_tooltip (n);
5839 act->set_sensitive (true);
5841 KeyEditor::UpdateBindings ();
5845 Editor::show_editor_list (bool yn)
5848 _editor_list_vbox.show ();
5850 _editor_list_vbox.hide ();
5855 Editor::change_region_layering_order (bool from_context_menu)
5857 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5859 if (!clicked_routeview) {
5860 if (layering_order_editor) {
5861 layering_order_editor->hide ();
5866 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5872 boost::shared_ptr<Playlist> pl = track->playlist();
5878 if (layering_order_editor == 0) {
5879 layering_order_editor = new RegionLayeringOrderEditor (*this);
5882 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5883 layering_order_editor->maybe_present ();
5887 Editor::update_region_layering_order_editor ()
5889 if (layering_order_editor && layering_order_editor->is_visible ()) {
5890 change_region_layering_order (true);
5895 Editor::setup_fade_images ()
5897 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5898 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5899 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5900 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5901 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5903 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5904 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5905 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5906 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5907 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5909 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5910 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5911 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5912 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5913 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5915 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5916 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5917 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5918 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5919 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5923 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5925 Editor::action_menu_item (std::string const & name)
5927 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5930 return *manage (a->create_menu_item ());
5934 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5936 EventBox* b = manage (new EventBox);
5937 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5938 Label* l = manage (new Label (name));
5942 _the_notebook.append_page (widget, *b);
5946 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5948 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5949 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5952 if (ev->type == GDK_2BUTTON_PRESS) {
5954 /* double-click on a notebook tab shrinks or expands the notebook */
5956 if (_notebook_shrunk) {
5957 if (pre_notebook_shrink_pane_width) {
5958 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5960 _notebook_shrunk = false;
5962 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5964 /* this expands the LHS of the edit pane to cover the notebook
5965 PAGE but leaves the tabs visible.
5967 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5968 _notebook_shrunk = true;
5976 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5978 using namespace Menu_Helpers;
5980 MenuList& items = _control_point_context_menu.items ();
5983 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5984 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5985 if (!can_remove_control_point (item)) {
5986 items.back().set_sensitive (false);
5989 _control_point_context_menu.popup (event->button.button, event->button.time);
5993 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5995 using namespace Menu_Helpers;
5997 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6002 /* We need to get the selection here and pass it to the operations, since
6003 popping up the menu will cause a region leave event which clears
6004 entered_regionview. */
6006 MidiRegionView& mrv = note->region_view();
6007 const RegionSelection rs = get_regions_from_selection_and_entered ();
6008 const uint32_t sel_size = mrv.selection_size ();
6010 MenuList& items = _note_context_menu.items();
6014 items.push_back(MenuElem(_("Delete"),
6015 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6018 items.push_back(MenuElem(_("Edit..."),
6019 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6020 if (sel_size != 1) {
6021 items.back().set_sensitive (false);
6024 items.push_back(MenuElem(_("Transpose..."),
6025 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6028 items.push_back(MenuElem(_("Legatize"),
6029 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6031 items.back().set_sensitive (false);
6034 items.push_back(MenuElem(_("Quantize..."),
6035 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6037 items.push_back(MenuElem(_("Remove Overlap"),
6038 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6040 items.back().set_sensitive (false);
6043 items.push_back(MenuElem(_("Transform..."),
6044 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6046 _note_context_menu.popup (event->button.button, event->button.time);
6050 Editor::zoom_vertical_modifier_released()
6052 _stepping_axis_view = 0;
6056 Editor::ui_parameter_changed (string parameter)
6058 if (parameter == "icon-set") {
6059 while (!_cursor_stack.empty()) {
6060 _cursor_stack.pop_back();
6062 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6063 _cursor_stack.push_back(_cursors->grabber);
6064 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6065 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6067 } else if (parameter == "draggable-playhead") {
6068 if (_verbose_cursor) {
6069 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6075 Editor::use_own_window (bool and_fill_it)
6077 bool new_window = !own_window();
6079 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6081 if (win && new_window) {
6082 win->set_name ("EditorWindow");
6084 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6086 // win->signal_realize().connect (*this, &Editor::on_realize);
6087 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6088 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6089 win->set_data ("ardour-bindings", bindings);
6094 DisplaySuspender ds;
6095 contents().show_all ();
6097 /* XXX: this is a bit unfortunate; it would probably
6098 be nicer if we could just call show () above rather
6099 than needing the show_all ()
6102 /* re-hide stuff if necessary */
6103 editor_list_button_toggled ();
6104 parameter_changed ("show-summary");
6105 parameter_changed ("show-group-tabs");
6106 parameter_changed ("show-zoom-tools");
6108 /* now reset all audio_time_axis heights, because widgets might need
6114 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6115 tv = (static_cast<TimeAxisView*>(*i));
6116 tv->reset_height ();
6119 if (current_mixer_strip) {
6120 current_mixer_strip->hide_things ();
6121 current_mixer_strip->parameter_changed ("mixer-element-visibility");