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());
831 PresentationInfo::Change.connect (*this, invalidator (*this), boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
835 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
837 /* problematic: has to return a value and thus cannot be x-thread */
839 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
841 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
842 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
844 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
846 _ignore_region_action = false;
847 _last_region_menu_was_main = false;
848 _popup_region_menu_item = 0;
850 _show_marker_lines = false;
852 /* Button bindings */
854 button_bindings = new Bindings ("editor-mouse");
856 XMLNode* node = button_settings();
858 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
859 button_bindings->load_operation (**i);
865 /* grab current parameter state */
866 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
867 UIConfiguration::instance().map_parameters (pc);
869 setup_fade_images ();
876 delete button_bindings;
878 delete _route_groups;
879 delete _track_canvas_viewport;
882 delete _verbose_cursor;
883 delete quantize_dialog;
889 delete _playlist_selector;
890 delete _time_info_box;
895 LuaInstance::destroy_instance ();
897 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
900 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
903 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
909 Editor::presentation_info_changed (PropertyChange const & what_changed)
911 if (what_changed.contains (Properties::selected)) {
912 track_selection_changed ();
917 Editor::button_settings () const
919 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
920 XMLNode* node = find_named_node (*settings, X_("Buttons"));
923 node = new XMLNode (X_("Buttons"));
930 Editor::get_smart_mode () const
932 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
936 Editor::catch_vanishing_regionview (RegionView *rv)
938 /* note: the selection will take care of the vanishing
939 audioregionview by itself.
942 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
946 if (clicked_regionview == rv) {
947 clicked_regionview = 0;
950 if (entered_regionview == rv) {
951 set_entered_regionview (0);
954 if (!_all_region_actions_sensitized) {
955 sensitize_all_region_actions (true);
960 Editor::set_entered_regionview (RegionView* rv)
962 if (rv == entered_regionview) {
966 if (entered_regionview) {
967 entered_regionview->exited ();
970 entered_regionview = rv;
972 if (entered_regionview != 0) {
973 entered_regionview->entered ();
976 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
977 /* This RegionView entry might have changed what region actions
978 are allowed, so sensitize them all in case a key is pressed.
980 sensitize_all_region_actions (true);
985 Editor::set_entered_track (TimeAxisView* tav)
988 entered_track->exited ();
994 entered_track->entered ();
999 Editor::instant_save ()
1001 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
1006 _session->add_instant_xml(get_state());
1008 Config->add_instant_xml(get_state());
1013 Editor::control_vertical_zoom_in_all ()
1015 tav_zoom_smooth (false, true);
1019 Editor::control_vertical_zoom_out_all ()
1021 tav_zoom_smooth (true, true);
1025 Editor::control_vertical_zoom_in_selected ()
1027 tav_zoom_smooth (false, false);
1031 Editor::control_vertical_zoom_out_selected ()
1033 tav_zoom_smooth (true, false);
1037 Editor::control_view (uint32_t view)
1039 goto_visual_state (view);
1043 Editor::control_unselect ()
1045 selection->clear_tracks ();
1049 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1051 TimeAxisView* tav = axis_view_from_stripable (s);
1055 case Selection::Add:
1056 selection->add (tav);
1058 case Selection::Toggle:
1059 selection->toggle (tav);
1061 case Selection::Extend:
1063 case Selection::Set:
1064 selection->set (tav);
1068 selection->clear_tracks ();
1073 Editor::control_step_tracks_up ()
1075 scroll_tracks_up_line ();
1079 Editor::control_step_tracks_down ()
1081 scroll_tracks_down_line ();
1085 Editor::control_scroll (float fraction)
1087 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1093 double step = fraction * current_page_samples();
1096 _control_scroll_target is an optional<T>
1098 it acts like a pointer to an framepos_t, with
1099 a operator conversion to boolean to check
1100 that it has a value could possibly use
1101 playhead_cursor->current_frame to store the
1102 value and a boolean in the class to know
1103 when it's out of date
1106 if (!_control_scroll_target) {
1107 _control_scroll_target = _session->transport_frame();
1108 _dragging_playhead = true;
1111 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1112 *_control_scroll_target = 0;
1113 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1114 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1116 *_control_scroll_target += (framepos_t) trunc (step);
1119 /* move visuals, we'll catch up with it later */
1121 playhead_cursor->set_position (*_control_scroll_target);
1122 UpdateAllTransportClocks (*_control_scroll_target);
1124 if (*_control_scroll_target > (current_page_samples() / 2)) {
1125 /* try to center PH in window */
1126 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1132 Now we do a timeout to actually bring the session to the right place
1133 according to the playhead. This is to avoid reading disk buffers on every
1134 call to control_scroll, which is driven by ScrollTimeline and therefore
1135 probably by a control surface wheel which can generate lots of events.
1137 /* cancel the existing timeout */
1139 control_scroll_connection.disconnect ();
1141 /* add the next timeout */
1143 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1147 Editor::deferred_control_scroll (framepos_t /*target*/)
1149 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1150 // reset for next stream
1151 _control_scroll_target = boost::none;
1152 _dragging_playhead = false;
1157 Editor::access_action (std::string action_group, std::string action_item)
1163 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1166 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1174 Editor::on_realize ()
1178 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1179 start_lock_event_timing ();
1184 Editor::start_lock_event_timing ()
1186 /* check if we should lock the GUI every 30 seconds */
1188 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1192 Editor::generic_event_handler (GdkEvent* ev)
1195 case GDK_BUTTON_PRESS:
1196 case GDK_BUTTON_RELEASE:
1197 case GDK_MOTION_NOTIFY:
1199 case GDK_KEY_RELEASE:
1200 if (contents().is_mapped()) {
1201 gettimeofday (&last_event_time, 0);
1205 case GDK_LEAVE_NOTIFY:
1206 switch (ev->crossing.detail) {
1207 case GDK_NOTIFY_UNKNOWN:
1208 case GDK_NOTIFY_INFERIOR:
1209 case GDK_NOTIFY_ANCESTOR:
1211 case GDK_NOTIFY_VIRTUAL:
1212 case GDK_NOTIFY_NONLINEAR:
1213 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1214 /* leaving window, so reset focus, thus ending any and
1215 all text entry operations.
1217 ARDOUR_UI::instance()->reset_focus (&contents());
1230 Editor::lock_timeout_callback ()
1232 struct timeval now, delta;
1234 gettimeofday (&now, 0);
1236 timersub (&now, &last_event_time, &delta);
1238 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1240 /* don't call again. Returning false will effectively
1241 disconnect us from the timer callback.
1243 unlock() will call start_lock_event_timing() to get things
1253 Editor::map_position_change (framepos_t frame)
1255 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1257 if (_session == 0) {
1261 if (_follow_playhead) {
1262 center_screen (frame);
1265 playhead_cursor->set_position (frame);
1269 Editor::center_screen (framepos_t frame)
1271 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1273 /* if we're off the page, then scroll.
1276 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1277 center_screen_internal (frame, page);
1282 Editor::center_screen_internal (framepos_t frame, float page)
1287 frame -= (framepos_t) page;
1292 reset_x_origin (frame);
1297 Editor::update_title ()
1299 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1301 if (!own_window()) {
1306 bool dirty = _session->dirty();
1308 string session_name;
1310 if (_session->snap_name() != _session->name()) {
1311 session_name = _session->snap_name();
1313 session_name = _session->name();
1317 session_name = "*" + session_name;
1320 WindowTitle title(session_name);
1321 title += S_("Window|Editor");
1322 title += Glib::get_application_name();
1323 own_window()->set_title (title.get_string());
1325 /* ::session_going_away() will have taken care of it */
1330 Editor::set_session (Session *t)
1332 SessionHandlePtr::set_session (t);
1338 _playlist_selector->set_session (_session);
1339 nudge_clock->set_session (_session);
1340 _summary->set_session (_session);
1341 _group_tabs->set_session (_session);
1342 _route_groups->set_session (_session);
1343 _regions->set_session (_session);
1344 _snapshots->set_session (_session);
1345 _routes->set_session (_session);
1346 _locations->set_session (_session);
1347 _time_info_box->set_session (_session);
1349 if (rhythm_ferret) {
1350 rhythm_ferret->set_session (_session);
1353 if (analysis_window) {
1354 analysis_window->set_session (_session);
1358 sfbrowser->set_session (_session);
1361 compute_fixed_ruler_scale ();
1363 /* Make sure we have auto loop and auto punch ranges */
1365 Location* loc = _session->locations()->auto_loop_location();
1367 loc->set_name (_("Loop"));
1370 loc = _session->locations()->auto_punch_location();
1373 loc->set_name (_("Punch"));
1376 refresh_location_display ();
1378 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1379 the selected Marker; this needs the LocationMarker list to be available.
1381 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1382 set_state (*node, Stateful::loading_state_version);
1384 /* catch up with the playhead */
1386 _session->request_locate (playhead_cursor->current_frame ());
1387 _pending_initial_locate = true;
1391 /* These signals can all be emitted by a non-GUI thread. Therefore the
1392 handlers for them must not attempt to directly interact with the GUI,
1393 but use PBD::Signal<T>::connect() which accepts an event loop
1394 ("context") where the handler will be asked to run.
1397 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1398 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1399 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1400 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1401 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1402 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1403 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1404 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1405 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1406 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1407 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1408 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1409 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1410 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1411 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1413 playhead_cursor->show ();
1415 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1416 Config->map_parameters (pc);
1417 _session->config.map_parameters (pc);
1419 restore_ruler_visibility ();
1420 //tempo_map_changed (PropertyChange (0));
1421 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1423 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1424 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1427 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1428 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1431 switch (_snap_type) {
1432 case SnapToRegionStart:
1433 case SnapToRegionEnd:
1434 case SnapToRegionSync:
1435 case SnapToRegionBoundary:
1436 build_region_boundary_cache ();
1443 /* catch up on selection of stripables (other selection state is lost
1444 * when a session is closed
1449 _session->get_stripables (sl);
1450 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1451 if ((*s)->presentation_info().selected()) {
1452 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1454 tl.push_back (rtav);
1459 selection->set (tl);
1462 /* register for undo history */
1463 _session->register_with_memento_command_factory(id(), this);
1464 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1466 LuaInstance::instance()->set_session(_session);
1468 start_updating_meters ();
1472 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1474 using namespace Menu_Helpers;
1476 void (Editor::*emf)(FadeShape);
1477 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1480 images = &_xfade_in_images;
1481 emf = &Editor::set_fade_in_shape;
1483 images = &_xfade_out_images;
1484 emf = &Editor::set_fade_out_shape;
1489 _("Linear (for highly correlated material)"),
1490 *(*images)[FadeLinear],
1491 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1495 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 _("Constant power"),
1500 *(*images)[FadeConstantPower],
1501 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1504 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1509 *(*images)[FadeSymmetric],
1510 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1514 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1519 *(*images)[FadeSlow],
1520 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1523 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1528 *(*images)[FadeFast],
1529 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1532 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1535 /** Pop up a context menu for when the user clicks on a start crossfade */
1537 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1539 using namespace Menu_Helpers;
1540 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1545 MenuList& items (xfade_in_context_menu.items());
1548 if (arv->audio_region()->fade_in_active()) {
1549 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1551 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1554 items.push_back (SeparatorElem());
1555 fill_xfade_menu (items, true);
1557 xfade_in_context_menu.popup (button, time);
1560 /** Pop up a context menu for when the user clicks on an end crossfade */
1562 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1564 using namespace Menu_Helpers;
1565 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1570 MenuList& items (xfade_out_context_menu.items());
1573 if (arv->audio_region()->fade_out_active()) {
1574 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1576 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1579 items.push_back (SeparatorElem());
1580 fill_xfade_menu (items, false);
1582 xfade_out_context_menu.popup (button, time);
1586 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1588 using namespace Menu_Helpers;
1589 Menu* (Editor::*build_menu_function)();
1592 switch (item_type) {
1594 case RegionViewName:
1595 case RegionViewNameHighlight:
1596 case LeftFrameHandle:
1597 case RightFrameHandle:
1598 if (with_selection) {
1599 build_menu_function = &Editor::build_track_selection_context_menu;
1601 build_menu_function = &Editor::build_track_region_context_menu;
1606 if (with_selection) {
1607 build_menu_function = &Editor::build_track_selection_context_menu;
1609 build_menu_function = &Editor::build_track_context_menu;
1614 if (clicked_routeview->track()) {
1615 build_menu_function = &Editor::build_track_context_menu;
1617 build_menu_function = &Editor::build_track_bus_context_menu;
1622 /* probably shouldn't happen but if it does, we don't care */
1626 menu = (this->*build_menu_function)();
1627 menu->set_name ("ArdourContextMenu");
1629 /* now handle specific situations */
1631 switch (item_type) {
1633 case RegionViewName:
1634 case RegionViewNameHighlight:
1635 case LeftFrameHandle:
1636 case RightFrameHandle:
1637 if (!with_selection) {
1638 if (region_edit_menu_split_item) {
1639 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1640 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1642 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1645 if (region_edit_menu_split_multichannel_item) {
1646 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1647 region_edit_menu_split_multichannel_item->set_sensitive (true);
1649 region_edit_menu_split_multichannel_item->set_sensitive (false);
1662 /* probably shouldn't happen but if it does, we don't care */
1666 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1668 /* Bounce to disk */
1670 using namespace Menu_Helpers;
1671 MenuList& edit_items = menu->items();
1673 edit_items.push_back (SeparatorElem());
1675 switch (clicked_routeview->audio_track()->freeze_state()) {
1676 case AudioTrack::NoFreeze:
1677 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1680 case AudioTrack::Frozen:
1681 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1684 case AudioTrack::UnFrozen:
1685 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1691 if (item_type == StreamItem && clicked_routeview) {
1692 clicked_routeview->build_underlay_menu(menu);
1695 /* When the region menu is opened, we setup the actions so that they look right
1698 sensitize_the_right_region_actions (false);
1699 _last_region_menu_was_main = false;
1701 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1702 menu->popup (button, time);
1706 Editor::build_track_context_menu ()
1708 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_context_menu.items();
1713 add_dstream_context_items (edit_items);
1714 return &track_context_menu;
1718 Editor::build_track_bus_context_menu ()
1720 using namespace Menu_Helpers;
1722 MenuList& edit_items = track_context_menu.items();
1725 add_bus_context_items (edit_items);
1726 return &track_context_menu;
1730 Editor::build_track_region_context_menu ()
1732 using namespace Menu_Helpers;
1733 MenuList& edit_items = track_region_context_menu.items();
1736 /* we've just cleared the track region context menu, so the menu that these
1737 two items were on will have disappeared; stop them dangling.
1739 region_edit_menu_split_item = 0;
1740 region_edit_menu_split_multichannel_item = 0;
1742 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1745 boost::shared_ptr<Track> tr;
1746 boost::shared_ptr<Playlist> pl;
1748 if ((tr = rtv->track())) {
1749 add_region_context_items (edit_items, tr);
1753 add_dstream_context_items (edit_items);
1755 return &track_region_context_menu;
1759 Editor::loudness_analyze_region_selection ()
1764 Selection& s (PublicEditor::instance ().get_selection ());
1765 RegionSelection ars = s.regions;
1766 ARDOUR::AnalysisGraph ag (_session);
1767 framecnt_t total_work = 0;
1769 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1770 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1774 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1777 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1778 total_work += arv->region ()->length ();
1781 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1783 ag.set_total_frames (total_work);
1784 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1787 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1788 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1792 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1796 ag.analyze_region (ar);
1799 if (!ag.canceled ()) {
1800 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1806 Editor::loudness_analyze_range_selection ()
1811 Selection& s (PublicEditor::instance ().get_selection ());
1812 TimeSelection ts = s.time;
1813 ARDOUR::AnalysisGraph ag (_session);
1814 framecnt_t total_work = 0;
1816 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1817 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1821 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1825 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1826 total_work += j->length ();
1830 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1832 ag.set_total_frames (total_work);
1833 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1836 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1837 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1841 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1845 ag.analyze_range (rui->route (), pl, ts);
1848 if (!ag.canceled ()) {
1849 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1855 Editor::spectral_analyze_region_selection ()
1857 if (analysis_window == 0) {
1858 analysis_window = new AnalysisWindow();
1861 analysis_window->set_session(_session);
1863 analysis_window->show_all();
1866 analysis_window->set_regionmode();
1867 analysis_window->analyze();
1869 analysis_window->present();
1873 Editor::spectral_analyze_range_selection()
1875 if (analysis_window == 0) {
1876 analysis_window = new AnalysisWindow();
1879 analysis_window->set_session(_session);
1881 analysis_window->show_all();
1884 analysis_window->set_rangemode();
1885 analysis_window->analyze();
1887 analysis_window->present();
1891 Editor::build_track_selection_context_menu ()
1893 using namespace Menu_Helpers;
1894 MenuList& edit_items = track_selection_context_menu.items();
1895 edit_items.clear ();
1897 add_selection_context_items (edit_items);
1898 // edit_items.push_back (SeparatorElem());
1899 // add_dstream_context_items (edit_items);
1901 return &track_selection_context_menu;
1905 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1907 using namespace Menu_Helpers;
1909 /* OK, stick the region submenu at the top of the list, and then add
1913 RegionSelection rs = get_regions_from_selection_and_entered ();
1915 string::size_type pos = 0;
1916 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1918 /* we have to hack up the region name because "_" has a special
1919 meaning for menu titles.
1922 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1923 menu_item_name.replace (pos, 1, "__");
1927 if (_popup_region_menu_item == 0) {
1928 _popup_region_menu_item = new MenuItem (menu_item_name);
1929 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1930 _popup_region_menu_item->show ();
1932 _popup_region_menu_item->set_label (menu_item_name);
1935 /* No latering allowed in later is higher layering model */
1936 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1937 if (act && Config->get_layer_model() == LaterHigher) {
1938 act->set_sensitive (false);
1940 act->set_sensitive (true);
1943 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1945 edit_items.push_back (*_popup_region_menu_item);
1946 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1947 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1949 edit_items.push_back (SeparatorElem());
1952 /** Add context menu items relevant to selection ranges.
1953 * @param edit_items List to add the items to.
1956 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1958 using namespace Menu_Helpers;
1960 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1961 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1963 edit_items.push_back (SeparatorElem());
1964 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1966 edit_items.push_back (SeparatorElem());
1967 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1968 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1970 edit_items.push_back (SeparatorElem());
1972 edit_items.push_back (
1974 _("Move Range Start to Previous Region Boundary"),
1975 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1979 edit_items.push_back (
1981 _("Move Range Start to Next Region Boundary"),
1982 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1986 edit_items.push_back (
1988 _("Move Range End to Previous Region Boundary"),
1989 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1993 edit_items.push_back (
1995 _("Move Range End to Next Region Boundary"),
1996 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
2000 edit_items.push_back (SeparatorElem());
2001 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
2002 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
2004 edit_items.push_back (SeparatorElem());
2005 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2007 edit_items.push_back (SeparatorElem());
2008 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2009 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2010 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2012 edit_items.push_back (SeparatorElem());
2013 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2015 edit_items.push_back (SeparatorElem());
2016 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2017 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2019 edit_items.push_back (SeparatorElem());
2020 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2021 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2022 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2023 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2024 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2025 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2026 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2032 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2034 using namespace Menu_Helpers;
2038 Menu *play_menu = manage (new Menu);
2039 MenuList& play_items = play_menu->items();
2040 play_menu->set_name ("ArdourContextMenu");
2042 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2043 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2044 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2045 play_items.push_back (SeparatorElem());
2046 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2048 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2052 Menu *select_menu = manage (new Menu);
2053 MenuList& select_items = select_menu->items();
2054 select_menu->set_name ("ArdourContextMenu");
2056 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2057 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2058 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2059 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2060 select_items.push_back (SeparatorElem());
2061 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2062 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2063 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2064 select_items.push_back (SeparatorElem());
2065 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2066 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2067 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2068 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2069 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2070 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2071 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2073 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2077 Menu *cutnpaste_menu = manage (new Menu);
2078 MenuList& cutnpaste_items = cutnpaste_menu->items();
2079 cutnpaste_menu->set_name ("ArdourContextMenu");
2081 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2082 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2083 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2085 cutnpaste_items.push_back (SeparatorElem());
2087 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2088 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2090 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2092 /* Adding new material */
2094 edit_items.push_back (SeparatorElem());
2095 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2096 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2100 Menu *nudge_menu = manage (new Menu());
2101 MenuList& nudge_items = nudge_menu->items();
2102 nudge_menu->set_name ("ArdourContextMenu");
2104 edit_items.push_back (SeparatorElem());
2105 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2106 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2107 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2108 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2110 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2114 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2116 using namespace Menu_Helpers;
2120 Menu *play_menu = manage (new Menu);
2121 MenuList& play_items = play_menu->items();
2122 play_menu->set_name ("ArdourContextMenu");
2124 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2125 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2126 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2130 Menu *select_menu = manage (new Menu);
2131 MenuList& select_items = select_menu->items();
2132 select_menu->set_name ("ArdourContextMenu");
2134 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2135 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2136 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2137 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2138 select_items.push_back (SeparatorElem());
2139 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2140 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2141 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2142 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2144 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2148 Menu *cutnpaste_menu = manage (new Menu);
2149 MenuList& cutnpaste_items = cutnpaste_menu->items();
2150 cutnpaste_menu->set_name ("ArdourContextMenu");
2152 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2153 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2154 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2156 Menu *nudge_menu = manage (new Menu());
2157 MenuList& nudge_items = nudge_menu->items();
2158 nudge_menu->set_name ("ArdourContextMenu");
2160 edit_items.push_back (SeparatorElem());
2161 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2162 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2163 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2164 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2166 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2170 Editor::snap_type() const
2176 Editor::snap_musical() const
2178 switch (_snap_type) {
2179 case SnapToBeatDiv128:
2180 case SnapToBeatDiv64:
2181 case SnapToBeatDiv32:
2182 case SnapToBeatDiv28:
2183 case SnapToBeatDiv24:
2184 case SnapToBeatDiv20:
2185 case SnapToBeatDiv16:
2186 case SnapToBeatDiv14:
2187 case SnapToBeatDiv12:
2188 case SnapToBeatDiv10:
2189 case SnapToBeatDiv8:
2190 case SnapToBeatDiv7:
2191 case SnapToBeatDiv6:
2192 case SnapToBeatDiv5:
2193 case SnapToBeatDiv4:
2194 case SnapToBeatDiv3:
2195 case SnapToBeatDiv2:
2207 Editor::snap_mode() const
2213 Editor::set_snap_to (SnapType st)
2215 unsigned int snap_ind = (unsigned int)st;
2217 if (internal_editing()) {
2218 internal_snap_type = st;
2220 pre_internal_snap_type = st;
2225 if (snap_ind > snap_type_strings.size() - 1) {
2227 _snap_type = (SnapType)snap_ind;
2230 string str = snap_type_strings[snap_ind];
2232 if (str != snap_type_selector.get_text()) {
2233 snap_type_selector.set_text (str);
2238 switch (_snap_type) {
2239 case SnapToBeatDiv128:
2240 case SnapToBeatDiv64:
2241 case SnapToBeatDiv32:
2242 case SnapToBeatDiv28:
2243 case SnapToBeatDiv24:
2244 case SnapToBeatDiv20:
2245 case SnapToBeatDiv16:
2246 case SnapToBeatDiv14:
2247 case SnapToBeatDiv12:
2248 case SnapToBeatDiv10:
2249 case SnapToBeatDiv8:
2250 case SnapToBeatDiv7:
2251 case SnapToBeatDiv6:
2252 case SnapToBeatDiv5:
2253 case SnapToBeatDiv4:
2254 case SnapToBeatDiv3:
2255 case SnapToBeatDiv2: {
2256 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2257 update_tempo_based_rulers ();
2261 case SnapToRegionStart:
2262 case SnapToRegionEnd:
2263 case SnapToRegionSync:
2264 case SnapToRegionBoundary:
2265 build_region_boundary_cache ();
2273 redisplay_tempo (false);
2275 SnapChanged (); /* EMIT SIGNAL */
2279 Editor::set_snap_mode (SnapMode mode)
2281 string str = snap_mode_strings[(int)mode];
2283 if (internal_editing()) {
2284 internal_snap_mode = mode;
2286 pre_internal_snap_mode = mode;
2291 if (str != snap_mode_selector.get_text ()) {
2292 snap_mode_selector.set_text (str);
2299 Editor::set_edit_point_preference (EditPoint ep, bool force)
2301 bool changed = (_edit_point != ep);
2304 if (Profile->get_mixbus())
2305 if (ep == EditAtSelectedMarker)
2306 ep = EditAtPlayhead;
2308 string str = edit_point_strings[(int)ep];
2309 if (str != edit_point_selector.get_text ()) {
2310 edit_point_selector.set_text (str);
2313 update_all_enter_cursors();
2315 if (!force && !changed) {
2319 const char* action=NULL;
2321 switch (_edit_point) {
2322 case EditAtPlayhead:
2323 action = "edit-at-playhead";
2325 case EditAtSelectedMarker:
2326 action = "edit-at-marker";
2329 action = "edit-at-mouse";
2333 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2335 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2339 bool in_track_canvas;
2341 if (!mouse_frame (foo, in_track_canvas)) {
2342 in_track_canvas = false;
2345 reset_canvas_action_sensitivity (in_track_canvas);
2346 sensitize_the_right_region_actions (false);
2352 Editor::set_state (const XMLNode& node, int version)
2354 XMLProperty const * prop;
2356 PBD::Unwinder<bool> nsi (no_save_instant, true);
2359 Tabbable::set_state (node, version);
2361 if (_session && (prop = node.property ("playhead"))) {
2363 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2365 playhead_cursor->set_position (pos);
2367 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2368 playhead_cursor->set_position (0);
2371 playhead_cursor->set_position (0);
2374 if ((prop = node.property ("mixer-width"))) {
2375 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2378 if ((prop = node.property ("zoom-focus"))) {
2379 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2381 zoom_focus_selection_done (zoom_focus);
2384 if ((prop = node.property ("zoom"))) {
2385 /* older versions of ardour used floating point samples_per_pixel */
2386 double f = PBD::atof (prop->value());
2387 reset_zoom (llrintf (f));
2389 reset_zoom (samples_per_pixel);
2392 if ((prop = node.property ("visible-track-count"))) {
2393 set_visible_track_count (PBD::atoi (prop->value()));
2396 if ((prop = node.property ("snap-to"))) {
2397 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2398 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2400 set_snap_to (_snap_type);
2403 if ((prop = node.property ("snap-mode"))) {
2404 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2405 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2406 * snap_mode_selection_done() will only mark an already active item as active
2407 * which does not trigger set_text().
2409 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2411 set_snap_mode (_snap_mode);
2414 if ((prop = node.property ("internal-snap-to"))) {
2415 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2418 if ((prop = node.property ("internal-snap-mode"))) {
2419 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2422 if ((prop = node.property ("pre-internal-snap-to"))) {
2423 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2426 if ((prop = node.property ("pre-internal-snap-mode"))) {
2427 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2430 if ((prop = node.property ("mouse-mode"))) {
2431 MouseMode m = str2mousemode(prop->value());
2432 set_mouse_mode (m, true);
2434 set_mouse_mode (MouseObject, true);
2437 if ((prop = node.property ("left-frame")) != 0) {
2439 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2443 reset_x_origin (pos);
2447 if ((prop = node.property ("y-origin")) != 0) {
2448 reset_y_origin (atof (prop->value ()));
2451 if ((prop = node.property ("join-object-range"))) {
2452 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2453 bool yn = string_is_affirmative (prop->value());
2455 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2456 tact->set_active (!yn);
2457 tact->set_active (yn);
2459 set_mouse_mode(mouse_mode, true);
2462 if ((prop = node.property ("edit-point"))) {
2463 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2465 set_edit_point_preference (_edit_point);
2468 if ((prop = node.property ("show-measures"))) {
2469 bool yn = string_is_affirmative (prop->value());
2470 _show_measures = yn;
2473 if ((prop = node.property ("follow-playhead"))) {
2474 bool yn = string_is_affirmative (prop->value());
2475 set_follow_playhead (yn);
2478 if ((prop = node.property ("stationary-playhead"))) {
2479 bool yn = string_is_affirmative (prop->value());
2480 set_stationary_playhead (yn);
2483 if ((prop = node.property ("region-list-sort-type"))) {
2484 RegionListSortType st;
2485 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2488 if ((prop = node.property ("show-editor-mixer"))) {
2490 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2493 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2494 bool yn = string_is_affirmative (prop->value());
2496 /* do it twice to force the change */
2498 tact->set_active (!yn);
2499 tact->set_active (yn);
2502 if ((prop = node.property ("show-editor-list"))) {
2504 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2507 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2508 bool yn = string_is_affirmative (prop->value());
2510 /* do it twice to force the change */
2512 tact->set_active (!yn);
2513 tact->set_active (yn);
2516 if ((prop = node.property (X_("editor-list-page")))) {
2517 _the_notebook.set_current_page (atoi (prop->value ()));
2520 if ((prop = node.property (X_("show-marker-lines")))) {
2521 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2523 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2524 bool yn = string_is_affirmative (prop->value ());
2526 tact->set_active (!yn);
2527 tact->set_active (yn);
2530 XMLNodeList children = node.children ();
2531 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2532 selection->set_state (**i, Stateful::current_state_version);
2533 _regions->set_state (**i);
2534 _locations->set_state (**i);
2537 if ((prop = node.property ("maximised"))) {
2538 bool yn = string_is_affirmative (prop->value());
2539 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2541 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2542 bool fs = tact && tact->get_active();
2544 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2548 if ((prop = node.property ("nudge-clock-value"))) {
2550 sscanf (prop->value().c_str(), "%" PRId64, &f);
2551 nudge_clock->set (f);
2553 nudge_clock->set_mode (AudioClock::Timecode);
2554 nudge_clock->set (_session->frame_rate() * 5, true);
2559 * Not all properties may have been in XML, but
2560 * those that are linked to a private variable may need changing
2565 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2567 yn = _show_measures;
2568 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2569 /* do it twice to force the change */
2570 tact->set_active (!yn);
2571 tact->set_active (yn);
2574 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2575 yn = _follow_playhead;
2577 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2578 if (tact->get_active() != yn) {
2579 tact->set_active (yn);
2583 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2584 yn = _stationary_playhead;
2586 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2587 if (tact->get_active() != yn) {
2588 tact->set_active (yn);
2593 return LuaInstance::instance()->set_state(node);
2597 Editor::get_state ()
2599 XMLNode* node = new XMLNode (X_("Editor"));
2603 id().print (buf, sizeof (buf));
2604 node->add_property ("id", buf);
2606 node->add_child_nocopy (Tabbable::get_state());
2608 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2609 node->add_property("edit-horizontal-pane-pos", string(buf));
2610 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2611 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2612 node->add_property("edit-vertical-pane-pos", string(buf));
2614 maybe_add_mixer_strip_width (*node);
2616 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2618 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2619 node->add_property ("zoom", buf);
2620 node->add_property ("snap-to", enum_2_string (_snap_type));
2621 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2622 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2623 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2624 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2625 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2626 node->add_property ("edit-point", enum_2_string (_edit_point));
2627 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2628 node->add_property ("visible-track-count", buf);
2630 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2631 node->add_property ("playhead", buf);
2632 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2633 node->add_property ("left-frame", buf);
2634 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2635 node->add_property ("y-origin", buf);
2637 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2638 node->add_property ("maximised", _maximised ? "yes" : "no");
2639 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2640 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2641 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2642 node->add_property ("mouse-mode", enum2str(mouse_mode));
2643 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2645 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2647 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2648 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2651 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2653 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2654 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2657 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2658 node->add_property (X_("editor-list-page"), buf);
2660 if (button_bindings) {
2661 XMLNode* bb = new XMLNode (X_("Buttons"));
2662 button_bindings->save (*bb);
2663 node->add_child_nocopy (*bb);
2666 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2668 node->add_child_nocopy (selection->get_state ());
2669 node->add_child_nocopy (_regions->get_state ());
2671 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2672 node->add_property ("nudge-clock-value", buf);
2674 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2675 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2676 node->add_child_nocopy (_locations->get_state ());
2681 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2682 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2684 * @return pair: TimeAxisView that y is over, layer index.
2686 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2687 * in stacked or expanded region display mode, otherwise 0.
2689 std::pair<TimeAxisView *, double>
2690 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2692 if (!trackview_relative_offset) {
2693 y -= _trackview_group->canvas_origin().y;
2697 return std::make_pair ( (TimeAxisView *) 0, 0);
2700 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2702 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2709 return std::make_pair ( (TimeAxisView *) 0, 0);
2712 /** Snap a position to the grid, if appropriate, taking into account current
2713 * grid settings and also the state of any snap modifier keys that may be pressed.
2714 * @param start Position to snap.
2715 * @param event Event to get current key modifier information from, or 0.
2718 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2720 if (!_session || !event) {
2724 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2725 if (_snap_mode == SnapOff) {
2726 snap_to_internal (start, direction, for_mark);
2728 start.set (start.frame, 0);
2731 if (_snap_mode != SnapOff) {
2732 snap_to_internal (start, direction, for_mark);
2733 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2734 /* SnapOff, but we pressed the snap_delta modifier */
2735 snap_to_internal (start, direction, for_mark);
2737 start.set (start.frame, 0);
2743 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2745 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2746 start.set (start.frame, 0);
2750 snap_to_internal (start, direction, for_mark, ensure_snap);
2754 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2756 framepos_t start = pos.frame;
2757 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2758 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2760 switch (_snap_type) {
2761 case SnapToTimecodeFrame:
2762 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2763 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2764 /* start is already on a whole timecode frame, do nothing */
2765 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2766 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2768 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2772 case SnapToTimecodeSeconds:
2773 if (_session->config.get_timecode_offset_negative()) {
2774 start += _session->config.get_timecode_offset ();
2776 start -= _session->config.get_timecode_offset ();
2778 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2779 (start % one_timecode_second == 0)) {
2780 /* start is already on a whole second, do nothing */
2781 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2782 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2784 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2787 if (_session->config.get_timecode_offset_negative()) {
2788 start -= _session->config.get_timecode_offset ();
2790 start += _session->config.get_timecode_offset ();
2794 case SnapToTimecodeMinutes:
2795 if (_session->config.get_timecode_offset_negative()) {
2796 start += _session->config.get_timecode_offset ();
2798 start -= _session->config.get_timecode_offset ();
2800 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2801 (start % one_timecode_minute == 0)) {
2802 /* start is already on a whole minute, do nothing */
2803 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2804 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2806 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2808 if (_session->config.get_timecode_offset_negative()) {
2809 start -= _session->config.get_timecode_offset ();
2811 start += _session->config.get_timecode_offset ();
2815 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2816 abort(); /*NOTREACHED*/
2823 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2825 const framepos_t one_second = _session->frame_rate();
2826 const framepos_t one_minute = _session->frame_rate() * 60;
2827 framepos_t presnap = start.frame;
2831 switch (_snap_type) {
2832 case SnapToTimecodeFrame:
2833 case SnapToTimecodeSeconds:
2834 case SnapToTimecodeMinutes:
2835 return timecode_snap_to_internal (start, direction, for_mark);
2838 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2839 start.frame % (one_second/75) == 0) {
2840 /* start is already on a whole CD frame, do nothing */
2841 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2842 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2844 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2847 start.set (start.frame, 0);
2852 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2853 start.frame % one_second == 0) {
2854 /* start is already on a whole second, do nothing */
2855 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2856 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2858 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2861 start.set (start.frame, 0);
2866 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2867 start.frame % one_minute == 0) {
2868 /* start is already on a whole minute, do nothing */
2869 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2870 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2872 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2875 start.set (start.frame, 0);
2880 start = _session->tempo_map().round_to_bar (start.frame, direction);
2884 start = _session->tempo_map().round_to_beat (start.frame, direction);
2887 case SnapToBeatDiv128:
2888 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2890 case SnapToBeatDiv64:
2891 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2893 case SnapToBeatDiv32:
2894 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2896 case SnapToBeatDiv28:
2897 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2899 case SnapToBeatDiv24:
2900 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2902 case SnapToBeatDiv20:
2903 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2905 case SnapToBeatDiv16:
2906 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2908 case SnapToBeatDiv14:
2909 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2911 case SnapToBeatDiv12:
2912 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2914 case SnapToBeatDiv10:
2915 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2917 case SnapToBeatDiv8:
2918 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2920 case SnapToBeatDiv7:
2921 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2923 case SnapToBeatDiv6:
2924 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2926 case SnapToBeatDiv5:
2927 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2929 case SnapToBeatDiv4:
2930 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2932 case SnapToBeatDiv3:
2933 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2935 case SnapToBeatDiv2:
2936 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2944 _session->locations()->marks_either_side (start.frame, before, after);
2946 if (before == max_framepos && after == max_framepos) {
2947 /* No marks to snap to, so just don't snap */
2949 } else if (before == max_framepos) {
2950 start.frame = after;
2951 } else if (after == max_framepos) {
2952 start.frame = before;
2953 } else if (before != max_framepos && after != max_framepos) {
2954 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2955 start.frame = after;
2956 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2957 start.frame = before;
2958 else if (direction == 0 ) {
2959 if ((start.frame - before) < (after - start.frame)) {
2960 start.frame = before;
2962 start.frame = after;
2967 start.set (start.frame, 0);
2971 case SnapToRegionStart:
2972 case SnapToRegionEnd:
2973 case SnapToRegionSync:
2974 case SnapToRegionBoundary:
2975 if (!region_boundary_cache.empty()) {
2977 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2978 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2980 if (direction > 0) {
2981 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2983 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2986 if (next != region_boundary_cache.begin ()) {
2991 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2992 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2994 if (start.frame > (p + n) / 2) {
3001 start.set (start.frame, 0);
3006 switch (_snap_mode) {
3016 if (presnap > start.frame) {
3017 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
3018 start.set (presnap, 0);
3021 } else if (presnap < start.frame) {
3022 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
3023 start.set (presnap, 0);
3028 /* handled at entry */
3035 Editor::setup_toolbar ()
3037 HBox* mode_box = manage(new HBox);
3038 mode_box->set_border_width (2);
3039 mode_box->set_spacing(2);
3041 HBox* mouse_mode_box = manage (new HBox);
3042 HBox* mouse_mode_hbox = manage (new HBox);
3043 VBox* mouse_mode_vbox = manage (new VBox);
3044 Alignment* mouse_mode_align = manage (new Alignment);
3046 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3047 mouse_mode_size_group->add_widget (smart_mode_button);
3048 mouse_mode_size_group->add_widget (mouse_move_button);
3049 mouse_mode_size_group->add_widget (mouse_cut_button);
3050 mouse_mode_size_group->add_widget (mouse_select_button);
3051 mouse_mode_size_group->add_widget (mouse_timefx_button);
3052 mouse_mode_size_group->add_widget (mouse_audition_button);
3053 mouse_mode_size_group->add_widget (mouse_draw_button);
3054 mouse_mode_size_group->add_widget (mouse_content_button);
3056 if (!Profile->get_mixbus()) {
3057 mouse_mode_size_group->add_widget (zoom_in_button);
3058 mouse_mode_size_group->add_widget (zoom_out_button);
3059 mouse_mode_size_group->add_widget (zoom_out_full_button);
3060 mouse_mode_size_group->add_widget (zoom_focus_selector);
3061 mouse_mode_size_group->add_widget (tav_shrink_button);
3062 mouse_mode_size_group->add_widget (tav_expand_button);
3064 mouse_mode_size_group->add_widget (zoom_preset_selector);
3065 mouse_mode_size_group->add_widget (visible_tracks_selector);
3068 mouse_mode_size_group->add_widget (snap_type_selector);
3069 mouse_mode_size_group->add_widget (snap_mode_selector);
3071 mouse_mode_size_group->add_widget (edit_point_selector);
3072 mouse_mode_size_group->add_widget (edit_mode_selector);
3074 mouse_mode_size_group->add_widget (*nudge_clock);
3075 mouse_mode_size_group->add_widget (nudge_forward_button);
3076 mouse_mode_size_group->add_widget (nudge_backward_button);
3078 mouse_mode_hbox->set_spacing (2);
3080 if (!ARDOUR::Profile->get_trx()) {
3081 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3084 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3085 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3087 if (!ARDOUR::Profile->get_mixbus()) {
3088 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3091 if (!ARDOUR::Profile->get_trx()) {
3092 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3093 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3094 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3095 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3098 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3100 mouse_mode_align->add (*mouse_mode_vbox);
3101 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3103 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3105 edit_mode_selector.set_name ("mouse mode button");
3107 if (!ARDOUR::Profile->get_trx()) {
3108 mode_box->pack_start (edit_mode_selector, false, false);
3111 mode_box->pack_start (*mouse_mode_box, false, false);
3115 _zoom_box.set_spacing (2);
3116 _zoom_box.set_border_width (2);
3120 zoom_preset_selector.set_name ("zoom button");
3121 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3123 zoom_in_button.set_name ("zoom button");
3124 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3125 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3126 zoom_in_button.set_related_action (act);
3128 zoom_out_button.set_name ("zoom button");
3129 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3130 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3131 zoom_out_button.set_related_action (act);
3133 zoom_out_full_button.set_name ("zoom button");
3134 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3135 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3136 zoom_out_full_button.set_related_action (act);
3138 zoom_focus_selector.set_name ("zoom button");
3140 if (ARDOUR::Profile->get_mixbus()) {
3141 _zoom_box.pack_start (zoom_preset_selector, false, false);
3142 } else if (ARDOUR::Profile->get_trx()) {
3143 mode_box->pack_start (zoom_out_button, false, false);
3144 mode_box->pack_start (zoom_in_button, false, false);
3146 _zoom_box.pack_start (zoom_out_button, false, false);
3147 _zoom_box.pack_start (zoom_in_button, false, false);
3148 _zoom_box.pack_start (zoom_out_full_button, false, false);
3149 _zoom_box.pack_start (zoom_focus_selector, false, false);
3152 /* Track zoom buttons */
3153 _track_box.set_spacing (2);
3154 _track_box.set_border_width (2);
3156 visible_tracks_selector.set_name ("zoom button");
3157 if (Profile->get_mixbus()) {
3158 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3160 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3163 tav_expand_button.set_name ("zoom button");
3164 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3165 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3166 tav_expand_button.set_related_action (act);
3168 tav_shrink_button.set_name ("zoom button");
3169 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3170 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3171 tav_shrink_button.set_related_action (act);
3173 if (ARDOUR::Profile->get_mixbus()) {
3174 _track_box.pack_start (visible_tracks_selector);
3175 } else if (ARDOUR::Profile->get_trx()) {
3176 _track_box.pack_start (tav_shrink_button);
3177 _track_box.pack_start (tav_expand_button);
3179 _track_box.pack_start (visible_tracks_selector);
3180 _track_box.pack_start (tav_shrink_button);
3181 _track_box.pack_start (tav_expand_button);
3184 snap_box.set_spacing (2);
3185 snap_box.set_border_width (2);
3187 snap_type_selector.set_name ("mouse mode button");
3189 snap_mode_selector.set_name ("mouse mode button");
3191 edit_point_selector.set_name ("mouse mode button");
3193 snap_box.pack_start (snap_mode_selector, false, false);
3194 snap_box.pack_start (snap_type_selector, false, false);
3197 HBox *ep_box = manage (new HBox);
3198 ep_box->set_spacing (2);
3199 ep_box->set_border_width (2);
3201 ep_box->pack_start (edit_point_selector, false, false);
3205 HBox *nudge_box = manage (new HBox);
3206 nudge_box->set_spacing (2);
3207 nudge_box->set_border_width (2);
3209 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3210 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3212 nudge_box->pack_start (nudge_backward_button, false, false);
3213 nudge_box->pack_start (nudge_forward_button, false, false);
3214 nudge_box->pack_start (*nudge_clock, false, false);
3217 /* Pack everything in... */
3219 toolbar_hbox.set_spacing (2);
3220 toolbar_hbox.set_border_width (2);
3222 toolbar_hbox.pack_start (*mode_box, false, false);
3224 if (!ARDOUR::Profile->get_trx()) {
3226 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3228 toolbar_hbox.pack_start (_zoom_box, false, false);
3230 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3232 toolbar_hbox.pack_start (_track_box, false, false);
3234 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3236 toolbar_hbox.pack_start (snap_box, false, false);
3238 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3240 toolbar_hbox.pack_start (*ep_box, false, false);
3242 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3244 toolbar_hbox.pack_start (*nudge_box, false, false);
3247 toolbar_hbox.show_all ();
3251 Editor::build_edit_point_menu ()
3253 using namespace Menu_Helpers;
3255 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3256 if(!Profile->get_mixbus())
3257 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3258 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3260 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3264 Editor::build_edit_mode_menu ()
3266 using namespace Menu_Helpers;
3268 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3269 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3270 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3271 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3273 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3277 Editor::build_snap_mode_menu ()
3279 using namespace Menu_Helpers;
3281 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3282 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3283 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3285 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3289 Editor::build_snap_type_menu ()
3291 using namespace Menu_Helpers;
3293 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3294 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3295 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3296 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3297 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3298 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3299 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3300 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3301 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3302 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3303 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3304 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3305 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3306 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3307 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3308 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3309 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3310 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3311 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3312 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3313 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3314 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3315 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3316 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3317 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3318 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3319 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3320 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3321 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3322 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3324 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3329 Editor::setup_tooltips ()
3331 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3332 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3333 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3334 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3335 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3336 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3337 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3338 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3339 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3340 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3341 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3342 set_tooltip (zoom_in_button, _("Zoom In"));
3343 set_tooltip (zoom_out_button, _("Zoom Out"));
3344 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3345 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3346 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3347 set_tooltip (tav_expand_button, _("Expand Tracks"));
3348 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3349 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3350 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3351 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3352 set_tooltip (edit_point_selector, _("Edit Point"));
3353 set_tooltip (edit_mode_selector, _("Edit Mode"));
3354 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3358 Editor::convert_drop_to_paths (
3359 vector<string>& paths,
3360 const RefPtr<Gdk::DragContext>& /*context*/,
3363 const SelectionData& data,
3367 if (_session == 0) {
3371 vector<string> uris = data.get_uris();
3375 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3376 are actually URI lists. So do it by hand.
3379 if (data.get_target() != "text/plain") {
3383 /* Parse the "uri-list" format that Nautilus provides,
3384 where each pathname is delimited by \r\n.
3386 THERE MAY BE NO NULL TERMINATING CHAR!!!
3389 string txt = data.get_text();
3393 p = (char *) malloc (txt.length() + 1);
3394 txt.copy (p, txt.length(), 0);
3395 p[txt.length()] = '\0';
3401 while (g_ascii_isspace (*p))
3405 while (*q && (*q != '\n') && (*q != '\r')) {
3412 while (q > p && g_ascii_isspace (*q))
3417 uris.push_back (string (p, q - p + 1));
3421 p = strchr (p, '\n');
3433 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3434 if ((*i).substr (0,7) == "file://") {
3435 paths.push_back (Glib::filename_from_uri (*i));
3443 Editor::new_tempo_section ()
3448 Editor::map_transport_state ()
3450 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3452 if (_session && _session->transport_stopped()) {
3453 have_pending_keyboard_selection = false;
3456 update_loop_range_view ();
3462 Editor::begin_selection_op_history ()
3464 selection_op_cmd_depth = 0;
3465 selection_op_history_it = 0;
3467 while(!selection_op_history.empty()) {
3468 delete selection_op_history.front();
3469 selection_op_history.pop_front();
3472 selection_undo_action->set_sensitive (false);
3473 selection_redo_action->set_sensitive (false);
3474 selection_op_history.push_front (&_selection_memento->get_state ());
3478 Editor::begin_reversible_selection_op (string name)
3481 //cerr << name << endl;
3482 /* begin/commit pairs can be nested */
3483 selection_op_cmd_depth++;
3488 Editor::commit_reversible_selection_op ()
3491 if (selection_op_cmd_depth == 1) {
3493 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3495 The user has undone some selection ops and then made a new one,
3496 making anything earlier in the list invalid.
3499 list<XMLNode *>::iterator it = selection_op_history.begin();
3500 list<XMLNode *>::iterator e_it = it;
3501 advance (e_it, selection_op_history_it);
3503 for ( ; it != e_it; ++it) {
3506 selection_op_history.erase (selection_op_history.begin(), e_it);
3509 selection_op_history.push_front (&_selection_memento->get_state ());
3510 selection_op_history_it = 0;
3512 selection_undo_action->set_sensitive (true);
3513 selection_redo_action->set_sensitive (false);
3516 if (selection_op_cmd_depth > 0) {
3517 selection_op_cmd_depth--;
3523 Editor::undo_selection_op ()
3526 selection_op_history_it++;
3528 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3529 if (n == selection_op_history_it) {
3530 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3531 selection_redo_action->set_sensitive (true);
3535 /* is there an earlier entry? */
3536 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3537 selection_undo_action->set_sensitive (false);
3543 Editor::redo_selection_op ()
3546 if (selection_op_history_it > 0) {
3547 selection_op_history_it--;
3550 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3551 if (n == selection_op_history_it) {
3552 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3553 selection_undo_action->set_sensitive (true);
3558 if (selection_op_history_it == 0) {
3559 selection_redo_action->set_sensitive (false);
3565 Editor::begin_reversible_command (string name)
3568 before.push_back (&_selection_memento->get_state ());
3569 _session->begin_reversible_command (name);
3574 Editor::begin_reversible_command (GQuark q)
3577 before.push_back (&_selection_memento->get_state ());
3578 _session->begin_reversible_command (q);
3583 Editor::abort_reversible_command ()
3586 while(!before.empty()) {
3587 delete before.front();
3590 _session->abort_reversible_command ();
3595 Editor::commit_reversible_command ()
3598 if (before.size() == 1) {
3599 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3600 redo_action->set_sensitive(false);
3601 undo_action->set_sensitive(true);
3602 begin_selection_op_history ();
3605 if (before.empty()) {
3606 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3611 _session->commit_reversible_command ();
3616 Editor::history_changed ()
3620 if (undo_action && _session) {
3621 if (_session->undo_depth() == 0) {
3622 label = S_("Command|Undo");
3624 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3626 undo_action->property_label() = label;
3629 if (redo_action && _session) {
3630 if (_session->redo_depth() == 0) {
3632 redo_action->set_sensitive (false);
3634 label = string_compose(_("Redo (%1)"), _session->next_redo());
3635 redo_action->set_sensitive (true);
3637 redo_action->property_label() = label;
3642 Editor::duplicate_range (bool with_dialog)
3646 RegionSelection rs = get_regions_from_selection_and_entered ();
3648 if ( selection->time.length() == 0 && rs.empty()) {
3654 ArdourDialog win (_("Duplicate"));
3655 Label label (_("Number of duplications:"));
3656 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3657 SpinButton spinner (adjustment, 0.0, 1);
3660 win.get_vbox()->set_spacing (12);
3661 win.get_vbox()->pack_start (hbox);
3662 hbox.set_border_width (6);
3663 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3665 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3666 place, visually. so do this by hand.
3669 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3670 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3671 spinner.grab_focus();
3677 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3678 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3679 win.set_default_response (RESPONSE_ACCEPT);
3681 spinner.grab_focus ();
3683 switch (win.run ()) {
3684 case RESPONSE_ACCEPT:
3690 times = adjustment.get_value();
3693 if ((current_mouse_mode() == Editing::MouseRange)) {
3694 if (selection->time.length()) {
3695 duplicate_selection (times);
3697 } else if (get_smart_mode()) {
3698 if (selection->time.length()) {
3699 duplicate_selection (times);
3701 duplicate_some_regions (rs, times);
3703 duplicate_some_regions (rs, times);
3708 Editor::set_edit_mode (EditMode m)
3710 Config->set_edit_mode (m);
3714 Editor::cycle_edit_mode ()
3716 switch (Config->get_edit_mode()) {
3718 Config->set_edit_mode (Ripple);
3722 Config->set_edit_mode (Lock);
3725 Config->set_edit_mode (Slide);
3731 Editor::edit_mode_selection_done ( EditMode m )
3733 Config->set_edit_mode ( m );
3737 Editor::snap_type_selection_done (SnapType snaptype)
3739 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3741 ract->set_active ();
3746 Editor::snap_mode_selection_done (SnapMode mode)
3748 RefPtr<RadioAction> ract = snap_mode_action (mode);
3751 ract->set_active (true);
3756 Editor::cycle_edit_point (bool with_marker)
3758 if(Profile->get_mixbus())
3759 with_marker = false;
3761 switch (_edit_point) {
3763 set_edit_point_preference (EditAtPlayhead);
3765 case EditAtPlayhead:
3767 set_edit_point_preference (EditAtSelectedMarker);
3769 set_edit_point_preference (EditAtMouse);
3772 case EditAtSelectedMarker:
3773 set_edit_point_preference (EditAtMouse);
3779 Editor::edit_point_selection_done (EditPoint ep)
3781 set_edit_point_preference ( ep );
3785 Editor::build_zoom_focus_menu ()
3787 using namespace Menu_Helpers;
3789 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3790 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3791 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3792 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3793 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3794 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3796 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3800 Editor::zoom_focus_selection_done ( ZoomFocus f )
3802 RefPtr<RadioAction> ract = zoom_focus_action (f);
3804 ract->set_active ();
3809 Editor::build_track_count_menu ()
3811 using namespace Menu_Helpers;
3813 if (!Profile->get_mixbus()) {
3814 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3815 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3816 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3817 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3818 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3819 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3820 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3821 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3822 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3823 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3824 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3825 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3826 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3828 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3829 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3830 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3831 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3832 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3833 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3834 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3835 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3836 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3837 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3839 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3840 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3841 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3842 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3843 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3844 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3845 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3846 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3847 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3848 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3849 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3854 Editor::set_zoom_preset (int64_t ms)
3857 temporal_zoom_session();
3861 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3862 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3866 Editor::set_visible_track_count (int32_t n)
3868 _visible_track_count = n;
3870 /* if the canvas hasn't really been allocated any size yet, just
3871 record the desired number of visible tracks and return. when canvas
3872 allocation happens, we will get called again and then we can do the
3876 if (_visible_canvas_height <= 1) {
3882 DisplaySuspender ds;
3884 if (_visible_track_count > 0) {
3885 h = trackviews_height() / _visible_track_count;
3886 std::ostringstream s;
3887 s << _visible_track_count;
3889 } else if (_visible_track_count == 0) {
3891 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3892 if ((*i)->marked_for_display()) {
3896 h = trackviews_height() / n;
3899 /* negative value means that the visible track count has
3900 been overridden by explicit track height changes.
3902 visible_tracks_selector.set_text (X_("*"));
3906 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3907 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3910 if (str != visible_tracks_selector.get_text()) {
3911 visible_tracks_selector.set_text (str);
3916 Editor::override_visible_track_count ()
3918 _visible_track_count = -1;
3919 visible_tracks_selector.set_text ( _("*") );
3923 Editor::edit_controls_button_release (GdkEventButton* ev)
3925 if (Keyboard::is_context_menu_event (ev)) {
3926 ARDOUR_UI::instance()->add_route ();
3927 } else if (ev->button == 1) {
3928 selection->clear_tracks ();
3935 Editor::mouse_select_button_release (GdkEventButton* ev)
3937 /* this handles just right-clicks */
3939 if (ev->button != 3) {
3947 Editor::set_zoom_focus (ZoomFocus f)
3949 string str = zoom_focus_strings[(int)f];
3951 if (str != zoom_focus_selector.get_text()) {
3952 zoom_focus_selector.set_text (str);
3955 if (zoom_focus != f) {
3962 Editor::cycle_zoom_focus ()
3964 switch (zoom_focus) {
3966 set_zoom_focus (ZoomFocusRight);
3968 case ZoomFocusRight:
3969 set_zoom_focus (ZoomFocusCenter);
3971 case ZoomFocusCenter:
3972 set_zoom_focus (ZoomFocusPlayhead);
3974 case ZoomFocusPlayhead:
3975 set_zoom_focus (ZoomFocusMouse);
3977 case ZoomFocusMouse:
3978 set_zoom_focus (ZoomFocusEdit);
3981 set_zoom_focus (ZoomFocusLeft);
3987 Editor::set_show_measures (bool yn)
3989 if (_show_measures != yn) {
3992 if ((_show_measures = yn) == true) {
3994 tempo_lines->show();
3997 std::vector<TempoMap::BBTPoint> grid;
3998 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3999 draw_measures (grid);
4007 Editor::toggle_follow_playhead ()
4009 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4011 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4012 set_follow_playhead (tact->get_active());
4016 /** @param yn true to follow playhead, otherwise false.
4017 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4020 Editor::set_follow_playhead (bool yn, bool catch_up)
4022 if (_follow_playhead != yn) {
4023 if ((_follow_playhead = yn) == true && catch_up) {
4025 reset_x_origin_to_follow_playhead ();
4032 Editor::toggle_stationary_playhead ()
4034 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4036 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4037 set_stationary_playhead (tact->get_active());
4042 Editor::set_stationary_playhead (bool yn)
4044 if (_stationary_playhead != yn) {
4045 if ((_stationary_playhead = yn) == true) {
4047 // FIXME need a 3.0 equivalent of this 2.X call
4048 // update_current_screen ();
4055 Editor::playlist_selector () const
4057 return *_playlist_selector;
4061 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4063 if (paste_count == 0) {
4064 /* don't bother calculating an offset that will be zero anyway */
4068 /* calculate basic unsnapped multi-paste offset */
4069 framecnt_t offset = paste_count * duration;
4071 /* snap offset so pos + offset is aligned to the grid */
4072 MusicFrame offset_pos (pos + offset, 0);
4073 snap_to(offset_pos, RoundUpMaybe);
4074 offset = offset_pos.frame - pos;
4080 Editor::get_grid_beat_divisions(framepos_t position)
4082 switch (_snap_type) {
4083 case SnapToBeatDiv128: return 128;
4084 case SnapToBeatDiv64: return 64;
4085 case SnapToBeatDiv32: return 32;
4086 case SnapToBeatDiv28: return 28;
4087 case SnapToBeatDiv24: return 24;
4088 case SnapToBeatDiv20: return 20;
4089 case SnapToBeatDiv16: return 16;
4090 case SnapToBeatDiv14: return 14;
4091 case SnapToBeatDiv12: return 12;
4092 case SnapToBeatDiv10: return 10;
4093 case SnapToBeatDiv8: return 8;
4094 case SnapToBeatDiv7: return 7;
4095 case SnapToBeatDiv6: return 6;
4096 case SnapToBeatDiv5: return 5;
4097 case SnapToBeatDiv4: return 4;
4098 case SnapToBeatDiv3: return 3;
4099 case SnapToBeatDiv2: return 2;
4105 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4106 if the grid is non-musical, returns 0.
4107 if the grid is snapped to bars, returns -1.
4108 @param event_state the current keyboard modifier mask.
4111 Editor::get_grid_music_divisions (uint32_t event_state)
4113 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4117 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4121 switch (_snap_type) {
4122 case SnapToBeatDiv128: return 128;
4123 case SnapToBeatDiv64: return 64;
4124 case SnapToBeatDiv32: return 32;
4125 case SnapToBeatDiv28: return 28;
4126 case SnapToBeatDiv24: return 24;
4127 case SnapToBeatDiv20: return 20;
4128 case SnapToBeatDiv16: return 16;
4129 case SnapToBeatDiv14: return 14;
4130 case SnapToBeatDiv12: return 12;
4131 case SnapToBeatDiv10: return 10;
4132 case SnapToBeatDiv8: return 8;
4133 case SnapToBeatDiv7: return 7;
4134 case SnapToBeatDiv6: return 6;
4135 case SnapToBeatDiv5: return 5;
4136 case SnapToBeatDiv4: return 4;
4137 case SnapToBeatDiv3: return 3;
4138 case SnapToBeatDiv2: return 2;
4139 case SnapToBeat: return 1;
4140 case SnapToBar : return -1;
4147 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4151 const unsigned divisions = get_grid_beat_divisions(position);
4153 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4156 switch (_snap_type) {
4158 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4161 const Meter& m = _session->tempo_map().meter_at_frame (position);
4162 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4170 return Evoral::Beats();
4174 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4178 ret = nudge_clock->current_duration (pos);
4179 next = ret + 1; /* XXXX fix me */
4185 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4187 ArdourDialog dialog (_("Playlist Deletion"));
4188 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4189 "If it is kept, its audio files will not be cleaned.\n"
4190 "If it is deleted, audio files used by it alone will be cleaned."),
4193 dialog.set_position (WIN_POS_CENTER);
4194 dialog.get_vbox()->pack_start (label);
4198 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4199 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4200 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4201 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4202 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4204 // by default gtk uses the left most button
4205 keep->grab_focus ();
4207 switch (dialog.run ()) {
4209 /* keep this and all remaining ones */
4214 /* delete this and all others */
4218 case RESPONSE_ACCEPT:
4219 /* delete the playlist */
4223 case RESPONSE_REJECT:
4224 /* keep the playlist */
4236 Editor::audio_region_selection_covers (framepos_t where)
4238 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4239 if ((*a)->region()->covers (where)) {
4248 Editor::prepare_for_cleanup ()
4250 cut_buffer->clear_regions ();
4251 cut_buffer->clear_playlists ();
4253 selection->clear_regions ();
4254 selection->clear_playlists ();
4256 _regions->suspend_redisplay ();
4260 Editor::finish_cleanup ()
4262 _regions->resume_redisplay ();
4266 Editor::transport_loop_location()
4269 return _session->locations()->auto_loop_location();
4276 Editor::transport_punch_location()
4279 return _session->locations()->auto_punch_location();
4286 Editor::control_layout_scroll (GdkEventScroll* ev)
4288 /* Just forward to the normal canvas scroll method. The coordinate
4289 systems are different but since the canvas is always larger than the
4290 track headers, and aligned with the trackview area, this will work.
4292 In the not too distant future this layout is going away anyway and
4293 headers will be on the canvas.
4295 return canvas_scroll_event (ev, false);
4299 Editor::session_state_saved (string)
4302 _snapshots->redisplay ();
4306 Editor::maximise_editing_space ()
4312 Gtk::Window* toplevel = current_toplevel();
4315 toplevel->fullscreen ();
4321 Editor::restore_editing_space ()
4327 Gtk::Window* toplevel = current_toplevel();
4330 toplevel->unfullscreen();
4336 * Make new playlists for a given track and also any others that belong
4337 * to the same active route group with the `select' property.
4342 Editor::new_playlists (TimeAxisView* v)
4344 begin_reversible_command (_("new playlists"));
4345 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4346 _session->playlists->get (playlists);
4347 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4348 commit_reversible_command ();
4352 * Use a copy of the current playlist for a given track and also any others that belong
4353 * to the same active route group with the `select' property.
4358 Editor::copy_playlists (TimeAxisView* v)
4360 begin_reversible_command (_("copy playlists"));
4361 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4362 _session->playlists->get (playlists);
4363 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4364 commit_reversible_command ();
4367 /** Clear the current playlist for a given track and also any others that belong
4368 * to the same active route group with the `select' property.
4373 Editor::clear_playlists (TimeAxisView* v)
4375 begin_reversible_command (_("clear playlists"));
4376 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4377 _session->playlists->get (playlists);
4378 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4379 commit_reversible_command ();
4383 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4385 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4389 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4391 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4395 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4397 atv.clear_playlist ();
4401 Editor::get_y_origin () const
4403 return vertical_adjustment.get_value ();
4406 /** Queue up a change to the viewport x origin.
4407 * @param frame New x origin.
4410 Editor::reset_x_origin (framepos_t frame)
4412 pending_visual_change.add (VisualChange::TimeOrigin);
4413 pending_visual_change.time_origin = frame;
4414 ensure_visual_change_idle_handler ();
4418 Editor::reset_y_origin (double y)
4420 pending_visual_change.add (VisualChange::YOrigin);
4421 pending_visual_change.y_origin = y;
4422 ensure_visual_change_idle_handler ();
4426 Editor::reset_zoom (framecnt_t spp)
4428 if (spp == samples_per_pixel) {
4432 pending_visual_change.add (VisualChange::ZoomLevel);
4433 pending_visual_change.samples_per_pixel = spp;
4434 ensure_visual_change_idle_handler ();
4438 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4440 reset_x_origin (frame);
4443 if (!no_save_visual) {
4444 undo_visual_stack.push_back (current_visual_state(false));
4448 Editor::VisualState::VisualState (bool with_tracks)
4449 : gui_state (with_tracks ? new GUIObjectState : 0)
4453 Editor::VisualState::~VisualState ()
4458 Editor::VisualState*
4459 Editor::current_visual_state (bool with_tracks)
4461 VisualState* vs = new VisualState (with_tracks);
4462 vs->y_position = vertical_adjustment.get_value();
4463 vs->samples_per_pixel = samples_per_pixel;
4464 vs->leftmost_frame = leftmost_frame;
4465 vs->zoom_focus = zoom_focus;
4468 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4475 Editor::undo_visual_state ()
4477 if (undo_visual_stack.empty()) {
4481 VisualState* vs = undo_visual_stack.back();
4482 undo_visual_stack.pop_back();
4485 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4488 use_visual_state (*vs);
4493 Editor::redo_visual_state ()
4495 if (redo_visual_stack.empty()) {
4499 VisualState* vs = redo_visual_stack.back();
4500 redo_visual_stack.pop_back();
4502 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4503 // why do we check here?
4504 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4507 use_visual_state (*vs);
4512 Editor::swap_visual_state ()
4514 if (undo_visual_stack.empty()) {
4515 redo_visual_state ();
4517 undo_visual_state ();
4522 Editor::use_visual_state (VisualState& vs)
4524 PBD::Unwinder<bool> nsv (no_save_visual, true);
4525 DisplaySuspender ds;
4527 vertical_adjustment.set_value (vs.y_position);
4529 set_zoom_focus (vs.zoom_focus);
4530 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4533 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4535 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4536 (*i)->clear_property_cache();
4537 (*i)->reset_visual_state ();
4541 _routes->update_visibility ();
4544 /** This is the core function that controls the zoom level of the canvas. It is called
4545 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4546 * @param spp new number of samples per pixel
4549 Editor::set_samples_per_pixel (framecnt_t spp)
4555 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4556 const framecnt_t lots_of_pixels = 4000;
4558 /* if the zoom level is greater than what you'd get trying to display 3
4559 * days of audio on a really big screen, then it's too big.
4562 if (spp * lots_of_pixels > three_days) {
4566 samples_per_pixel = spp;
4569 tempo_lines->tempo_map_changed();
4572 bool const showing_time_selection = selection->time.length() > 0;
4574 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4575 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4576 (*i)->reshow_selection (selection->time);
4580 ZoomChanged (); /* EMIT_SIGNAL */
4582 ArdourCanvas::GtkCanvasViewport* c;
4584 c = get_track_canvas();
4586 c->canvas()->zoomed ();
4589 if (playhead_cursor) {
4590 playhead_cursor->set_position (playhead_cursor->current_frame ());
4593 refresh_location_display();
4594 _summary->set_overlays_dirty ();
4596 update_marker_labels ();
4602 Editor::playhead_cursor_sample () const
4604 return playhead_cursor->current_frame();
4608 Editor::queue_visual_videotimeline_update ()
4611 * pending_visual_change.add (VisualChange::VideoTimeline);
4612 * or maybe even more specific: which videotimeline-image
4613 * currently it calls update_video_timeline() to update
4614 * _all outdated_ images on the video-timeline.
4615 * see 'exposeimg()' in video_image_frame.cc
4617 ensure_visual_change_idle_handler ();
4621 Editor::ensure_visual_change_idle_handler ()
4623 if (pending_visual_change.idle_handler_id < 0) {
4624 // see comment in add_to_idle_resize above.
4625 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4626 pending_visual_change.being_handled = false;
4631 Editor::_idle_visual_changer (void* arg)
4633 return static_cast<Editor*>(arg)->idle_visual_changer ();
4637 Editor::idle_visual_changer ()
4639 /* set_horizontal_position() below (and maybe other calls) call
4640 gtk_main_iteration(), so it's possible that a signal will be handled
4641 half-way through this method. If this signal wants an
4642 idle_visual_changer we must schedule another one after this one, so
4643 mark the idle_handler_id as -1 here to allow that. Also make a note
4644 that we are doing the visual change, so that changes in response to
4645 super-rapid-screen-update can be dropped if we are still processing
4649 pending_visual_change.idle_handler_id = -1;
4650 pending_visual_change.being_handled = true;
4652 VisualChange vc = pending_visual_change;
4654 pending_visual_change.pending = (VisualChange::Type) 0;
4656 visual_changer (vc);
4658 pending_visual_change.being_handled = false;
4660 return 0; /* this is always a one-shot call */
4664 Editor::visual_changer (const VisualChange& vc)
4666 double const last_time_origin = horizontal_position ();
4668 if (vc.pending & VisualChange::ZoomLevel) {
4669 set_samples_per_pixel (vc.samples_per_pixel);
4671 compute_fixed_ruler_scale ();
4673 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4674 update_tempo_based_rulers ();
4676 update_video_timeline();
4679 if (vc.pending & VisualChange::TimeOrigin) {
4680 set_horizontal_position (vc.time_origin / samples_per_pixel);
4683 if (vc.pending & VisualChange::YOrigin) {
4684 vertical_adjustment.set_value (vc.y_origin);
4687 if (last_time_origin == horizontal_position ()) {
4688 /* changed signal not emitted */
4689 update_fixed_rulers ();
4690 redisplay_tempo (true);
4693 if (!(vc.pending & VisualChange::ZoomLevel)) {
4694 update_video_timeline();
4697 _summary->set_overlays_dirty ();
4700 struct EditorOrderTimeAxisSorter {
4701 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4702 return a->order () < b->order ();
4707 Editor::sort_track_selection (TrackViewList& sel)
4709 EditorOrderTimeAxisSorter cmp;
4714 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4717 framepos_t where = 0;
4718 EditPoint ep = _edit_point;
4720 if (Profile->get_mixbus()) {
4721 if (ep == EditAtSelectedMarker) {
4722 ep = EditAtPlayhead;
4726 if (from_outside_canvas && (ep == EditAtMouse)) {
4727 ep = EditAtPlayhead;
4728 } else if (from_context_menu && (ep == EditAtMouse)) {
4729 return canvas_event_sample (&context_click_event, 0, 0);
4732 if (entered_marker) {
4733 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4734 return entered_marker->position();
4737 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4738 ep = EditAtSelectedMarker;
4741 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4742 ep = EditAtPlayhead;
4745 MusicFrame snap_mf (0, 0);
4748 case EditAtPlayhead:
4749 if (_dragging_playhead) {
4750 where = *_control_scroll_target;
4752 where = _session->audible_frame();
4754 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4757 case EditAtSelectedMarker:
4758 if (!selection->markers.empty()) {
4760 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4763 where = loc->start();
4767 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4775 if (!mouse_frame (where, ignored)) {
4776 /* XXX not right but what can we do ? */
4779 snap_mf.frame = where;
4781 where = snap_mf.frame;
4782 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4790 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4792 if (!_session) return;
4794 begin_reversible_command (cmd);
4798 if ((tll = transport_loop_location()) == 0) {
4799 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4800 XMLNode &before = _session->locations()->get_state();
4801 _session->locations()->add (loc, true);
4802 _session->set_auto_loop_location (loc);
4803 XMLNode &after = _session->locations()->get_state();
4804 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4806 XMLNode &before = tll->get_state();
4807 tll->set_hidden (false, this);
4808 tll->set (start, end);
4809 XMLNode &after = tll->get_state();
4810 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4813 commit_reversible_command ();
4817 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4819 if (!_session) return;
4821 begin_reversible_command (cmd);
4825 if ((tpl = transport_punch_location()) == 0) {
4826 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4827 XMLNode &before = _session->locations()->get_state();
4828 _session->locations()->add (loc, true);
4829 _session->set_auto_punch_location (loc);
4830 XMLNode &after = _session->locations()->get_state();
4831 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4833 XMLNode &before = tpl->get_state();
4834 tpl->set_hidden (false, this);
4835 tpl->set (start, end);
4836 XMLNode &after = tpl->get_state();
4837 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4840 commit_reversible_command ();
4843 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4844 * @param rs List to which found regions are added.
4845 * @param where Time to look at.
4846 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4849 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4851 const TrackViewList* tracks;
4854 tracks = &track_views;
4859 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4861 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4864 boost::shared_ptr<Track> tr;
4865 boost::shared_ptr<Playlist> pl;
4867 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4869 boost::shared_ptr<RegionList> regions = pl->regions_at (
4870 (framepos_t) floor ( (double) where * tr->speed()));
4872 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4873 RegionView* rv = rtv->view()->find_view (*i);
4884 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4886 const TrackViewList* tracks;
4889 tracks = &track_views;
4894 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4895 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4897 boost::shared_ptr<Track> tr;
4898 boost::shared_ptr<Playlist> pl;
4900 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4902 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4903 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4905 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4907 RegionView* rv = rtv->view()->find_view (*i);
4918 /** Get regions using the following method:
4920 * Make a region list using:
4921 * (a) any selected regions
4922 * (b) the intersection of any selected tracks and the edit point(*)
4923 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4925 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4927 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4931 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4933 RegionSelection regions;
4935 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4936 regions.add (entered_regionview);
4938 regions = selection->regions;
4941 if ( regions.empty() ) {
4942 TrackViewList tracks = selection->tracks;
4944 if (!tracks.empty()) {
4945 /* no region selected or entered, but some selected tracks:
4946 * act on all regions on the selected tracks at the edit point
4948 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4949 get_regions_at(regions, where, tracks);
4956 /** Get regions using the following method:
4958 * Make a region list using:
4959 * (a) any selected regions
4960 * (b) the intersection of any selected tracks and the edit point(*)
4961 * (c) if neither exists, then whatever region is under the mouse
4963 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4965 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4968 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4970 RegionSelection regions;
4972 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4973 regions.add (entered_regionview);
4975 regions = selection->regions;
4978 if ( regions.empty() ) {
4979 TrackViewList tracks = selection->tracks;
4981 if (!tracks.empty()) {
4982 /* no region selected or entered, but some selected tracks:
4983 * act on all regions on the selected tracks at the edit point
4985 get_regions_at(regions, pos, tracks);
4992 /** Start with regions that are selected, or the entered regionview if none are selected.
4993 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4994 * of the regions that we started with.
4998 Editor::get_regions_from_selection_and_entered () const
5000 RegionSelection regions = selection->regions;
5002 if (regions.empty() && entered_regionview) {
5003 regions.add (entered_regionview);
5010 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5012 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5013 RouteTimeAxisView* rtav;
5015 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5016 boost::shared_ptr<Playlist> pl;
5017 std::vector<boost::shared_ptr<Region> > results;
5018 boost::shared_ptr<Track> tr;
5020 if ((tr = rtav->track()) == 0) {
5025 if ((pl = (tr->playlist())) != 0) {
5026 boost::shared_ptr<Region> r = pl->region_by_id (id);
5028 RegionView* rv = rtav->view()->find_view (r);
5030 regions.push_back (rv);
5039 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5042 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5043 MidiTimeAxisView* mtav;
5045 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5047 mtav->get_per_region_note_selection (selection);
5054 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5056 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5058 RouteTimeAxisView* tatv;
5060 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5062 boost::shared_ptr<Playlist> pl;
5063 vector<boost::shared_ptr<Region> > results;
5065 boost::shared_ptr<Track> tr;
5067 if ((tr = tatv->track()) == 0) {
5072 if ((pl = (tr->playlist())) != 0) {
5073 if (src_comparison) {
5074 pl->get_source_equivalent_regions (region, results);
5076 pl->get_region_list_equivalent_regions (region, results);
5080 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5081 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5082 regions.push_back (marv);
5091 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5093 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5094 RouteTimeAxisView* tatv;
5095 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5096 if (!tatv->track()) {
5099 RegionView* marv = tatv->view()->find_view (region);
5109 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5111 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5112 RouteTimeAxisView* rtav;
5113 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5114 if (rtav->route() == route) {
5123 Editor::show_rhythm_ferret ()
5125 if (rhythm_ferret == 0) {
5126 rhythm_ferret = new RhythmFerret(*this);
5129 rhythm_ferret->set_session (_session);
5130 rhythm_ferret->show ();
5131 rhythm_ferret->present ();
5135 Editor::first_idle ()
5137 MessageDialog* dialog = 0;
5139 if (track_views.size() > 1) {
5140 Timers::TimerSuspender t;
5141 dialog = new MessageDialog (
5142 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5146 ARDOUR_UI::instance()->flush_pending (60);
5149 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5153 // first idle adds route children (automation tracks), so we need to redisplay here
5154 _routes->redisplay ();
5158 if (_session->undo_depth() == 0) {
5159 undo_action->set_sensitive(false);
5161 redo_action->set_sensitive(false);
5162 begin_selection_op_history ();
5168 Editor::_idle_resize (gpointer arg)
5170 return ((Editor*)arg)->idle_resize ();
5174 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5176 if (resize_idle_id < 0) {
5177 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5178 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5179 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5181 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5182 _pending_resize_amount = 0;
5185 /* make a note of the smallest resulting height, so that we can clamp the
5186 lower limit at TimeAxisView::hSmall */
5188 int32_t min_resulting = INT32_MAX;
5190 _pending_resize_amount += h;
5191 _pending_resize_view = view;
5193 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5195 if (selection->tracks.contains (_pending_resize_view)) {
5196 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5197 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5201 if (min_resulting < 0) {
5206 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5207 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5211 /** Handle pending resizing of tracks */
5213 Editor::idle_resize ()
5215 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5217 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5218 selection->tracks.contains (_pending_resize_view)) {
5220 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5221 if (*i != _pending_resize_view) {
5222 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5227 _pending_resize_amount = 0;
5228 _group_tabs->set_dirty ();
5229 resize_idle_id = -1;
5237 ENSURE_GUI_THREAD (*this, &Editor::located);
5240 playhead_cursor->set_position (_session->audible_frame ());
5241 if (_follow_playhead && !_pending_initial_locate) {
5242 reset_x_origin_to_follow_playhead ();
5246 _pending_locate_request = false;
5247 _pending_initial_locate = false;
5251 Editor::region_view_added (RegionView * rv)
5253 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5254 if (rv->region ()->id () == (*pr)) {
5255 selection->add (rv);
5256 selection->regions.pending.erase (pr);
5261 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5263 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5264 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5265 if (rv->region()->id () == (*rnote).first) {
5266 mrv->select_notes ((*rnote).second);
5267 selection->pending_midi_note_selection.erase(rnote);
5273 _summary->set_background_dirty ();
5277 Editor::region_view_removed ()
5279 _summary->set_background_dirty ();
5283 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5285 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5286 if ((*j)->stripable() == s) {
5296 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5300 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5301 TimeAxisView* tv = axis_view_from_stripable (*i);
5311 Editor::suspend_route_redisplay ()
5314 _routes->suspend_redisplay();
5319 Editor::resume_route_redisplay ()
5322 _routes->redisplay(); // queue redisplay
5323 _routes->resume_redisplay();
5328 Editor::add_vcas (VCAList& vlist)
5332 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5333 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5336 add_stripables (sl);
5340 Editor::add_routes (RouteList& rlist)
5344 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5348 add_stripables (sl);
5352 Editor::add_stripables (StripableList& sl)
5354 list<TimeAxisView*> new_views;
5355 boost::shared_ptr<VCA> v;
5356 boost::shared_ptr<Route> r;
5357 TrackViewList new_selection;
5358 bool from_scratch = (track_views.size() == 0);
5360 sl.sort (StripablePresentationInfoSorter());
5362 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5364 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5366 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5368 new_views.push_back (vtv);
5370 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5372 if (r->is_auditioner() || r->is_monitor()) {
5376 RouteTimeAxisView* rtv;
5377 DataType dt = r->input()->default_type();
5379 if (dt == ARDOUR::DataType::AUDIO) {
5380 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5382 } else if (dt == ARDOUR::DataType::MIDI) {
5383 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5386 throw unknown_type();
5389 new_views.push_back (rtv);
5390 track_views.push_back (rtv);
5391 new_selection.push_back (rtv);
5393 rtv->effective_gain_display ();
5395 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5396 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5400 if (new_views.size() > 0) {
5401 _routes->time_axis_views_added (new_views);
5402 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5405 /* note: !new_selection.empty() means that we got some routes rather
5409 if (!from_scratch && !new_selection.empty()) {
5410 selection->tracks.clear();
5411 selection->add (new_selection);
5412 begin_selection_op_history();
5415 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5416 show_editor_mixer (true);
5419 editor_list_button.set_sensitive (true);
5423 Editor::timeaxisview_deleted (TimeAxisView *tv)
5425 if (tv == entered_track) {
5429 if (_session && _session->deletion_in_progress()) {
5430 /* the situation is under control */
5434 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5436 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5438 _routes->route_removed (tv);
5440 TimeAxisView::Children c = tv->get_child_list ();
5441 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5442 if (entered_track == i->get()) {
5447 /* remove it from the list of track views */
5449 TrackViewList::iterator i;
5451 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5452 i = track_views.erase (i);
5455 /* update whatever the current mixer strip is displaying, if revelant */
5457 boost::shared_ptr<Route> route;
5460 route = rtav->route ();
5463 if (current_mixer_strip && current_mixer_strip->route() == route) {
5465 TimeAxisView* next_tv;
5467 if (track_views.empty()) {
5469 } else if (i == track_views.end()) {
5470 next_tv = track_views.front();
5475 // skip VCAs (cannot be selected, n/a in editor-mixer)
5476 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5477 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5478 next_tv = track_views.front();
5480 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5481 /* just in case: no master, only a VCA remains */
5487 set_selected_mixer_strip (*next_tv);
5489 /* make the editor mixer strip go away setting the
5490 * button to inactive (which also unticks the menu option)
5493 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5499 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5504 if (apply_to_selection) {
5505 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5507 TrackSelection::iterator j = i;
5510 hide_track_in_display (*i, false);
5515 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5517 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5518 // this will hide the mixer strip
5519 set_selected_mixer_strip (*tv);
5522 _routes->hide_track_in_display (*tv);
5527 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5532 _routes->show_track_in_display (*tv);
5533 if (move_into_view) {
5534 ensure_time_axis_view_is_visible (*tv, false);
5539 Editor::sync_track_view_list_and_routes ()
5541 track_views = TrackViewList (_routes->views ());
5543 _summary->set_background_dirty();
5544 _group_tabs->set_dirty ();
5546 return false; // do not call again (until needed)
5550 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5552 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5557 /** Find a RouteTimeAxisView by the ID of its route */
5559 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5561 RouteTimeAxisView* v;
5563 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5564 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5565 if(v->route()->id() == id) {
5575 Editor::fit_route_group (RouteGroup *g)
5577 TrackViewList ts = axis_views_from_routes (g->route_list ());
5582 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5584 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5587 _session->cancel_audition ();
5591 if (_session->is_auditioning()) {
5592 _session->cancel_audition ();
5593 if (r == last_audition_region) {
5598 _session->audition_region (r);
5599 last_audition_region = r;
5604 Editor::hide_a_region (boost::shared_ptr<Region> r)
5606 r->set_hidden (true);
5610 Editor::show_a_region (boost::shared_ptr<Region> r)
5612 r->set_hidden (false);
5616 Editor::audition_region_from_region_list ()
5618 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5622 Editor::hide_region_from_region_list ()
5624 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5628 Editor::show_region_in_region_list ()
5630 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5634 Editor::step_edit_status_change (bool yn)
5637 start_step_editing ();
5639 stop_step_editing ();
5644 Editor::start_step_editing ()
5646 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5650 Editor::stop_step_editing ()
5652 step_edit_connection.disconnect ();
5656 Editor::check_step_edit ()
5658 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5659 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5661 mtv->check_step_edit ();
5665 return true; // do it again, till we stop
5669 Editor::scroll_press (Direction dir)
5671 ++_scroll_callbacks;
5673 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5674 /* delay the first auto-repeat */
5680 scroll_backward (1);
5688 scroll_up_one_track ();
5692 scroll_down_one_track ();
5696 /* do hacky auto-repeat */
5697 if (!_scroll_connection.connected ()) {
5699 _scroll_connection = Glib::signal_timeout().connect (
5700 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5703 _scroll_callbacks = 0;
5710 Editor::scroll_release ()
5712 _scroll_connection.disconnect ();
5715 /** Queue a change for the Editor viewport x origin to follow the playhead */
5717 Editor::reset_x_origin_to_follow_playhead ()
5719 framepos_t const frame = playhead_cursor->current_frame ();
5721 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5723 if (_session->transport_speed() < 0) {
5725 if (frame > (current_page_samples() / 2)) {
5726 center_screen (frame-(current_page_samples()/2));
5728 center_screen (current_page_samples()/2);
5735 if (frame < leftmost_frame) {
5737 if (_session->transport_rolling()) {
5738 /* rolling; end up with the playhead at the right of the page */
5739 l = frame - current_page_samples ();
5741 /* not rolling: end up with the playhead 1/4 of the way along the page */
5742 l = frame - current_page_samples() / 4;
5746 if (_session->transport_rolling()) {
5747 /* rolling: end up with the playhead on the left of the page */
5750 /* not rolling: end up with the playhead 3/4 of the way along the page */
5751 l = frame - 3 * current_page_samples() / 4;
5759 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5765 Editor::super_rapid_screen_update ()
5767 if (!_session || !_session->engine().running()) {
5771 /* METERING / MIXER STRIPS */
5773 /* update track meters, if required */
5774 if (contents().is_mapped() && meters_running) {
5775 RouteTimeAxisView* rtv;
5776 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5777 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5778 rtv->fast_update ();
5783 /* and any current mixer strip */
5784 if (current_mixer_strip) {
5785 current_mixer_strip->fast_update ();
5788 /* PLAYHEAD AND VIEWPORT */
5790 framepos_t const frame = _session->audible_frame();
5792 /* There are a few reasons why we might not update the playhead / viewport stuff:
5794 * 1. we don't update things when there's a pending locate request, otherwise
5795 * when the editor requests a locate there is a chance that this method
5796 * will move the playhead before the locate request is processed, causing
5798 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5799 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5802 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5804 last_update_frame = frame;
5806 if (!_dragging_playhead) {
5807 playhead_cursor->set_position (frame);
5810 if (!_stationary_playhead) {
5812 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5813 /* We only do this if we aren't already
5814 handling a visual change (ie if
5815 pending_visual_change.being_handled is
5816 false) so that these requests don't stack
5817 up there are too many of them to handle in
5820 reset_x_origin_to_follow_playhead ();
5825 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5826 framepos_t const frame = playhead_cursor->current_frame ();
5827 double target = ((double)frame - (double)current_page_samples()/2.0);
5828 if (target <= 0.0) {
5831 // compare to EditorCursor::set_position()
5832 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5833 double const new_pos = sample_to_pixel_unrounded (target);
5834 if (rint (new_pos) != rint (old_pos)) {
5835 reset_x_origin (pixel_to_sample (floor (new_pos)));
5846 Editor::session_going_away ()
5848 _have_idled = false;
5850 _session_connections.drop_connections ();
5852 super_rapid_screen_update_connection.disconnect ();
5854 selection->clear ();
5855 cut_buffer->clear ();
5857 clicked_regionview = 0;
5858 clicked_axisview = 0;
5859 clicked_routeview = 0;
5860 entered_regionview = 0;
5862 last_update_frame = 0;
5865 playhead_cursor->hide ();
5867 /* rip everything out of the list displays */
5871 _route_groups->clear ();
5873 /* do this first so that deleting a track doesn't reset cms to null
5874 and thus cause a leak.
5877 if (current_mixer_strip) {
5878 if (current_mixer_strip->get_parent() != 0) {
5879 global_hpacker.remove (*current_mixer_strip);
5881 delete current_mixer_strip;
5882 current_mixer_strip = 0;
5885 /* delete all trackviews */
5887 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5890 track_views.clear ();
5892 nudge_clock->set_session (0);
5894 editor_list_button.set_active(false);
5895 editor_list_button.set_sensitive(false);
5897 /* clear tempo/meter rulers */
5898 remove_metric_marks ();
5900 clear_marker_display ();
5902 stop_step_editing ();
5906 /* get rid of any existing editor mixer strip */
5908 WindowTitle title(Glib::get_application_name());
5909 title += _("Editor");
5911 own_window()->set_title (title.get_string());
5914 SessionHandlePtr::session_going_away ();
5918 Editor::trigger_script (int i)
5920 LuaInstance::instance()-> call_action (i);
5924 Editor::show_editor_list (bool yn)
5927 _editor_list_vbox.show ();
5929 _editor_list_vbox.hide ();
5934 Editor::change_region_layering_order (bool from_context_menu)
5936 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5938 if (!clicked_routeview) {
5939 if (layering_order_editor) {
5940 layering_order_editor->hide ();
5945 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5951 boost::shared_ptr<Playlist> pl = track->playlist();
5957 if (layering_order_editor == 0) {
5958 layering_order_editor = new RegionLayeringOrderEditor (*this);
5961 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5962 layering_order_editor->maybe_present ();
5966 Editor::update_region_layering_order_editor ()
5968 if (layering_order_editor && layering_order_editor->is_visible ()) {
5969 change_region_layering_order (true);
5974 Editor::setup_fade_images ()
5976 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5977 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5978 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5979 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5980 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5982 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5983 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5984 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5985 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5986 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5990 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5992 Editor::action_menu_item (std::string const & name)
5994 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5997 return *manage (a->create_menu_item ());
6001 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6003 EventBox* b = manage (new EventBox);
6004 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6005 Label* l = manage (new Label (name));
6009 _the_notebook.append_page (widget, *b);
6013 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6015 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6016 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6019 if (ev->type == GDK_2BUTTON_PRESS) {
6021 /* double-click on a notebook tab shrinks or expands the notebook */
6023 if (_notebook_shrunk) {
6024 if (pre_notebook_shrink_pane_width) {
6025 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6027 _notebook_shrunk = false;
6029 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6031 /* this expands the LHS of the edit pane to cover the notebook
6032 PAGE but leaves the tabs visible.
6034 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6035 _notebook_shrunk = true;
6043 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6045 using namespace Menu_Helpers;
6047 MenuList& items = _control_point_context_menu.items ();
6050 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6051 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6052 if (!can_remove_control_point (item)) {
6053 items.back().set_sensitive (false);
6056 _control_point_context_menu.popup (event->button.button, event->button.time);
6060 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6062 using namespace Menu_Helpers;
6064 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6069 /* We need to get the selection here and pass it to the operations, since
6070 popping up the menu will cause a region leave event which clears
6071 entered_regionview. */
6073 MidiRegionView& mrv = note->region_view();
6074 const RegionSelection rs = get_regions_from_selection_and_entered ();
6075 const uint32_t sel_size = mrv.selection_size ();
6077 MenuList& items = _note_context_menu.items();
6081 items.push_back(MenuElem(_("Delete"),
6082 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6085 items.push_back(MenuElem(_("Edit..."),
6086 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6087 if (sel_size != 1) {
6088 items.back().set_sensitive (false);
6091 items.push_back(MenuElem(_("Transpose..."),
6092 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6095 items.push_back(MenuElem(_("Legatize"),
6096 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6098 items.back().set_sensitive (false);
6101 items.push_back(MenuElem(_("Quantize..."),
6102 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6104 items.push_back(MenuElem(_("Remove Overlap"),
6105 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6107 items.back().set_sensitive (false);
6110 items.push_back(MenuElem(_("Transform..."),
6111 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6113 _note_context_menu.popup (event->button.button, event->button.time);
6117 Editor::zoom_vertical_modifier_released()
6119 _stepping_axis_view = 0;
6123 Editor::ui_parameter_changed (string parameter)
6125 if (parameter == "icon-set") {
6126 while (!_cursor_stack.empty()) {
6127 _cursor_stack.pop_back();
6129 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6130 _cursor_stack.push_back(_cursors->grabber);
6131 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6132 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6134 } else if (parameter == "draggable-playhead") {
6135 if (_verbose_cursor) {
6136 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6142 Editor::use_own_window (bool and_fill_it)
6144 bool new_window = !own_window();
6146 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6148 if (win && new_window) {
6149 win->set_name ("EditorWindow");
6151 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6153 // win->signal_realize().connect (*this, &Editor::on_realize);
6154 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6155 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6156 win->set_data ("ardour-bindings", bindings);
6161 DisplaySuspender ds;
6162 contents().show_all ();
6164 /* XXX: this is a bit unfortunate; it would probably
6165 be nicer if we could just call show () above rather
6166 than needing the show_all ()
6169 /* re-hide stuff if necessary */
6170 editor_list_button_toggled ();
6171 parameter_changed ("show-summary");
6172 parameter_changed ("show-group-tabs");
6173 parameter_changed ("show-zoom-tools");
6175 /* now reset all audio_time_axis heights, because widgets might need
6181 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6182 tv = (static_cast<TimeAxisView*>(*i));
6183 tv->reset_height ();
6186 if (current_mixer_strip) {
6187 current_mixer_strip->hide_things ();
6188 current_mixer_strip->parameter_changed ("mixer-element-visibility");