2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
86 #include "control_protocol/control_protocol.h"
89 #include "analysis_window.h"
90 #include "ardour_spacer.h"
91 #include "audio_clock.h"
92 #include "audio_region_view.h"
93 #include "audio_streamview.h"
94 #include "audio_time_axis.h"
95 #include "automation_time_axis.h"
96 #include "bundle_manager.h"
97 #include "crossfade_edit.h"
101 #include "editor_cursors.h"
102 #include "editor_drag.h"
103 #include "editor_group_tabs.h"
104 #include "editor_locations.h"
105 #include "editor_regions.h"
106 #include "editor_route_groups.h"
107 #include "editor_routes.h"
108 #include "editor_snapshots.h"
109 #include "editor_summary.h"
110 #include "export_report.h"
111 #include "global_port_matrix.h"
112 #include "gui_object.h"
113 #include "gui_thread.h"
114 #include "keyboard.h"
115 #include "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 , selection (new Selection (this))
390 , cut_buffer (new Selection (this))
391 , _selection_memento (new SelectionMemento())
392 , _all_region_actions_sensitized (false)
393 , _ignore_region_action (false)
394 , _last_region_menu_was_main (false)
395 , _track_selection_change_without_scroll (false)
396 , cd_marker_bar_drag_rect (0)
397 , range_bar_drag_rect (0)
398 , transport_bar_drag_rect (0)
399 , transport_bar_range_rect (0)
400 , transport_bar_preroll_rect (0)
401 , transport_bar_postroll_rect (0)
402 , transport_loop_range_rect (0)
403 , transport_punch_range_rect (0)
404 , transport_punchin_line (0)
405 , transport_punchout_line (0)
406 , transport_preroll_rect (0)
407 , transport_postroll_rect (0)
409 , rubberband_rect (0)
415 , autoscroll_horizontal_allowed (false)
416 , autoscroll_vertical_allowed (false)
418 , autoscroll_widget (0)
419 , show_gain_after_trim (false)
420 , selection_op_cmd_depth (0)
421 , selection_op_history_it (0)
422 , no_save_instant (false)
424 , current_mixer_strip (0)
425 , show_editor_mixer_when_tracks_arrive (false)
426 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
427 , current_stepping_trackview (0)
428 , last_track_height_step_timestamp (0)
430 , entered_regionview (0)
431 , clear_entered_track (false)
432 , _edit_point (EditAtMouse)
433 , meters_running (false)
435 , _have_idled (false)
436 , resize_idle_id (-1)
437 , _pending_resize_amount (0)
438 , _pending_resize_view (0)
439 , _pending_locate_request (false)
440 , _pending_initial_locate (false)
444 , layering_order_editor (0)
445 , _last_cut_copy_source_track (0)
446 , _region_selection_change_updates_region_list (true)
448 , _following_mixer_selection (false)
449 , _control_point_toggled_on_press (false)
450 , _stepping_axis_view (0)
451 , quantize_dialog (0)
452 , _main_menu_disabler (0)
453 , myactions (X_("editor"))
455 /* we are a singleton */
457 PublicEditor::_instance = this;
461 last_event_time.tv_sec = 0;
462 last_event_time.tv_usec = 0;
464 selection_op_history.clear();
467 snap_type_strings = I18N (_snap_type_strings);
468 snap_mode_strings = I18N (_snap_mode_strings);
469 zoom_focus_strings = I18N (_zoom_focus_strings);
470 edit_mode_strings = I18N (_edit_mode_strings);
471 edit_point_strings = I18N (_edit_point_strings);
472 #ifdef USE_RUBBERBAND
473 rb_opt_strings = I18N (_rb_opt_strings);
477 build_edit_mode_menu();
478 build_zoom_focus_menu();
479 build_track_count_menu();
480 build_snap_mode_menu();
481 build_snap_type_menu();
482 build_edit_point_menu();
484 location_marker_color = UIConfiguration::instance().color ("location marker");
485 location_range_color = UIConfiguration::instance().color ("location range");
486 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
487 location_loop_color = UIConfiguration::instance().color ("location loop");
488 location_punch_color = UIConfiguration::instance().color ("location punch");
490 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
492 TimeAxisView::setup_sizes ();
493 ArdourMarker::setup_sizes (timebar_height);
494 TempoCurve::setup_sizes (timebar_height);
496 bbt_label.set_name ("EditorRulerLabel");
497 bbt_label.set_size_request (-1, (int)timebar_height);
498 bbt_label.set_alignment (1.0, 0.5);
499 bbt_label.set_padding (5,0);
501 bbt_label.set_no_show_all();
502 minsec_label.set_name ("EditorRulerLabel");
503 minsec_label.set_size_request (-1, (int)timebar_height);
504 minsec_label.set_alignment (1.0, 0.5);
505 minsec_label.set_padding (5,0);
506 minsec_label.hide ();
507 minsec_label.set_no_show_all();
508 timecode_label.set_name ("EditorRulerLabel");
509 timecode_label.set_size_request (-1, (int)timebar_height);
510 timecode_label.set_alignment (1.0, 0.5);
511 timecode_label.set_padding (5,0);
512 timecode_label.hide ();
513 timecode_label.set_no_show_all();
514 samples_label.set_name ("EditorRulerLabel");
515 samples_label.set_size_request (-1, (int)timebar_height);
516 samples_label.set_alignment (1.0, 0.5);
517 samples_label.set_padding (5,0);
518 samples_label.hide ();
519 samples_label.set_no_show_all();
521 tempo_label.set_name ("EditorRulerLabel");
522 tempo_label.set_size_request (-1, (int)timebar_height);
523 tempo_label.set_alignment (1.0, 0.5);
524 tempo_label.set_padding (5,0);
526 tempo_label.set_no_show_all();
528 meter_label.set_name ("EditorRulerLabel");
529 meter_label.set_size_request (-1, (int)timebar_height);
530 meter_label.set_alignment (1.0, 0.5);
531 meter_label.set_padding (5,0);
533 meter_label.set_no_show_all();
535 if (Profile->get_trx()) {
536 mark_label.set_text (_("Markers"));
538 mark_label.set_name ("EditorRulerLabel");
539 mark_label.set_size_request (-1, (int)timebar_height);
540 mark_label.set_alignment (1.0, 0.5);
541 mark_label.set_padding (5,0);
543 mark_label.set_no_show_all();
545 cd_mark_label.set_name ("EditorRulerLabel");
546 cd_mark_label.set_size_request (-1, (int)timebar_height);
547 cd_mark_label.set_alignment (1.0, 0.5);
548 cd_mark_label.set_padding (5,0);
549 cd_mark_label.hide();
550 cd_mark_label.set_no_show_all();
552 videotl_bar_height = 4;
553 videotl_label.set_name ("EditorRulerLabel");
554 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
555 videotl_label.set_alignment (1.0, 0.5);
556 videotl_label.set_padding (5,0);
557 videotl_label.hide();
558 videotl_label.set_no_show_all();
560 range_mark_label.set_name ("EditorRulerLabel");
561 range_mark_label.set_size_request (-1, (int)timebar_height);
562 range_mark_label.set_alignment (1.0, 0.5);
563 range_mark_label.set_padding (5,0);
564 range_mark_label.hide();
565 range_mark_label.set_no_show_all();
567 transport_mark_label.set_name ("EditorRulerLabel");
568 transport_mark_label.set_size_request (-1, (int)timebar_height);
569 transport_mark_label.set_alignment (1.0, 0.5);
570 transport_mark_label.set_padding (5,0);
571 transport_mark_label.hide();
572 transport_mark_label.set_no_show_all();
574 initialize_canvas ();
576 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
578 _summary = new EditorSummary (this);
580 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
582 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
584 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
585 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
587 edit_controls_vbox.set_spacing (0);
588 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
589 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
591 HBox* h = manage (new HBox);
592 _group_tabs = new EditorGroupTabs (this);
593 if (!ARDOUR::Profile->get_trx()) {
594 h->pack_start (*_group_tabs, PACK_SHRINK);
596 h->pack_start (edit_controls_vbox);
597 controls_layout.add (*h);
599 controls_layout.set_name ("EditControlsBase");
600 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
601 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
602 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
604 _cursors = new MouseCursors;
605 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
606 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
608 /* Push default cursor to ever-present bottom of cursor stack. */
609 push_canvas_cursor(_cursors->grabber);
611 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
613 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
614 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
615 pad_line_1->set_outline_color (0xFF0000FF);
621 edit_packer.set_col_spacings (0);
622 edit_packer.set_row_spacings (0);
623 edit_packer.set_homogeneous (false);
624 edit_packer.set_border_width (0);
625 edit_packer.set_name ("EditorWindow");
627 time_bars_event_box.add (time_bars_vbox);
628 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
629 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
631 /* labels for the time bars */
632 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
634 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
636 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
638 bottom_hbox.set_border_width (2);
639 bottom_hbox.set_spacing (3);
641 _route_groups = new EditorRouteGroups (this);
642 _routes = new EditorRoutes (this);
643 _regions = new EditorRegions (this);
644 _snapshots = new EditorSnapshots (this);
645 _locations = new EditorLocations (this);
646 _time_info_box = new TimeInfoBox (true);
648 /* these are static location signals */
650 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
651 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
654 add_notebook_page (_("Regions"), _regions->widget ());
655 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
656 add_notebook_page (_("Snapshots"), _snapshots->widget ());
657 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
658 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
660 _the_notebook.set_show_tabs (true);
661 _the_notebook.set_scrollable (true);
662 _the_notebook.popup_disable ();
663 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
664 _the_notebook.show_all ();
666 _notebook_shrunk = false;
669 /* Pick up some settings we need to cache, early */
671 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
674 if (settings && (prop = settings->property ("notebook-shrunk"))) {
675 _notebook_shrunk = string_is_affirmative (prop->value ());
678 editor_summary_pane.set_check_divider_position (true);
679 editor_summary_pane.add (edit_packer);
681 Button* summary_arrows_left_left = manage (new Button);
682 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
683 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
684 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
686 Button* summary_arrows_left_right = manage (new Button);
687 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
688 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
689 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 VBox* summary_arrows_left = manage (new VBox);
692 summary_arrows_left->pack_start (*summary_arrows_left_left);
693 summary_arrows_left->pack_start (*summary_arrows_left_right);
695 Button* summary_arrows_right_up = manage (new Button);
696 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
697 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
698 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 Button* summary_arrows_right_down = manage (new Button);
701 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
702 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
703 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 VBox* summary_arrows_right = manage (new VBox);
706 summary_arrows_right->pack_start (*summary_arrows_right_up);
707 summary_arrows_right->pack_start (*summary_arrows_right_down);
709 Frame* summary_frame = manage (new Frame);
710 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
712 summary_frame->add (*_summary);
713 summary_frame->show ();
715 _summary_hbox.pack_start (*summary_arrows_left, false, false);
716 _summary_hbox.pack_start (*summary_frame, true, true);
717 _summary_hbox.pack_start (*summary_arrows_right, false, false);
719 if (!ARDOUR::Profile->get_trx()) {
720 editor_summary_pane.add (_summary_hbox);
723 edit_pane.set_check_divider_position (true);
724 edit_pane.add (editor_summary_pane);
725 if (!ARDOUR::Profile->get_trx()) {
726 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
727 _editor_list_vbox.pack_start (_the_notebook);
728 edit_pane.add (_editor_list_vbox);
729 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
732 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
733 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
740 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
741 /* initial allocation is 90% to canvas, 10% to notebook */
742 edit_pane.set_divider (0, 0.90);
744 edit_pane.set_divider (0, fract);
747 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
748 /* initial allocation is 90% to canvas, 10% to summary */
749 editor_summary_pane.set_divider (0, 0.90);
752 editor_summary_pane.set_divider (0, fract);
756 global_vpacker.set_spacing (2);
757 global_vpacker.set_border_width (0);
759 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
761 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
762 ebox->set_name("EditorWindow");
763 ebox->add (toolbar_hbox);
765 Gtk::EventBox* epane_box = manage (new Gtk::EventBox); //a themeable box
766 epane_box->set_name("EditorWindow");
767 epane_box->add (edit_pane);
769 Gtk::EventBox* epane_box2 = manage (new Gtk::EventBox); //a themeable box
770 epane_box2->set_name("EditorWindow");
771 epane_box2->add (global_vpacker);
773 global_vpacker.pack_start (*ebox, false, false);
774 global_vpacker.pack_start (*epane_box, true, true);
775 global_hpacker.pack_start (*epane_box2, true, true);
777 /* need to show the "contents" widget so that notebook will show if tab is switched to
780 global_hpacker.show ();
782 /* register actions now so that set_state() can find them and set toggles/checks etc */
789 _playlist_selector = new PlaylistSelector();
790 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
792 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
796 nudge_forward_button.set_name ("nudge button");
797 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
799 nudge_backward_button.set_name ("nudge button");
800 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
802 fade_context_menu.set_name ("ArdourContextMenu");
804 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
806 /* allow external control surfaces/protocols to do various things */
808 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
809 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
810 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
811 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
812 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
813 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
814 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
815 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
816 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
817 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
818 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
819 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
820 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
821 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
823 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
824 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
825 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
826 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
827 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
829 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
833 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
835 /* problematic: has to return a value and thus cannot be x-thread */
837 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
839 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
840 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
842 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
844 _ignore_region_action = false;
845 _last_region_menu_was_main = false;
846 _popup_region_menu_item = 0;
848 _show_marker_lines = false;
850 /* Button bindings */
852 button_bindings = new Bindings ("editor-mouse");
854 XMLNode* node = button_settings();
856 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
857 button_bindings->load_operation (**i);
863 /* grab current parameter state */
864 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
865 UIConfiguration::instance().map_parameters (pc);
867 setup_fade_images ();
874 delete button_bindings;
876 delete _route_groups;
877 delete _track_canvas_viewport;
880 delete _verbose_cursor;
881 delete quantize_dialog;
887 delete _playlist_selector;
888 delete _time_info_box;
893 LuaInstance::destroy_instance ();
895 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
898 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
901 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
907 Editor::button_settings () const
909 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
910 XMLNode* node = find_named_node (*settings, X_("Buttons"));
913 node = new XMLNode (X_("Buttons"));
920 Editor::get_smart_mode () const
922 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
926 Editor::catch_vanishing_regionview (RegionView *rv)
928 /* note: the selection will take care of the vanishing
929 audioregionview by itself.
932 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
936 if (clicked_regionview == rv) {
937 clicked_regionview = 0;
940 if (entered_regionview == rv) {
941 set_entered_regionview (0);
944 if (!_all_region_actions_sensitized) {
945 sensitize_all_region_actions (true);
950 Editor::set_entered_regionview (RegionView* rv)
952 if (rv == entered_regionview) {
956 if (entered_regionview) {
957 entered_regionview->exited ();
960 entered_regionview = rv;
962 if (entered_regionview != 0) {
963 entered_regionview->entered ();
966 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
967 /* This RegionView entry might have changed what region actions
968 are allowed, so sensitize them all in case a key is pressed.
970 sensitize_all_region_actions (true);
975 Editor::set_entered_track (TimeAxisView* tav)
978 entered_track->exited ();
984 entered_track->entered ();
989 Editor::instant_save ()
991 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
996 _session->add_instant_xml(get_state());
998 Config->add_instant_xml(get_state());
1003 Editor::control_vertical_zoom_in_all ()
1005 tav_zoom_smooth (false, true);
1009 Editor::control_vertical_zoom_out_all ()
1011 tav_zoom_smooth (true, true);
1015 Editor::control_vertical_zoom_in_selected ()
1017 tav_zoom_smooth (false, false);
1021 Editor::control_vertical_zoom_out_selected ()
1023 tav_zoom_smooth (true, false);
1027 Editor::control_view (uint32_t view)
1029 goto_visual_state (view);
1033 Editor::control_unselect ()
1035 selection->clear_tracks ();
1039 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1041 TimeAxisView* tav = axis_view_from_stripable (s);
1045 case Selection::Add:
1046 selection->add (tav);
1048 case Selection::Toggle:
1049 selection->toggle (tav);
1051 case Selection::Extend:
1053 case Selection::Set:
1054 selection->set (tav);
1058 selection->clear_tracks ();
1063 Editor::control_step_tracks_up ()
1065 scroll_tracks_up_line ();
1069 Editor::control_step_tracks_down ()
1071 scroll_tracks_down_line ();
1075 Editor::control_scroll (float fraction)
1077 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1083 double step = fraction * current_page_samples();
1086 _control_scroll_target is an optional<T>
1088 it acts like a pointer to an framepos_t, with
1089 a operator conversion to boolean to check
1090 that it has a value could possibly use
1091 playhead_cursor->current_frame to store the
1092 value and a boolean in the class to know
1093 when it's out of date
1096 if (!_control_scroll_target) {
1097 _control_scroll_target = _session->transport_frame();
1098 _dragging_playhead = true;
1101 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1102 *_control_scroll_target = 0;
1103 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1104 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1106 *_control_scroll_target += (framepos_t) trunc (step);
1109 /* move visuals, we'll catch up with it later */
1111 playhead_cursor->set_position (*_control_scroll_target);
1112 UpdateAllTransportClocks (*_control_scroll_target);
1114 if (*_control_scroll_target > (current_page_samples() / 2)) {
1115 /* try to center PH in window */
1116 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1122 Now we do a timeout to actually bring the session to the right place
1123 according to the playhead. This is to avoid reading disk buffers on every
1124 call to control_scroll, which is driven by ScrollTimeline and therefore
1125 probably by a control surface wheel which can generate lots of events.
1127 /* cancel the existing timeout */
1129 control_scroll_connection.disconnect ();
1131 /* add the next timeout */
1133 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1137 Editor::deferred_control_scroll (framepos_t /*target*/)
1139 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1140 // reset for next stream
1141 _control_scroll_target = boost::none;
1142 _dragging_playhead = false;
1147 Editor::access_action (std::string action_group, std::string action_item)
1153 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1156 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1164 Editor::on_realize ()
1168 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1169 start_lock_event_timing ();
1174 Editor::start_lock_event_timing ()
1176 /* check if we should lock the GUI every 30 seconds */
1178 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1182 Editor::generic_event_handler (GdkEvent* ev)
1185 case GDK_BUTTON_PRESS:
1186 case GDK_BUTTON_RELEASE:
1187 case GDK_MOTION_NOTIFY:
1189 case GDK_KEY_RELEASE:
1190 if (contents().is_mapped()) {
1191 gettimeofday (&last_event_time, 0);
1195 case GDK_LEAVE_NOTIFY:
1196 switch (ev->crossing.detail) {
1197 case GDK_NOTIFY_UNKNOWN:
1198 case GDK_NOTIFY_INFERIOR:
1199 case GDK_NOTIFY_ANCESTOR:
1201 case GDK_NOTIFY_VIRTUAL:
1202 case GDK_NOTIFY_NONLINEAR:
1203 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1204 /* leaving window, so reset focus, thus ending any and
1205 all text entry operations.
1207 ARDOUR_UI::instance()->reset_focus (&contents());
1220 Editor::lock_timeout_callback ()
1222 struct timeval now, delta;
1224 gettimeofday (&now, 0);
1226 timersub (&now, &last_event_time, &delta);
1228 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1230 /* don't call again. Returning false will effectively
1231 disconnect us from the timer callback.
1233 unlock() will call start_lock_event_timing() to get things
1243 Editor::map_position_change (framepos_t frame)
1245 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1247 if (_session == 0) {
1251 if (_follow_playhead) {
1252 center_screen (frame);
1255 playhead_cursor->set_position (frame);
1259 Editor::center_screen (framepos_t frame)
1261 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1263 /* if we're off the page, then scroll.
1266 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1267 center_screen_internal (frame, page);
1272 Editor::center_screen_internal (framepos_t frame, float page)
1277 frame -= (framepos_t) page;
1282 reset_x_origin (frame);
1287 Editor::update_title ()
1289 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1291 if (!own_window()) {
1296 bool dirty = _session->dirty();
1298 string session_name;
1300 if (_session->snap_name() != _session->name()) {
1301 session_name = _session->snap_name();
1303 session_name = _session->name();
1307 session_name = "*" + session_name;
1310 WindowTitle title(session_name);
1311 title += S_("Window|Editor");
1312 title += Glib::get_application_name();
1313 own_window()->set_title (title.get_string());
1315 /* ::session_going_away() will have taken care of it */
1320 Editor::set_session (Session *t)
1322 SessionHandlePtr::set_session (t);
1328 _playlist_selector->set_session (_session);
1329 nudge_clock->set_session (_session);
1330 _summary->set_session (_session);
1331 _group_tabs->set_session (_session);
1332 _route_groups->set_session (_session);
1333 _regions->set_session (_session);
1334 _snapshots->set_session (_session);
1335 _routes->set_session (_session);
1336 _locations->set_session (_session);
1337 _time_info_box->set_session (_session);
1339 if (rhythm_ferret) {
1340 rhythm_ferret->set_session (_session);
1343 if (analysis_window) {
1344 analysis_window->set_session (_session);
1348 sfbrowser->set_session (_session);
1351 compute_fixed_ruler_scale ();
1353 /* Make sure we have auto loop and auto punch ranges */
1355 Location* loc = _session->locations()->auto_loop_location();
1357 loc->set_name (_("Loop"));
1360 loc = _session->locations()->auto_punch_location();
1363 loc->set_name (_("Punch"));
1366 refresh_location_display ();
1368 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1369 the selected Marker; this needs the LocationMarker list to be available.
1371 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1372 set_state (*node, Stateful::loading_state_version);
1374 /* catch up with the playhead */
1376 _session->request_locate (playhead_cursor->current_frame ());
1377 _pending_initial_locate = true;
1381 /* These signals can all be emitted by a non-GUI thread. Therefore the
1382 handlers for them must not attempt to directly interact with the GUI,
1383 but use PBD::Signal<T>::connect() which accepts an event loop
1384 ("context") where the handler will be asked to run.
1387 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1388 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1389 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1390 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1391 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1392 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1393 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1394 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1395 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1396 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1397 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1398 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1399 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1400 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1401 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1403 playhead_cursor->show ();
1405 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1406 Config->map_parameters (pc);
1407 _session->config.map_parameters (pc);
1409 restore_ruler_visibility ();
1410 //tempo_map_changed (PropertyChange (0));
1411 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1413 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1414 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1417 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1418 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1421 switch (_snap_type) {
1422 case SnapToRegionStart:
1423 case SnapToRegionEnd:
1424 case SnapToRegionSync:
1425 case SnapToRegionBoundary:
1426 build_region_boundary_cache ();
1433 /* catch up on selection of stripables (other selection state is lost
1434 * when a session is closed
1439 _session->get_stripables (sl);
1440 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1441 if ((*s)->presentation_info().selected()) {
1442 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1444 tl.push_back (rtav);
1449 selection->set (tl);
1452 /* register for undo history */
1453 _session->register_with_memento_command_factory(id(), this);
1454 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1456 LuaInstance::instance()->set_session(_session);
1458 start_updating_meters ();
1462 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1464 using namespace Menu_Helpers;
1466 void (Editor::*emf)(FadeShape);
1467 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1470 images = &_xfade_in_images;
1471 emf = &Editor::set_fade_in_shape;
1473 images = &_xfade_out_images;
1474 emf = &Editor::set_fade_out_shape;
1479 _("Linear (for highly correlated material)"),
1480 *(*images)[FadeLinear],
1481 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1485 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1489 _("Constant power"),
1490 *(*images)[FadeConstantPower],
1491 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1494 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 *(*images)[FadeSymmetric],
1500 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1504 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1509 *(*images)[FadeSlow],
1510 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1513 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1518 *(*images)[FadeFast],
1519 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1522 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1525 /** Pop up a context menu for when the user clicks on a start crossfade */
1527 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1529 using namespace Menu_Helpers;
1530 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1535 MenuList& items (xfade_in_context_menu.items());
1538 if (arv->audio_region()->fade_in_active()) {
1539 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1541 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1544 items.push_back (SeparatorElem());
1545 fill_xfade_menu (items, true);
1547 xfade_in_context_menu.popup (button, time);
1550 /** Pop up a context menu for when the user clicks on an end crossfade */
1552 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1554 using namespace Menu_Helpers;
1555 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1560 MenuList& items (xfade_out_context_menu.items());
1563 if (arv->audio_region()->fade_out_active()) {
1564 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1566 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1569 items.push_back (SeparatorElem());
1570 fill_xfade_menu (items, false);
1572 xfade_out_context_menu.popup (button, time);
1576 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1578 using namespace Menu_Helpers;
1579 Menu* (Editor::*build_menu_function)();
1582 switch (item_type) {
1584 case RegionViewName:
1585 case RegionViewNameHighlight:
1586 case LeftFrameHandle:
1587 case RightFrameHandle:
1588 if (with_selection) {
1589 build_menu_function = &Editor::build_track_selection_context_menu;
1591 build_menu_function = &Editor::build_track_region_context_menu;
1596 if (with_selection) {
1597 build_menu_function = &Editor::build_track_selection_context_menu;
1599 build_menu_function = &Editor::build_track_context_menu;
1604 if (clicked_routeview->track()) {
1605 build_menu_function = &Editor::build_track_context_menu;
1607 build_menu_function = &Editor::build_track_bus_context_menu;
1612 /* probably shouldn't happen but if it does, we don't care */
1616 menu = (this->*build_menu_function)();
1617 menu->set_name ("ArdourContextMenu");
1619 /* now handle specific situations */
1621 switch (item_type) {
1623 case RegionViewName:
1624 case RegionViewNameHighlight:
1625 case LeftFrameHandle:
1626 case RightFrameHandle:
1627 if (!with_selection) {
1628 if (region_edit_menu_split_item) {
1629 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1630 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1632 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1635 if (region_edit_menu_split_multichannel_item) {
1636 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1637 region_edit_menu_split_multichannel_item->set_sensitive (true);
1639 region_edit_menu_split_multichannel_item->set_sensitive (false);
1652 /* probably shouldn't happen but if it does, we don't care */
1656 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1658 /* Bounce to disk */
1660 using namespace Menu_Helpers;
1661 MenuList& edit_items = menu->items();
1663 edit_items.push_back (SeparatorElem());
1665 switch (clicked_routeview->audio_track()->freeze_state()) {
1666 case AudioTrack::NoFreeze:
1667 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1670 case AudioTrack::Frozen:
1671 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1674 case AudioTrack::UnFrozen:
1675 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1681 if (item_type == StreamItem && clicked_routeview) {
1682 clicked_routeview->build_underlay_menu(menu);
1685 /* When the region menu is opened, we setup the actions so that they look right
1688 sensitize_the_right_region_actions (false);
1689 _last_region_menu_was_main = false;
1691 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1692 menu->popup (button, time);
1696 Editor::build_track_context_menu ()
1698 using namespace Menu_Helpers;
1700 MenuList& edit_items = track_context_menu.items();
1703 add_dstream_context_items (edit_items);
1704 return &track_context_menu;
1708 Editor::build_track_bus_context_menu ()
1710 using namespace Menu_Helpers;
1712 MenuList& edit_items = track_context_menu.items();
1715 add_bus_context_items (edit_items);
1716 return &track_context_menu;
1720 Editor::build_track_region_context_menu ()
1722 using namespace Menu_Helpers;
1723 MenuList& edit_items = track_region_context_menu.items();
1726 /* we've just cleared the track region context menu, so the menu that these
1727 two items were on will have disappeared; stop them dangling.
1729 region_edit_menu_split_item = 0;
1730 region_edit_menu_split_multichannel_item = 0;
1732 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1735 boost::shared_ptr<Track> tr;
1736 boost::shared_ptr<Playlist> pl;
1738 if ((tr = rtv->track())) {
1739 add_region_context_items (edit_items, tr);
1743 add_dstream_context_items (edit_items);
1745 return &track_region_context_menu;
1749 Editor::loudness_analyze_region_selection ()
1754 Selection& s (PublicEditor::instance ().get_selection ());
1755 RegionSelection ars = s.regions;
1756 ARDOUR::AnalysisGraph ag (_session);
1757 framecnt_t total_work = 0;
1759 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1760 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1764 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1767 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1768 total_work += arv->region ()->length ();
1771 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1773 ag.set_total_frames (total_work);
1774 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1777 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1778 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1782 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1786 ag.analyze_region (ar);
1789 if (!ag.canceled ()) {
1790 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1796 Editor::loudness_analyze_range_selection ()
1801 Selection& s (PublicEditor::instance ().get_selection ());
1802 TimeSelection ts = s.time;
1803 ARDOUR::AnalysisGraph ag (_session);
1804 framecnt_t total_work = 0;
1806 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1807 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1811 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1815 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1816 total_work += j->length ();
1820 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1822 ag.set_total_frames (total_work);
1823 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1826 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1827 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1831 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1835 ag.analyze_range (rui->route (), pl, ts);
1838 if (!ag.canceled ()) {
1839 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1845 Editor::spectral_analyze_region_selection ()
1847 if (analysis_window == 0) {
1848 analysis_window = new AnalysisWindow();
1851 analysis_window->set_session(_session);
1853 analysis_window->show_all();
1856 analysis_window->set_regionmode();
1857 analysis_window->analyze();
1859 analysis_window->present();
1863 Editor::spectral_analyze_range_selection()
1865 if (analysis_window == 0) {
1866 analysis_window = new AnalysisWindow();
1869 analysis_window->set_session(_session);
1871 analysis_window->show_all();
1874 analysis_window->set_rangemode();
1875 analysis_window->analyze();
1877 analysis_window->present();
1881 Editor::build_track_selection_context_menu ()
1883 using namespace Menu_Helpers;
1884 MenuList& edit_items = track_selection_context_menu.items();
1885 edit_items.clear ();
1887 add_selection_context_items (edit_items);
1888 // edit_items.push_back (SeparatorElem());
1889 // add_dstream_context_items (edit_items);
1891 return &track_selection_context_menu;
1895 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1897 using namespace Menu_Helpers;
1899 /* OK, stick the region submenu at the top of the list, and then add
1903 RegionSelection rs = get_regions_from_selection_and_entered ();
1905 string::size_type pos = 0;
1906 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1908 /* we have to hack up the region name because "_" has a special
1909 meaning for menu titles.
1912 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1913 menu_item_name.replace (pos, 1, "__");
1917 if (_popup_region_menu_item == 0) {
1918 _popup_region_menu_item = new MenuItem (menu_item_name);
1919 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1920 _popup_region_menu_item->show ();
1922 _popup_region_menu_item->set_label (menu_item_name);
1925 /* No latering allowed in later is higher layering model */
1926 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1927 if (act && Config->get_layer_model() == LaterHigher) {
1928 act->set_sensitive (false);
1930 act->set_sensitive (true);
1933 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1935 edit_items.push_back (*_popup_region_menu_item);
1936 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1937 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1939 edit_items.push_back (SeparatorElem());
1942 /** Add context menu items relevant to selection ranges.
1943 * @param edit_items List to add the items to.
1946 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1948 using namespace Menu_Helpers;
1950 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1951 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1953 edit_items.push_back (SeparatorElem());
1954 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1956 edit_items.push_back (SeparatorElem());
1957 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1958 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1960 edit_items.push_back (SeparatorElem());
1962 edit_items.push_back (
1964 _("Move Range Start to Previous Region Boundary"),
1965 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1969 edit_items.push_back (
1971 _("Move Range Start to Next Region Boundary"),
1972 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1976 edit_items.push_back (
1978 _("Move Range End to Previous Region Boundary"),
1979 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1983 edit_items.push_back (
1985 _("Move Range End to Next Region Boundary"),
1986 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1990 edit_items.push_back (SeparatorElem());
1991 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1992 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1994 edit_items.push_back (SeparatorElem());
1995 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1997 edit_items.push_back (SeparatorElem());
1998 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1999 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2000 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2002 edit_items.push_back (SeparatorElem());
2003 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2005 edit_items.push_back (SeparatorElem());
2006 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2007 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2009 edit_items.push_back (SeparatorElem());
2010 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2011 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2012 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2013 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2014 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2015 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2016 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2022 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2024 using namespace Menu_Helpers;
2028 Menu *play_menu = manage (new Menu);
2029 MenuList& play_items = play_menu->items();
2030 play_menu->set_name ("ArdourContextMenu");
2032 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2033 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2034 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2035 play_items.push_back (SeparatorElem());
2036 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2038 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2042 Menu *select_menu = manage (new Menu);
2043 MenuList& select_items = select_menu->items();
2044 select_menu->set_name ("ArdourContextMenu");
2046 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2047 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2048 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2049 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2050 select_items.push_back (SeparatorElem());
2051 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2052 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2053 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2054 select_items.push_back (SeparatorElem());
2055 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2056 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2057 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2058 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2059 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2060 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2061 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2063 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2067 Menu *cutnpaste_menu = manage (new Menu);
2068 MenuList& cutnpaste_items = cutnpaste_menu->items();
2069 cutnpaste_menu->set_name ("ArdourContextMenu");
2071 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2072 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2073 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2075 cutnpaste_items.push_back (SeparatorElem());
2077 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2078 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2080 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2082 /* Adding new material */
2084 edit_items.push_back (SeparatorElem());
2085 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2086 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2090 Menu *nudge_menu = manage (new Menu());
2091 MenuList& nudge_items = nudge_menu->items();
2092 nudge_menu->set_name ("ArdourContextMenu");
2094 edit_items.push_back (SeparatorElem());
2095 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2096 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2097 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2098 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2100 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2104 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2106 using namespace Menu_Helpers;
2110 Menu *play_menu = manage (new Menu);
2111 MenuList& play_items = play_menu->items();
2112 play_menu->set_name ("ArdourContextMenu");
2114 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2115 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2116 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2120 Menu *select_menu = manage (new Menu);
2121 MenuList& select_items = select_menu->items();
2122 select_menu->set_name ("ArdourContextMenu");
2124 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2125 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2126 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2127 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2128 select_items.push_back (SeparatorElem());
2129 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2130 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2131 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2132 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2134 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2138 Menu *cutnpaste_menu = manage (new Menu);
2139 MenuList& cutnpaste_items = cutnpaste_menu->items();
2140 cutnpaste_menu->set_name ("ArdourContextMenu");
2142 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2143 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2144 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2146 Menu *nudge_menu = manage (new Menu());
2147 MenuList& nudge_items = nudge_menu->items();
2148 nudge_menu->set_name ("ArdourContextMenu");
2150 edit_items.push_back (SeparatorElem());
2151 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2152 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2153 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2154 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2156 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2160 Editor::snap_type() const
2166 Editor::snap_musical() const
2168 switch (_snap_type) {
2169 case SnapToBeatDiv128:
2170 case SnapToBeatDiv64:
2171 case SnapToBeatDiv32:
2172 case SnapToBeatDiv28:
2173 case SnapToBeatDiv24:
2174 case SnapToBeatDiv20:
2175 case SnapToBeatDiv16:
2176 case SnapToBeatDiv14:
2177 case SnapToBeatDiv12:
2178 case SnapToBeatDiv10:
2179 case SnapToBeatDiv8:
2180 case SnapToBeatDiv7:
2181 case SnapToBeatDiv6:
2182 case SnapToBeatDiv5:
2183 case SnapToBeatDiv4:
2184 case SnapToBeatDiv3:
2185 case SnapToBeatDiv2:
2197 Editor::snap_mode() const
2203 Editor::set_snap_to (SnapType st)
2205 unsigned int snap_ind = (unsigned int)st;
2207 if (internal_editing()) {
2208 internal_snap_type = st;
2210 pre_internal_snap_type = st;
2215 if (snap_ind > snap_type_strings.size() - 1) {
2217 _snap_type = (SnapType)snap_ind;
2220 string str = snap_type_strings[snap_ind];
2222 if (str != snap_type_selector.get_text()) {
2223 snap_type_selector.set_text (str);
2228 switch (_snap_type) {
2229 case SnapToBeatDiv128:
2230 case SnapToBeatDiv64:
2231 case SnapToBeatDiv32:
2232 case SnapToBeatDiv28:
2233 case SnapToBeatDiv24:
2234 case SnapToBeatDiv20:
2235 case SnapToBeatDiv16:
2236 case SnapToBeatDiv14:
2237 case SnapToBeatDiv12:
2238 case SnapToBeatDiv10:
2239 case SnapToBeatDiv8:
2240 case SnapToBeatDiv7:
2241 case SnapToBeatDiv6:
2242 case SnapToBeatDiv5:
2243 case SnapToBeatDiv4:
2244 case SnapToBeatDiv3:
2245 case SnapToBeatDiv2: {
2246 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2247 update_tempo_based_rulers ();
2251 case SnapToRegionStart:
2252 case SnapToRegionEnd:
2253 case SnapToRegionSync:
2254 case SnapToRegionBoundary:
2255 build_region_boundary_cache ();
2263 redisplay_tempo (false);
2265 SnapChanged (); /* EMIT SIGNAL */
2269 Editor::set_snap_mode (SnapMode mode)
2271 string str = snap_mode_strings[(int)mode];
2273 if (internal_editing()) {
2274 internal_snap_mode = mode;
2276 pre_internal_snap_mode = mode;
2281 if (str != snap_mode_selector.get_text ()) {
2282 snap_mode_selector.set_text (str);
2289 Editor::set_edit_point_preference (EditPoint ep, bool force)
2291 bool changed = (_edit_point != ep);
2294 if (Profile->get_mixbus())
2295 if (ep == EditAtSelectedMarker)
2296 ep = EditAtPlayhead;
2298 string str = edit_point_strings[(int)ep];
2299 if (str != edit_point_selector.get_text ()) {
2300 edit_point_selector.set_text (str);
2303 update_all_enter_cursors();
2305 if (!force && !changed) {
2309 const char* action=NULL;
2311 switch (_edit_point) {
2312 case EditAtPlayhead:
2313 action = "edit-at-playhead";
2315 case EditAtSelectedMarker:
2316 action = "edit-at-marker";
2319 action = "edit-at-mouse";
2323 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2325 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2329 bool in_track_canvas;
2331 if (!mouse_frame (foo, in_track_canvas)) {
2332 in_track_canvas = false;
2335 reset_canvas_action_sensitivity (in_track_canvas);
2336 sensitize_the_right_region_actions (false);
2342 Editor::set_state (const XMLNode& node, int version)
2344 XMLProperty const * prop;
2346 PBD::Unwinder<bool> nsi (no_save_instant, true);
2349 Tabbable::set_state (node, version);
2351 if (_session && (prop = node.property ("playhead"))) {
2353 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2355 playhead_cursor->set_position (pos);
2357 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2358 playhead_cursor->set_position (0);
2361 playhead_cursor->set_position (0);
2364 if ((prop = node.property ("mixer-width"))) {
2365 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2368 if ((prop = node.property ("zoom-focus"))) {
2369 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2371 zoom_focus_selection_done (zoom_focus);
2374 if ((prop = node.property ("zoom"))) {
2375 /* older versions of ardour used floating point samples_per_pixel */
2376 double f = PBD::atof (prop->value());
2377 reset_zoom (llrintf (f));
2379 reset_zoom (samples_per_pixel);
2382 if ((prop = node.property ("visible-track-count"))) {
2383 set_visible_track_count (PBD::atoi (prop->value()));
2386 if ((prop = node.property ("snap-to"))) {
2387 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2388 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2390 set_snap_to (_snap_type);
2393 if ((prop = node.property ("snap-mode"))) {
2394 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2395 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2396 * snap_mode_selection_done() will only mark an already active item as active
2397 * which does not trigger set_text().
2399 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2401 set_snap_mode (_snap_mode);
2404 if ((prop = node.property ("internal-snap-to"))) {
2405 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2408 if ((prop = node.property ("internal-snap-mode"))) {
2409 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2412 if ((prop = node.property ("pre-internal-snap-to"))) {
2413 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2416 if ((prop = node.property ("pre-internal-snap-mode"))) {
2417 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2420 if ((prop = node.property ("mouse-mode"))) {
2421 MouseMode m = str2mousemode(prop->value());
2422 set_mouse_mode (m, true);
2424 set_mouse_mode (MouseObject, true);
2427 if ((prop = node.property ("left-frame")) != 0) {
2429 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2433 reset_x_origin (pos);
2437 if ((prop = node.property ("y-origin")) != 0) {
2438 reset_y_origin (atof (prop->value ()));
2441 if ((prop = node.property ("join-object-range"))) {
2442 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2443 bool yn = string_is_affirmative (prop->value());
2445 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2446 tact->set_active (!yn);
2447 tact->set_active (yn);
2449 set_mouse_mode(mouse_mode, true);
2452 if ((prop = node.property ("edit-point"))) {
2453 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2455 set_edit_point_preference (_edit_point);
2458 if ((prop = node.property ("show-measures"))) {
2459 bool yn = string_is_affirmative (prop->value());
2460 _show_measures = yn;
2463 if ((prop = node.property ("follow-playhead"))) {
2464 bool yn = string_is_affirmative (prop->value());
2465 set_follow_playhead (yn);
2468 if ((prop = node.property ("stationary-playhead"))) {
2469 bool yn = string_is_affirmative (prop->value());
2470 set_stationary_playhead (yn);
2473 if ((prop = node.property ("region-list-sort-type"))) {
2474 RegionListSortType st;
2475 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2478 if ((prop = node.property ("show-editor-mixer"))) {
2480 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2483 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2484 bool yn = string_is_affirmative (prop->value());
2486 /* do it twice to force the change */
2488 tact->set_active (!yn);
2489 tact->set_active (yn);
2492 if ((prop = node.property ("show-editor-list"))) {
2494 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2497 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2498 bool yn = string_is_affirmative (prop->value());
2500 /* do it twice to force the change */
2502 tact->set_active (!yn);
2503 tact->set_active (yn);
2506 if ((prop = node.property (X_("editor-list-page")))) {
2507 _the_notebook.set_current_page (atoi (prop->value ()));
2510 if ((prop = node.property (X_("show-marker-lines")))) {
2511 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2513 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2514 bool yn = string_is_affirmative (prop->value ());
2516 tact->set_active (!yn);
2517 tact->set_active (yn);
2520 XMLNodeList children = node.children ();
2521 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2522 selection->set_state (**i, Stateful::current_state_version);
2523 _regions->set_state (**i);
2524 _locations->set_state (**i);
2527 if ((prop = node.property ("maximised"))) {
2528 bool yn = string_is_affirmative (prop->value());
2529 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2531 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2532 bool fs = tact && tact->get_active();
2534 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2538 if ((prop = node.property ("nudge-clock-value"))) {
2540 sscanf (prop->value().c_str(), "%" PRId64, &f);
2541 nudge_clock->set (f);
2543 nudge_clock->set_mode (AudioClock::Timecode);
2544 nudge_clock->set (_session->frame_rate() * 5, true);
2549 * Not all properties may have been in XML, but
2550 * those that are linked to a private variable may need changing
2555 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2557 yn = _show_measures;
2558 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2559 /* do it twice to force the change */
2560 tact->set_active (!yn);
2561 tact->set_active (yn);
2564 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2565 yn = _follow_playhead;
2567 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2568 if (tact->get_active() != yn) {
2569 tact->set_active (yn);
2573 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2574 yn = _stationary_playhead;
2576 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2577 if (tact->get_active() != yn) {
2578 tact->set_active (yn);
2583 return LuaInstance::instance()->set_state(node);
2587 Editor::get_state ()
2589 XMLNode* node = new XMLNode (X_("Editor"));
2593 id().print (buf, sizeof (buf));
2594 node->add_property ("id", buf);
2596 node->add_child_nocopy (Tabbable::get_state());
2598 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2599 node->add_property("edit-horizontal-pane-pos", string(buf));
2600 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2601 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2602 node->add_property("edit-vertical-pane-pos", string(buf));
2604 maybe_add_mixer_strip_width (*node);
2606 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2608 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2609 node->add_property ("zoom", buf);
2610 node->add_property ("snap-to", enum_2_string (_snap_type));
2611 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2612 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2613 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2614 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2615 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2616 node->add_property ("edit-point", enum_2_string (_edit_point));
2617 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2618 node->add_property ("visible-track-count", buf);
2620 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2621 node->add_property ("playhead", buf);
2622 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2623 node->add_property ("left-frame", buf);
2624 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2625 node->add_property ("y-origin", buf);
2627 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2628 node->add_property ("maximised", _maximised ? "yes" : "no");
2629 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2630 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2631 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2632 node->add_property ("mouse-mode", enum2str(mouse_mode));
2633 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2635 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2637 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2638 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2641 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2643 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2644 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2647 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2648 node->add_property (X_("editor-list-page"), buf);
2650 if (button_bindings) {
2651 XMLNode* bb = new XMLNode (X_("Buttons"));
2652 button_bindings->save (*bb);
2653 node->add_child_nocopy (*bb);
2656 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2658 node->add_child_nocopy (selection->get_state ());
2659 node->add_child_nocopy (_regions->get_state ());
2661 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2662 node->add_property ("nudge-clock-value", buf);
2664 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2665 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2666 node->add_child_nocopy (_locations->get_state ());
2671 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2672 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2674 * @return pair: TimeAxisView that y is over, layer index.
2676 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2677 * in stacked or expanded region display mode, otherwise 0.
2679 std::pair<TimeAxisView *, double>
2680 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2682 if (!trackview_relative_offset) {
2683 y -= _trackview_group->canvas_origin().y;
2687 return std::make_pair ( (TimeAxisView *) 0, 0);
2690 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2692 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2699 return std::make_pair ( (TimeAxisView *) 0, 0);
2702 /** Snap a position to the grid, if appropriate, taking into account current
2703 * grid settings and also the state of any snap modifier keys that may be pressed.
2704 * @param start Position to snap.
2705 * @param event Event to get current key modifier information from, or 0.
2708 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2710 if (!_session || !event) {
2714 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2715 if (_snap_mode == SnapOff) {
2716 snap_to_internal (start, direction, for_mark);
2718 start.set (start.frame, 0);
2721 if (_snap_mode != SnapOff) {
2722 snap_to_internal (start, direction, for_mark);
2723 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2724 /* SnapOff, but we pressed the snap_delta modifier */
2725 snap_to_internal (start, direction, for_mark);
2727 start.set (start.frame, 0);
2733 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2735 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2736 start.set (start.frame, 0);
2740 snap_to_internal (start, direction, for_mark, ensure_snap);
2744 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2746 framepos_t start = pos.frame;
2747 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2748 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2750 switch (_snap_type) {
2751 case SnapToTimecodeFrame:
2752 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2753 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2754 /* start is already on a whole timecode frame, do nothing */
2755 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2756 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2758 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2762 case SnapToTimecodeSeconds:
2763 if (_session->config.get_timecode_offset_negative()) {
2764 start += _session->config.get_timecode_offset ();
2766 start -= _session->config.get_timecode_offset ();
2768 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2769 (start % one_timecode_second == 0)) {
2770 /* start is already on a whole second, do nothing */
2771 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2772 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2774 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2777 if (_session->config.get_timecode_offset_negative()) {
2778 start -= _session->config.get_timecode_offset ();
2780 start += _session->config.get_timecode_offset ();
2784 case SnapToTimecodeMinutes:
2785 if (_session->config.get_timecode_offset_negative()) {
2786 start += _session->config.get_timecode_offset ();
2788 start -= _session->config.get_timecode_offset ();
2790 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2791 (start % one_timecode_minute == 0)) {
2792 /* start is already on a whole minute, do nothing */
2793 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2794 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2796 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2798 if (_session->config.get_timecode_offset_negative()) {
2799 start -= _session->config.get_timecode_offset ();
2801 start += _session->config.get_timecode_offset ();
2805 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2806 abort(); /*NOTREACHED*/
2813 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2815 const framepos_t one_second = _session->frame_rate();
2816 const framepos_t one_minute = _session->frame_rate() * 60;
2817 framepos_t presnap = start.frame;
2821 switch (_snap_type) {
2822 case SnapToTimecodeFrame:
2823 case SnapToTimecodeSeconds:
2824 case SnapToTimecodeMinutes:
2825 return timecode_snap_to_internal (start, direction, for_mark);
2828 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2829 start.frame % (one_second/75) == 0) {
2830 /* start is already on a whole CD frame, do nothing */
2831 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2832 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2834 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2837 start.set (start.frame, 0);
2842 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2843 start.frame % one_second == 0) {
2844 /* start is already on a whole second, do nothing */
2845 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2846 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2848 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2851 start.set (start.frame, 0);
2856 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2857 start.frame % one_minute == 0) {
2858 /* start is already on a whole minute, do nothing */
2859 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2860 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2862 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2865 start.set (start.frame, 0);
2870 start = _session->tempo_map().round_to_bar (start.frame, direction);
2874 start = _session->tempo_map().round_to_beat (start.frame, direction);
2877 case SnapToBeatDiv128:
2878 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2880 case SnapToBeatDiv64:
2881 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2883 case SnapToBeatDiv32:
2884 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2886 case SnapToBeatDiv28:
2887 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2889 case SnapToBeatDiv24:
2890 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2892 case SnapToBeatDiv20:
2893 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2895 case SnapToBeatDiv16:
2896 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2898 case SnapToBeatDiv14:
2899 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2901 case SnapToBeatDiv12:
2902 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2904 case SnapToBeatDiv10:
2905 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2907 case SnapToBeatDiv8:
2908 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2910 case SnapToBeatDiv7:
2911 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2913 case SnapToBeatDiv6:
2914 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2916 case SnapToBeatDiv5:
2917 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2919 case SnapToBeatDiv4:
2920 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2922 case SnapToBeatDiv3:
2923 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2925 case SnapToBeatDiv2:
2926 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2934 _session->locations()->marks_either_side (start.frame, before, after);
2936 if (before == max_framepos && after == max_framepos) {
2937 /* No marks to snap to, so just don't snap */
2939 } else if (before == max_framepos) {
2940 start.frame = after;
2941 } else if (after == max_framepos) {
2942 start.frame = before;
2943 } else if (before != max_framepos && after != max_framepos) {
2944 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2945 start.frame = after;
2946 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2947 start.frame = before;
2948 else if (direction == 0 ) {
2949 if ((start.frame - before) < (after - start.frame)) {
2950 start.frame = before;
2952 start.frame = after;
2957 start.set (start.frame, 0);
2961 case SnapToRegionStart:
2962 case SnapToRegionEnd:
2963 case SnapToRegionSync:
2964 case SnapToRegionBoundary:
2965 if (!region_boundary_cache.empty()) {
2967 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2968 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2970 if (direction > 0) {
2971 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2973 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2976 if (next != region_boundary_cache.begin ()) {
2981 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2982 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2984 if (start.frame > (p + n) / 2) {
2991 start.set (start.frame, 0);
2996 switch (_snap_mode) {
3006 if (presnap > start.frame) {
3007 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
3008 start.set (presnap, 0);
3011 } else if (presnap < start.frame) {
3012 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
3013 start.set (presnap, 0);
3018 /* handled at entry */
3025 Editor::setup_toolbar ()
3027 HBox* mode_box = manage(new HBox);
3028 mode_box->set_border_width (2);
3029 mode_box->set_spacing(2);
3031 HBox* mouse_mode_box = manage (new HBox);
3032 HBox* mouse_mode_hbox = manage (new HBox);
3033 VBox* mouse_mode_vbox = manage (new VBox);
3034 Alignment* mouse_mode_align = manage (new Alignment);
3036 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3037 mouse_mode_size_group->add_widget (smart_mode_button);
3038 mouse_mode_size_group->add_widget (mouse_move_button);
3039 mouse_mode_size_group->add_widget (mouse_cut_button);
3040 mouse_mode_size_group->add_widget (mouse_select_button);
3041 mouse_mode_size_group->add_widget (mouse_timefx_button);
3042 mouse_mode_size_group->add_widget (mouse_audition_button);
3043 mouse_mode_size_group->add_widget (mouse_draw_button);
3044 mouse_mode_size_group->add_widget (mouse_content_button);
3046 if (!Profile->get_mixbus()) {
3047 mouse_mode_size_group->add_widget (zoom_in_button);
3048 mouse_mode_size_group->add_widget (zoom_out_button);
3049 mouse_mode_size_group->add_widget (zoom_out_full_button);
3050 mouse_mode_size_group->add_widget (zoom_focus_selector);
3051 mouse_mode_size_group->add_widget (tav_shrink_button);
3052 mouse_mode_size_group->add_widget (tav_expand_button);
3054 mouse_mode_size_group->add_widget (zoom_preset_selector);
3055 mouse_mode_size_group->add_widget (visible_tracks_selector);
3058 mouse_mode_size_group->add_widget (snap_type_selector);
3059 mouse_mode_size_group->add_widget (snap_mode_selector);
3061 mouse_mode_size_group->add_widget (edit_point_selector);
3062 mouse_mode_size_group->add_widget (edit_mode_selector);
3064 mouse_mode_size_group->add_widget (*nudge_clock);
3065 mouse_mode_size_group->add_widget (nudge_forward_button);
3066 mouse_mode_size_group->add_widget (nudge_backward_button);
3068 mouse_mode_hbox->set_spacing (2);
3070 if (!ARDOUR::Profile->get_trx()) {
3071 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3074 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3075 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3077 if (!ARDOUR::Profile->get_mixbus()) {
3078 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3081 if (!ARDOUR::Profile->get_trx()) {
3082 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3083 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3084 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3085 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3088 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3090 mouse_mode_align->add (*mouse_mode_vbox);
3091 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3093 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3095 edit_mode_selector.set_name ("mouse mode button");
3097 if (!ARDOUR::Profile->get_trx()) {
3098 mode_box->pack_start (edit_mode_selector, false, false);
3101 mode_box->pack_start (*mouse_mode_box, false, false);
3105 _zoom_box.set_spacing (2);
3106 _zoom_box.set_border_width (2);
3110 zoom_preset_selector.set_name ("zoom button");
3111 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3113 zoom_in_button.set_name ("zoom button");
3114 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3115 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3116 zoom_in_button.set_related_action (act);
3118 zoom_out_button.set_name ("zoom button");
3119 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3120 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3121 zoom_out_button.set_related_action (act);
3123 zoom_out_full_button.set_name ("zoom button");
3124 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3125 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3126 zoom_out_full_button.set_related_action (act);
3128 zoom_focus_selector.set_name ("zoom button");
3130 if (ARDOUR::Profile->get_mixbus()) {
3131 _zoom_box.pack_start (zoom_preset_selector, false, false);
3132 } else if (ARDOUR::Profile->get_trx()) {
3133 mode_box->pack_start (zoom_out_button, false, false);
3134 mode_box->pack_start (zoom_in_button, false, false);
3136 _zoom_box.pack_start (zoom_out_button, false, false);
3137 _zoom_box.pack_start (zoom_in_button, false, false);
3138 _zoom_box.pack_start (zoom_out_full_button, false, false);
3139 _zoom_box.pack_start (zoom_focus_selector, false, false);
3142 /* Track zoom buttons */
3143 _track_box.set_spacing (2);
3144 _track_box.set_border_width (2);
3146 visible_tracks_selector.set_name ("zoom button");
3147 if (Profile->get_mixbus()) {
3148 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3150 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3153 tav_expand_button.set_name ("zoom button");
3154 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3155 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3156 tav_expand_button.set_related_action (act);
3158 tav_shrink_button.set_name ("zoom button");
3159 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3160 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3161 tav_shrink_button.set_related_action (act);
3163 if (ARDOUR::Profile->get_mixbus()) {
3164 _track_box.pack_start (visible_tracks_selector);
3165 } else if (ARDOUR::Profile->get_trx()) {
3166 _track_box.pack_start (tav_shrink_button);
3167 _track_box.pack_start (tav_expand_button);
3169 _track_box.pack_start (visible_tracks_selector);
3170 _track_box.pack_start (tav_shrink_button);
3171 _track_box.pack_start (tav_expand_button);
3174 snap_box.set_spacing (2);
3175 snap_box.set_border_width (2);
3177 snap_type_selector.set_name ("mouse mode button");
3179 snap_mode_selector.set_name ("mouse mode button");
3181 edit_point_selector.set_name ("mouse mode button");
3183 snap_box.pack_start (snap_mode_selector, false, false);
3184 snap_box.pack_start (snap_type_selector, false, false);
3187 HBox *ep_box = manage (new HBox);
3188 ep_box->set_spacing (2);
3189 ep_box->set_border_width (2);
3191 ep_box->pack_start (edit_point_selector, false, false);
3195 HBox *nudge_box = manage (new HBox);
3196 nudge_box->set_spacing (2);
3197 nudge_box->set_border_width (2);
3199 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3200 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3202 nudge_box->pack_start (nudge_backward_button, false, false);
3203 nudge_box->pack_start (nudge_forward_button, false, false);
3204 nudge_box->pack_start (*nudge_clock, false, false);
3207 /* Pack everything in... */
3209 toolbar_hbox.set_spacing (2);
3210 toolbar_hbox.set_border_width (2);
3212 toolbar_hbox.pack_start (*mode_box, false, false);
3214 if (!ARDOUR::Profile->get_trx()) {
3216 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3218 toolbar_hbox.pack_start (_zoom_box, false, false);
3220 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3222 toolbar_hbox.pack_start (_track_box, false, false);
3224 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3226 toolbar_hbox.pack_start (snap_box, false, false);
3228 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3230 toolbar_hbox.pack_start (*ep_box, false, false);
3232 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3234 toolbar_hbox.pack_start (*nudge_box, false, false);
3237 toolbar_hbox.show_all ();
3241 Editor::build_edit_point_menu ()
3243 using namespace Menu_Helpers;
3245 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3246 if(!Profile->get_mixbus())
3247 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3248 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3250 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3254 Editor::build_edit_mode_menu ()
3256 using namespace Menu_Helpers;
3258 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3259 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3260 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3261 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3263 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3267 Editor::build_snap_mode_menu ()
3269 using namespace Menu_Helpers;
3271 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3272 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3273 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3275 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3279 Editor::build_snap_type_menu ()
3281 using namespace Menu_Helpers;
3283 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3284 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3287 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3288 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3289 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3290 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3291 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3292 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3293 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3294 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3295 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3296 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3297 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3298 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3299 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3300 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3301 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3302 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3303 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3304 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3305 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3306 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3307 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3308 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3309 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3310 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3311 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3312 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3314 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3319 Editor::setup_tooltips ()
3321 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3322 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3323 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3324 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3325 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3326 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3327 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3328 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3329 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3330 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3331 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3332 set_tooltip (zoom_in_button, _("Zoom In"));
3333 set_tooltip (zoom_out_button, _("Zoom Out"));
3334 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3335 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3336 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3337 set_tooltip (tav_expand_button, _("Expand Tracks"));
3338 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3339 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3340 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3341 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3342 set_tooltip (edit_point_selector, _("Edit Point"));
3343 set_tooltip (edit_mode_selector, _("Edit Mode"));
3344 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3348 Editor::convert_drop_to_paths (
3349 vector<string>& paths,
3350 const RefPtr<Gdk::DragContext>& /*context*/,
3353 const SelectionData& data,
3357 if (_session == 0) {
3361 vector<string> uris = data.get_uris();
3365 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3366 are actually URI lists. So do it by hand.
3369 if (data.get_target() != "text/plain") {
3373 /* Parse the "uri-list" format that Nautilus provides,
3374 where each pathname is delimited by \r\n.
3376 THERE MAY BE NO NULL TERMINATING CHAR!!!
3379 string txt = data.get_text();
3383 p = (char *) malloc (txt.length() + 1);
3384 txt.copy (p, txt.length(), 0);
3385 p[txt.length()] = '\0';
3391 while (g_ascii_isspace (*p))
3395 while (*q && (*q != '\n') && (*q != '\r')) {
3402 while (q > p && g_ascii_isspace (*q))
3407 uris.push_back (string (p, q - p + 1));
3411 p = strchr (p, '\n');
3423 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3424 if ((*i).substr (0,7) == "file://") {
3425 paths.push_back (Glib::filename_from_uri (*i));
3433 Editor::new_tempo_section ()
3438 Editor::map_transport_state ()
3440 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3442 if (_session && _session->transport_stopped()) {
3443 have_pending_keyboard_selection = false;
3446 update_loop_range_view ();
3452 Editor::begin_selection_op_history ()
3454 selection_op_cmd_depth = 0;
3455 selection_op_history_it = 0;
3457 while(!selection_op_history.empty()) {
3458 delete selection_op_history.front();
3459 selection_op_history.pop_front();
3462 selection_undo_action->set_sensitive (false);
3463 selection_redo_action->set_sensitive (false);
3464 selection_op_history.push_front (&_selection_memento->get_state ());
3468 Editor::begin_reversible_selection_op (string name)
3471 //cerr << name << endl;
3472 /* begin/commit pairs can be nested */
3473 selection_op_cmd_depth++;
3478 Editor::commit_reversible_selection_op ()
3481 if (selection_op_cmd_depth == 1) {
3483 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3485 The user has undone some selection ops and then made a new one,
3486 making anything earlier in the list invalid.
3489 list<XMLNode *>::iterator it = selection_op_history.begin();
3490 list<XMLNode *>::iterator e_it = it;
3491 advance (e_it, selection_op_history_it);
3493 for ( ; it != e_it; ++it) {
3496 selection_op_history.erase (selection_op_history.begin(), e_it);
3499 selection_op_history.push_front (&_selection_memento->get_state ());
3500 selection_op_history_it = 0;
3502 selection_undo_action->set_sensitive (true);
3503 selection_redo_action->set_sensitive (false);
3506 if (selection_op_cmd_depth > 0) {
3507 selection_op_cmd_depth--;
3513 Editor::undo_selection_op ()
3516 selection_op_history_it++;
3518 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3519 if (n == selection_op_history_it) {
3520 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3521 selection_redo_action->set_sensitive (true);
3525 /* is there an earlier entry? */
3526 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3527 selection_undo_action->set_sensitive (false);
3533 Editor::redo_selection_op ()
3536 if (selection_op_history_it > 0) {
3537 selection_op_history_it--;
3540 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3541 if (n == selection_op_history_it) {
3542 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3543 selection_undo_action->set_sensitive (true);
3548 if (selection_op_history_it == 0) {
3549 selection_redo_action->set_sensitive (false);
3555 Editor::begin_reversible_command (string name)
3558 before.push_back (&_selection_memento->get_state ());
3559 _session->begin_reversible_command (name);
3564 Editor::begin_reversible_command (GQuark q)
3567 before.push_back (&_selection_memento->get_state ());
3568 _session->begin_reversible_command (q);
3573 Editor::abort_reversible_command ()
3576 while(!before.empty()) {
3577 delete before.front();
3580 _session->abort_reversible_command ();
3585 Editor::commit_reversible_command ()
3588 if (before.size() == 1) {
3589 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3590 redo_action->set_sensitive(false);
3591 undo_action->set_sensitive(true);
3592 begin_selection_op_history ();
3595 if (before.empty()) {
3596 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3601 _session->commit_reversible_command ();
3606 Editor::history_changed ()
3610 if (undo_action && _session) {
3611 if (_session->undo_depth() == 0) {
3612 label = S_("Command|Undo");
3614 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3616 undo_action->property_label() = label;
3619 if (redo_action && _session) {
3620 if (_session->redo_depth() == 0) {
3622 redo_action->set_sensitive (false);
3624 label = string_compose(_("Redo (%1)"), _session->next_redo());
3625 redo_action->set_sensitive (true);
3627 redo_action->property_label() = label;
3632 Editor::duplicate_range (bool with_dialog)
3636 RegionSelection rs = get_regions_from_selection_and_entered ();
3638 if ( selection->time.length() == 0 && rs.empty()) {
3644 ArdourDialog win (_("Duplicate"));
3645 Label label (_("Number of duplications:"));
3646 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3647 SpinButton spinner (adjustment, 0.0, 1);
3650 win.get_vbox()->set_spacing (12);
3651 win.get_vbox()->pack_start (hbox);
3652 hbox.set_border_width (6);
3653 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3655 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3656 place, visually. so do this by hand.
3659 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3660 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3661 spinner.grab_focus();
3667 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3668 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3669 win.set_default_response (RESPONSE_ACCEPT);
3671 spinner.grab_focus ();
3673 switch (win.run ()) {
3674 case RESPONSE_ACCEPT:
3680 times = adjustment.get_value();
3683 if ((current_mouse_mode() == Editing::MouseRange)) {
3684 if (selection->time.length()) {
3685 duplicate_selection (times);
3687 } else if (get_smart_mode()) {
3688 if (selection->time.length()) {
3689 duplicate_selection (times);
3691 duplicate_some_regions (rs, times);
3693 duplicate_some_regions (rs, times);
3698 Editor::set_edit_mode (EditMode m)
3700 Config->set_edit_mode (m);
3704 Editor::cycle_edit_mode ()
3706 switch (Config->get_edit_mode()) {
3708 Config->set_edit_mode (Ripple);
3712 Config->set_edit_mode (Lock);
3715 Config->set_edit_mode (Slide);
3721 Editor::edit_mode_selection_done ( EditMode m )
3723 Config->set_edit_mode ( m );
3727 Editor::snap_type_selection_done (SnapType snaptype)
3729 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3731 ract->set_active ();
3736 Editor::snap_mode_selection_done (SnapMode mode)
3738 RefPtr<RadioAction> ract = snap_mode_action (mode);
3741 ract->set_active (true);
3746 Editor::cycle_edit_point (bool with_marker)
3748 if(Profile->get_mixbus())
3749 with_marker = false;
3751 switch (_edit_point) {
3753 set_edit_point_preference (EditAtPlayhead);
3755 case EditAtPlayhead:
3757 set_edit_point_preference (EditAtSelectedMarker);
3759 set_edit_point_preference (EditAtMouse);
3762 case EditAtSelectedMarker:
3763 set_edit_point_preference (EditAtMouse);
3769 Editor::edit_point_selection_done (EditPoint ep)
3771 set_edit_point_preference ( ep );
3775 Editor::build_zoom_focus_menu ()
3777 using namespace Menu_Helpers;
3779 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3780 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3781 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3782 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3783 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3784 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3786 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3790 Editor::zoom_focus_selection_done ( ZoomFocus f )
3792 RefPtr<RadioAction> ract = zoom_focus_action (f);
3794 ract->set_active ();
3799 Editor::build_track_count_menu ()
3801 using namespace Menu_Helpers;
3803 if (!Profile->get_mixbus()) {
3804 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3805 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3806 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3807 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3808 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3809 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3810 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3811 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3812 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3813 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3814 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3815 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3816 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3818 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3819 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3820 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3821 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3822 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3823 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3824 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3825 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3826 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3827 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3829 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3830 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3831 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3832 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3833 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3834 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3835 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3836 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3837 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3838 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3839 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3844 Editor::set_zoom_preset (int64_t ms)
3847 temporal_zoom_session();
3851 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3852 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3856 Editor::set_visible_track_count (int32_t n)
3858 _visible_track_count = n;
3860 /* if the canvas hasn't really been allocated any size yet, just
3861 record the desired number of visible tracks and return. when canvas
3862 allocation happens, we will get called again and then we can do the
3866 if (_visible_canvas_height <= 1) {
3872 DisplaySuspender ds;
3874 if (_visible_track_count > 0) {
3875 h = trackviews_height() / _visible_track_count;
3876 std::ostringstream s;
3877 s << _visible_track_count;
3879 } else if (_visible_track_count == 0) {
3881 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3882 if ((*i)->marked_for_display()) {
3886 h = trackviews_height() / n;
3889 /* negative value means that the visible track count has
3890 been overridden by explicit track height changes.
3892 visible_tracks_selector.set_text (X_("*"));
3896 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3897 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3900 if (str != visible_tracks_selector.get_text()) {
3901 visible_tracks_selector.set_text (str);
3906 Editor::override_visible_track_count ()
3908 _visible_track_count = -1;
3909 visible_tracks_selector.set_text ( _("*") );
3913 Editor::edit_controls_button_release (GdkEventButton* ev)
3915 if (Keyboard::is_context_menu_event (ev)) {
3916 ARDOUR_UI::instance()->add_route ();
3917 } else if (ev->button == 1) {
3918 selection->clear_tracks ();
3925 Editor::mouse_select_button_release (GdkEventButton* ev)
3927 /* this handles just right-clicks */
3929 if (ev->button != 3) {
3937 Editor::set_zoom_focus (ZoomFocus f)
3939 string str = zoom_focus_strings[(int)f];
3941 if (str != zoom_focus_selector.get_text()) {
3942 zoom_focus_selector.set_text (str);
3945 if (zoom_focus != f) {
3952 Editor::cycle_zoom_focus ()
3954 switch (zoom_focus) {
3956 set_zoom_focus (ZoomFocusRight);
3958 case ZoomFocusRight:
3959 set_zoom_focus (ZoomFocusCenter);
3961 case ZoomFocusCenter:
3962 set_zoom_focus (ZoomFocusPlayhead);
3964 case ZoomFocusPlayhead:
3965 set_zoom_focus (ZoomFocusMouse);
3967 case ZoomFocusMouse:
3968 set_zoom_focus (ZoomFocusEdit);
3971 set_zoom_focus (ZoomFocusLeft);
3977 Editor::set_show_measures (bool yn)
3979 if (_show_measures != yn) {
3982 if ((_show_measures = yn) == true) {
3984 tempo_lines->show();
3987 std::vector<TempoMap::BBTPoint> grid;
3988 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3989 draw_measures (grid);
3997 Editor::toggle_follow_playhead ()
3999 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4001 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4002 set_follow_playhead (tact->get_active());
4006 /** @param yn true to follow playhead, otherwise false.
4007 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4010 Editor::set_follow_playhead (bool yn, bool catch_up)
4012 if (_follow_playhead != yn) {
4013 if ((_follow_playhead = yn) == true && catch_up) {
4015 reset_x_origin_to_follow_playhead ();
4022 Editor::toggle_stationary_playhead ()
4024 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4026 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4027 set_stationary_playhead (tact->get_active());
4032 Editor::set_stationary_playhead (bool yn)
4034 if (_stationary_playhead != yn) {
4035 if ((_stationary_playhead = yn) == true) {
4037 // FIXME need a 3.0 equivalent of this 2.X call
4038 // update_current_screen ();
4045 Editor::playlist_selector () const
4047 return *_playlist_selector;
4051 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4053 if (paste_count == 0) {
4054 /* don't bother calculating an offset that will be zero anyway */
4058 /* calculate basic unsnapped multi-paste offset */
4059 framecnt_t offset = paste_count * duration;
4061 /* snap offset so pos + offset is aligned to the grid */
4062 MusicFrame offset_pos (pos + offset, 0);
4063 snap_to(offset_pos, RoundUpMaybe);
4064 offset = offset_pos.frame - pos;
4070 Editor::get_grid_beat_divisions(framepos_t position)
4072 switch (_snap_type) {
4073 case SnapToBeatDiv128: return 128;
4074 case SnapToBeatDiv64: return 64;
4075 case SnapToBeatDiv32: return 32;
4076 case SnapToBeatDiv28: return 28;
4077 case SnapToBeatDiv24: return 24;
4078 case SnapToBeatDiv20: return 20;
4079 case SnapToBeatDiv16: return 16;
4080 case SnapToBeatDiv14: return 14;
4081 case SnapToBeatDiv12: return 12;
4082 case SnapToBeatDiv10: return 10;
4083 case SnapToBeatDiv8: return 8;
4084 case SnapToBeatDiv7: return 7;
4085 case SnapToBeatDiv6: return 6;
4086 case SnapToBeatDiv5: return 5;
4087 case SnapToBeatDiv4: return 4;
4088 case SnapToBeatDiv3: return 3;
4089 case SnapToBeatDiv2: return 2;
4095 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4096 if the grid is non-musical, returns 0.
4097 if the grid is snapped to bars, returns -1.
4098 @param event_state the current keyboard modifier mask.
4101 Editor::get_grid_music_divisions (uint32_t event_state)
4103 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4107 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4111 switch (_snap_type) {
4112 case SnapToBeatDiv128: return 128;
4113 case SnapToBeatDiv64: return 64;
4114 case SnapToBeatDiv32: return 32;
4115 case SnapToBeatDiv28: return 28;
4116 case SnapToBeatDiv24: return 24;
4117 case SnapToBeatDiv20: return 20;
4118 case SnapToBeatDiv16: return 16;
4119 case SnapToBeatDiv14: return 14;
4120 case SnapToBeatDiv12: return 12;
4121 case SnapToBeatDiv10: return 10;
4122 case SnapToBeatDiv8: return 8;
4123 case SnapToBeatDiv7: return 7;
4124 case SnapToBeatDiv6: return 6;
4125 case SnapToBeatDiv5: return 5;
4126 case SnapToBeatDiv4: return 4;
4127 case SnapToBeatDiv3: return 3;
4128 case SnapToBeatDiv2: return 2;
4129 case SnapToBeat: return 1;
4130 case SnapToBar : return -1;
4137 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4141 const unsigned divisions = get_grid_beat_divisions(position);
4143 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4146 switch (_snap_type) {
4148 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4151 const Meter& m = _session->tempo_map().meter_at_frame (position);
4152 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4160 return Evoral::Beats();
4164 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4168 ret = nudge_clock->current_duration (pos);
4169 next = ret + 1; /* XXXX fix me */
4175 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4177 ArdourDialog dialog (_("Playlist Deletion"));
4178 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4179 "If it is kept, its audio files will not be cleaned.\n"
4180 "If it is deleted, audio files used by it alone will be cleaned."),
4183 dialog.set_position (WIN_POS_CENTER);
4184 dialog.get_vbox()->pack_start (label);
4188 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4189 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4190 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4191 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4192 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4194 // by default gtk uses the left most button
4195 keep->grab_focus ();
4197 switch (dialog.run ()) {
4199 /* keep this and all remaining ones */
4204 /* delete this and all others */
4208 case RESPONSE_ACCEPT:
4209 /* delete the playlist */
4213 case RESPONSE_REJECT:
4214 /* keep the playlist */
4226 Editor::audio_region_selection_covers (framepos_t where)
4228 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4229 if ((*a)->region()->covers (where)) {
4238 Editor::prepare_for_cleanup ()
4240 cut_buffer->clear_regions ();
4241 cut_buffer->clear_playlists ();
4243 selection->clear_regions ();
4244 selection->clear_playlists ();
4246 _regions->suspend_redisplay ();
4250 Editor::finish_cleanup ()
4252 _regions->resume_redisplay ();
4256 Editor::transport_loop_location()
4259 return _session->locations()->auto_loop_location();
4266 Editor::transport_punch_location()
4269 return _session->locations()->auto_punch_location();
4276 Editor::control_layout_scroll (GdkEventScroll* ev)
4278 /* Just forward to the normal canvas scroll method. The coordinate
4279 systems are different but since the canvas is always larger than the
4280 track headers, and aligned with the trackview area, this will work.
4282 In the not too distant future this layout is going away anyway and
4283 headers will be on the canvas.
4285 return canvas_scroll_event (ev, false);
4289 Editor::session_state_saved (string)
4292 _snapshots->redisplay ();
4296 Editor::maximise_editing_space ()
4302 Gtk::Window* toplevel = current_toplevel();
4305 toplevel->fullscreen ();
4311 Editor::restore_editing_space ()
4317 Gtk::Window* toplevel = current_toplevel();
4320 toplevel->unfullscreen();
4326 * Make new playlists for a given track and also any others that belong
4327 * to the same active route group with the `select' property.
4332 Editor::new_playlists (TimeAxisView* v)
4334 begin_reversible_command (_("new playlists"));
4335 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4336 _session->playlists->get (playlists);
4337 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4338 commit_reversible_command ();
4342 * Use a copy of the current playlist for a given track and also any others that belong
4343 * to the same active route group with the `select' property.
4348 Editor::copy_playlists (TimeAxisView* v)
4350 begin_reversible_command (_("copy playlists"));
4351 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4352 _session->playlists->get (playlists);
4353 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4354 commit_reversible_command ();
4357 /** Clear the current playlist for a given track and also any others that belong
4358 * to the same active route group with the `select' property.
4363 Editor::clear_playlists (TimeAxisView* v)
4365 begin_reversible_command (_("clear playlists"));
4366 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4367 _session->playlists->get (playlists);
4368 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4369 commit_reversible_command ();
4373 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4375 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4379 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4381 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4385 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4387 atv.clear_playlist ();
4391 Editor::get_y_origin () const
4393 return vertical_adjustment.get_value ();
4396 /** Queue up a change to the viewport x origin.
4397 * @param frame New x origin.
4400 Editor::reset_x_origin (framepos_t frame)
4402 pending_visual_change.add (VisualChange::TimeOrigin);
4403 pending_visual_change.time_origin = frame;
4404 ensure_visual_change_idle_handler ();
4408 Editor::reset_y_origin (double y)
4410 pending_visual_change.add (VisualChange::YOrigin);
4411 pending_visual_change.y_origin = y;
4412 ensure_visual_change_idle_handler ();
4416 Editor::reset_zoom (framecnt_t spp)
4418 if (spp == samples_per_pixel) {
4422 pending_visual_change.add (VisualChange::ZoomLevel);
4423 pending_visual_change.samples_per_pixel = spp;
4424 ensure_visual_change_idle_handler ();
4428 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4430 reset_x_origin (frame);
4433 if (!no_save_visual) {
4434 undo_visual_stack.push_back (current_visual_state(false));
4438 Editor::VisualState::VisualState (bool with_tracks)
4439 : gui_state (with_tracks ? new GUIObjectState : 0)
4443 Editor::VisualState::~VisualState ()
4448 Editor::VisualState*
4449 Editor::current_visual_state (bool with_tracks)
4451 VisualState* vs = new VisualState (with_tracks);
4452 vs->y_position = vertical_adjustment.get_value();
4453 vs->samples_per_pixel = samples_per_pixel;
4454 vs->leftmost_frame = leftmost_frame;
4455 vs->zoom_focus = zoom_focus;
4458 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4465 Editor::undo_visual_state ()
4467 if (undo_visual_stack.empty()) {
4471 VisualState* vs = undo_visual_stack.back();
4472 undo_visual_stack.pop_back();
4475 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4478 use_visual_state (*vs);
4483 Editor::redo_visual_state ()
4485 if (redo_visual_stack.empty()) {
4489 VisualState* vs = redo_visual_stack.back();
4490 redo_visual_stack.pop_back();
4492 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4493 // why do we check here?
4494 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4497 use_visual_state (*vs);
4502 Editor::swap_visual_state ()
4504 if (undo_visual_stack.empty()) {
4505 redo_visual_state ();
4507 undo_visual_state ();
4512 Editor::use_visual_state (VisualState& vs)
4514 PBD::Unwinder<bool> nsv (no_save_visual, true);
4515 DisplaySuspender ds;
4517 vertical_adjustment.set_value (vs.y_position);
4519 set_zoom_focus (vs.zoom_focus);
4520 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4523 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4525 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4526 (*i)->clear_property_cache();
4527 (*i)->reset_visual_state ();
4531 _routes->update_visibility ();
4534 /** This is the core function that controls the zoom level of the canvas. It is called
4535 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4536 * @param spp new number of samples per pixel
4539 Editor::set_samples_per_pixel (framecnt_t spp)
4545 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4546 const framecnt_t lots_of_pixels = 4000;
4548 /* if the zoom level is greater than what you'd get trying to display 3
4549 * days of audio on a really big screen, then it's too big.
4552 if (spp * lots_of_pixels > three_days) {
4556 samples_per_pixel = spp;
4559 tempo_lines->tempo_map_changed();
4562 bool const showing_time_selection = selection->time.length() > 0;
4564 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4565 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4566 (*i)->reshow_selection (selection->time);
4570 ZoomChanged (); /* EMIT_SIGNAL */
4572 ArdourCanvas::GtkCanvasViewport* c;
4574 c = get_track_canvas();
4576 c->canvas()->zoomed ();
4579 if (playhead_cursor) {
4580 playhead_cursor->set_position (playhead_cursor->current_frame ());
4583 refresh_location_display();
4584 _summary->set_overlays_dirty ();
4586 update_marker_labels ();
4592 Editor::playhead_cursor_sample () const
4594 return playhead_cursor->current_frame();
4598 Editor::queue_visual_videotimeline_update ()
4601 * pending_visual_change.add (VisualChange::VideoTimeline);
4602 * or maybe even more specific: which videotimeline-image
4603 * currently it calls update_video_timeline() to update
4604 * _all outdated_ images on the video-timeline.
4605 * see 'exposeimg()' in video_image_frame.cc
4607 ensure_visual_change_idle_handler ();
4611 Editor::ensure_visual_change_idle_handler ()
4613 if (pending_visual_change.idle_handler_id < 0) {
4614 // see comment in add_to_idle_resize above.
4615 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4616 pending_visual_change.being_handled = false;
4621 Editor::_idle_visual_changer (void* arg)
4623 return static_cast<Editor*>(arg)->idle_visual_changer ();
4627 Editor::idle_visual_changer ()
4629 /* set_horizontal_position() below (and maybe other calls) call
4630 gtk_main_iteration(), so it's possible that a signal will be handled
4631 half-way through this method. If this signal wants an
4632 idle_visual_changer we must schedule another one after this one, so
4633 mark the idle_handler_id as -1 here to allow that. Also make a note
4634 that we are doing the visual change, so that changes in response to
4635 super-rapid-screen-update can be dropped if we are still processing
4639 pending_visual_change.idle_handler_id = -1;
4640 pending_visual_change.being_handled = true;
4642 VisualChange vc = pending_visual_change;
4644 pending_visual_change.pending = (VisualChange::Type) 0;
4646 visual_changer (vc);
4648 pending_visual_change.being_handled = false;
4650 return 0; /* this is always a one-shot call */
4654 Editor::visual_changer (const VisualChange& vc)
4656 double const last_time_origin = horizontal_position ();
4658 if (vc.pending & VisualChange::ZoomLevel) {
4659 set_samples_per_pixel (vc.samples_per_pixel);
4661 compute_fixed_ruler_scale ();
4663 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4664 update_tempo_based_rulers ();
4666 update_video_timeline();
4669 if (vc.pending & VisualChange::TimeOrigin) {
4670 set_horizontal_position (vc.time_origin / samples_per_pixel);
4673 if (vc.pending & VisualChange::YOrigin) {
4674 vertical_adjustment.set_value (vc.y_origin);
4677 if (last_time_origin == horizontal_position ()) {
4678 /* changed signal not emitted */
4679 update_fixed_rulers ();
4680 redisplay_tempo (true);
4683 if (!(vc.pending & VisualChange::ZoomLevel)) {
4684 update_video_timeline();
4687 _summary->set_overlays_dirty ();
4690 struct EditorOrderTimeAxisSorter {
4691 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4692 return a->order () < b->order ();
4697 Editor::sort_track_selection (TrackViewList& sel)
4699 EditorOrderTimeAxisSorter cmp;
4704 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4707 framepos_t where = 0;
4708 EditPoint ep = _edit_point;
4710 if (Profile->get_mixbus()) {
4711 if (ep == EditAtSelectedMarker) {
4712 ep = EditAtPlayhead;
4716 if (from_outside_canvas && (ep == EditAtMouse)) {
4717 ep = EditAtPlayhead;
4718 } else if (from_context_menu && (ep == EditAtMouse)) {
4719 return canvas_event_sample (&context_click_event, 0, 0);
4722 if (entered_marker) {
4723 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4724 return entered_marker->position();
4727 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4728 ep = EditAtSelectedMarker;
4731 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4732 ep = EditAtPlayhead;
4735 MusicFrame snap_mf (0, 0);
4738 case EditAtPlayhead:
4739 if (_dragging_playhead) {
4740 where = *_control_scroll_target;
4742 where = _session->audible_frame();
4744 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4747 case EditAtSelectedMarker:
4748 if (!selection->markers.empty()) {
4750 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4753 where = loc->start();
4757 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4765 if (!mouse_frame (where, ignored)) {
4766 /* XXX not right but what can we do ? */
4769 snap_mf.frame = where;
4771 where = snap_mf.frame;
4772 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4780 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4782 if (!_session) return;
4784 begin_reversible_command (cmd);
4788 if ((tll = transport_loop_location()) == 0) {
4789 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4790 XMLNode &before = _session->locations()->get_state();
4791 _session->locations()->add (loc, true);
4792 _session->set_auto_loop_location (loc);
4793 XMLNode &after = _session->locations()->get_state();
4794 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4796 XMLNode &before = tll->get_state();
4797 tll->set_hidden (false, this);
4798 tll->set (start, end);
4799 XMLNode &after = tll->get_state();
4800 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4803 commit_reversible_command ();
4807 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4809 if (!_session) return;
4811 begin_reversible_command (cmd);
4815 if ((tpl = transport_punch_location()) == 0) {
4816 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4817 XMLNode &before = _session->locations()->get_state();
4818 _session->locations()->add (loc, true);
4819 _session->set_auto_punch_location (loc);
4820 XMLNode &after = _session->locations()->get_state();
4821 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4823 XMLNode &before = tpl->get_state();
4824 tpl->set_hidden (false, this);
4825 tpl->set (start, end);
4826 XMLNode &after = tpl->get_state();
4827 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4830 commit_reversible_command ();
4833 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4834 * @param rs List to which found regions are added.
4835 * @param where Time to look at.
4836 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4839 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4841 const TrackViewList* tracks;
4844 tracks = &track_views;
4849 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4851 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4854 boost::shared_ptr<Track> tr;
4855 boost::shared_ptr<Playlist> pl;
4857 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4859 boost::shared_ptr<RegionList> regions = pl->regions_at (
4860 (framepos_t) floor ( (double) where * tr->speed()));
4862 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4863 RegionView* rv = rtv->view()->find_view (*i);
4874 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4876 const TrackViewList* tracks;
4879 tracks = &track_views;
4884 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4885 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4887 boost::shared_ptr<Track> tr;
4888 boost::shared_ptr<Playlist> pl;
4890 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4892 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4893 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4895 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4897 RegionView* rv = rtv->view()->find_view (*i);
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, and edit_point == mouse, 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
4921 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4923 RegionSelection regions;
4925 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4926 regions.add (entered_regionview);
4928 regions = selection->regions;
4931 if ( regions.empty() ) {
4932 TrackViewList tracks = selection->tracks;
4934 if (!tracks.empty()) {
4935 /* no region selected or entered, but some selected tracks:
4936 * act on all regions on the selected tracks at the edit point
4938 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4939 get_regions_at(regions, where, tracks);
4946 /** Get regions using the following method:
4948 * Make a region list using:
4949 * (a) any selected regions
4950 * (b) the intersection of any selected tracks and the edit point(*)
4951 * (c) if neither exists, then whatever region is under the mouse
4953 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4955 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4958 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4960 RegionSelection regions;
4962 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4963 regions.add (entered_regionview);
4965 regions = selection->regions;
4968 if ( regions.empty() ) {
4969 TrackViewList tracks = selection->tracks;
4971 if (!tracks.empty()) {
4972 /* no region selected or entered, but some selected tracks:
4973 * act on all regions on the selected tracks at the edit point
4975 get_regions_at(regions, pos, tracks);
4982 /** Start with regions that are selected, or the entered regionview if none are selected.
4983 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4984 * of the regions that we started with.
4988 Editor::get_regions_from_selection_and_entered () const
4990 RegionSelection regions = selection->regions;
4992 if (regions.empty() && entered_regionview) {
4993 regions.add (entered_regionview);
5000 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5002 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5003 RouteTimeAxisView* rtav;
5005 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5006 boost::shared_ptr<Playlist> pl;
5007 std::vector<boost::shared_ptr<Region> > results;
5008 boost::shared_ptr<Track> tr;
5010 if ((tr = rtav->track()) == 0) {
5015 if ((pl = (tr->playlist())) != 0) {
5016 boost::shared_ptr<Region> r = pl->region_by_id (id);
5018 RegionView* rv = rtav->view()->find_view (r);
5020 regions.push_back (rv);
5029 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5032 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5033 MidiTimeAxisView* mtav;
5035 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5037 mtav->get_per_region_note_selection (selection);
5044 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5046 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5048 RouteTimeAxisView* tatv;
5050 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5052 boost::shared_ptr<Playlist> pl;
5053 vector<boost::shared_ptr<Region> > results;
5055 boost::shared_ptr<Track> tr;
5057 if ((tr = tatv->track()) == 0) {
5062 if ((pl = (tr->playlist())) != 0) {
5063 if (src_comparison) {
5064 pl->get_source_equivalent_regions (region, results);
5066 pl->get_region_list_equivalent_regions (region, results);
5070 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5071 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5072 regions.push_back (marv);
5081 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5083 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5084 RouteTimeAxisView* tatv;
5085 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5086 if (!tatv->track()) {
5089 RegionView* marv = tatv->view()->find_view (region);
5099 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5101 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5102 RouteTimeAxisView* rtav;
5103 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5104 if (rtav->route() == route) {
5113 Editor::show_rhythm_ferret ()
5115 if (rhythm_ferret == 0) {
5116 rhythm_ferret = new RhythmFerret(*this);
5119 rhythm_ferret->set_session (_session);
5120 rhythm_ferret->show ();
5121 rhythm_ferret->present ();
5125 Editor::first_idle ()
5127 MessageDialog* dialog = 0;
5129 if (track_views.size() > 1) {
5130 Timers::TimerSuspender t;
5131 dialog = new MessageDialog (
5132 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5136 ARDOUR_UI::instance()->flush_pending (60);
5139 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5143 // first idle adds route children (automation tracks), so we need to redisplay here
5144 _routes->redisplay ();
5148 if (_session->undo_depth() == 0) {
5149 undo_action->set_sensitive(false);
5151 redo_action->set_sensitive(false);
5152 begin_selection_op_history ();
5158 Editor::_idle_resize (gpointer arg)
5160 return ((Editor*)arg)->idle_resize ();
5164 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5166 if (resize_idle_id < 0) {
5167 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5168 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5169 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5171 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5172 _pending_resize_amount = 0;
5175 /* make a note of the smallest resulting height, so that we can clamp the
5176 lower limit at TimeAxisView::hSmall */
5178 int32_t min_resulting = INT32_MAX;
5180 _pending_resize_amount += h;
5181 _pending_resize_view = view;
5183 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5185 if (selection->tracks.contains (_pending_resize_view)) {
5186 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5187 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5191 if (min_resulting < 0) {
5196 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5197 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5201 /** Handle pending resizing of tracks */
5203 Editor::idle_resize ()
5205 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5207 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5208 selection->tracks.contains (_pending_resize_view)) {
5210 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5211 if (*i != _pending_resize_view) {
5212 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5217 _pending_resize_amount = 0;
5218 _group_tabs->set_dirty ();
5219 resize_idle_id = -1;
5227 ENSURE_GUI_THREAD (*this, &Editor::located);
5230 playhead_cursor->set_position (_session->audible_frame ());
5231 if (_follow_playhead && !_pending_initial_locate) {
5232 reset_x_origin_to_follow_playhead ();
5236 _pending_locate_request = false;
5237 _pending_initial_locate = false;
5241 Editor::region_view_added (RegionView * rv)
5243 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5244 if (rv->region ()->id () == (*pr)) {
5245 selection->add (rv);
5246 selection->regions.pending.erase (pr);
5251 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5253 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5254 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5255 if (rv->region()->id () == (*rnote).first) {
5256 mrv->select_notes ((*rnote).second);
5257 selection->pending_midi_note_selection.erase(rnote);
5263 _summary->set_background_dirty ();
5267 Editor::region_view_removed ()
5269 _summary->set_background_dirty ();
5273 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5275 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5276 if ((*j)->stripable() == s) {
5286 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5290 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5291 TimeAxisView* tv = axis_view_from_stripable (*i);
5301 Editor::suspend_route_redisplay ()
5304 _routes->suspend_redisplay();
5309 Editor::resume_route_redisplay ()
5312 _routes->redisplay(); // queue redisplay
5313 _routes->resume_redisplay();
5318 Editor::add_vcas (VCAList& vlist)
5322 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5323 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5326 add_stripables (sl);
5330 Editor::add_routes (RouteList& rlist)
5334 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5338 add_stripables (sl);
5342 Editor::add_stripables (StripableList& sl)
5344 list<TimeAxisView*> new_views;
5345 boost::shared_ptr<VCA> v;
5346 boost::shared_ptr<Route> r;
5347 TrackViewList new_selection;
5348 bool from_scratch = (track_views.size() == 0);
5350 sl.sort (StripablePresentationInfoSorter());
5352 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5354 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5356 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5358 new_views.push_back (vtv);
5360 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5362 if (r->is_auditioner() || r->is_monitor()) {
5366 RouteTimeAxisView* rtv;
5367 DataType dt = r->input()->default_type();
5369 if (dt == ARDOUR::DataType::AUDIO) {
5370 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5372 } else if (dt == ARDOUR::DataType::MIDI) {
5373 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5376 throw unknown_type();
5379 new_views.push_back (rtv);
5380 track_views.push_back (rtv);
5381 new_selection.push_back (rtv);
5383 rtv->effective_gain_display ();
5385 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5386 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5390 if (new_views.size() > 0) {
5391 _routes->time_axis_views_added (new_views);
5392 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5395 /* note: !new_selection.empty() means that we got some routes rather
5399 if (!from_scratch && !new_selection.empty()) {
5400 selection->tracks.clear();
5401 selection->add (new_selection);
5402 begin_selection_op_history();
5405 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5406 show_editor_mixer (true);
5409 editor_list_button.set_sensitive (true);
5413 Editor::timeaxisview_deleted (TimeAxisView *tv)
5415 if (tv == entered_track) {
5419 if (_session && _session->deletion_in_progress()) {
5420 /* the situation is under control */
5424 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5426 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5428 _routes->route_removed (tv);
5430 TimeAxisView::Children c = tv->get_child_list ();
5431 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5432 if (entered_track == i->get()) {
5437 /* remove it from the list of track views */
5439 TrackViewList::iterator i;
5441 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5442 i = track_views.erase (i);
5445 /* update whatever the current mixer strip is displaying, if revelant */
5447 boost::shared_ptr<Route> route;
5450 route = rtav->route ();
5453 if (current_mixer_strip && current_mixer_strip->route() == route) {
5455 TimeAxisView* next_tv;
5457 if (track_views.empty()) {
5459 } else if (i == track_views.end()) {
5460 next_tv = track_views.front();
5465 // skip VCAs (cannot be selected, n/a in editor-mixer)
5466 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5467 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5468 next_tv = track_views.front();
5470 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5471 /* just in case: no master, only a VCA remains */
5477 set_selected_mixer_strip (*next_tv);
5479 /* make the editor mixer strip go away setting the
5480 * button to inactive (which also unticks the menu option)
5483 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5489 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5494 if (apply_to_selection) {
5495 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5497 TrackSelection::iterator j = i;
5500 hide_track_in_display (*i, false);
5505 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5507 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5508 // this will hide the mixer strip
5509 set_selected_mixer_strip (*tv);
5512 _routes->hide_track_in_display (*tv);
5517 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5522 _routes->show_track_in_display (*tv);
5523 if (move_into_view) {
5524 ensure_time_axis_view_is_visible (*tv, false);
5529 Editor::sync_track_view_list_and_routes ()
5531 track_views = TrackViewList (_routes->views ());
5533 _summary->set_background_dirty();
5534 _group_tabs->set_dirty ();
5536 return false; // do not call again (until needed)
5540 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5542 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5547 /** Find a RouteTimeAxisView by the ID of its route */
5549 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5551 RouteTimeAxisView* v;
5553 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5554 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5555 if(v->route()->id() == id) {
5565 Editor::fit_route_group (RouteGroup *g)
5567 TrackViewList ts = axis_views_from_routes (g->route_list ());
5572 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5574 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5577 _session->cancel_audition ();
5581 if (_session->is_auditioning()) {
5582 _session->cancel_audition ();
5583 if (r == last_audition_region) {
5588 _session->audition_region (r);
5589 last_audition_region = r;
5594 Editor::hide_a_region (boost::shared_ptr<Region> r)
5596 r->set_hidden (true);
5600 Editor::show_a_region (boost::shared_ptr<Region> r)
5602 r->set_hidden (false);
5606 Editor::audition_region_from_region_list ()
5608 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5612 Editor::hide_region_from_region_list ()
5614 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5618 Editor::show_region_in_region_list ()
5620 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5624 Editor::step_edit_status_change (bool yn)
5627 start_step_editing ();
5629 stop_step_editing ();
5634 Editor::start_step_editing ()
5636 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5640 Editor::stop_step_editing ()
5642 step_edit_connection.disconnect ();
5646 Editor::check_step_edit ()
5648 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5649 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5651 mtv->check_step_edit ();
5655 return true; // do it again, till we stop
5659 Editor::scroll_press (Direction dir)
5661 ++_scroll_callbacks;
5663 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5664 /* delay the first auto-repeat */
5670 scroll_backward (1);
5678 scroll_up_one_track ();
5682 scroll_down_one_track ();
5686 /* do hacky auto-repeat */
5687 if (!_scroll_connection.connected ()) {
5689 _scroll_connection = Glib::signal_timeout().connect (
5690 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5693 _scroll_callbacks = 0;
5700 Editor::scroll_release ()
5702 _scroll_connection.disconnect ();
5705 /** Queue a change for the Editor viewport x origin to follow the playhead */
5707 Editor::reset_x_origin_to_follow_playhead ()
5709 framepos_t const frame = playhead_cursor->current_frame ();
5711 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5713 if (_session->transport_speed() < 0) {
5715 if (frame > (current_page_samples() / 2)) {
5716 center_screen (frame-(current_page_samples()/2));
5718 center_screen (current_page_samples()/2);
5725 if (frame < leftmost_frame) {
5727 if (_session->transport_rolling()) {
5728 /* rolling; end up with the playhead at the right of the page */
5729 l = frame - current_page_samples ();
5731 /* not rolling: end up with the playhead 1/4 of the way along the page */
5732 l = frame - current_page_samples() / 4;
5736 if (_session->transport_rolling()) {
5737 /* rolling: end up with the playhead on the left of the page */
5740 /* not rolling: end up with the playhead 3/4 of the way along the page */
5741 l = frame - 3 * current_page_samples() / 4;
5749 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5755 Editor::super_rapid_screen_update ()
5757 if (!_session || !_session->engine().running()) {
5761 /* METERING / MIXER STRIPS */
5763 /* update track meters, if required */
5764 if (contents().is_mapped() && meters_running) {
5765 RouteTimeAxisView* rtv;
5766 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5767 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5768 rtv->fast_update ();
5773 /* and any current mixer strip */
5774 if (current_mixer_strip) {
5775 current_mixer_strip->fast_update ();
5778 /* PLAYHEAD AND VIEWPORT */
5780 framepos_t const frame = _session->audible_frame();
5782 /* There are a few reasons why we might not update the playhead / viewport stuff:
5784 * 1. we don't update things when there's a pending locate request, otherwise
5785 * when the editor requests a locate there is a chance that this method
5786 * will move the playhead before the locate request is processed, causing
5788 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5789 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5792 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5794 last_update_frame = frame;
5796 if (!_dragging_playhead) {
5797 playhead_cursor->set_position (frame);
5800 if (!_stationary_playhead) {
5802 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5803 /* We only do this if we aren't already
5804 handling a visual change (ie if
5805 pending_visual_change.being_handled is
5806 false) so that these requests don't stack
5807 up there are too many of them to handle in
5810 reset_x_origin_to_follow_playhead ();
5815 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5816 framepos_t const frame = playhead_cursor->current_frame ();
5817 double target = ((double)frame - (double)current_page_samples()/2.0);
5818 if (target <= 0.0) {
5821 // compare to EditorCursor::set_position()
5822 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5823 double const new_pos = sample_to_pixel_unrounded (target);
5824 if (rint (new_pos) != rint (old_pos)) {
5825 reset_x_origin (pixel_to_sample (floor (new_pos)));
5836 Editor::session_going_away ()
5838 _have_idled = false;
5840 _session_connections.drop_connections ();
5842 super_rapid_screen_update_connection.disconnect ();
5844 selection->clear ();
5845 cut_buffer->clear ();
5847 clicked_regionview = 0;
5848 clicked_axisview = 0;
5849 clicked_routeview = 0;
5850 entered_regionview = 0;
5852 last_update_frame = 0;
5855 playhead_cursor->hide ();
5857 /* rip everything out of the list displays */
5861 _route_groups->clear ();
5863 /* do this first so that deleting a track doesn't reset cms to null
5864 and thus cause a leak.
5867 if (current_mixer_strip) {
5868 if (current_mixer_strip->get_parent() != 0) {
5869 global_hpacker.remove (*current_mixer_strip);
5871 delete current_mixer_strip;
5872 current_mixer_strip = 0;
5875 /* delete all trackviews */
5877 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5880 track_views.clear ();
5882 nudge_clock->set_session (0);
5884 editor_list_button.set_active(false);
5885 editor_list_button.set_sensitive(false);
5887 /* clear tempo/meter rulers */
5888 remove_metric_marks ();
5890 clear_marker_display ();
5892 stop_step_editing ();
5896 /* get rid of any existing editor mixer strip */
5898 WindowTitle title(Glib::get_application_name());
5899 title += _("Editor");
5901 own_window()->set_title (title.get_string());
5904 SessionHandlePtr::session_going_away ();
5908 Editor::trigger_script (int i)
5910 LuaInstance::instance()-> call_action (i);
5914 Editor::show_editor_list (bool yn)
5917 _editor_list_vbox.show ();
5919 _editor_list_vbox.hide ();
5924 Editor::change_region_layering_order (bool from_context_menu)
5926 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5928 if (!clicked_routeview) {
5929 if (layering_order_editor) {
5930 layering_order_editor->hide ();
5935 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5941 boost::shared_ptr<Playlist> pl = track->playlist();
5947 if (layering_order_editor == 0) {
5948 layering_order_editor = new RegionLayeringOrderEditor (*this);
5951 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5952 layering_order_editor->maybe_present ();
5956 Editor::update_region_layering_order_editor ()
5958 if (layering_order_editor && layering_order_editor->is_visible ()) {
5959 change_region_layering_order (true);
5964 Editor::setup_fade_images ()
5966 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5967 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5968 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5969 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5970 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5972 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5973 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5974 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5975 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5976 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5980 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5982 Editor::action_menu_item (std::string const & name)
5984 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5987 return *manage (a->create_menu_item ());
5991 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5993 EventBox* b = manage (new EventBox);
5994 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5995 Label* l = manage (new Label (name));
5999 _the_notebook.append_page (widget, *b);
6003 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6005 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6006 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6009 if (ev->type == GDK_2BUTTON_PRESS) {
6011 /* double-click on a notebook tab shrinks or expands the notebook */
6013 if (_notebook_shrunk) {
6014 if (pre_notebook_shrink_pane_width) {
6015 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6017 _notebook_shrunk = false;
6019 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6021 /* this expands the LHS of the edit pane to cover the notebook
6022 PAGE but leaves the tabs visible.
6024 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6025 _notebook_shrunk = true;
6033 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6035 using namespace Menu_Helpers;
6037 MenuList& items = _control_point_context_menu.items ();
6040 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6041 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6042 if (!can_remove_control_point (item)) {
6043 items.back().set_sensitive (false);
6046 _control_point_context_menu.popup (event->button.button, event->button.time);
6050 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6052 using namespace Menu_Helpers;
6054 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6059 /* We need to get the selection here and pass it to the operations, since
6060 popping up the menu will cause a region leave event which clears
6061 entered_regionview. */
6063 MidiRegionView& mrv = note->region_view();
6064 const RegionSelection rs = get_regions_from_selection_and_entered ();
6065 const uint32_t sel_size = mrv.selection_size ();
6067 MenuList& items = _note_context_menu.items();
6071 items.push_back(MenuElem(_("Delete"),
6072 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6075 items.push_back(MenuElem(_("Edit..."),
6076 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6077 if (sel_size != 1) {
6078 items.back().set_sensitive (false);
6081 items.push_back(MenuElem(_("Transpose..."),
6082 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6085 items.push_back(MenuElem(_("Legatize"),
6086 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6088 items.back().set_sensitive (false);
6091 items.push_back(MenuElem(_("Quantize..."),
6092 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6094 items.push_back(MenuElem(_("Remove Overlap"),
6095 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6097 items.back().set_sensitive (false);
6100 items.push_back(MenuElem(_("Transform..."),
6101 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6103 _note_context_menu.popup (event->button.button, event->button.time);
6107 Editor::zoom_vertical_modifier_released()
6109 _stepping_axis_view = 0;
6113 Editor::ui_parameter_changed (string parameter)
6115 if (parameter == "icon-set") {
6116 while (!_cursor_stack.empty()) {
6117 _cursor_stack.pop_back();
6119 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6120 _cursor_stack.push_back(_cursors->grabber);
6121 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6122 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6124 } else if (parameter == "draggable-playhead") {
6125 if (_verbose_cursor) {
6126 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6132 Editor::use_own_window (bool and_fill_it)
6134 bool new_window = !own_window();
6136 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6138 if (win && new_window) {
6139 win->set_name ("EditorWindow");
6141 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6143 // win->signal_realize().connect (*this, &Editor::on_realize);
6144 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6145 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6146 win->set_data ("ardour-bindings", bindings);
6151 DisplaySuspender ds;
6152 contents().show_all ();
6154 /* XXX: this is a bit unfortunate; it would probably
6155 be nicer if we could just call show () above rather
6156 than needing the show_all ()
6159 /* re-hide stuff if necessary */
6160 editor_list_button_toggled ();
6161 parameter_changed ("show-summary");
6162 parameter_changed ("show-group-tabs");
6163 parameter_changed ("show-zoom-tools");
6165 /* now reset all audio_time_axis heights, because widgets might need
6171 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6172 tv = (static_cast<TimeAxisView*>(*i));
6173 tv->reset_height ();
6176 if (current_mixer_strip) {
6177 current_mixer_strip->hide_things ();
6178 current_mixer_strip->parameter_changed ("mixer-element-visibility");