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 "audio_clock.h"
91 #include "audio_region_view.h"
92 #include "audio_streamview.h"
93 #include "audio_time_axis.h"
94 #include "automation_time_axis.h"
95 #include "bundle_manager.h"
96 #include "crossfade_edit.h"
100 #include "editor_cursors.h"
101 #include "editor_drag.h"
102 #include "editor_group_tabs.h"
103 #include "editor_locations.h"
104 #include "editor_regions.h"
105 #include "editor_route_groups.h"
106 #include "editor_routes.h"
107 #include "editor_snapshots.h"
108 #include "editor_summary.h"
109 #include "export_report.h"
110 #include "global_port_matrix.h"
111 #include "gui_object.h"
112 #include "gui_thread.h"
113 #include "keyboard.h"
114 #include "keyeditor.h"
115 #include "luainstance.h"
117 #include "midi_region_view.h"
118 #include "midi_time_axis.h"
119 #include "mixer_strip.h"
120 #include "mixer_ui.h"
121 #include "mouse_cursors.h"
122 #include "note_base.h"
123 #include "playlist_selector.h"
124 #include "public_editor.h"
125 #include "quantize_dialog.h"
126 #include "region_layering_order_editor.h"
127 #include "rgb_macros.h"
128 #include "rhythm_ferret.h"
129 #include "route_sorter.h"
130 #include "selection.h"
131 #include "simple_progress_dialog.h"
133 #include "tempo_lines.h"
134 #include "time_axis_view.h"
135 #include "time_info_box.h"
137 #include "tooltips.h"
138 #include "ui_config.h"
140 #include "vca_time_axis.h"
141 #include "verbose_cursor.h"
143 #include "pbd/i18n.h"
146 using namespace ARDOUR;
147 using namespace ARDOUR_UI_UTILS;
150 using namespace Glib;
151 using namespace Gtkmm2ext;
152 using namespace Editing;
154 using PBD::internationalize;
156 using Gtkmm2ext::Keyboard;
158 double Editor::timebar_height = 15.0;
160 static const gchar *_snap_type_strings[] = {
194 static const gchar *_snap_mode_strings[] = {
201 static const gchar *_edit_point_strings[] = {
208 static const gchar *_edit_mode_strings[] = {
216 static const gchar *_zoom_focus_strings[] = {
226 #ifdef USE_RUBBERBAND
227 static const gchar *_rb_opt_strings[] = {
230 N_("Balanced multitimbral mixture"),
231 N_("Unpitched percussion with stable notes"),
232 N_("Crisp monophonic instrumental"),
233 N_("Unpitched solo percussion"),
234 N_("Resample without preserving pitch"),
239 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
242 : PublicEditor (global_hpacker)
243 , editor_mixer_strip_width (Wide)
244 , constructed (false)
245 , _playlist_selector (0)
247 , no_save_visual (false)
249 , samples_per_pixel (2048)
250 , zoom_focus (ZoomFocusPlayhead)
251 , mouse_mode (MouseObject)
252 , pre_internal_snap_type (SnapToBeat)
253 , pre_internal_snap_mode (SnapOff)
254 , internal_snap_type (SnapToBeat)
255 , internal_snap_mode (SnapOff)
256 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
257 , _notebook_shrunk (false)
258 , location_marker_color (0)
259 , location_range_color (0)
260 , location_loop_color (0)
261 , location_punch_color (0)
262 , location_cd_marker_color (0)
264 , _show_marker_lines (false)
265 , clicked_axisview (0)
266 , clicked_routeview (0)
267 , clicked_regionview (0)
268 , clicked_selection (0)
269 , clicked_control_point (0)
270 , button_release_can_deselect (true)
271 , _mouse_changed_selection (false)
272 , region_edit_menu_split_item (0)
273 , region_edit_menu_split_multichannel_item (0)
274 , track_region_edit_playlist_menu (0)
275 , track_edit_playlist_submenu (0)
276 , track_selection_edit_playlist_submenu (0)
277 , _popup_region_menu_item (0)
279 , _track_canvas_viewport (0)
280 , within_track_canvas (false)
281 , _verbose_cursor (0)
285 , range_marker_group (0)
286 , transport_marker_group (0)
287 , cd_marker_group (0)
288 , _time_markers_group (0)
289 , hv_scroll_group (0)
291 , cursor_scroll_group (0)
292 , no_scroll_group (0)
293 , _trackview_group (0)
294 , _drag_motion_group (0)
295 , _canvas_drop_zone (0)
296 , no_ruler_shown_update (false)
297 , ruler_grabbed_widget (0)
299 , minsec_mark_interval (0)
300 , minsec_mark_modulo (0)
302 , timecode_mark_modulo (0)
303 , timecode_nmarks (0)
304 , _samples_ruler_interval (0)
307 , bbt_bar_helper_on (0)
308 , bbt_accent_modulo (0)
313 , visible_timebars (0)
314 , editor_ruler_menu (0)
318 , range_marker_bar (0)
319 , transport_marker_bar (0)
321 , minsec_label (_("Mins:Secs"))
322 , bbt_label (_("Bars:Beats"))
323 , timecode_label (_("Timecode"))
324 , samples_label (_("Samples"))
325 , tempo_label (_("Tempo"))
326 , meter_label (_("Meter"))
327 , mark_label (_("Location Markers"))
328 , range_mark_label (_("Range Markers"))
329 , transport_mark_label (_("Loop/Punch Ranges"))
330 , cd_mark_label (_("CD Markers"))
331 , videotl_label (_("Video Timeline"))
333 , playhead_cursor (0)
334 , edit_packer (4, 4, true)
335 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
336 , horizontal_adjustment (0.0, 0.0, 1e16)
337 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
338 , controls_layout (unused_adjustment, vertical_adjustment)
339 , _scroll_callbacks (0)
340 , _visible_canvas_width (0)
341 , _visible_canvas_height (0)
342 , _full_canvas_height (0)
343 , edit_controls_left_menu (0)
344 , edit_controls_right_menu (0)
345 , last_update_frame (0)
346 , cut_buffer_start (0)
347 , cut_buffer_length (0)
348 , button_bindings (0)
352 , current_interthread_info (0)
353 , analysis_window (0)
354 , select_new_marker (false)
356 , scrubbing_direction (0)
357 , scrub_reversals (0)
358 , scrub_reverse_distance (0)
359 , have_pending_keyboard_selection (false)
360 , pending_keyboard_selection_start (0)
361 , _snap_type (SnapToBeat)
362 , _snap_mode (SnapOff)
363 , snap_threshold (5.0)
364 , ignore_gui_changes (false)
365 , _drags (new DragManager (this))
367 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
368 , _dragging_playhead (false)
369 , _dragging_edit_point (false)
370 , _show_measures (true)
371 , _follow_playhead (true)
372 , _stationary_playhead (false)
375 , global_rect_group (0)
376 , time_line_group (0)
377 , tempo_marker_menu (0)
378 , meter_marker_menu (0)
380 , range_marker_menu (0)
381 , transport_marker_menu (0)
382 , new_transport_marker_menu (0)
384 , marker_menu_item (0)
385 , bbt_beat_subdivision (4)
386 , _visible_track_count (-1)
387 , toolbar_selection_clock_table (2,3)
388 , automation_mode_button (_("mode"))
389 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
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 , _ignore_follow_edits (false)
397 , cd_marker_bar_drag_rect (0)
398 , range_bar_drag_rect (0)
399 , transport_bar_drag_rect (0)
400 , transport_bar_range_rect (0)
401 , transport_bar_preroll_rect (0)
402 , transport_bar_postroll_rect (0)
403 , transport_loop_range_rect (0)
404 , transport_punch_range_rect (0)
405 , transport_punchin_line (0)
406 , transport_punchout_line (0)
407 , transport_preroll_rect (0)
408 , transport_postroll_rect (0)
410 , rubberband_rect (0)
416 , autoscroll_horizontal_allowed (false)
417 , autoscroll_vertical_allowed (false)
419 , autoscroll_widget (0)
420 , show_gain_after_trim (false)
421 , selection_op_cmd_depth (0)
422 , selection_op_history_it (0)
423 , no_save_instant (false)
425 , current_mixer_strip (0)
426 , show_editor_mixer_when_tracks_arrive (false)
427 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
428 , current_stepping_trackview (0)
429 , last_track_height_step_timestamp (0)
431 , entered_regionview (0)
432 , clear_entered_track (false)
433 , _edit_point (EditAtMouse)
434 , meters_running (false)
436 , _have_idled (false)
437 , resize_idle_id (-1)
438 , _pending_resize_amount (0)
439 , _pending_resize_view (0)
440 , _pending_locate_request (false)
441 , _pending_initial_locate (false)
445 , layering_order_editor (0)
446 , _last_cut_copy_source_track (0)
447 , _region_selection_change_updates_region_list (true)
449 , _following_mixer_selection (false)
450 , _control_point_toggled_on_press (false)
451 , _stepping_axis_view (0)
452 , quantize_dialog (0)
453 , _main_menu_disabler (0)
454 , myactions (X_("editor"))
456 /* we are a singleton */
458 PublicEditor::_instance = this;
462 last_event_time.tv_sec = 0;
463 last_event_time.tv_usec = 0;
465 selection_op_history.clear();
468 snap_type_strings = I18N (_snap_type_strings);
469 snap_mode_strings = I18N (_snap_mode_strings);
470 zoom_focus_strings = I18N (_zoom_focus_strings);
471 edit_mode_strings = I18N (_edit_mode_strings);
472 edit_point_strings = I18N (_edit_point_strings);
473 #ifdef USE_RUBBERBAND
474 rb_opt_strings = I18N (_rb_opt_strings);
478 build_edit_mode_menu();
479 build_zoom_focus_menu();
480 build_track_count_menu();
481 build_snap_mode_menu();
482 build_snap_type_menu();
483 build_edit_point_menu();
485 location_marker_color = UIConfiguration::instance().color ("location marker");
486 location_range_color = UIConfiguration::instance().color ("location range");
487 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
488 location_loop_color = UIConfiguration::instance().color ("location loop");
489 location_punch_color = UIConfiguration::instance().color ("location punch");
491 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
493 TimeAxisView::setup_sizes ();
494 ArdourMarker::setup_sizes (timebar_height);
495 TempoCurve::setup_sizes (timebar_height);
497 bbt_label.set_name ("EditorRulerLabel");
498 bbt_label.set_size_request (-1, (int)timebar_height);
499 bbt_label.set_alignment (1.0, 0.5);
500 bbt_label.set_padding (5,0);
502 bbt_label.set_no_show_all();
503 minsec_label.set_name ("EditorRulerLabel");
504 minsec_label.set_size_request (-1, (int)timebar_height);
505 minsec_label.set_alignment (1.0, 0.5);
506 minsec_label.set_padding (5,0);
507 minsec_label.hide ();
508 minsec_label.set_no_show_all();
509 timecode_label.set_name ("EditorRulerLabel");
510 timecode_label.set_size_request (-1, (int)timebar_height);
511 timecode_label.set_alignment (1.0, 0.5);
512 timecode_label.set_padding (5,0);
513 timecode_label.hide ();
514 timecode_label.set_no_show_all();
515 samples_label.set_name ("EditorRulerLabel");
516 samples_label.set_size_request (-1, (int)timebar_height);
517 samples_label.set_alignment (1.0, 0.5);
518 samples_label.set_padding (5,0);
519 samples_label.hide ();
520 samples_label.set_no_show_all();
522 tempo_label.set_name ("EditorRulerLabel");
523 tempo_label.set_size_request (-1, (int)timebar_height);
524 tempo_label.set_alignment (1.0, 0.5);
525 tempo_label.set_padding (5,0);
527 tempo_label.set_no_show_all();
529 meter_label.set_name ("EditorRulerLabel");
530 meter_label.set_size_request (-1, (int)timebar_height);
531 meter_label.set_alignment (1.0, 0.5);
532 meter_label.set_padding (5,0);
534 meter_label.set_no_show_all();
536 if (Profile->get_trx()) {
537 mark_label.set_text (_("Markers"));
539 mark_label.set_name ("EditorRulerLabel");
540 mark_label.set_size_request (-1, (int)timebar_height);
541 mark_label.set_alignment (1.0, 0.5);
542 mark_label.set_padding (5,0);
544 mark_label.set_no_show_all();
546 cd_mark_label.set_name ("EditorRulerLabel");
547 cd_mark_label.set_size_request (-1, (int)timebar_height);
548 cd_mark_label.set_alignment (1.0, 0.5);
549 cd_mark_label.set_padding (5,0);
550 cd_mark_label.hide();
551 cd_mark_label.set_no_show_all();
553 videotl_bar_height = 4;
554 videotl_label.set_name ("EditorRulerLabel");
555 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
556 videotl_label.set_alignment (1.0, 0.5);
557 videotl_label.set_padding (5,0);
558 videotl_label.hide();
559 videotl_label.set_no_show_all();
561 range_mark_label.set_name ("EditorRulerLabel");
562 range_mark_label.set_size_request (-1, (int)timebar_height);
563 range_mark_label.set_alignment (1.0, 0.5);
564 range_mark_label.set_padding (5,0);
565 range_mark_label.hide();
566 range_mark_label.set_no_show_all();
568 transport_mark_label.set_name ("EditorRulerLabel");
569 transport_mark_label.set_size_request (-1, (int)timebar_height);
570 transport_mark_label.set_alignment (1.0, 0.5);
571 transport_mark_label.set_padding (5,0);
572 transport_mark_label.hide();
573 transport_mark_label.set_no_show_all();
575 initialize_canvas ();
577 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
579 _summary = new EditorSummary (this);
581 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
582 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
584 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
586 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
587 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
589 edit_controls_vbox.set_spacing (0);
590 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
591 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
593 HBox* h = manage (new HBox);
594 _group_tabs = new EditorGroupTabs (this);
595 if (!ARDOUR::Profile->get_trx()) {
596 h->pack_start (*_group_tabs, PACK_SHRINK);
598 h->pack_start (edit_controls_vbox);
599 controls_layout.add (*h);
601 controls_layout.set_name ("EditControlsBase");
602 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
603 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
604 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
606 _cursors = new MouseCursors;
607 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
608 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
610 /* Push default cursor to ever-present bottom of cursor stack. */
611 push_canvas_cursor(_cursors->grabber);
613 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
615 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
616 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
617 pad_line_1->set_outline_color (0xFF0000FF);
623 edit_packer.set_col_spacings (0);
624 edit_packer.set_row_spacings (0);
625 edit_packer.set_homogeneous (false);
626 edit_packer.set_border_width (0);
627 edit_packer.set_name ("EditorWindow");
629 time_bars_event_box.add (time_bars_vbox);
630 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
631 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
633 /* labels for the time bars */
634 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
636 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
638 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
640 bottom_hbox.set_border_width (2);
641 bottom_hbox.set_spacing (3);
643 _route_groups = new EditorRouteGroups (this);
644 _routes = new EditorRoutes (this);
645 _regions = new EditorRegions (this);
646 _snapshots = new EditorSnapshots (this);
647 _locations = new EditorLocations (this);
648 _time_info_box = new TimeInfoBox ();
650 /* these are static location signals */
652 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
654 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
656 add_notebook_page (_("Regions"), _regions->widget ());
657 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
658 add_notebook_page (_("Snapshots"), _snapshots->widget ());
659 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
660 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
662 _the_notebook.set_show_tabs (true);
663 _the_notebook.set_scrollable (true);
664 _the_notebook.popup_disable ();
665 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
666 _the_notebook.show_all ();
668 _notebook_shrunk = false;
671 /* Pick up some settings we need to cache, early */
673 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
676 if (settings && (prop = settings->property ("notebook-shrunk"))) {
677 _notebook_shrunk = string_is_affirmative (prop->value ());
680 editor_summary_pane.set_check_divider_position (true);
681 editor_summary_pane.add (edit_packer);
683 Button* summary_arrows_left_left = manage (new Button);
684 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
685 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
686 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
688 Button* summary_arrows_left_right = manage (new Button);
689 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
690 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
691 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
693 VBox* summary_arrows_left = manage (new VBox);
694 summary_arrows_left->pack_start (*summary_arrows_left_left);
695 summary_arrows_left->pack_start (*summary_arrows_left_right);
697 Button* summary_arrows_right_up = manage (new Button);
698 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
699 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
700 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
702 Button* summary_arrows_right_down = manage (new Button);
703 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
704 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
705 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
707 VBox* summary_arrows_right = manage (new VBox);
708 summary_arrows_right->pack_start (*summary_arrows_right_up);
709 summary_arrows_right->pack_start (*summary_arrows_right_down);
711 Frame* summary_frame = manage (new Frame);
712 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
714 summary_frame->add (*_summary);
715 summary_frame->show ();
717 _summary_hbox.pack_start (*summary_arrows_left, false, false);
718 _summary_hbox.pack_start (*summary_frame, true, true);
719 _summary_hbox.pack_start (*summary_arrows_right, false, false);
721 if (!ARDOUR::Profile->get_trx()) {
722 editor_summary_pane.add (_summary_hbox);
725 edit_pane.set_check_divider_position (true);
726 edit_pane.add (editor_summary_pane);
727 if (!ARDOUR::Profile->get_trx()) {
728 VBox* editor_list_vbox = manage (new VBox);
729 editor_list_vbox->pack_start (*_time_info_box, false, false, 0);
730 editor_list_vbox->pack_start (_the_notebook);
731 edit_pane.add (*editor_list_vbox);
732 edit_pane.set_child_minsize (*editor_list_vbox, 30); /* rough guess at width of notebook tabs */
735 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
736 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
743 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
744 /* initial allocation is 90% to canvas, 10% to notebook */
745 edit_pane.set_divider (0, 0.90);
747 edit_pane.set_divider (0, fract);
750 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
751 /* initial allocation is 90% to canvas, 10% to summary */
752 editor_summary_pane.set_divider (0, 0.90);
755 editor_summary_pane.set_divider (0, fract);
759 top_hbox.pack_start (toolbar_frame);
761 HBox *hbox = manage (new HBox);
762 hbox->pack_start (edit_pane, true, true);
764 global_vpacker.pack_start (top_hbox, false, false);
765 global_vpacker.pack_start (*hbox, true, true);
766 global_hpacker.pack_start (global_vpacker, true, true);
768 /* need to show the "contents" widget so that notebook will show if tab is switched to
771 global_hpacker.show ();
773 /* register actions now so that set_state() can find them and set toggles/checks etc */
780 _playlist_selector = new PlaylistSelector();
781 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
783 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
787 nudge_forward_button.set_name ("nudge button");
788 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
790 nudge_backward_button.set_name ("nudge button");
791 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
793 fade_context_menu.set_name ("ArdourContextMenu");
795 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
797 /* allow external control surfaces/protocols to do various things */
799 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
800 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
801 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
802 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
803 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
804 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
805 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
806 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
807 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
808 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
809 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
810 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
811 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
812 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
814 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
815 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
816 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
817 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
818 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
820 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
824 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
826 /* problematic: has to return a value and thus cannot be x-thread */
828 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
830 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
831 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
833 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
835 _ignore_region_action = false;
836 _last_region_menu_was_main = false;
837 _popup_region_menu_item = 0;
839 _ignore_follow_edits = false;
841 _show_marker_lines = false;
843 /* Button bindings */
845 button_bindings = new Bindings ("editor-mouse");
847 XMLNode* node = button_settings();
849 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
850 button_bindings->load_operation (**i);
856 /* grab current parameter state */
857 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
858 UIConfiguration::instance().map_parameters (pc);
860 setup_fade_images ();
862 LuaInstance::instance(); // instantiate
863 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
870 delete button_bindings;
872 delete _route_groups;
873 delete _track_canvas_viewport;
876 delete _verbose_cursor;
877 delete quantize_dialog;
883 delete _playlist_selector;
884 delete _time_info_box;
886 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
892 Editor::button_settings () const
894 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
895 XMLNode* node = find_named_node (*settings, X_("Buttons"));
898 node = new XMLNode (X_("Buttons"));
905 Editor::get_smart_mode () const
907 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
911 Editor::catch_vanishing_regionview (RegionView *rv)
913 /* note: the selection will take care of the vanishing
914 audioregionview by itself.
917 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
921 if (clicked_regionview == rv) {
922 clicked_regionview = 0;
925 if (entered_regionview == rv) {
926 set_entered_regionview (0);
929 if (!_all_region_actions_sensitized) {
930 sensitize_all_region_actions (true);
935 Editor::set_entered_regionview (RegionView* rv)
937 if (rv == entered_regionview) {
941 if (entered_regionview) {
942 entered_regionview->exited ();
945 entered_regionview = rv;
947 if (entered_regionview != 0) {
948 entered_regionview->entered ();
951 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
952 /* This RegionView entry might have changed what region actions
953 are allowed, so sensitize them all in case a key is pressed.
955 sensitize_all_region_actions (true);
960 Editor::set_entered_track (TimeAxisView* tav)
963 entered_track->exited ();
969 entered_track->entered ();
974 Editor::instant_save ()
976 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
981 _session->add_instant_xml(get_state());
983 Config->add_instant_xml(get_state());
988 Editor::control_vertical_zoom_in_all ()
990 tav_zoom_smooth (false, true);
994 Editor::control_vertical_zoom_out_all ()
996 tav_zoom_smooth (true, true);
1000 Editor::control_vertical_zoom_in_selected ()
1002 tav_zoom_smooth (false, false);
1006 Editor::control_vertical_zoom_out_selected ()
1008 tav_zoom_smooth (true, false);
1012 Editor::control_view (uint32_t view)
1014 goto_visual_state (view);
1018 Editor::control_unselect ()
1020 selection->clear_tracks ();
1024 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1026 TimeAxisView* tav = axis_view_from_stripable (s);
1030 case Selection::Add:
1031 selection->add (tav);
1033 case Selection::Toggle:
1034 selection->toggle (tav);
1036 case Selection::Extend:
1038 case Selection::Set:
1039 selection->set (tav);
1043 selection->clear_tracks ();
1048 Editor::control_step_tracks_up ()
1050 scroll_tracks_up_line ();
1054 Editor::control_step_tracks_down ()
1056 scroll_tracks_down_line ();
1060 Editor::control_scroll (float fraction)
1062 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1068 double step = fraction * current_page_samples();
1071 _control_scroll_target is an optional<T>
1073 it acts like a pointer to an framepos_t, with
1074 a operator conversion to boolean to check
1075 that it has a value could possibly use
1076 playhead_cursor->current_frame to store the
1077 value and a boolean in the class to know
1078 when it's out of date
1081 if (!_control_scroll_target) {
1082 _control_scroll_target = _session->transport_frame();
1083 _dragging_playhead = true;
1086 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1087 *_control_scroll_target = 0;
1088 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1089 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1091 *_control_scroll_target += (framepos_t) trunc (step);
1094 /* move visuals, we'll catch up with it later */
1096 playhead_cursor->set_position (*_control_scroll_target);
1097 UpdateAllTransportClocks (*_control_scroll_target);
1099 if (*_control_scroll_target > (current_page_samples() / 2)) {
1100 /* try to center PH in window */
1101 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1107 Now we do a timeout to actually bring the session to the right place
1108 according to the playhead. This is to avoid reading disk buffers on every
1109 call to control_scroll, which is driven by ScrollTimeline and therefore
1110 probably by a control surface wheel which can generate lots of events.
1112 /* cancel the existing timeout */
1114 control_scroll_connection.disconnect ();
1116 /* add the next timeout */
1118 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1122 Editor::deferred_control_scroll (framepos_t /*target*/)
1124 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1125 // reset for next stream
1126 _control_scroll_target = boost::none;
1127 _dragging_playhead = false;
1132 Editor::access_action (std::string action_group, std::string action_item)
1138 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1141 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1149 Editor::on_realize ()
1153 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1154 start_lock_event_timing ();
1159 Editor::start_lock_event_timing ()
1161 /* check if we should lock the GUI every 30 seconds */
1163 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1167 Editor::generic_event_handler (GdkEvent* ev)
1170 case GDK_BUTTON_PRESS:
1171 case GDK_BUTTON_RELEASE:
1172 case GDK_MOTION_NOTIFY:
1174 case GDK_KEY_RELEASE:
1175 if (contents().is_mapped()) {
1176 gettimeofday (&last_event_time, 0);
1180 case GDK_LEAVE_NOTIFY:
1181 switch (ev->crossing.detail) {
1182 case GDK_NOTIFY_UNKNOWN:
1183 case GDK_NOTIFY_INFERIOR:
1184 case GDK_NOTIFY_ANCESTOR:
1186 case GDK_NOTIFY_VIRTUAL:
1187 case GDK_NOTIFY_NONLINEAR:
1188 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1189 /* leaving window, so reset focus, thus ending any and
1190 all text entry operations.
1192 ARDOUR_UI::instance()->reset_focus (&contents());
1205 Editor::lock_timeout_callback ()
1207 struct timeval now, delta;
1209 gettimeofday (&now, 0);
1211 timersub (&now, &last_event_time, &delta);
1213 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1215 /* don't call again. Returning false will effectively
1216 disconnect us from the timer callback.
1218 unlock() will call start_lock_event_timing() to get things
1228 Editor::map_position_change (framepos_t frame)
1230 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1232 if (_session == 0) {
1236 if (_follow_playhead) {
1237 center_screen (frame);
1240 playhead_cursor->set_position (frame);
1244 Editor::center_screen (framepos_t frame)
1246 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1248 /* if we're off the page, then scroll.
1251 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1252 center_screen_internal (frame, page);
1257 Editor::center_screen_internal (framepos_t frame, float page)
1262 frame -= (framepos_t) page;
1267 reset_x_origin (frame);
1272 Editor::update_title ()
1274 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1276 if (!own_window()) {
1281 bool dirty = _session->dirty();
1283 string session_name;
1285 if (_session->snap_name() != _session->name()) {
1286 session_name = _session->snap_name();
1288 session_name = _session->name();
1292 session_name = "*" + session_name;
1295 WindowTitle title(session_name);
1296 title += S_("Window|Editor");
1297 title += Glib::get_application_name();
1298 own_window()->set_title (title.get_string());
1300 /* ::session_going_away() will have taken care of it */
1305 Editor::set_session (Session *t)
1307 SessionHandlePtr::set_session (t);
1313 _playlist_selector->set_session (_session);
1314 nudge_clock->set_session (_session);
1315 _summary->set_session (_session);
1316 _group_tabs->set_session (_session);
1317 _route_groups->set_session (_session);
1318 _regions->set_session (_session);
1319 _snapshots->set_session (_session);
1320 _routes->set_session (_session);
1321 _locations->set_session (_session);
1322 _time_info_box->set_session (_session);
1324 if (rhythm_ferret) {
1325 rhythm_ferret->set_session (_session);
1328 if (analysis_window) {
1329 analysis_window->set_session (_session);
1333 sfbrowser->set_session (_session);
1336 compute_fixed_ruler_scale ();
1338 /* Make sure we have auto loop and auto punch ranges */
1340 Location* loc = _session->locations()->auto_loop_location();
1342 loc->set_name (_("Loop"));
1345 loc = _session->locations()->auto_punch_location();
1348 loc->set_name (_("Punch"));
1351 refresh_location_display ();
1353 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1354 the selected Marker; this needs the LocationMarker list to be available.
1356 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1357 set_state (*node, Stateful::loading_state_version);
1359 /* catch up with the playhead */
1361 _session->request_locate (playhead_cursor->current_frame ());
1362 _pending_initial_locate = true;
1366 /* These signals can all be emitted by a non-GUI thread. Therefore the
1367 handlers for them must not attempt to directly interact with the GUI,
1368 but use PBD::Signal<T>::connect() which accepts an event loop
1369 ("context") where the handler will be asked to run.
1372 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1373 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1374 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1375 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1376 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1377 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1378 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1379 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1380 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1381 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1382 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1383 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1384 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1385 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1386 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1388 playhead_cursor->show ();
1390 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1391 Config->map_parameters (pc);
1392 _session->config.map_parameters (pc);
1394 restore_ruler_visibility ();
1395 //tempo_map_changed (PropertyChange (0));
1396 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1398 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1399 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1402 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1403 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1406 switch (_snap_type) {
1407 case SnapToRegionStart:
1408 case SnapToRegionEnd:
1409 case SnapToRegionSync:
1410 case SnapToRegionBoundary:
1411 build_region_boundary_cache ();
1418 /* catch up on selection of stripables (other selection state is lost
1419 * when a session is closed
1424 _session->get_stripables (sl);
1425 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1426 if ((*s)->presentation_info().selected()) {
1427 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1429 tl.push_back (rtav);
1434 selection->set (tl);
1437 /* register for undo history */
1438 _session->register_with_memento_command_factory(id(), this);
1439 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1441 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1443 LuaInstance::instance()->set_session(_session);
1445 start_updating_meters ();
1449 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1451 if (a->get_name() == "RegionMenu") {
1452 /* When the main menu's region menu is opened, we setup the actions so that they look right
1453 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1454 so we resensitize all region actions when the entered regionview or the region selection
1455 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1456 happens after the region context menu is opened. So we set a flag here, too.
1460 sensitize_the_right_region_actions ();
1461 _last_region_menu_was_main = true;
1466 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1468 using namespace Menu_Helpers;
1470 void (Editor::*emf)(FadeShape);
1471 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1474 images = &_xfade_in_images;
1475 emf = &Editor::set_fade_in_shape;
1477 images = &_xfade_out_images;
1478 emf = &Editor::set_fade_out_shape;
1483 _("Linear (for highly correlated material)"),
1484 *(*images)[FadeLinear],
1485 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1493 _("Constant power"),
1494 *(*images)[FadeConstantPower],
1495 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1498 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1503 *(*images)[FadeSymmetric],
1504 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 *(*images)[FadeSlow],
1514 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1517 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1522 *(*images)[FadeFast],
1523 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1526 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1529 /** Pop up a context menu for when the user clicks on a start crossfade */
1531 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1533 using namespace Menu_Helpers;
1534 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1539 MenuList& items (xfade_in_context_menu.items());
1542 if (arv->audio_region()->fade_in_active()) {
1543 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1545 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1548 items.push_back (SeparatorElem());
1549 fill_xfade_menu (items, true);
1551 xfade_in_context_menu.popup (button, time);
1554 /** Pop up a context menu for when the user clicks on an end crossfade */
1556 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1558 using namespace Menu_Helpers;
1559 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1564 MenuList& items (xfade_out_context_menu.items());
1567 if (arv->audio_region()->fade_out_active()) {
1568 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1570 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1573 items.push_back (SeparatorElem());
1574 fill_xfade_menu (items, false);
1576 xfade_out_context_menu.popup (button, time);
1580 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1582 using namespace Menu_Helpers;
1583 Menu* (Editor::*build_menu_function)();
1586 switch (item_type) {
1588 case RegionViewName:
1589 case RegionViewNameHighlight:
1590 case LeftFrameHandle:
1591 case RightFrameHandle:
1592 if (with_selection) {
1593 build_menu_function = &Editor::build_track_selection_context_menu;
1595 build_menu_function = &Editor::build_track_region_context_menu;
1600 if (with_selection) {
1601 build_menu_function = &Editor::build_track_selection_context_menu;
1603 build_menu_function = &Editor::build_track_context_menu;
1608 if (clicked_routeview->track()) {
1609 build_menu_function = &Editor::build_track_context_menu;
1611 build_menu_function = &Editor::build_track_bus_context_menu;
1616 /* probably shouldn't happen but if it does, we don't care */
1620 menu = (this->*build_menu_function)();
1621 menu->set_name ("ArdourContextMenu");
1623 /* now handle specific situations */
1625 switch (item_type) {
1627 case RegionViewName:
1628 case RegionViewNameHighlight:
1629 case LeftFrameHandle:
1630 case RightFrameHandle:
1631 if (!with_selection) {
1632 if (region_edit_menu_split_item) {
1633 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1634 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1636 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1639 if (region_edit_menu_split_multichannel_item) {
1640 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1641 region_edit_menu_split_multichannel_item->set_sensitive (true);
1643 region_edit_menu_split_multichannel_item->set_sensitive (false);
1656 /* probably shouldn't happen but if it does, we don't care */
1660 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1662 /* Bounce to disk */
1664 using namespace Menu_Helpers;
1665 MenuList& edit_items = menu->items();
1667 edit_items.push_back (SeparatorElem());
1669 switch (clicked_routeview->audio_track()->freeze_state()) {
1670 case AudioTrack::NoFreeze:
1671 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1674 case AudioTrack::Frozen:
1675 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1678 case AudioTrack::UnFrozen:
1679 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1685 if (item_type == StreamItem && clicked_routeview) {
1686 clicked_routeview->build_underlay_menu(menu);
1689 /* When the region menu is opened, we setup the actions so that they look right
1692 sensitize_the_right_region_actions ();
1693 _last_region_menu_was_main = false;
1695 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1696 menu->popup (button, time);
1700 Editor::build_track_context_menu ()
1702 using namespace Menu_Helpers;
1704 MenuList& edit_items = track_context_menu.items();
1707 add_dstream_context_items (edit_items);
1708 return &track_context_menu;
1712 Editor::build_track_bus_context_menu ()
1714 using namespace Menu_Helpers;
1716 MenuList& edit_items = track_context_menu.items();
1719 add_bus_context_items (edit_items);
1720 return &track_context_menu;
1724 Editor::build_track_region_context_menu ()
1726 using namespace Menu_Helpers;
1727 MenuList& edit_items = track_region_context_menu.items();
1730 /* we've just cleared the track region context menu, so the menu that these
1731 two items were on will have disappeared; stop them dangling.
1733 region_edit_menu_split_item = 0;
1734 region_edit_menu_split_multichannel_item = 0;
1736 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1739 boost::shared_ptr<Track> tr;
1740 boost::shared_ptr<Playlist> pl;
1742 if ((tr = rtv->track())) {
1743 add_region_context_items (edit_items, tr);
1747 add_dstream_context_items (edit_items);
1749 return &track_region_context_menu;
1753 Editor::loudness_analyze_region_selection ()
1758 Selection& s (PublicEditor::instance ().get_selection ());
1759 RegionSelection ars = s.regions;
1760 ARDOUR::AnalysisGraph ag (_session);
1761 framecnt_t total_work = 0;
1763 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1764 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1768 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1771 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1772 total_work += arv->region ()->length ();
1775 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1777 ag.set_total_frames (total_work);
1778 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1781 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1782 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1786 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1790 ag.analyze_region (ar);
1793 if (!ag.canceled ()) {
1794 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1800 Editor::loudness_analyze_range_selection ()
1805 Selection& s (PublicEditor::instance ().get_selection ());
1806 TimeSelection ts = s.time;
1807 ARDOUR::AnalysisGraph ag (_session);
1808 framecnt_t total_work = 0;
1810 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1811 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1815 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1819 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1820 total_work += j->length ();
1824 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1826 ag.set_total_frames (total_work);
1827 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1830 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1831 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1835 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1839 ag.analyze_range (rui->route (), pl, ts);
1842 if (!ag.canceled ()) {
1843 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1849 Editor::spectral_analyze_region_selection ()
1851 if (analysis_window == 0) {
1852 analysis_window = new AnalysisWindow();
1855 analysis_window->set_session(_session);
1857 analysis_window->show_all();
1860 analysis_window->set_regionmode();
1861 analysis_window->analyze();
1863 analysis_window->present();
1867 Editor::spectral_analyze_range_selection()
1869 if (analysis_window == 0) {
1870 analysis_window = new AnalysisWindow();
1873 analysis_window->set_session(_session);
1875 analysis_window->show_all();
1878 analysis_window->set_rangemode();
1879 analysis_window->analyze();
1881 analysis_window->present();
1885 Editor::build_track_selection_context_menu ()
1887 using namespace Menu_Helpers;
1888 MenuList& edit_items = track_selection_context_menu.items();
1889 edit_items.clear ();
1891 add_selection_context_items (edit_items);
1892 // edit_items.push_back (SeparatorElem());
1893 // add_dstream_context_items (edit_items);
1895 return &track_selection_context_menu;
1899 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1901 using namespace Menu_Helpers;
1903 /* OK, stick the region submenu at the top of the list, and then add
1907 RegionSelection rs = get_regions_from_selection_and_entered ();
1909 string::size_type pos = 0;
1910 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1912 /* we have to hack up the region name because "_" has a special
1913 meaning for menu titles.
1916 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1917 menu_item_name.replace (pos, 1, "__");
1921 if (_popup_region_menu_item == 0) {
1922 _popup_region_menu_item = new MenuItem (menu_item_name);
1923 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1924 _popup_region_menu_item->show ();
1926 _popup_region_menu_item->set_label (menu_item_name);
1929 /* No latering allowed in later is higher layering model */
1930 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1931 if (act && Config->get_layer_model() == LaterHigher) {
1932 act->set_sensitive (false);
1934 act->set_sensitive (true);
1937 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1939 edit_items.push_back (*_popup_region_menu_item);
1940 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1941 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1943 edit_items.push_back (SeparatorElem());
1946 /** Add context menu items relevant to selection ranges.
1947 * @param edit_items List to add the items to.
1950 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1952 using namespace Menu_Helpers;
1954 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1955 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1957 edit_items.push_back (SeparatorElem());
1958 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1960 edit_items.push_back (SeparatorElem());
1961 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1962 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1964 edit_items.push_back (SeparatorElem());
1966 edit_items.push_back (
1968 _("Move Range Start to Previous Region Boundary"),
1969 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1973 edit_items.push_back (
1975 _("Move Range Start to Next Region Boundary"),
1976 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1980 edit_items.push_back (
1982 _("Move Range End to Previous Region Boundary"),
1983 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1987 edit_items.push_back (
1989 _("Move Range End to Next Region Boundary"),
1990 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1994 edit_items.push_back (SeparatorElem());
1995 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1996 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1998 edit_items.push_back (SeparatorElem());
1999 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2001 edit_items.push_back (SeparatorElem());
2002 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2003 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2004 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2006 edit_items.push_back (SeparatorElem());
2007 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2009 edit_items.push_back (SeparatorElem());
2010 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2011 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2013 edit_items.push_back (SeparatorElem());
2014 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2015 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2016 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2017 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2018 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2019 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2020 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2026 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2028 using namespace Menu_Helpers;
2032 Menu *play_menu = manage (new Menu);
2033 MenuList& play_items = play_menu->items();
2034 play_menu->set_name ("ArdourContextMenu");
2036 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2037 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2038 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2039 play_items.push_back (SeparatorElem());
2040 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2042 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2046 Menu *select_menu = manage (new Menu);
2047 MenuList& select_items = select_menu->items();
2048 select_menu->set_name ("ArdourContextMenu");
2050 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2051 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2052 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2053 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2054 select_items.push_back (SeparatorElem());
2055 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2056 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2057 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2058 select_items.push_back (SeparatorElem());
2059 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2060 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2061 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2062 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2063 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2064 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2065 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2067 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2071 Menu *cutnpaste_menu = manage (new Menu);
2072 MenuList& cutnpaste_items = cutnpaste_menu->items();
2073 cutnpaste_menu->set_name ("ArdourContextMenu");
2075 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2076 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2077 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2079 cutnpaste_items.push_back (SeparatorElem());
2081 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2082 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2084 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2086 /* Adding new material */
2088 edit_items.push_back (SeparatorElem());
2089 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2090 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2094 Menu *nudge_menu = manage (new Menu());
2095 MenuList& nudge_items = nudge_menu->items();
2096 nudge_menu->set_name ("ArdourContextMenu");
2098 edit_items.push_back (SeparatorElem());
2099 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2100 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2101 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2102 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2104 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2108 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2110 using namespace Menu_Helpers;
2114 Menu *play_menu = manage (new Menu);
2115 MenuList& play_items = play_menu->items();
2116 play_menu->set_name ("ArdourContextMenu");
2118 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2119 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2120 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2124 Menu *select_menu = manage (new Menu);
2125 MenuList& select_items = select_menu->items();
2126 select_menu->set_name ("ArdourContextMenu");
2128 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2129 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2130 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2131 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2132 select_items.push_back (SeparatorElem());
2133 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2134 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2135 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2136 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2138 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2142 Menu *cutnpaste_menu = manage (new Menu);
2143 MenuList& cutnpaste_items = cutnpaste_menu->items();
2144 cutnpaste_menu->set_name ("ArdourContextMenu");
2146 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2147 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2148 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2150 Menu *nudge_menu = manage (new Menu());
2151 MenuList& nudge_items = nudge_menu->items();
2152 nudge_menu->set_name ("ArdourContextMenu");
2154 edit_items.push_back (SeparatorElem());
2155 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2156 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2157 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2158 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2160 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2164 Editor::snap_type() const
2170 Editor::snap_musical() const
2172 switch (_snap_type) {
2173 case SnapToBeatDiv128:
2174 case SnapToBeatDiv64:
2175 case SnapToBeatDiv32:
2176 case SnapToBeatDiv28:
2177 case SnapToBeatDiv24:
2178 case SnapToBeatDiv20:
2179 case SnapToBeatDiv16:
2180 case SnapToBeatDiv14:
2181 case SnapToBeatDiv12:
2182 case SnapToBeatDiv10:
2183 case SnapToBeatDiv8:
2184 case SnapToBeatDiv7:
2185 case SnapToBeatDiv6:
2186 case SnapToBeatDiv5:
2187 case SnapToBeatDiv4:
2188 case SnapToBeatDiv3:
2189 case SnapToBeatDiv2:
2201 Editor::snap_mode() const
2207 Editor::set_snap_to (SnapType st)
2209 unsigned int snap_ind = (unsigned int)st;
2211 if (internal_editing()) {
2212 internal_snap_type = st;
2214 pre_internal_snap_type = st;
2219 if (snap_ind > snap_type_strings.size() - 1) {
2221 _snap_type = (SnapType)snap_ind;
2224 string str = snap_type_strings[snap_ind];
2226 if (str != snap_type_selector.get_text()) {
2227 snap_type_selector.set_text (str);
2232 switch (_snap_type) {
2233 case SnapToBeatDiv128:
2234 case SnapToBeatDiv64:
2235 case SnapToBeatDiv32:
2236 case SnapToBeatDiv28:
2237 case SnapToBeatDiv24:
2238 case SnapToBeatDiv20:
2239 case SnapToBeatDiv16:
2240 case SnapToBeatDiv14:
2241 case SnapToBeatDiv12:
2242 case SnapToBeatDiv10:
2243 case SnapToBeatDiv8:
2244 case SnapToBeatDiv7:
2245 case SnapToBeatDiv6:
2246 case SnapToBeatDiv5:
2247 case SnapToBeatDiv4:
2248 case SnapToBeatDiv3:
2249 case SnapToBeatDiv2: {
2250 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2251 update_tempo_based_rulers ();
2255 case SnapToRegionStart:
2256 case SnapToRegionEnd:
2257 case SnapToRegionSync:
2258 case SnapToRegionBoundary:
2259 build_region_boundary_cache ();
2267 redisplay_tempo (false);
2269 SnapChanged (); /* EMIT SIGNAL */
2273 Editor::set_snap_mode (SnapMode mode)
2275 string str = snap_mode_strings[(int)mode];
2277 if (internal_editing()) {
2278 internal_snap_mode = mode;
2280 pre_internal_snap_mode = mode;
2285 if (str != snap_mode_selector.get_text ()) {
2286 snap_mode_selector.set_text (str);
2293 Editor::set_edit_point_preference (EditPoint ep, bool force)
2295 bool changed = (_edit_point != ep);
2298 if (Profile->get_mixbus())
2299 if (ep == EditAtSelectedMarker)
2300 ep = EditAtPlayhead;
2302 string str = edit_point_strings[(int)ep];
2303 if (str != edit_point_selector.get_text ()) {
2304 edit_point_selector.set_text (str);
2307 update_all_enter_cursors();
2309 if (!force && !changed) {
2313 const char* action=NULL;
2315 switch (_edit_point) {
2316 case EditAtPlayhead:
2317 action = "edit-at-playhead";
2319 case EditAtSelectedMarker:
2320 action = "edit-at-marker";
2323 action = "edit-at-mouse";
2327 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2329 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2333 bool in_track_canvas;
2335 if (!mouse_frame (foo, in_track_canvas)) {
2336 in_track_canvas = false;
2339 reset_canvas_action_sensitivity (in_track_canvas);
2345 Editor::set_state (const XMLNode& node, int version)
2347 XMLProperty const * prop;
2349 PBD::Unwinder<bool> nsi (no_save_instant, true);
2352 Tabbable::set_state (node, version);
2354 if (_session && (prop = node.property ("playhead"))) {
2356 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2358 playhead_cursor->set_position (pos);
2360 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2361 playhead_cursor->set_position (0);
2364 playhead_cursor->set_position (0);
2367 if ((prop = node.property ("mixer-width"))) {
2368 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2371 if ((prop = node.property ("zoom-focus"))) {
2372 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2374 zoom_focus_selection_done (zoom_focus);
2377 if ((prop = node.property ("zoom"))) {
2378 /* older versions of ardour used floating point samples_per_pixel */
2379 double f = PBD::atof (prop->value());
2380 reset_zoom (llrintf (f));
2382 reset_zoom (samples_per_pixel);
2385 if ((prop = node.property ("visible-track-count"))) {
2386 set_visible_track_count (PBD::atoi (prop->value()));
2389 if ((prop = node.property ("snap-to"))) {
2390 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2391 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2393 set_snap_to (_snap_type);
2396 if ((prop = node.property ("snap-mode"))) {
2397 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2398 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2399 * snap_mode_selection_done() will only mark an already active item as active
2400 * which does not trigger set_text().
2402 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2404 set_snap_mode (_snap_mode);
2407 if ((prop = node.property ("internal-snap-to"))) {
2408 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2411 if ((prop = node.property ("internal-snap-mode"))) {
2412 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2415 if ((prop = node.property ("pre-internal-snap-to"))) {
2416 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2419 if ((prop = node.property ("pre-internal-snap-mode"))) {
2420 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2423 if ((prop = node.property ("mouse-mode"))) {
2424 MouseMode m = str2mousemode(prop->value());
2425 set_mouse_mode (m, true);
2427 set_mouse_mode (MouseObject, true);
2430 if ((prop = node.property ("left-frame")) != 0) {
2432 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2436 reset_x_origin (pos);
2440 if ((prop = node.property ("y-origin")) != 0) {
2441 reset_y_origin (atof (prop->value ()));
2444 if ((prop = node.property ("join-object-range"))) {
2445 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2446 bool yn = string_is_affirmative (prop->value());
2448 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2449 tact->set_active (!yn);
2450 tact->set_active (yn);
2452 set_mouse_mode(mouse_mode, true);
2455 if ((prop = node.property ("edit-point"))) {
2456 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2458 set_edit_point_preference (_edit_point);
2461 if ((prop = node.property ("show-measures"))) {
2462 bool yn = string_is_affirmative (prop->value());
2463 _show_measures = yn;
2466 if ((prop = node.property ("follow-playhead"))) {
2467 bool yn = string_is_affirmative (prop->value());
2468 set_follow_playhead (yn);
2471 if ((prop = node.property ("stationary-playhead"))) {
2472 bool yn = string_is_affirmative (prop->value());
2473 set_stationary_playhead (yn);
2476 if ((prop = node.property ("region-list-sort-type"))) {
2477 RegionListSortType st;
2478 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2481 if ((prop = node.property ("show-editor-mixer"))) {
2483 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2486 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2487 bool yn = string_is_affirmative (prop->value());
2489 /* do it twice to force the change */
2491 tact->set_active (!yn);
2492 tact->set_active (yn);
2495 if ((prop = node.property ("show-editor-list"))) {
2497 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2500 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2501 bool yn = string_is_affirmative (prop->value());
2503 /* do it twice to force the change */
2505 tact->set_active (!yn);
2506 tact->set_active (yn);
2509 if ((prop = node.property (X_("editor-list-page")))) {
2510 _the_notebook.set_current_page (atoi (prop->value ()));
2513 if ((prop = node.property (X_("show-marker-lines")))) {
2514 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2516 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2517 bool yn = string_is_affirmative (prop->value ());
2519 tact->set_active (!yn);
2520 tact->set_active (yn);
2523 XMLNodeList children = node.children ();
2524 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2525 selection->set_state (**i, Stateful::current_state_version);
2526 _regions->set_state (**i);
2529 if ((prop = node.property ("maximised"))) {
2530 bool yn = string_is_affirmative (prop->value());
2531 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2533 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2534 bool fs = tact && tact->get_active();
2536 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2540 if ((prop = node.property ("nudge-clock-value"))) {
2542 sscanf (prop->value().c_str(), "%" PRId64, &f);
2543 nudge_clock->set (f);
2545 nudge_clock->set_mode (AudioClock::Timecode);
2546 nudge_clock->set (_session->frame_rate() * 5, true);
2551 * Not all properties may have been in XML, but
2552 * those that are linked to a private variable may need changing
2557 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2559 yn = _show_measures;
2560 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2561 /* do it twice to force the change */
2562 tact->set_active (!yn);
2563 tact->set_active (yn);
2566 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2567 yn = _follow_playhead;
2569 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2570 if (tact->get_active() != yn) {
2571 tact->set_active (yn);
2575 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2576 yn = _stationary_playhead;
2578 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2579 if (tact->get_active() != yn) {
2580 tact->set_active (yn);
2585 return LuaInstance::instance()->set_state(node);
2589 Editor::get_state ()
2591 XMLNode* node = new XMLNode (X_("Editor"));
2595 id().print (buf, sizeof (buf));
2596 node->add_property ("id", buf);
2598 node->add_child_nocopy (Tabbable::get_state());
2600 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2601 node->add_property("edit-horizontal-pane-pos", string(buf));
2602 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2603 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2604 node->add_property("edit-vertical-pane-pos", string(buf));
2606 maybe_add_mixer_strip_width (*node);
2608 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2610 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2611 node->add_property ("zoom", buf);
2612 node->add_property ("snap-to", enum_2_string (_snap_type));
2613 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2614 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2615 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2616 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2617 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2618 node->add_property ("edit-point", enum_2_string (_edit_point));
2619 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2620 node->add_property ("visible-track-count", buf);
2622 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2623 node->add_property ("playhead", buf);
2624 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2625 node->add_property ("left-frame", buf);
2626 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2627 node->add_property ("y-origin", buf);
2629 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2630 node->add_property ("maximised", _maximised ? "yes" : "no");
2631 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2632 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2633 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2634 node->add_property ("mouse-mode", enum2str(mouse_mode));
2635 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2637 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2639 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2640 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2643 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2645 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2646 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2649 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2650 node->add_property (X_("editor-list-page"), buf);
2652 if (button_bindings) {
2653 XMLNode* bb = new XMLNode (X_("Buttons"));
2654 button_bindings->save (*bb);
2655 node->add_child_nocopy (*bb);
2658 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2660 node->add_child_nocopy (selection->get_state ());
2661 node->add_child_nocopy (_regions->get_state ());
2663 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2664 node->add_property ("nudge-clock-value", buf);
2666 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2667 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2672 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2673 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2675 * @return pair: TimeAxisView that y is over, layer index.
2677 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2678 * in stacked or expanded region display mode, otherwise 0.
2680 std::pair<TimeAxisView *, double>
2681 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2683 if (!trackview_relative_offset) {
2684 y -= _trackview_group->canvas_origin().y;
2688 return std::make_pair ( (TimeAxisView *) 0, 0);
2691 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2693 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2700 return std::make_pair ( (TimeAxisView *) 0, 0);
2703 /** Snap a position to the grid, if appropriate, taking into account current
2704 * grid settings and also the state of any snap modifier keys that may be pressed.
2705 * @param start Position to snap.
2706 * @param event Event to get current key modifier information from, or 0.
2709 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2711 if (!_session || !event) {
2715 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2716 if (_snap_mode == SnapOff) {
2717 snap_to_internal (start, direction, for_mark);
2720 if (_snap_mode != SnapOff) {
2721 snap_to_internal (start, direction, for_mark);
2722 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2723 /* SnapOff, but we pressed the snap_delta modifier */
2724 snap_to_internal (start, direction, for_mark);
2730 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2732 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2736 snap_to_internal (start, direction, for_mark, ensure_snap);
2740 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2742 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2743 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2745 switch (_snap_type) {
2746 case SnapToTimecodeFrame:
2747 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2748 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2749 /* start is already on a whole timecode frame, do nothing */
2750 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2751 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2753 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2757 case SnapToTimecodeSeconds:
2758 if (_session->config.get_timecode_offset_negative()) {
2759 start += _session->config.get_timecode_offset ();
2761 start -= _session->config.get_timecode_offset ();
2763 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2764 (start % one_timecode_second == 0)) {
2765 /* start is already on a whole second, do nothing */
2766 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2767 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2769 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2772 if (_session->config.get_timecode_offset_negative()) {
2773 start -= _session->config.get_timecode_offset ();
2775 start += _session->config.get_timecode_offset ();
2779 case SnapToTimecodeMinutes:
2780 if (_session->config.get_timecode_offset_negative()) {
2781 start += _session->config.get_timecode_offset ();
2783 start -= _session->config.get_timecode_offset ();
2785 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2786 (start % one_timecode_minute == 0)) {
2787 /* start is already on a whole minute, do nothing */
2788 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2789 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2791 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2793 if (_session->config.get_timecode_offset_negative()) {
2794 start -= _session->config.get_timecode_offset ();
2796 start += _session->config.get_timecode_offset ();
2800 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2801 abort(); /*NOTREACHED*/
2806 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2808 const framepos_t one_second = _session->frame_rate();
2809 const framepos_t one_minute = _session->frame_rate() * 60;
2810 framepos_t presnap = start;
2814 switch (_snap_type) {
2815 case SnapToTimecodeFrame:
2816 case SnapToTimecodeSeconds:
2817 case SnapToTimecodeMinutes:
2818 return timecode_snap_to_internal (start, direction, for_mark);
2821 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2822 start % (one_second/75) == 0) {
2823 /* start is already on a whole CD frame, do nothing */
2824 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2825 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2827 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2832 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2833 start % one_second == 0) {
2834 /* start is already on a whole second, do nothing */
2835 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2836 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2838 start = (framepos_t) floor ((double) start / one_second) * one_second;
2843 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2844 start % one_minute == 0) {
2845 /* start is already on a whole minute, do nothing */
2846 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2847 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2849 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2854 start = _session->tempo_map().round_to_bar (start, direction);
2858 start = _session->tempo_map().round_to_beat (start, direction);
2861 case SnapToBeatDiv128:
2862 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2864 case SnapToBeatDiv64:
2865 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2867 case SnapToBeatDiv32:
2868 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2870 case SnapToBeatDiv28:
2871 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2873 case SnapToBeatDiv24:
2874 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2876 case SnapToBeatDiv20:
2877 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2879 case SnapToBeatDiv16:
2880 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2882 case SnapToBeatDiv14:
2883 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2885 case SnapToBeatDiv12:
2886 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2888 case SnapToBeatDiv10:
2889 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2891 case SnapToBeatDiv8:
2892 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2894 case SnapToBeatDiv7:
2895 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2897 case SnapToBeatDiv6:
2898 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2900 case SnapToBeatDiv5:
2901 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2903 case SnapToBeatDiv4:
2904 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2906 case SnapToBeatDiv3:
2907 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2909 case SnapToBeatDiv2:
2910 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2918 _session->locations()->marks_either_side (start, before, after);
2920 if (before == max_framepos && after == max_framepos) {
2921 /* No marks to snap to, so just don't snap */
2923 } else if (before == max_framepos) {
2925 } else if (after == max_framepos) {
2927 } else if (before != max_framepos && after != max_framepos) {
2928 /* have before and after */
2929 if ((start - before) < (after - start)) {
2938 case SnapToRegionStart:
2939 case SnapToRegionEnd:
2940 case SnapToRegionSync:
2941 case SnapToRegionBoundary:
2942 if (!region_boundary_cache.empty()) {
2944 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2945 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2947 if (direction > 0) {
2948 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2950 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2953 if (next != region_boundary_cache.begin ()) {
2958 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2959 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2961 if (start > (p + n) / 2) {
2970 switch (_snap_mode) {
2980 if (presnap > start) {
2981 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2985 } else if (presnap < start) {
2986 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2992 /* handled at entry */
3000 Editor::setup_toolbar ()
3002 HBox* mode_box = manage(new HBox);
3003 mode_box->set_border_width (2);
3004 mode_box->set_spacing(2);
3006 HBox* mouse_mode_box = manage (new HBox);
3007 HBox* mouse_mode_hbox = manage (new HBox);
3008 VBox* mouse_mode_vbox = manage (new VBox);
3009 Alignment* mouse_mode_align = manage (new Alignment);
3011 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3012 mouse_mode_size_group->add_widget (smart_mode_button);
3013 mouse_mode_size_group->add_widget (mouse_move_button);
3014 mouse_mode_size_group->add_widget (mouse_cut_button);
3015 mouse_mode_size_group->add_widget (mouse_select_button);
3016 mouse_mode_size_group->add_widget (mouse_timefx_button);
3017 mouse_mode_size_group->add_widget (mouse_audition_button);
3018 mouse_mode_size_group->add_widget (mouse_draw_button);
3019 mouse_mode_size_group->add_widget (mouse_content_button);
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_preset_selector);
3024 mouse_mode_size_group->add_widget (zoom_out_full_button);
3025 mouse_mode_size_group->add_widget (zoom_focus_selector);
3027 mouse_mode_size_group->add_widget (tav_shrink_button);
3028 mouse_mode_size_group->add_widget (tav_expand_button);
3029 mouse_mode_size_group->add_widget (visible_tracks_selector);
3031 mouse_mode_size_group->add_widget (snap_type_selector);
3032 mouse_mode_size_group->add_widget (snap_mode_selector);
3034 mouse_mode_size_group->add_widget (edit_point_selector);
3035 mouse_mode_size_group->add_widget (edit_mode_selector);
3037 mouse_mode_size_group->add_widget (*nudge_clock);
3038 mouse_mode_size_group->add_widget (nudge_forward_button);
3039 mouse_mode_size_group->add_widget (nudge_backward_button);
3041 mouse_mode_hbox->set_spacing (2);
3043 if (!ARDOUR::Profile->get_trx()) {
3044 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3047 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3048 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3050 if (!ARDOUR::Profile->get_mixbus()) {
3051 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3054 if (!ARDOUR::Profile->get_trx()) {
3055 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3056 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3057 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3058 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3061 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3063 mouse_mode_align->add (*mouse_mode_vbox);
3064 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3066 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3068 edit_mode_selector.set_name ("mouse mode button");
3070 if (!ARDOUR::Profile->get_trx()) {
3071 mode_box->pack_start (edit_mode_selector, false, false);
3074 mode_box->pack_start (*mouse_mode_box, false, false);
3078 _zoom_box.set_spacing (2);
3079 _zoom_box.set_border_width (2);
3083 zoom_preset_selector.set_name ("zoom button");
3084 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3085 zoom_preset_selector.set_size_request (42, -1);
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 visible_tracks_selector.set_name ("zoom button");
3118 if (Profile->get_mixbus()) {
3119 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3120 visible_tracks_selector.set_size_request (42, -1);
3122 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3125 tav_expand_button.set_name ("zoom button");
3126 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3127 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3128 tav_expand_button.set_related_action (act);
3130 tav_shrink_button.set_name ("zoom button");
3131 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3132 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3133 tav_shrink_button.set_related_action (act);
3135 if (ARDOUR::Profile->get_mixbus()) {
3136 _zoom_box.pack_start (visible_tracks_selector);
3137 } else if (ARDOUR::Profile->get_trx()) {
3138 _zoom_box.pack_start (tav_shrink_button);
3139 _zoom_box.pack_start (tav_expand_button);
3141 _zoom_box.pack_start (visible_tracks_selector);
3142 _zoom_box.pack_start (tav_shrink_button);
3143 _zoom_box.pack_start (tav_expand_button);
3146 snap_box.set_spacing (2);
3147 snap_box.set_border_width (2);
3149 snap_type_selector.set_name ("mouse mode button");
3151 snap_mode_selector.set_name ("mouse mode button");
3153 edit_point_selector.set_name ("mouse mode button");
3155 snap_box.pack_start (snap_mode_selector, false, false);
3156 snap_box.pack_start (snap_type_selector, false, false);
3157 snap_box.pack_start (edit_point_selector, false, false);
3161 HBox *nudge_box = manage (new HBox);
3162 nudge_box->set_spacing (2);
3163 nudge_box->set_border_width (2);
3165 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3166 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3168 nudge_box->pack_start (nudge_backward_button, false, false);
3169 nudge_box->pack_start (nudge_forward_button, false, false);
3170 nudge_box->pack_start (*nudge_clock, false, false);
3173 /* Pack everything in... */
3175 HBox* hbox = manage (new HBox);
3176 hbox->set_spacing(2);
3178 toolbar_hbox.set_spacing (2);
3179 toolbar_hbox.set_border_width (1);
3181 toolbar_hbox.pack_start (*mode_box, false, false);
3182 if (!ARDOUR::Profile->get_trx()) {
3183 toolbar_hbox.pack_start (_zoom_box, false, false);
3184 toolbar_hbox.pack_start (*hbox, false, false);
3187 if (!ARDOUR::Profile->get_trx()) {
3188 hbox->pack_start (snap_box, false, false);
3189 hbox->pack_start (*nudge_box, false, false);
3194 toolbar_base.set_name ("ToolBarBase");
3195 toolbar_base.add (toolbar_hbox);
3197 _toolbar_viewport.add (toolbar_base);
3198 /* stick to the required height but allow width to vary if there's not enough room */
3199 _toolbar_viewport.set_size_request (1, -1);
3201 toolbar_frame.set_shadow_type (SHADOW_OUT);
3202 toolbar_frame.set_name ("BaseFrame");
3203 toolbar_frame.add (_toolbar_viewport);
3207 Editor::build_edit_point_menu ()
3209 using namespace Menu_Helpers;
3211 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3212 if(!Profile->get_mixbus())
3213 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3214 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3216 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3220 Editor::build_edit_mode_menu ()
3222 using namespace Menu_Helpers;
3224 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3225 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3226 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3227 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3229 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3233 Editor::build_snap_mode_menu ()
3235 using namespace Menu_Helpers;
3237 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3238 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3239 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3241 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3245 Editor::build_snap_type_menu ()
3247 using namespace Menu_Helpers;
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3273 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3274 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3275 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3276 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3277 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3278 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3280 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3285 Editor::setup_tooltips ()
3287 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3288 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3289 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3290 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3291 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3292 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3293 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3294 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3295 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3296 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3297 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3298 set_tooltip (zoom_in_button, _("Zoom In"));
3299 set_tooltip (zoom_out_button, _("Zoom Out"));
3300 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3301 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3302 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3303 set_tooltip (tav_expand_button, _("Expand Tracks"));
3304 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3305 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3306 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3307 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3308 set_tooltip (edit_point_selector, _("Edit Point"));
3309 set_tooltip (edit_mode_selector, _("Edit Mode"));
3310 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3314 Editor::convert_drop_to_paths (
3315 vector<string>& paths,
3316 const RefPtr<Gdk::DragContext>& /*context*/,
3319 const SelectionData& data,
3323 if (_session == 0) {
3327 vector<string> uris = data.get_uris();
3331 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3332 are actually URI lists. So do it by hand.
3335 if (data.get_target() != "text/plain") {
3339 /* Parse the "uri-list" format that Nautilus provides,
3340 where each pathname is delimited by \r\n.
3342 THERE MAY BE NO NULL TERMINATING CHAR!!!
3345 string txt = data.get_text();
3349 p = (char *) malloc (txt.length() + 1);
3350 txt.copy (p, txt.length(), 0);
3351 p[txt.length()] = '\0';
3357 while (g_ascii_isspace (*p))
3361 while (*q && (*q != '\n') && (*q != '\r')) {
3368 while (q > p && g_ascii_isspace (*q))
3373 uris.push_back (string (p, q - p + 1));
3377 p = strchr (p, '\n');
3389 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3390 if ((*i).substr (0,7) == "file://") {
3391 paths.push_back (Glib::filename_from_uri (*i));
3399 Editor::new_tempo_section ()
3404 Editor::map_transport_state ()
3406 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3408 if (_session && _session->transport_stopped()) {
3409 have_pending_keyboard_selection = false;
3412 update_loop_range_view ();
3418 Editor::begin_selection_op_history ()
3420 selection_op_cmd_depth = 0;
3421 selection_op_history_it = 0;
3423 while(!selection_op_history.empty()) {
3424 delete selection_op_history.front();
3425 selection_op_history.pop_front();
3428 selection_undo_action->set_sensitive (false);
3429 selection_redo_action->set_sensitive (false);
3430 selection_op_history.push_front (&_selection_memento->get_state ());
3434 Editor::begin_reversible_selection_op (string name)
3437 //cerr << name << endl;
3438 /* begin/commit pairs can be nested */
3439 selection_op_cmd_depth++;
3444 Editor::commit_reversible_selection_op ()
3447 if (selection_op_cmd_depth == 1) {
3449 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3451 The user has undone some selection ops and then made a new one,
3452 making anything earlier in the list invalid.
3455 list<XMLNode *>::iterator it = selection_op_history.begin();
3456 list<XMLNode *>::iterator e_it = it;
3457 advance (e_it, selection_op_history_it);
3459 for ( ; it != e_it; ++it) {
3462 selection_op_history.erase (selection_op_history.begin(), e_it);
3465 selection_op_history.push_front (&_selection_memento->get_state ());
3466 selection_op_history_it = 0;
3468 selection_undo_action->set_sensitive (true);
3469 selection_redo_action->set_sensitive (false);
3472 if (selection_op_cmd_depth > 0) {
3473 selection_op_cmd_depth--;
3479 Editor::undo_selection_op ()
3482 selection_op_history_it++;
3484 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3485 if (n == selection_op_history_it) {
3486 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3487 selection_redo_action->set_sensitive (true);
3491 /* is there an earlier entry? */
3492 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3493 selection_undo_action->set_sensitive (false);
3499 Editor::redo_selection_op ()
3502 if (selection_op_history_it > 0) {
3503 selection_op_history_it--;
3506 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3507 if (n == selection_op_history_it) {
3508 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3509 selection_undo_action->set_sensitive (true);
3514 if (selection_op_history_it == 0) {
3515 selection_redo_action->set_sensitive (false);
3521 Editor::begin_reversible_command (string name)
3524 before.push_back (&_selection_memento->get_state ());
3525 _session->begin_reversible_command (name);
3530 Editor::begin_reversible_command (GQuark q)
3533 before.push_back (&_selection_memento->get_state ());
3534 _session->begin_reversible_command (q);
3539 Editor::abort_reversible_command ()
3542 while(!before.empty()) {
3543 delete before.front();
3546 _session->abort_reversible_command ();
3551 Editor::commit_reversible_command ()
3554 if (before.size() == 1) {
3555 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3556 redo_action->set_sensitive(false);
3557 undo_action->set_sensitive(true);
3558 begin_selection_op_history ();
3561 if (before.empty()) {
3562 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3567 _session->commit_reversible_command ();
3572 Editor::history_changed ()
3576 if (undo_action && _session) {
3577 if (_session->undo_depth() == 0) {
3578 label = S_("Command|Undo");
3580 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3582 undo_action->property_label() = label;
3585 if (redo_action && _session) {
3586 if (_session->redo_depth() == 0) {
3588 redo_action->set_sensitive (false);
3590 label = string_compose(_("Redo (%1)"), _session->next_redo());
3591 redo_action->set_sensitive (true);
3593 redo_action->property_label() = label;
3598 Editor::duplicate_range (bool with_dialog)
3602 RegionSelection rs = get_regions_from_selection_and_entered ();
3604 if ( selection->time.length() == 0 && rs.empty()) {
3610 ArdourDialog win (_("Duplicate"));
3611 Label label (_("Number of duplications:"));
3612 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3613 SpinButton spinner (adjustment, 0.0, 1);
3616 win.get_vbox()->set_spacing (12);
3617 win.get_vbox()->pack_start (hbox);
3618 hbox.set_border_width (6);
3619 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3621 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3622 place, visually. so do this by hand.
3625 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3626 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3627 spinner.grab_focus();
3633 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3634 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3635 win.set_default_response (RESPONSE_ACCEPT);
3637 spinner.grab_focus ();
3639 switch (win.run ()) {
3640 case RESPONSE_ACCEPT:
3646 times = adjustment.get_value();
3649 if ((current_mouse_mode() == Editing::MouseRange)) {
3650 if (selection->time.length()) {
3651 duplicate_selection (times);
3653 } else if (get_smart_mode()) {
3654 if (selection->time.length()) {
3655 duplicate_selection (times);
3657 duplicate_some_regions (rs, times);
3659 duplicate_some_regions (rs, times);
3664 Editor::set_edit_mode (EditMode m)
3666 Config->set_edit_mode (m);
3670 Editor::cycle_edit_mode ()
3672 switch (Config->get_edit_mode()) {
3674 Config->set_edit_mode (Ripple);
3678 Config->set_edit_mode (Lock);
3681 Config->set_edit_mode (Slide);
3687 Editor::edit_mode_selection_done ( EditMode m )
3689 Config->set_edit_mode ( m );
3693 Editor::snap_type_selection_done (SnapType snaptype)
3695 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3697 ract->set_active ();
3702 Editor::snap_mode_selection_done (SnapMode mode)
3704 RefPtr<RadioAction> ract = snap_mode_action (mode);
3707 ract->set_active (true);
3712 Editor::cycle_edit_point (bool with_marker)
3714 if(Profile->get_mixbus())
3715 with_marker = false;
3717 switch (_edit_point) {
3719 set_edit_point_preference (EditAtPlayhead);
3721 case EditAtPlayhead:
3723 set_edit_point_preference (EditAtSelectedMarker);
3725 set_edit_point_preference (EditAtMouse);
3728 case EditAtSelectedMarker:
3729 set_edit_point_preference (EditAtMouse);
3735 Editor::edit_point_selection_done (EditPoint ep)
3737 set_edit_point_preference ( ep );
3741 Editor::build_zoom_focus_menu ()
3743 using namespace Menu_Helpers;
3745 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3746 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3747 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3748 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3749 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3750 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3752 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3756 Editor::zoom_focus_selection_done ( ZoomFocus f )
3758 RefPtr<RadioAction> ract = zoom_focus_action (f);
3760 ract->set_active ();
3765 Editor::build_track_count_menu ()
3767 using namespace Menu_Helpers;
3769 if (!Profile->get_mixbus()) {
3770 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3790 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3791 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3792 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3793 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3795 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3796 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3797 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3798 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3799 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3800 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3801 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3802 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3803 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3804 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3805 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3810 Editor::set_zoom_preset (int64_t ms)
3813 temporal_zoom_session();
3817 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3818 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3822 Editor::set_visible_track_count (int32_t n)
3824 _visible_track_count = n;
3826 /* if the canvas hasn't really been allocated any size yet, just
3827 record the desired number of visible tracks and return. when canvas
3828 allocation happens, we will get called again and then we can do the
3832 if (_visible_canvas_height <= 1) {
3838 DisplaySuspender ds;
3840 if (_visible_track_count > 0) {
3841 h = trackviews_height() / _visible_track_count;
3842 std::ostringstream s;
3843 s << _visible_track_count;
3845 } else if (_visible_track_count == 0) {
3847 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3848 if ((*i)->marked_for_display()) {
3852 h = trackviews_height() / n;
3855 /* negative value means that the visible track count has
3856 been overridden by explicit track height changes.
3858 visible_tracks_selector.set_text (X_("*"));
3862 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3863 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3866 if (str != visible_tracks_selector.get_text()) {
3867 visible_tracks_selector.set_text (str);
3872 Editor::override_visible_track_count ()
3874 _visible_track_count = -1;
3875 visible_tracks_selector.set_text ( _("*") );
3879 Editor::edit_controls_button_release (GdkEventButton* ev)
3881 if (Keyboard::is_context_menu_event (ev)) {
3882 ARDOUR_UI::instance()->add_route ();
3883 } else if (ev->button == 1) {
3884 selection->clear_tracks ();
3891 Editor::mouse_select_button_release (GdkEventButton* ev)
3893 /* this handles just right-clicks */
3895 if (ev->button != 3) {
3903 Editor::set_zoom_focus (ZoomFocus f)
3905 string str = zoom_focus_strings[(int)f];
3907 if (str != zoom_focus_selector.get_text()) {
3908 zoom_focus_selector.set_text (str);
3911 if (zoom_focus != f) {
3918 Editor::cycle_zoom_focus ()
3920 switch (zoom_focus) {
3922 set_zoom_focus (ZoomFocusRight);
3924 case ZoomFocusRight:
3925 set_zoom_focus (ZoomFocusCenter);
3927 case ZoomFocusCenter:
3928 set_zoom_focus (ZoomFocusPlayhead);
3930 case ZoomFocusPlayhead:
3931 set_zoom_focus (ZoomFocusMouse);
3933 case ZoomFocusMouse:
3934 set_zoom_focus (ZoomFocusEdit);
3937 set_zoom_focus (ZoomFocusLeft);
3943 Editor::set_show_measures (bool yn)
3945 if (_show_measures != yn) {
3948 if ((_show_measures = yn) == true) {
3950 tempo_lines->show();
3953 std::vector<TempoMap::BBTPoint> grid;
3954 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3955 draw_measures (grid);
3963 Editor::toggle_follow_playhead ()
3965 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3967 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3968 set_follow_playhead (tact->get_active());
3972 /** @param yn true to follow playhead, otherwise false.
3973 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3976 Editor::set_follow_playhead (bool yn, bool catch_up)
3978 if (_follow_playhead != yn) {
3979 if ((_follow_playhead = yn) == true && catch_up) {
3981 reset_x_origin_to_follow_playhead ();
3988 Editor::toggle_stationary_playhead ()
3990 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3992 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3993 set_stationary_playhead (tact->get_active());
3998 Editor::set_stationary_playhead (bool yn)
4000 if (_stationary_playhead != yn) {
4001 if ((_stationary_playhead = yn) == true) {
4003 // FIXME need a 3.0 equivalent of this 2.X call
4004 // update_current_screen ();
4011 Editor::playlist_selector () const
4013 return *_playlist_selector;
4017 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4019 if (paste_count == 0) {
4020 /* don't bother calculating an offset that will be zero anyway */
4024 /* calculate basic unsnapped multi-paste offset */
4025 framecnt_t offset = paste_count * duration;
4027 /* snap offset so pos + offset is aligned to the grid */
4028 framepos_t offset_pos = pos + offset;
4029 snap_to(offset_pos, RoundUpMaybe);
4030 offset = offset_pos - pos;
4036 Editor::get_grid_beat_divisions(framepos_t position)
4038 switch (_snap_type) {
4039 case SnapToBeatDiv128: return 128;
4040 case SnapToBeatDiv64: return 64;
4041 case SnapToBeatDiv32: return 32;
4042 case SnapToBeatDiv28: return 28;
4043 case SnapToBeatDiv24: return 24;
4044 case SnapToBeatDiv20: return 20;
4045 case SnapToBeatDiv16: return 16;
4046 case SnapToBeatDiv14: return 14;
4047 case SnapToBeatDiv12: return 12;
4048 case SnapToBeatDiv10: return 10;
4049 case SnapToBeatDiv8: return 8;
4050 case SnapToBeatDiv7: return 7;
4051 case SnapToBeatDiv6: return 6;
4052 case SnapToBeatDiv5: return 5;
4053 case SnapToBeatDiv4: return 4;
4054 case SnapToBeatDiv3: return 3;
4055 case SnapToBeatDiv2: return 2;
4061 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4062 if the grid is non-musical, returns 0.
4063 if the grid is snapped to bars, returns -1.
4064 @param event_state the current keyboard modifier mask.
4067 Editor::get_grid_music_divisions (uint32_t event_state)
4069 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4073 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4077 switch (_snap_type) {
4078 case SnapToBeatDiv128: return 128;
4079 case SnapToBeatDiv64: return 64;
4080 case SnapToBeatDiv32: return 32;
4081 case SnapToBeatDiv28: return 28;
4082 case SnapToBeatDiv24: return 24;
4083 case SnapToBeatDiv20: return 20;
4084 case SnapToBeatDiv16: return 16;
4085 case SnapToBeatDiv14: return 14;
4086 case SnapToBeatDiv12: return 12;
4087 case SnapToBeatDiv10: return 10;
4088 case SnapToBeatDiv8: return 8;
4089 case SnapToBeatDiv7: return 7;
4090 case SnapToBeatDiv6: return 6;
4091 case SnapToBeatDiv5: return 5;
4092 case SnapToBeatDiv4: return 4;
4093 case SnapToBeatDiv3: return 3;
4094 case SnapToBeatDiv2: return 2;
4095 case SnapToBeat: return 1;
4096 case SnapToBar : return -1;
4103 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4107 const unsigned divisions = get_grid_beat_divisions(position);
4109 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4112 switch (_snap_type) {
4114 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4117 const Meter& m = _session->tempo_map().meter_at_frame (position);
4118 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4126 return Evoral::Beats();
4130 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4134 ret = nudge_clock->current_duration (pos);
4135 next = ret + 1; /* XXXX fix me */
4141 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4143 ArdourDialog dialog (_("Playlist Deletion"));
4144 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4145 "If it is kept, its audio files will not be cleaned.\n"
4146 "If it is deleted, audio files used by it alone will be cleaned."),
4149 dialog.set_position (WIN_POS_CENTER);
4150 dialog.get_vbox()->pack_start (label);
4154 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4155 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4156 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4157 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4158 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4160 // by default gtk uses the left most button
4161 keep->grab_focus ();
4163 switch (dialog.run ()) {
4165 /* keep this and all remaining ones */
4170 /* delete this and all others */
4174 case RESPONSE_ACCEPT:
4175 /* delete the playlist */
4179 case RESPONSE_REJECT:
4180 /* keep the playlist */
4192 Editor::audio_region_selection_covers (framepos_t where)
4194 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4195 if ((*a)->region()->covers (where)) {
4204 Editor::prepare_for_cleanup ()
4206 cut_buffer->clear_regions ();
4207 cut_buffer->clear_playlists ();
4209 selection->clear_regions ();
4210 selection->clear_playlists ();
4212 _regions->suspend_redisplay ();
4216 Editor::finish_cleanup ()
4218 _regions->resume_redisplay ();
4222 Editor::transport_loop_location()
4225 return _session->locations()->auto_loop_location();
4232 Editor::transport_punch_location()
4235 return _session->locations()->auto_punch_location();
4242 Editor::control_layout_scroll (GdkEventScroll* ev)
4244 /* Just forward to the normal canvas scroll method. The coordinate
4245 systems are different but since the canvas is always larger than the
4246 track headers, and aligned with the trackview area, this will work.
4248 In the not too distant future this layout is going away anyway and
4249 headers will be on the canvas.
4251 return canvas_scroll_event (ev, false);
4255 Editor::session_state_saved (string)
4258 _snapshots->redisplay ();
4262 Editor::maximise_editing_space ()
4268 Gtk::Window* toplevel = current_toplevel();
4271 toplevel->fullscreen ();
4277 Editor::restore_editing_space ()
4283 Gtk::Window* toplevel = current_toplevel();
4286 toplevel->unfullscreen();
4292 * Make new playlists for a given track and also any others that belong
4293 * to the same active route group with the `select' property.
4298 Editor::new_playlists (TimeAxisView* v)
4300 begin_reversible_command (_("new playlists"));
4301 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4302 _session->playlists->get (playlists);
4303 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4304 commit_reversible_command ();
4308 * Use a copy of the current playlist for a given track and also any others that belong
4309 * to the same active route group with the `select' property.
4314 Editor::copy_playlists (TimeAxisView* v)
4316 begin_reversible_command (_("copy playlists"));
4317 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4318 _session->playlists->get (playlists);
4319 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4320 commit_reversible_command ();
4323 /** Clear the current playlist for a given track and also any others that belong
4324 * to the same active route group with the `select' property.
4329 Editor::clear_playlists (TimeAxisView* v)
4331 begin_reversible_command (_("clear playlists"));
4332 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4333 _session->playlists->get (playlists);
4334 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4335 commit_reversible_command ();
4339 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4341 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4345 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4347 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4351 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4353 atv.clear_playlist ();
4357 Editor::get_y_origin () const
4359 return vertical_adjustment.get_value ();
4362 /** Queue up a change to the viewport x origin.
4363 * @param frame New x origin.
4366 Editor::reset_x_origin (framepos_t frame)
4368 pending_visual_change.add (VisualChange::TimeOrigin);
4369 pending_visual_change.time_origin = frame;
4370 ensure_visual_change_idle_handler ();
4374 Editor::reset_y_origin (double y)
4376 pending_visual_change.add (VisualChange::YOrigin);
4377 pending_visual_change.y_origin = y;
4378 ensure_visual_change_idle_handler ();
4382 Editor::reset_zoom (framecnt_t spp)
4384 if (spp == samples_per_pixel) {
4388 pending_visual_change.add (VisualChange::ZoomLevel);
4389 pending_visual_change.samples_per_pixel = spp;
4390 ensure_visual_change_idle_handler ();
4394 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4396 reset_x_origin (frame);
4399 if (!no_save_visual) {
4400 undo_visual_stack.push_back (current_visual_state(false));
4404 Editor::VisualState::VisualState (bool with_tracks)
4405 : gui_state (with_tracks ? new GUIObjectState : 0)
4409 Editor::VisualState::~VisualState ()
4414 Editor::VisualState*
4415 Editor::current_visual_state (bool with_tracks)
4417 VisualState* vs = new VisualState (with_tracks);
4418 vs->y_position = vertical_adjustment.get_value();
4419 vs->samples_per_pixel = samples_per_pixel;
4420 vs->leftmost_frame = leftmost_frame;
4421 vs->zoom_focus = zoom_focus;
4424 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4431 Editor::undo_visual_state ()
4433 if (undo_visual_stack.empty()) {
4437 VisualState* vs = undo_visual_stack.back();
4438 undo_visual_stack.pop_back();
4441 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4444 use_visual_state (*vs);
4449 Editor::redo_visual_state ()
4451 if (redo_visual_stack.empty()) {
4455 VisualState* vs = redo_visual_stack.back();
4456 redo_visual_stack.pop_back();
4458 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4459 // why do we check here?
4460 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4463 use_visual_state (*vs);
4468 Editor::swap_visual_state ()
4470 if (undo_visual_stack.empty()) {
4471 redo_visual_state ();
4473 undo_visual_state ();
4478 Editor::use_visual_state (VisualState& vs)
4480 PBD::Unwinder<bool> nsv (no_save_visual, true);
4481 DisplaySuspender ds;
4483 vertical_adjustment.set_value (vs.y_position);
4485 set_zoom_focus (vs.zoom_focus);
4486 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4489 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4491 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4492 (*i)->clear_property_cache();
4493 (*i)->reset_visual_state ();
4497 _routes->update_visibility ();
4500 /** This is the core function that controls the zoom level of the canvas. It is called
4501 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4502 * @param spp new number of samples per pixel
4505 Editor::set_samples_per_pixel (framecnt_t spp)
4511 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4512 const framecnt_t lots_of_pixels = 4000;
4514 /* if the zoom level is greater than what you'd get trying to display 3
4515 * days of audio on a really big screen, then it's too big.
4518 if (spp * lots_of_pixels > three_days) {
4522 samples_per_pixel = spp;
4525 tempo_lines->tempo_map_changed();
4528 bool const showing_time_selection = selection->time.length() > 0;
4530 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4531 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4532 (*i)->reshow_selection (selection->time);
4536 ZoomChanged (); /* EMIT_SIGNAL */
4538 ArdourCanvas::GtkCanvasViewport* c;
4540 c = get_track_canvas();
4542 c->canvas()->zoomed ();
4545 if (playhead_cursor) {
4546 playhead_cursor->set_position (playhead_cursor->current_frame ());
4549 refresh_location_display();
4550 _summary->set_overlays_dirty ();
4552 update_marker_labels ();
4558 Editor::playhead_cursor_sample () const
4560 return playhead_cursor->current_frame();
4564 Editor::queue_visual_videotimeline_update ()
4567 * pending_visual_change.add (VisualChange::VideoTimeline);
4568 * or maybe even more specific: which videotimeline-image
4569 * currently it calls update_video_timeline() to update
4570 * _all outdated_ images on the video-timeline.
4571 * see 'exposeimg()' in video_image_frame.cc
4573 ensure_visual_change_idle_handler ();
4577 Editor::ensure_visual_change_idle_handler ()
4579 if (pending_visual_change.idle_handler_id < 0) {
4580 // see comment in add_to_idle_resize above.
4581 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4582 pending_visual_change.being_handled = false;
4587 Editor::_idle_visual_changer (void* arg)
4589 return static_cast<Editor*>(arg)->idle_visual_changer ();
4593 Editor::idle_visual_changer ()
4595 /* set_horizontal_position() below (and maybe other calls) call
4596 gtk_main_iteration(), so it's possible that a signal will be handled
4597 half-way through this method. If this signal wants an
4598 idle_visual_changer we must schedule another one after this one, so
4599 mark the idle_handler_id as -1 here to allow that. Also make a note
4600 that we are doing the visual change, so that changes in response to
4601 super-rapid-screen-update can be dropped if we are still processing
4605 pending_visual_change.idle_handler_id = -1;
4606 pending_visual_change.being_handled = true;
4608 VisualChange vc = pending_visual_change;
4610 pending_visual_change.pending = (VisualChange::Type) 0;
4612 visual_changer (vc);
4614 pending_visual_change.being_handled = false;
4616 return 0; /* this is always a one-shot call */
4620 Editor::visual_changer (const VisualChange& vc)
4622 double const last_time_origin = horizontal_position ();
4624 if (vc.pending & VisualChange::ZoomLevel) {
4625 set_samples_per_pixel (vc.samples_per_pixel);
4627 compute_fixed_ruler_scale ();
4629 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4630 update_tempo_based_rulers ();
4632 update_video_timeline();
4635 if (vc.pending & VisualChange::TimeOrigin) {
4636 set_horizontal_position (vc.time_origin / samples_per_pixel);
4639 if (vc.pending & VisualChange::YOrigin) {
4640 vertical_adjustment.set_value (vc.y_origin);
4643 if (last_time_origin == horizontal_position ()) {
4644 /* changed signal not emitted */
4645 update_fixed_rulers ();
4646 redisplay_tempo (true);
4649 if (!(vc.pending & VisualChange::ZoomLevel)) {
4650 update_video_timeline();
4653 _summary->set_overlays_dirty ();
4656 struct EditorOrderTimeAxisSorter {
4657 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4658 return a->order () < b->order ();
4663 Editor::sort_track_selection (TrackViewList& sel)
4665 EditorOrderTimeAxisSorter cmp;
4670 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4673 framepos_t where = 0;
4674 EditPoint ep = _edit_point;
4676 if (Profile->get_mixbus()) {
4677 if (ep == EditAtSelectedMarker) {
4678 ep = EditAtPlayhead;
4682 if (from_outside_canvas && (ep == EditAtMouse)) {
4683 ep = EditAtPlayhead;
4684 } else if (from_context_menu && (ep == EditAtMouse)) {
4685 return canvas_event_sample (&context_click_event, 0, 0);
4688 if (entered_marker) {
4689 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4690 return entered_marker->position();
4693 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4694 ep = EditAtSelectedMarker;
4697 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4698 ep = EditAtPlayhead;
4702 case EditAtPlayhead:
4703 if (_dragging_playhead) {
4704 where = *_control_scroll_target;
4706 where = _session->audible_frame();
4708 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4711 case EditAtSelectedMarker:
4712 if (!selection->markers.empty()) {
4714 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4717 where = loc->start();
4721 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4729 if (!mouse_frame (where, ignored)) {
4730 /* XXX not right but what can we do ? */
4734 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4742 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4744 if (!_session) return;
4746 begin_reversible_command (cmd);
4750 if ((tll = transport_loop_location()) == 0) {
4751 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4752 XMLNode &before = _session->locations()->get_state();
4753 _session->locations()->add (loc, true);
4754 _session->set_auto_loop_location (loc);
4755 XMLNode &after = _session->locations()->get_state();
4756 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4758 XMLNode &before = tll->get_state();
4759 tll->set_hidden (false, this);
4760 tll->set (start, end);
4761 XMLNode &after = tll->get_state();
4762 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4765 commit_reversible_command ();
4769 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4771 if (!_session) return;
4773 begin_reversible_command (cmd);
4777 if ((tpl = transport_punch_location()) == 0) {
4778 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4779 XMLNode &before = _session->locations()->get_state();
4780 _session->locations()->add (loc, true);
4781 _session->set_auto_punch_location (loc);
4782 XMLNode &after = _session->locations()->get_state();
4783 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4785 XMLNode &before = tpl->get_state();
4786 tpl->set_hidden (false, this);
4787 tpl->set (start, end);
4788 XMLNode &after = tpl->get_state();
4789 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4792 commit_reversible_command ();
4795 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4796 * @param rs List to which found regions are added.
4797 * @param where Time to look at.
4798 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4801 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4803 const TrackViewList* tracks;
4806 tracks = &track_views;
4811 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4813 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4816 boost::shared_ptr<Track> tr;
4817 boost::shared_ptr<Playlist> pl;
4819 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4821 boost::shared_ptr<RegionList> regions = pl->regions_at (
4822 (framepos_t) floor ( (double) where * tr->speed()));
4824 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4825 RegionView* rv = rtv->view()->find_view (*i);
4836 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4838 const TrackViewList* tracks;
4841 tracks = &track_views;
4846 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4847 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4849 boost::shared_ptr<Track> tr;
4850 boost::shared_ptr<Playlist> pl;
4852 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4854 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4855 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4857 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4859 RegionView* rv = rtv->view()->find_view (*i);
4870 /** Get regions using the following method:
4872 * Make a region list using:
4873 * (a) any selected regions
4874 * (b) the intersection of any selected tracks and the edit point(*)
4875 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4877 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4879 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4883 Editor::get_regions_from_selection_and_edit_point ()
4885 RegionSelection regions;
4887 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4888 regions.add (entered_regionview);
4890 regions = selection->regions;
4893 if ( regions.empty() ) {
4894 TrackViewList tracks = selection->tracks;
4896 if (!tracks.empty()) {
4897 /* no region selected or entered, but some selected tracks:
4898 * act on all regions on the selected tracks at the edit point
4900 framepos_t const where = get_preferred_edit_position ();
4901 get_regions_at(regions, where, tracks);
4908 /** Get regions using the following method:
4910 * Make a region list using:
4911 * (a) any selected regions
4912 * (b) the intersection of any selected tracks and the edit point(*)
4913 * (c) if neither exists, then whatever region is under the mouse
4915 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4917 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4920 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4922 RegionSelection regions;
4924 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4925 regions.add (entered_regionview);
4927 regions = selection->regions;
4930 if ( regions.empty() ) {
4931 TrackViewList tracks = selection->tracks;
4933 if (!tracks.empty()) {
4934 /* no region selected or entered, but some selected tracks:
4935 * act on all regions on the selected tracks at the edit point
4937 get_regions_at(regions, pos, tracks);
4944 /** Start with regions that are selected, or the entered regionview if none are selected.
4945 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4946 * of the regions that we started with.
4950 Editor::get_regions_from_selection_and_entered () const
4952 RegionSelection regions = selection->regions;
4954 if (regions.empty() && entered_regionview) {
4955 regions.add (entered_regionview);
4962 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4964 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4965 RouteTimeAxisView* rtav;
4967 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4968 boost::shared_ptr<Playlist> pl;
4969 std::vector<boost::shared_ptr<Region> > results;
4970 boost::shared_ptr<Track> tr;
4972 if ((tr = rtav->track()) == 0) {
4977 if ((pl = (tr->playlist())) != 0) {
4978 boost::shared_ptr<Region> r = pl->region_by_id (id);
4980 RegionView* rv = rtav->view()->find_view (r);
4982 regions.push_back (rv);
4991 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4994 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4995 MidiTimeAxisView* mtav;
4997 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4999 mtav->get_per_region_note_selection (selection);
5006 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5008 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5010 RouteTimeAxisView* tatv;
5012 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5014 boost::shared_ptr<Playlist> pl;
5015 vector<boost::shared_ptr<Region> > results;
5017 boost::shared_ptr<Track> tr;
5019 if ((tr = tatv->track()) == 0) {
5024 if ((pl = (tr->playlist())) != 0) {
5025 if (src_comparison) {
5026 pl->get_source_equivalent_regions (region, results);
5028 pl->get_region_list_equivalent_regions (region, results);
5032 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5033 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5034 regions.push_back (marv);
5043 Editor::show_rhythm_ferret ()
5045 if (rhythm_ferret == 0) {
5046 rhythm_ferret = new RhythmFerret(*this);
5049 rhythm_ferret->set_session (_session);
5050 rhythm_ferret->show ();
5051 rhythm_ferret->present ();
5055 Editor::first_idle ()
5057 MessageDialog* dialog = 0;
5059 if (track_views.size() > 1) {
5060 Timers::TimerSuspender t;
5061 dialog = new MessageDialog (
5062 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5066 ARDOUR_UI::instance()->flush_pending (60);
5069 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5073 // first idle adds route children (automation tracks), so we need to redisplay here
5074 _routes->redisplay ();
5078 if (_session->undo_depth() == 0) {
5079 undo_action->set_sensitive(false);
5081 redo_action->set_sensitive(false);
5082 begin_selection_op_history ();
5088 Editor::_idle_resize (gpointer arg)
5090 return ((Editor*)arg)->idle_resize ();
5094 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5096 if (resize_idle_id < 0) {
5097 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5098 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5099 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5101 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5102 _pending_resize_amount = 0;
5105 /* make a note of the smallest resulting height, so that we can clamp the
5106 lower limit at TimeAxisView::hSmall */
5108 int32_t min_resulting = INT32_MAX;
5110 _pending_resize_amount += h;
5111 _pending_resize_view = view;
5113 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5115 if (selection->tracks.contains (_pending_resize_view)) {
5116 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5117 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5121 if (min_resulting < 0) {
5126 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5127 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5131 /** Handle pending resizing of tracks */
5133 Editor::idle_resize ()
5135 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5137 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5138 selection->tracks.contains (_pending_resize_view)) {
5140 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5141 if (*i != _pending_resize_view) {
5142 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5147 _pending_resize_amount = 0;
5148 _group_tabs->set_dirty ();
5149 resize_idle_id = -1;
5157 ENSURE_GUI_THREAD (*this, &Editor::located);
5160 playhead_cursor->set_position (_session->audible_frame ());
5161 if (_follow_playhead && !_pending_initial_locate) {
5162 reset_x_origin_to_follow_playhead ();
5166 _pending_locate_request = false;
5167 _pending_initial_locate = false;
5171 Editor::region_view_added (RegionView * rv)
5173 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5174 if (rv->region ()->id () == (*pr)) {
5175 selection->add (rv);
5176 selection->regions.pending.erase (pr);
5181 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5183 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5184 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5185 if (rv->region()->id () == (*rnote).first) {
5186 mrv->select_notes ((*rnote).second);
5187 selection->pending_midi_note_selection.erase(rnote);
5193 _summary->set_background_dirty ();
5197 Editor::region_view_removed ()
5199 _summary->set_background_dirty ();
5203 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5205 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5206 if ((*j)->stripable() == s) {
5216 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5220 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5221 TimeAxisView* tv = axis_view_from_stripable (*i);
5231 Editor::suspend_route_redisplay ()
5234 _routes->suspend_redisplay();
5239 Editor::resume_route_redisplay ()
5242 _routes->redisplay(); // queue redisplay
5243 _routes->resume_redisplay();
5248 Editor::add_vcas (VCAList& vlist)
5252 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5253 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5256 add_stripables (sl);
5260 Editor::add_routes (RouteList& rlist)
5264 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5268 add_stripables (sl);
5272 Editor::add_stripables (StripableList& sl)
5274 list<TimeAxisView*> new_views;
5275 boost::shared_ptr<VCA> v;
5276 boost::shared_ptr<Route> r;
5277 TrackViewList new_selection;
5278 bool from_scratch = (track_views.size() == 0);
5280 sl.sort (StripablePresentationInfoSorter());
5282 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5284 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5286 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5288 new_views.push_back (vtv);
5290 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5292 if (r->is_auditioner() || r->is_monitor()) {
5296 RouteTimeAxisView* rtv;
5297 DataType dt = r->input()->default_type();
5299 if (dt == ARDOUR::DataType::AUDIO) {
5300 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5302 } else if (dt == ARDOUR::DataType::MIDI) {
5303 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5306 throw unknown_type();
5309 new_views.push_back (rtv);
5310 track_views.push_back (rtv);
5311 new_selection.push_back (rtv);
5313 rtv->effective_gain_display ();
5315 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5316 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5320 if (new_views.size() > 0) {
5321 _routes->time_axis_views_added (new_views);
5322 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5325 /* note: !new_selection.empty() means that we got some routes rather
5329 if (!from_scratch && !new_selection.empty()) {
5330 selection->tracks.clear();
5331 selection->add (new_selection);
5332 begin_selection_op_history();
5335 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5336 show_editor_mixer (true);
5339 editor_list_button.set_sensitive (true);
5343 Editor::timeaxisview_deleted (TimeAxisView *tv)
5345 if (tv == entered_track) {
5349 if (_session && _session->deletion_in_progress()) {
5350 /* the situation is under control */
5354 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5356 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5358 _routes->route_removed (tv);
5360 TimeAxisView::Children c = tv->get_child_list ();
5361 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5362 if (entered_track == i->get()) {
5367 /* remove it from the list of track views */
5369 TrackViewList::iterator i;
5371 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5372 i = track_views.erase (i);
5375 /* update whatever the current mixer strip is displaying, if revelant */
5377 boost::shared_ptr<Route> route;
5380 route = rtav->route ();
5383 if (current_mixer_strip && current_mixer_strip->route() == route) {
5385 TimeAxisView* next_tv;
5387 if (track_views.empty()) {
5389 } else if (i == track_views.end()) {
5390 next_tv = track_views.front();
5397 set_selected_mixer_strip (*next_tv);
5399 /* make the editor mixer strip go away setting the
5400 * button to inactive (which also unticks the menu option)
5403 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5409 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5411 if (apply_to_selection) {
5412 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5414 TrackSelection::iterator j = i;
5417 hide_track_in_display (*i, false);
5422 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5424 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5425 // this will hide the mixer strip
5426 set_selected_mixer_strip (*tv);
5429 _routes->hide_track_in_display (*tv);
5434 Editor::sync_track_view_list_and_routes ()
5436 track_views = TrackViewList (_routes->views ());
5438 _summary->set_background_dirty();
5439 _group_tabs->set_dirty ();
5441 return false; // do not call again (until needed)
5445 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5447 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5452 /** Find a RouteTimeAxisView by the ID of its route */
5454 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5456 RouteTimeAxisView* v;
5458 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5459 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5460 if(v->route()->id() == id) {
5470 Editor::fit_route_group (RouteGroup *g)
5472 TrackViewList ts = axis_views_from_routes (g->route_list ());
5477 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5479 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5482 _session->cancel_audition ();
5486 if (_session->is_auditioning()) {
5487 _session->cancel_audition ();
5488 if (r == last_audition_region) {
5493 _session->audition_region (r);
5494 last_audition_region = r;
5499 Editor::hide_a_region (boost::shared_ptr<Region> r)
5501 r->set_hidden (true);
5505 Editor::show_a_region (boost::shared_ptr<Region> r)
5507 r->set_hidden (false);
5511 Editor::audition_region_from_region_list ()
5513 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5517 Editor::hide_region_from_region_list ()
5519 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5523 Editor::show_region_in_region_list ()
5525 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5529 Editor::step_edit_status_change (bool yn)
5532 start_step_editing ();
5534 stop_step_editing ();
5539 Editor::start_step_editing ()
5541 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5545 Editor::stop_step_editing ()
5547 step_edit_connection.disconnect ();
5551 Editor::check_step_edit ()
5553 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5554 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5556 mtv->check_step_edit ();
5560 return true; // do it again, till we stop
5564 Editor::scroll_press (Direction dir)
5566 ++_scroll_callbacks;
5568 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5569 /* delay the first auto-repeat */
5575 scroll_backward (1);
5583 scroll_up_one_track ();
5587 scroll_down_one_track ();
5591 /* do hacky auto-repeat */
5592 if (!_scroll_connection.connected ()) {
5594 _scroll_connection = Glib::signal_timeout().connect (
5595 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5598 _scroll_callbacks = 0;
5605 Editor::scroll_release ()
5607 _scroll_connection.disconnect ();
5610 /** Queue a change for the Editor viewport x origin to follow the playhead */
5612 Editor::reset_x_origin_to_follow_playhead ()
5614 framepos_t const frame = playhead_cursor->current_frame ();
5616 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5618 if (_session->transport_speed() < 0) {
5620 if (frame > (current_page_samples() / 2)) {
5621 center_screen (frame-(current_page_samples()/2));
5623 center_screen (current_page_samples()/2);
5630 if (frame < leftmost_frame) {
5632 if (_session->transport_rolling()) {
5633 /* rolling; end up with the playhead at the right of the page */
5634 l = frame - current_page_samples ();
5636 /* not rolling: end up with the playhead 1/4 of the way along the page */
5637 l = frame - current_page_samples() / 4;
5641 if (_session->transport_rolling()) {
5642 /* rolling: end up with the playhead on the left of the page */
5645 /* not rolling: end up with the playhead 3/4 of the way along the page */
5646 l = frame - 3 * current_page_samples() / 4;
5654 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5660 Editor::super_rapid_screen_update ()
5662 if (!_session || !_session->engine().running()) {
5666 /* METERING / MIXER STRIPS */
5668 /* update track meters, if required */
5669 if (contents().is_mapped() && meters_running) {
5670 RouteTimeAxisView* rtv;
5671 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5672 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5673 rtv->fast_update ();
5678 /* and any current mixer strip */
5679 if (current_mixer_strip) {
5680 current_mixer_strip->fast_update ();
5683 /* PLAYHEAD AND VIEWPORT */
5685 framepos_t const frame = _session->audible_frame();
5687 /* There are a few reasons why we might not update the playhead / viewport stuff:
5689 * 1. we don't update things when there's a pending locate request, otherwise
5690 * when the editor requests a locate there is a chance that this method
5691 * will move the playhead before the locate request is processed, causing
5693 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5694 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5697 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5699 last_update_frame = frame;
5701 if (!_dragging_playhead) {
5702 playhead_cursor->set_position (frame);
5705 if (!_stationary_playhead) {
5707 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5708 /* We only do this if we aren't already
5709 handling a visual change (ie if
5710 pending_visual_change.being_handled is
5711 false) so that these requests don't stack
5712 up there are too many of them to handle in
5715 reset_x_origin_to_follow_playhead ();
5720 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5721 framepos_t const frame = playhead_cursor->current_frame ();
5722 double target = ((double)frame - (double)current_page_samples()/2.0);
5723 if (target <= 0.0) {
5726 // compare to EditorCursor::set_position()
5727 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5728 double const new_pos = sample_to_pixel_unrounded (target);
5729 if (rint (new_pos) != rint (old_pos)) {
5730 reset_x_origin (pixel_to_sample (floor (new_pos)));
5741 Editor::session_going_away ()
5743 _have_idled = false;
5745 _session_connections.drop_connections ();
5747 super_rapid_screen_update_connection.disconnect ();
5749 selection->clear ();
5750 cut_buffer->clear ();
5752 clicked_regionview = 0;
5753 clicked_axisview = 0;
5754 clicked_routeview = 0;
5755 entered_regionview = 0;
5757 last_update_frame = 0;
5760 playhead_cursor->hide ();
5762 /* rip everything out of the list displays */
5766 _route_groups->clear ();
5768 /* do this first so that deleting a track doesn't reset cms to null
5769 and thus cause a leak.
5772 if (current_mixer_strip) {
5773 if (current_mixer_strip->get_parent() != 0) {
5774 global_hpacker.remove (*current_mixer_strip);
5776 delete current_mixer_strip;
5777 current_mixer_strip = 0;
5780 /* delete all trackviews */
5782 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5785 track_views.clear ();
5787 nudge_clock->set_session (0);
5789 editor_list_button.set_active(false);
5790 editor_list_button.set_sensitive(false);
5792 /* clear tempo/meter rulers */
5793 remove_metric_marks ();
5795 clear_marker_display ();
5797 stop_step_editing ();
5801 /* get rid of any existing editor mixer strip */
5803 WindowTitle title(Glib::get_application_name());
5804 title += _("Editor");
5806 own_window()->set_title (title.get_string());
5809 SessionHandlePtr::session_going_away ();
5813 Editor::trigger_script (int i)
5815 LuaInstance::instance()-> call_action (i);
5819 Editor::set_script_action_name (int i, const std::string& n)
5821 string const a = string_compose (X_("script-action-%1"), i + 1);
5822 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5825 act->set_label (string_compose (_("Unset #%1"), i + 1));
5826 act->set_tooltip (_("no action bound"));
5827 act->set_sensitive (false);
5830 act->set_tooltip (n);
5831 act->set_sensitive (true);
5833 KeyEditor::UpdateBindings ();
5837 Editor::show_editor_list (bool yn)
5840 _the_notebook.show ();
5842 _the_notebook.hide ();
5847 Editor::change_region_layering_order (bool from_context_menu)
5849 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5851 if (!clicked_routeview) {
5852 if (layering_order_editor) {
5853 layering_order_editor->hide ();
5858 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5864 boost::shared_ptr<Playlist> pl = track->playlist();
5870 if (layering_order_editor == 0) {
5871 layering_order_editor = new RegionLayeringOrderEditor (*this);
5874 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5875 layering_order_editor->maybe_present ();
5879 Editor::update_region_layering_order_editor ()
5881 if (layering_order_editor && layering_order_editor->is_visible ()) {
5882 change_region_layering_order (true);
5887 Editor::setup_fade_images ()
5889 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5890 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5891 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5892 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5893 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5895 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5896 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5897 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5898 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5899 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5901 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5902 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5903 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5904 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5905 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5907 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5908 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5909 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5910 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5911 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5915 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5917 Editor::action_menu_item (std::string const & name)
5919 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5922 return *manage (a->create_menu_item ());
5926 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5928 EventBox* b = manage (new EventBox);
5929 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5930 Label* l = manage (new Label (name));
5934 _the_notebook.append_page (widget, *b);
5938 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5940 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5941 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5944 if (ev->type == GDK_2BUTTON_PRESS) {
5946 /* double-click on a notebook tab shrinks or expands the notebook */
5948 if (_notebook_shrunk) {
5949 if (pre_notebook_shrink_pane_width) {
5950 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5952 _notebook_shrunk = false;
5954 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5956 /* this expands the LHS of the edit pane to cover the notebook
5957 PAGE but leaves the tabs visible.
5959 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5960 _notebook_shrunk = true;
5968 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5970 using namespace Menu_Helpers;
5972 MenuList& items = _control_point_context_menu.items ();
5975 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5976 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5977 if (!can_remove_control_point (item)) {
5978 items.back().set_sensitive (false);
5981 _control_point_context_menu.popup (event->button.button, event->button.time);
5985 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5987 using namespace Menu_Helpers;
5989 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5994 /* We need to get the selection here and pass it to the operations, since
5995 popping up the menu will cause a region leave event which clears
5996 entered_regionview. */
5998 MidiRegionView& mrv = note->region_view();
5999 const RegionSelection rs = get_regions_from_selection_and_entered ();
6000 const uint32_t sel_size = mrv.selection_size ();
6002 MenuList& items = _note_context_menu.items();
6006 items.push_back(MenuElem(_("Delete"),
6007 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6010 items.push_back(MenuElem(_("Edit..."),
6011 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6012 if (sel_size != 1) {
6013 items.back().set_sensitive (false);
6016 items.push_back(MenuElem(_("Transpose..."),
6017 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6020 items.push_back(MenuElem(_("Legatize"),
6021 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6023 items.back().set_sensitive (false);
6026 items.push_back(MenuElem(_("Quantize..."),
6027 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6029 items.push_back(MenuElem(_("Remove Overlap"),
6030 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6032 items.back().set_sensitive (false);
6035 items.push_back(MenuElem(_("Transform..."),
6036 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6038 _note_context_menu.popup (event->button.button, event->button.time);
6042 Editor::zoom_vertical_modifier_released()
6044 _stepping_axis_view = 0;
6048 Editor::ui_parameter_changed (string parameter)
6050 if (parameter == "icon-set") {
6051 while (!_cursor_stack.empty()) {
6052 _cursor_stack.pop_back();
6054 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6055 _cursor_stack.push_back(_cursors->grabber);
6056 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6057 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6059 } else if (parameter == "draggable-playhead") {
6060 if (_verbose_cursor) {
6061 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6067 Editor::use_own_window (bool and_fill_it)
6069 bool new_window = !own_window();
6071 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6073 if (win && new_window) {
6074 win->set_name ("EditorWindow");
6076 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6078 // win->signal_realize().connect (*this, &Editor::on_realize);
6079 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6080 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6081 win->set_data ("ardour-bindings", bindings);
6086 DisplaySuspender ds;
6087 contents().show_all ();
6089 /* XXX: this is a bit unfortunate; it would probably
6090 be nicer if we could just call show () above rather
6091 than needing the show_all ()
6094 /* re-hide stuff if necessary */
6095 editor_list_button_toggled ();
6096 parameter_changed ("show-summary");
6097 parameter_changed ("show-group-tabs");
6098 parameter_changed ("show-zoom-tools");
6100 /* now reset all audio_time_axis heights, because widgets might need
6106 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6107 tv = (static_cast<TimeAxisView*>(*i));
6108 tv->reset_height ();
6111 if (current_mixer_strip) {
6112 current_mixer_strip->hide_things ();
6113 current_mixer_strip->parameter_changed ("mixer-element-visibility");