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/eventboxext.h"
61 #include "gtkmm2ext/grouped_buttons.h"
62 #include "gtkmm2ext/gtk_ui.h"
63 #include <gtkmm2ext/keyboard.h>
64 #include "gtkmm2ext/utils.h"
65 #include "gtkmm2ext/window_title.h"
66 #include "gtkmm2ext/choice.h"
67 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
69 #include "ardour/analysis_graph.h"
70 #include "ardour/audio_track.h"
71 #include "ardour/audioengine.h"
72 #include "ardour/audioregion.h"
73 #include "ardour/lmath.h"
74 #include "ardour/location.h"
75 #include "ardour/profile.h"
76 #include "ardour/route.h"
77 #include "ardour/route_group.h"
78 #include "ardour/session_playlists.h"
79 #include "ardour/tempo.h"
80 #include "ardour/utils.h"
81 #include "ardour/vca_manager.h"
82 #include "ardour/vca.h"
84 #include "canvas/debug.h"
85 #include "canvas/text.h"
87 #include "control_protocol/control_protocol.h"
90 #include "analysis_window.h"
91 #include "ardour_spacer.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
102 #include "editor_cursors.h"
103 #include "editor_drag.h"
104 #include "editor_group_tabs.h"
105 #include "editor_locations.h"
106 #include "editor_regions.h"
107 #include "editor_route_groups.h"
108 #include "editor_routes.h"
109 #include "editor_snapshots.h"
110 #include "editor_summary.h"
111 #include "export_report.h"
112 #include "global_port_matrix.h"
113 #include "gui_object.h"
114 #include "gui_thread.h"
115 #include "keyboard.h"
116 #include "luainstance.h"
118 #include "midi_region_view.h"
119 #include "midi_time_axis.h"
120 #include "mixer_strip.h"
121 #include "mixer_ui.h"
122 #include "mouse_cursors.h"
123 #include "note_base.h"
124 #include "playlist_selector.h"
125 #include "public_editor.h"
126 #include "quantize_dialog.h"
127 #include "region_layering_order_editor.h"
128 #include "rgb_macros.h"
129 #include "rhythm_ferret.h"
130 #include "route_sorter.h"
131 #include "selection.h"
132 #include "simple_progress_dialog.h"
134 #include "tempo_lines.h"
135 #include "time_axis_view.h"
136 #include "time_info_box.h"
138 #include "tooltips.h"
139 #include "ui_config.h"
141 #include "vca_time_axis.h"
142 #include "verbose_cursor.h"
144 #include "pbd/i18n.h"
147 using namespace ARDOUR;
148 using namespace ARDOUR_UI_UTILS;
151 using namespace Glib;
152 using namespace Gtkmm2ext;
153 using namespace Editing;
155 using PBD::internationalize;
157 using Gtkmm2ext::Keyboard;
159 double Editor::timebar_height = 15.0;
161 static const gchar *_snap_type_strings[] = {
195 static const gchar *_snap_mode_strings[] = {
202 static const gchar *_edit_point_strings[] = {
209 static const gchar *_edit_mode_strings[] = {
217 static const gchar *_zoom_focus_strings[] = {
227 #ifdef USE_RUBBERBAND
228 static const gchar *_rb_opt_strings[] = {
231 N_("Balanced multitimbral mixture"),
232 N_("Unpitched percussion with stable notes"),
233 N_("Crisp monophonic instrumental"),
234 N_("Unpitched solo percussion"),
235 N_("Resample without preserving pitch"),
240 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
243 : PublicEditor (global_hpacker)
244 , editor_mixer_strip_width (Wide)
245 , constructed (false)
246 , _playlist_selector (0)
248 , no_save_visual (false)
250 , samples_per_pixel (2048)
251 , zoom_focus (ZoomFocusPlayhead)
252 , mouse_mode (MouseObject)
253 , pre_internal_snap_type (SnapToBeat)
254 , pre_internal_snap_mode (SnapOff)
255 , internal_snap_type (SnapToBeat)
256 , internal_snap_mode (SnapOff)
257 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
258 , _notebook_shrunk (false)
259 , location_marker_color (0)
260 , location_range_color (0)
261 , location_loop_color (0)
262 , location_punch_color (0)
263 , location_cd_marker_color (0)
265 , _show_marker_lines (false)
266 , clicked_axisview (0)
267 , clicked_routeview (0)
268 , clicked_regionview (0)
269 , clicked_selection (0)
270 , clicked_control_point (0)
271 , button_release_can_deselect (true)
272 , _mouse_changed_selection (false)
273 , region_edit_menu_split_item (0)
274 , region_edit_menu_split_multichannel_item (0)
275 , track_region_edit_playlist_menu (0)
276 , track_edit_playlist_submenu (0)
277 , track_selection_edit_playlist_submenu (0)
278 , _popup_region_menu_item (0)
280 , _track_canvas_viewport (0)
281 , within_track_canvas (false)
282 , _verbose_cursor (0)
286 , range_marker_group (0)
287 , transport_marker_group (0)
288 , cd_marker_group (0)
289 , _time_markers_group (0)
290 , hv_scroll_group (0)
292 , cursor_scroll_group (0)
293 , no_scroll_group (0)
294 , _trackview_group (0)
295 , _drag_motion_group (0)
296 , _canvas_drop_zone (0)
297 , no_ruler_shown_update (false)
298 , ruler_grabbed_widget (0)
300 , minsec_mark_interval (0)
301 , minsec_mark_modulo (0)
303 , timecode_mark_modulo (0)
304 , timecode_nmarks (0)
305 , _samples_ruler_interval (0)
308 , bbt_bar_helper_on (0)
309 , bbt_accent_modulo (0)
314 , visible_timebars (0)
315 , editor_ruler_menu (0)
319 , range_marker_bar (0)
320 , transport_marker_bar (0)
322 , minsec_label (_("Mins:Secs"))
323 , bbt_label (_("Bars:Beats"))
324 , timecode_label (_("Timecode"))
325 , samples_label (_("Samples"))
326 , tempo_label (_("Tempo"))
327 , meter_label (_("Meter"))
328 , mark_label (_("Location Markers"))
329 , range_mark_label (_("Range Markers"))
330 , transport_mark_label (_("Loop/Punch Ranges"))
331 , cd_mark_label (_("CD Markers"))
332 , videotl_label (_("Video Timeline"))
334 , playhead_cursor (0)
335 , edit_packer (4, 4, true)
336 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
337 , horizontal_adjustment (0.0, 0.0, 1e16)
338 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
339 , controls_layout (unused_adjustment, vertical_adjustment)
340 , _scroll_callbacks (0)
341 , _visible_canvas_width (0)
342 , _visible_canvas_height (0)
343 , _full_canvas_height (0)
344 , edit_controls_left_menu (0)
345 , edit_controls_right_menu (0)
346 , _last_update_time (0)
347 , _err_screen_engine (0)
348 , cut_buffer_start (0)
349 , cut_buffer_length (0)
350 , button_bindings (0)
354 , current_interthread_info (0)
355 , analysis_window (0)
356 , select_new_marker (false)
358 , scrubbing_direction (0)
359 , scrub_reversals (0)
360 , scrub_reverse_distance (0)
361 , have_pending_keyboard_selection (false)
362 , pending_keyboard_selection_start (0)
363 , _snap_type (SnapToBeat)
364 , _snap_mode (SnapOff)
365 , snap_threshold (5.0)
366 , ignore_gui_changes (false)
367 , _drags (new DragManager (this))
369 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
370 , _dragging_playhead (false)
371 , _dragging_edit_point (false)
372 , _show_measures (true)
373 , _follow_playhead (true)
374 , _stationary_playhead (false)
377 , global_rect_group (0)
378 , time_line_group (0)
379 , tempo_marker_menu (0)
380 , meter_marker_menu (0)
382 , range_marker_menu (0)
383 , transport_marker_menu (0)
384 , new_transport_marker_menu (0)
386 , marker_menu_item (0)
387 , bbt_beat_subdivision (4)
388 , _visible_track_count (-1)
389 , toolbar_selection_clock_table (2,3)
390 , automation_mode_button (_("mode"))
391 , selection (new Selection (this))
392 , cut_buffer (new Selection (this))
393 , _selection_memento (new SelectionMemento())
394 , _all_region_actions_sensitized (false)
395 , _ignore_region_action (false)
396 , _last_region_menu_was_main (false)
397 , _track_selection_change_without_scroll (false)
398 , cd_marker_bar_drag_rect (0)
399 , range_bar_drag_rect (0)
400 , transport_bar_drag_rect (0)
401 , transport_bar_range_rect (0)
402 , transport_bar_preroll_rect (0)
403 , transport_bar_postroll_rect (0)
404 , transport_loop_range_rect (0)
405 , transport_punch_range_rect (0)
406 , transport_punchin_line (0)
407 , transport_punchout_line (0)
408 , transport_preroll_rect (0)
409 , transport_postroll_rect (0)
411 , rubberband_rect (0)
417 , autoscroll_horizontal_allowed (false)
418 , autoscroll_vertical_allowed (false)
420 , autoscroll_widget (0)
421 , show_gain_after_trim (false)
422 , selection_op_cmd_depth (0)
423 , selection_op_history_it (0)
424 , no_save_instant (false)
426 , current_mixer_strip (0)
427 , show_editor_mixer_when_tracks_arrive (false)
428 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
429 , current_stepping_trackview (0)
430 , last_track_height_step_timestamp (0)
432 , entered_regionview (0)
433 , clear_entered_track (false)
434 , _edit_point (EditAtMouse)
435 , meters_running (false)
437 , _have_idled (false)
438 , resize_idle_id (-1)
439 , _pending_resize_amount (0)
440 , _pending_resize_view (0)
441 , _pending_locate_request (false)
442 , _pending_initial_locate (false)
446 , layering_order_editor (0)
447 , _last_cut_copy_source_track (0)
448 , _region_selection_change_updates_region_list (true)
450 , _following_mixer_selection (false)
451 , _control_point_toggled_on_press (false)
452 , _stepping_axis_view (0)
453 , quantize_dialog (0)
454 , _main_menu_disabler (0)
455 , myactions (X_("editor"))
457 /* we are a singleton */
459 PublicEditor::_instance = this;
463 last_event_time.tv_sec = 0;
464 last_event_time.tv_usec = 0;
466 selection_op_history.clear();
469 snap_type_strings = I18N (_snap_type_strings);
470 snap_mode_strings = I18N (_snap_mode_strings);
471 zoom_focus_strings = I18N (_zoom_focus_strings);
472 edit_mode_strings = I18N (_edit_mode_strings);
473 edit_point_strings = I18N (_edit_point_strings);
474 #ifdef USE_RUBBERBAND
475 rb_opt_strings = I18N (_rb_opt_strings);
479 build_edit_mode_menu();
480 build_zoom_focus_menu();
481 build_track_count_menu();
482 build_snap_mode_menu();
483 build_snap_type_menu();
484 build_edit_point_menu();
486 location_marker_color = UIConfiguration::instance().color ("location marker");
487 location_range_color = UIConfiguration::instance().color ("location range");
488 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
489 location_loop_color = UIConfiguration::instance().color ("location loop");
490 location_punch_color = UIConfiguration::instance().color ("location punch");
492 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
494 TimeAxisView::setup_sizes ();
495 ArdourMarker::setup_sizes (timebar_height);
496 TempoCurve::setup_sizes (timebar_height);
498 bbt_label.set_name ("EditorRulerLabel");
499 bbt_label.set_size_request (-1, (int)timebar_height);
500 bbt_label.set_alignment (1.0, 0.5);
501 bbt_label.set_padding (5,0);
503 bbt_label.set_no_show_all();
504 minsec_label.set_name ("EditorRulerLabel");
505 minsec_label.set_size_request (-1, (int)timebar_height);
506 minsec_label.set_alignment (1.0, 0.5);
507 minsec_label.set_padding (5,0);
508 minsec_label.hide ();
509 minsec_label.set_no_show_all();
510 timecode_label.set_name ("EditorRulerLabel");
511 timecode_label.set_size_request (-1, (int)timebar_height);
512 timecode_label.set_alignment (1.0, 0.5);
513 timecode_label.set_padding (5,0);
514 timecode_label.hide ();
515 timecode_label.set_no_show_all();
516 samples_label.set_name ("EditorRulerLabel");
517 samples_label.set_size_request (-1, (int)timebar_height);
518 samples_label.set_alignment (1.0, 0.5);
519 samples_label.set_padding (5,0);
520 samples_label.hide ();
521 samples_label.set_no_show_all();
523 tempo_label.set_name ("EditorRulerLabel");
524 tempo_label.set_size_request (-1, (int)timebar_height);
525 tempo_label.set_alignment (1.0, 0.5);
526 tempo_label.set_padding (5,0);
528 tempo_label.set_no_show_all();
530 meter_label.set_name ("EditorRulerLabel");
531 meter_label.set_size_request (-1, (int)timebar_height);
532 meter_label.set_alignment (1.0, 0.5);
533 meter_label.set_padding (5,0);
535 meter_label.set_no_show_all();
537 if (Profile->get_trx()) {
538 mark_label.set_text (_("Markers"));
540 mark_label.set_name ("EditorRulerLabel");
541 mark_label.set_size_request (-1, (int)timebar_height);
542 mark_label.set_alignment (1.0, 0.5);
543 mark_label.set_padding (5,0);
545 mark_label.set_no_show_all();
547 cd_mark_label.set_name ("EditorRulerLabel");
548 cd_mark_label.set_size_request (-1, (int)timebar_height);
549 cd_mark_label.set_alignment (1.0, 0.5);
550 cd_mark_label.set_padding (5,0);
551 cd_mark_label.hide();
552 cd_mark_label.set_no_show_all();
554 videotl_bar_height = 4;
555 videotl_label.set_name ("EditorRulerLabel");
556 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
557 videotl_label.set_alignment (1.0, 0.5);
558 videotl_label.set_padding (5,0);
559 videotl_label.hide();
560 videotl_label.set_no_show_all();
562 range_mark_label.set_name ("EditorRulerLabel");
563 range_mark_label.set_size_request (-1, (int)timebar_height);
564 range_mark_label.set_alignment (1.0, 0.5);
565 range_mark_label.set_padding (5,0);
566 range_mark_label.hide();
567 range_mark_label.set_no_show_all();
569 transport_mark_label.set_name ("EditorRulerLabel");
570 transport_mark_label.set_size_request (-1, (int)timebar_height);
571 transport_mark_label.set_alignment (1.0, 0.5);
572 transport_mark_label.set_padding (5,0);
573 transport_mark_label.hide();
574 transport_mark_label.set_no_show_all();
576 initialize_canvas ();
578 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
580 _summary = new EditorSummary (this);
582 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
584 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
586 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
587 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
589 edit_controls_vbox.set_spacing (0);
590 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
591 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
593 HBox* h = manage (new HBox);
594 _group_tabs = new EditorGroupTabs (this);
595 if (!ARDOUR::Profile->get_trx()) {
596 h->pack_start (*_group_tabs, PACK_SHRINK);
598 h->pack_start (edit_controls_vbox);
599 controls_layout.add (*h);
601 controls_layout.set_name ("EditControlsBase");
602 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
603 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
604 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
606 _cursors = new MouseCursors;
607 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
608 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
610 /* Push default cursor to ever-present bottom of cursor stack. */
611 push_canvas_cursor(_cursors->grabber);
613 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
615 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
616 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
617 pad_line_1->set_outline_color (0xFF0000FF);
623 edit_packer.set_col_spacings (0);
624 edit_packer.set_row_spacings (0);
625 edit_packer.set_homogeneous (false);
626 edit_packer.set_border_width (0);
627 edit_packer.set_name ("EditorWindow");
629 time_bars_event_box.add (time_bars_vbox);
630 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
631 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
633 /* labels for the time bars */
634 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
636 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
638 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
640 bottom_hbox.set_border_width (2);
641 bottom_hbox.set_spacing (3);
643 _route_groups = new EditorRouteGroups (this);
644 _routes = new EditorRoutes (this);
645 _regions = new EditorRegions (this);
646 _snapshots = new EditorSnapshots (this);
647 _locations = new EditorLocations (this);
648 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
650 /* these are static location signals */
652 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
654 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
656 add_notebook_page (_("Regions"), _regions->widget ());
657 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
658 add_notebook_page (_("Snapshots"), _snapshots->widget ());
659 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
660 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
662 _the_notebook.set_show_tabs (true);
663 _the_notebook.set_scrollable (true);
664 _the_notebook.popup_disable ();
665 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
666 _the_notebook.show_all ();
668 _notebook_shrunk = false;
671 /* Pick up some settings we need to cache, early */
673 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
676 if (settings && (prop = settings->property ("notebook-shrunk"))) {
677 _notebook_shrunk = string_is_affirmative (prop->value ());
680 editor_summary_pane.set_check_divider_position (true);
681 editor_summary_pane.add (edit_packer);
683 Button* summary_arrows_left_left = manage (new Button);
684 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
685 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
686 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
688 Button* summary_arrows_left_right = manage (new Button);
689 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
690 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
691 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
693 VBox* summary_arrows_left = manage (new VBox);
694 summary_arrows_left->pack_start (*summary_arrows_left_left);
695 summary_arrows_left->pack_start (*summary_arrows_left_right);
697 Button* summary_arrows_right_up = manage (new Button);
698 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
699 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
700 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
702 Button* summary_arrows_right_down = manage (new Button);
703 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
704 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
705 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
707 VBox* summary_arrows_right = manage (new VBox);
708 summary_arrows_right->pack_start (*summary_arrows_right_up);
709 summary_arrows_right->pack_start (*summary_arrows_right_down);
711 Frame* summary_frame = manage (new Frame);
712 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
714 summary_frame->add (*_summary);
715 summary_frame->show ();
717 _summary_hbox.pack_start (*summary_arrows_left, false, false);
718 _summary_hbox.pack_start (*summary_frame, true, true);
719 _summary_hbox.pack_start (*summary_arrows_right, false, false);
721 if (!ARDOUR::Profile->get_trx()) {
722 editor_summary_pane.add (_summary_hbox);
725 edit_pane.set_check_divider_position (true);
726 edit_pane.add (editor_summary_pane);
727 if (!ARDOUR::Profile->get_trx()) {
728 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
729 _editor_list_vbox.pack_start (_the_notebook);
730 edit_pane.add (_editor_list_vbox);
731 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
734 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
735 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
742 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
743 /* initial allocation is 90% to canvas, 10% to notebook */
744 edit_pane.set_divider (0, 0.90);
746 edit_pane.set_divider (0, fract);
749 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
750 /* initial allocation is 90% to canvas, 10% to summary */
751 editor_summary_pane.set_divider (0, 0.90);
754 editor_summary_pane.set_divider (0, fract);
758 global_vpacker.set_spacing (2);
759 global_vpacker.set_border_width (0);
761 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
763 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
764 ebox->set_name("EditorWindow");
765 ebox->add (toolbar_hbox);
767 Gtk::EventBox* epane_box = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
768 epane_box->set_name("EditorWindow");
769 epane_box->add (edit_pane);
771 Gtk::EventBox* epane_box2 = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
772 epane_box2->set_name("EditorWindow");
773 epane_box2->add (global_vpacker);
775 global_vpacker.pack_start (*ebox, false, false);
776 global_vpacker.pack_start (*epane_box, true, true);
777 global_hpacker.pack_start (*epane_box2, true, true);
779 /* need to show the "contents" widget so that notebook will show if tab is switched to
782 global_hpacker.show ();
784 /* register actions now so that set_state() can find them and set toggles/checks etc */
791 _playlist_selector = new PlaylistSelector();
792 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
794 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
798 nudge_forward_button.set_name ("nudge button");
799 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
801 nudge_backward_button.set_name ("nudge button");
802 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
804 fade_context_menu.set_name ("ArdourContextMenu");
806 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
808 /* allow external control surfaces/protocols to do various things */
810 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
811 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
812 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
813 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
814 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
815 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
816 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
817 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
818 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
819 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
820 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
821 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
822 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
823 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
825 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
826 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
827 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
828 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
829 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
831 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), 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::button_settings () const
911 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
912 XMLNode* node = find_named_node (*settings, X_("Buttons"));
915 node = new XMLNode (X_("Buttons"));
922 Editor::get_smart_mode () const
924 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
928 Editor::catch_vanishing_regionview (RegionView *rv)
930 /* note: the selection will take care of the vanishing
931 audioregionview by itself.
934 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
938 if (clicked_regionview == rv) {
939 clicked_regionview = 0;
942 if (entered_regionview == rv) {
943 set_entered_regionview (0);
946 if (!_all_region_actions_sensitized) {
947 sensitize_all_region_actions (true);
952 Editor::set_entered_regionview (RegionView* rv)
954 if (rv == entered_regionview) {
958 if (entered_regionview) {
959 entered_regionview->exited ();
962 entered_regionview = rv;
964 if (entered_regionview != 0) {
965 entered_regionview->entered ();
968 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
969 /* This RegionView entry might have changed what region actions
970 are allowed, so sensitize them all in case a key is pressed.
972 sensitize_all_region_actions (true);
977 Editor::set_entered_track (TimeAxisView* tav)
980 entered_track->exited ();
986 entered_track->entered ();
991 Editor::instant_save ()
993 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
998 _session->add_instant_xml(get_state());
1000 Config->add_instant_xml(get_state());
1005 Editor::control_vertical_zoom_in_all ()
1007 tav_zoom_smooth (false, true);
1011 Editor::control_vertical_zoom_out_all ()
1013 tav_zoom_smooth (true, true);
1017 Editor::control_vertical_zoom_in_selected ()
1019 tav_zoom_smooth (false, false);
1023 Editor::control_vertical_zoom_out_selected ()
1025 tav_zoom_smooth (true, false);
1029 Editor::control_view (uint32_t view)
1031 goto_visual_state (view);
1035 Editor::control_unselect ()
1037 selection->clear_tracks ();
1041 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1043 TimeAxisView* tav = axis_view_from_stripable (s);
1047 case Selection::Add:
1048 selection->add (tav);
1050 case Selection::Toggle:
1051 selection->toggle (tav);
1053 case Selection::Extend:
1055 case Selection::Set:
1056 selection->set (tav);
1060 selection->clear_tracks ();
1065 Editor::control_step_tracks_up ()
1067 scroll_tracks_up_line ();
1071 Editor::control_step_tracks_down ()
1073 scroll_tracks_down_line ();
1077 Editor::control_scroll (float fraction)
1079 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1085 double step = fraction * current_page_samples();
1088 _control_scroll_target is an optional<T>
1090 it acts like a pointer to an framepos_t, with
1091 a operator conversion to boolean to check
1092 that it has a value could possibly use
1093 playhead_cursor->current_frame to store the
1094 value and a boolean in the class to know
1095 when it's out of date
1098 if (!_control_scroll_target) {
1099 _control_scroll_target = _session->transport_frame();
1100 _dragging_playhead = true;
1103 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1104 *_control_scroll_target = 0;
1105 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1106 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1108 *_control_scroll_target += (framepos_t) trunc (step);
1111 /* move visuals, we'll catch up with it later */
1113 playhead_cursor->set_position (*_control_scroll_target);
1114 UpdateAllTransportClocks (*_control_scroll_target);
1116 if (*_control_scroll_target > (current_page_samples() / 2)) {
1117 /* try to center PH in window */
1118 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1124 Now we do a timeout to actually bring the session to the right place
1125 according to the playhead. This is to avoid reading disk buffers on every
1126 call to control_scroll, which is driven by ScrollTimeline and therefore
1127 probably by a control surface wheel which can generate lots of events.
1129 /* cancel the existing timeout */
1131 control_scroll_connection.disconnect ();
1133 /* add the next timeout */
1135 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1139 Editor::deferred_control_scroll (framepos_t /*target*/)
1141 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1142 // reset for next stream
1143 _control_scroll_target = boost::none;
1144 _dragging_playhead = false;
1149 Editor::access_action (std::string action_group, std::string action_item)
1155 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1158 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1166 Editor::on_realize ()
1170 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1171 start_lock_event_timing ();
1176 Editor::start_lock_event_timing ()
1178 /* check if we should lock the GUI every 30 seconds */
1180 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1184 Editor::generic_event_handler (GdkEvent* ev)
1187 case GDK_BUTTON_PRESS:
1188 case GDK_BUTTON_RELEASE:
1189 case GDK_MOTION_NOTIFY:
1191 case GDK_KEY_RELEASE:
1192 if (contents().is_mapped()) {
1193 gettimeofday (&last_event_time, 0);
1197 case GDK_LEAVE_NOTIFY:
1198 switch (ev->crossing.detail) {
1199 case GDK_NOTIFY_UNKNOWN:
1200 case GDK_NOTIFY_INFERIOR:
1201 case GDK_NOTIFY_ANCESTOR:
1203 case GDK_NOTIFY_VIRTUAL:
1204 case GDK_NOTIFY_NONLINEAR:
1205 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1206 /* leaving window, so reset focus, thus ending any and
1207 all text entry operations.
1209 ARDOUR_UI::instance()->reset_focus (&contents());
1222 Editor::lock_timeout_callback ()
1224 struct timeval now, delta;
1226 gettimeofday (&now, 0);
1228 timersub (&now, &last_event_time, &delta);
1230 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1232 /* don't call again. Returning false will effectively
1233 disconnect us from the timer callback.
1235 unlock() will call start_lock_event_timing() to get things
1245 Editor::map_position_change (framepos_t frame)
1247 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1249 if (_session == 0) {
1253 if (_follow_playhead) {
1254 center_screen (frame);
1257 playhead_cursor->set_position (frame);
1261 Editor::center_screen (framepos_t frame)
1263 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1265 /* if we're off the page, then scroll.
1268 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1269 center_screen_internal (frame, page);
1274 Editor::center_screen_internal (framepos_t frame, float page)
1279 frame -= (framepos_t) page;
1284 reset_x_origin (frame);
1289 Editor::update_title ()
1291 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1293 if (!own_window()) {
1298 bool dirty = _session->dirty();
1300 string session_name;
1302 if (_session->snap_name() != _session->name()) {
1303 session_name = _session->snap_name();
1305 session_name = _session->name();
1309 session_name = "*" + session_name;
1312 WindowTitle title(session_name);
1313 title += S_("Window|Editor");
1314 title += Glib::get_application_name();
1315 own_window()->set_title (title.get_string());
1317 /* ::session_going_away() will have taken care of it */
1322 Editor::set_session (Session *t)
1324 SessionHandlePtr::set_session (t);
1330 _playlist_selector->set_session (_session);
1331 nudge_clock->set_session (_session);
1332 _summary->set_session (_session);
1333 _group_tabs->set_session (_session);
1334 _route_groups->set_session (_session);
1335 _regions->set_session (_session);
1336 _snapshots->set_session (_session);
1337 _routes->set_session (_session);
1338 _locations->set_session (_session);
1339 _time_info_box->set_session (_session);
1341 if (rhythm_ferret) {
1342 rhythm_ferret->set_session (_session);
1345 if (analysis_window) {
1346 analysis_window->set_session (_session);
1350 sfbrowser->set_session (_session);
1353 compute_fixed_ruler_scale ();
1355 /* Make sure we have auto loop and auto punch ranges */
1357 Location* loc = _session->locations()->auto_loop_location();
1359 loc->set_name (_("Loop"));
1362 loc = _session->locations()->auto_punch_location();
1365 loc->set_name (_("Punch"));
1368 refresh_location_display ();
1370 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1371 the selected Marker; this needs the LocationMarker list to be available.
1373 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1374 set_state (*node, Stateful::loading_state_version);
1376 /* catch up with the playhead */
1378 _session->request_locate (playhead_cursor->current_frame ());
1379 _pending_initial_locate = true;
1383 /* These signals can all be emitted by a non-GUI thread. Therefore the
1384 handlers for them must not attempt to directly interact with the GUI,
1385 but use PBD::Signal<T>::connect() which accepts an event loop
1386 ("context") where the handler will be asked to run.
1389 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1390 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1391 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1392 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1393 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1394 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1395 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1396 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1397 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1398 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1399 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1400 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1401 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1402 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1403 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1405 playhead_cursor->show ();
1407 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1408 Config->map_parameters (pc);
1409 _session->config.map_parameters (pc);
1411 restore_ruler_visibility ();
1412 //tempo_map_changed (PropertyChange (0));
1413 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1415 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1416 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1419 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1420 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1423 switch (_snap_type) {
1424 case SnapToRegionStart:
1425 case SnapToRegionEnd:
1426 case SnapToRegionSync:
1427 case SnapToRegionBoundary:
1428 build_region_boundary_cache ();
1435 /* catch up on selection of stripables (other selection state is lost
1436 * when a session is closed
1441 _session->get_stripables (sl);
1442 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1443 if ((*s)->presentation_info().selected()) {
1444 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1446 tl.push_back (rtav);
1451 selection->set (tl);
1454 /* register for undo history */
1455 _session->register_with_memento_command_factory(id(), this);
1456 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1458 LuaInstance::instance()->set_session(_session);
1460 start_updating_meters ();
1464 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1466 using namespace Menu_Helpers;
1468 void (Editor::*emf)(FadeShape);
1469 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1472 images = &_xfade_in_images;
1473 emf = &Editor::set_fade_in_shape;
1475 images = &_xfade_out_images;
1476 emf = &Editor::set_fade_out_shape;
1481 _("Linear (for highly correlated material)"),
1482 *(*images)[FadeLinear],
1483 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 _("Constant power"),
1492 *(*images)[FadeConstantPower],
1493 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *(*images)[FadeSymmetric],
1502 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 *(*images)[FadeSlow],
1512 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1515 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 *(*images)[FadeFast],
1521 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1524 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1527 /** Pop up a context menu for when the user clicks on a start crossfade */
1529 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1531 using namespace Menu_Helpers;
1532 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1537 MenuList& items (xfade_in_context_menu.items());
1540 if (arv->audio_region()->fade_in_active()) {
1541 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1543 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1546 items.push_back (SeparatorElem());
1547 fill_xfade_menu (items, true);
1549 xfade_in_context_menu.popup (button, time);
1552 /** Pop up a context menu for when the user clicks on an end crossfade */
1554 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1556 using namespace Menu_Helpers;
1557 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1562 MenuList& items (xfade_out_context_menu.items());
1565 if (arv->audio_region()->fade_out_active()) {
1566 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1568 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1571 items.push_back (SeparatorElem());
1572 fill_xfade_menu (items, false);
1574 xfade_out_context_menu.popup (button, time);
1578 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1580 using namespace Menu_Helpers;
1581 Menu* (Editor::*build_menu_function)();
1584 switch (item_type) {
1586 case RegionViewName:
1587 case RegionViewNameHighlight:
1588 case LeftFrameHandle:
1589 case RightFrameHandle:
1590 if (with_selection) {
1591 build_menu_function = &Editor::build_track_selection_context_menu;
1593 build_menu_function = &Editor::build_track_region_context_menu;
1598 if (with_selection) {
1599 build_menu_function = &Editor::build_track_selection_context_menu;
1601 build_menu_function = &Editor::build_track_context_menu;
1606 if (clicked_routeview->track()) {
1607 build_menu_function = &Editor::build_track_context_menu;
1609 build_menu_function = &Editor::build_track_bus_context_menu;
1614 /* probably shouldn't happen but if it does, we don't care */
1618 menu = (this->*build_menu_function)();
1619 menu->set_name ("ArdourContextMenu");
1621 /* now handle specific situations */
1623 switch (item_type) {
1625 case RegionViewName:
1626 case RegionViewNameHighlight:
1627 case LeftFrameHandle:
1628 case RightFrameHandle:
1629 if (!with_selection) {
1630 if (region_edit_menu_split_item) {
1631 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1632 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1634 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1637 if (region_edit_menu_split_multichannel_item) {
1638 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1639 region_edit_menu_split_multichannel_item->set_sensitive (true);
1641 region_edit_menu_split_multichannel_item->set_sensitive (false);
1654 /* probably shouldn't happen but if it does, we don't care */
1658 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1660 /* Bounce to disk */
1662 using namespace Menu_Helpers;
1663 MenuList& edit_items = menu->items();
1665 edit_items.push_back (SeparatorElem());
1667 switch (clicked_routeview->audio_track()->freeze_state()) {
1668 case AudioTrack::NoFreeze:
1669 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1672 case AudioTrack::Frozen:
1673 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1676 case AudioTrack::UnFrozen:
1677 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1683 if (item_type == StreamItem && clicked_routeview) {
1684 clicked_routeview->build_underlay_menu(menu);
1687 /* When the region menu is opened, we setup the actions so that they look right
1690 sensitize_the_right_region_actions (false);
1691 _last_region_menu_was_main = false;
1693 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1694 menu->popup (button, time);
1698 Editor::build_track_context_menu ()
1700 using namespace Menu_Helpers;
1702 MenuList& edit_items = track_context_menu.items();
1705 add_dstream_context_items (edit_items);
1706 return &track_context_menu;
1710 Editor::build_track_bus_context_menu ()
1712 using namespace Menu_Helpers;
1714 MenuList& edit_items = track_context_menu.items();
1717 add_bus_context_items (edit_items);
1718 return &track_context_menu;
1722 Editor::build_track_region_context_menu ()
1724 using namespace Menu_Helpers;
1725 MenuList& edit_items = track_region_context_menu.items();
1728 /* we've just cleared the track region context menu, so the menu that these
1729 two items were on will have disappeared; stop them dangling.
1731 region_edit_menu_split_item = 0;
1732 region_edit_menu_split_multichannel_item = 0;
1734 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1737 boost::shared_ptr<Track> tr;
1738 boost::shared_ptr<Playlist> pl;
1740 if ((tr = rtv->track())) {
1741 add_region_context_items (edit_items, tr);
1745 add_dstream_context_items (edit_items);
1747 return &track_region_context_menu;
1751 Editor::loudness_analyze_region_selection ()
1756 Selection& s (PublicEditor::instance ().get_selection ());
1757 RegionSelection ars = s.regions;
1758 ARDOUR::AnalysisGraph ag (_session);
1759 framecnt_t total_work = 0;
1761 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1762 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1766 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1769 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1770 total_work += arv->region ()->length ();
1773 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1775 ag.set_total_frames (total_work);
1776 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1779 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1780 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1784 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1788 ag.analyze_region (ar);
1791 if (!ag.canceled ()) {
1792 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1798 Editor::loudness_analyze_range_selection ()
1803 Selection& s (PublicEditor::instance ().get_selection ());
1804 TimeSelection ts = s.time;
1805 ARDOUR::AnalysisGraph ag (_session);
1806 framecnt_t total_work = 0;
1808 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1809 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1813 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1817 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1818 total_work += j->length ();
1822 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1824 ag.set_total_frames (total_work);
1825 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1828 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1829 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1833 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1837 ag.analyze_range (rui->route (), pl, ts);
1840 if (!ag.canceled ()) {
1841 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1847 Editor::spectral_analyze_region_selection ()
1849 if (analysis_window == 0) {
1850 analysis_window = new AnalysisWindow();
1853 analysis_window->set_session(_session);
1855 analysis_window->show_all();
1858 analysis_window->set_regionmode();
1859 analysis_window->analyze();
1861 analysis_window->present();
1865 Editor::spectral_analyze_range_selection()
1867 if (analysis_window == 0) {
1868 analysis_window = new AnalysisWindow();
1871 analysis_window->set_session(_session);
1873 analysis_window->show_all();
1876 analysis_window->set_rangemode();
1877 analysis_window->analyze();
1879 analysis_window->present();
1883 Editor::build_track_selection_context_menu ()
1885 using namespace Menu_Helpers;
1886 MenuList& edit_items = track_selection_context_menu.items();
1887 edit_items.clear ();
1889 add_selection_context_items (edit_items);
1890 // edit_items.push_back (SeparatorElem());
1891 // add_dstream_context_items (edit_items);
1893 return &track_selection_context_menu;
1897 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1899 using namespace Menu_Helpers;
1901 /* OK, stick the region submenu at the top of the list, and then add
1905 RegionSelection rs = get_regions_from_selection_and_entered ();
1907 string::size_type pos = 0;
1908 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1910 /* we have to hack up the region name because "_" has a special
1911 meaning for menu titles.
1914 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1915 menu_item_name.replace (pos, 1, "__");
1919 if (_popup_region_menu_item == 0) {
1920 _popup_region_menu_item = new MenuItem (menu_item_name);
1921 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1922 _popup_region_menu_item->show ();
1924 _popup_region_menu_item->set_label (menu_item_name);
1927 /* No layering allowed in later is higher layering model */
1928 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1929 if (act && Config->get_layer_model() == LaterHigher) {
1930 act->set_sensitive (false);
1932 act->set_sensitive (true);
1935 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1937 edit_items.push_back (*_popup_region_menu_item);
1938 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1939 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1941 edit_items.push_back (SeparatorElem());
1944 /** Add context menu items relevant to selection ranges.
1945 * @param edit_items List to add the items to.
1948 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1950 using namespace Menu_Helpers;
1952 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1953 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1955 edit_items.push_back (SeparatorElem());
1956 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1958 edit_items.push_back (SeparatorElem());
1959 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1960 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1962 edit_items.push_back (SeparatorElem());
1964 edit_items.push_back (
1966 _("Move Range Start to Previous Region Boundary"),
1967 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1971 edit_items.push_back (
1973 _("Move Range Start to Next Region Boundary"),
1974 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1978 edit_items.push_back (
1980 _("Move Range End to Previous Region Boundary"),
1981 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1985 edit_items.push_back (
1987 _("Move Range End to Next Region Boundary"),
1988 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1992 edit_items.push_back (SeparatorElem());
1993 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1994 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1996 edit_items.push_back (SeparatorElem());
1997 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1999 edit_items.push_back (SeparatorElem());
2000 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2001 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2002 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2004 edit_items.push_back (SeparatorElem());
2005 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2007 edit_items.push_back (SeparatorElem());
2008 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2009 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2011 edit_items.push_back (SeparatorElem());
2012 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2013 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2014 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2015 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2016 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2017 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2018 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2024 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2026 using namespace Menu_Helpers;
2030 Menu *play_menu = manage (new Menu);
2031 MenuList& play_items = play_menu->items();
2032 play_menu->set_name ("ArdourContextMenu");
2034 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2035 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2036 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2037 play_items.push_back (SeparatorElem());
2038 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2040 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2044 Menu *select_menu = manage (new Menu);
2045 MenuList& select_items = select_menu->items();
2046 select_menu->set_name ("ArdourContextMenu");
2048 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2049 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2050 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2051 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2052 select_items.push_back (SeparatorElem());
2053 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2054 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2055 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2056 select_items.push_back (SeparatorElem());
2057 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2058 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2059 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2060 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2061 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2062 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2063 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2065 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2069 Menu *cutnpaste_menu = manage (new Menu);
2070 MenuList& cutnpaste_items = cutnpaste_menu->items();
2071 cutnpaste_menu->set_name ("ArdourContextMenu");
2073 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2074 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2075 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2077 cutnpaste_items.push_back (SeparatorElem());
2079 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2080 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2082 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2084 /* Adding new material */
2086 edit_items.push_back (SeparatorElem());
2087 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2088 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2092 Menu *nudge_menu = manage (new Menu());
2093 MenuList& nudge_items = nudge_menu->items();
2094 nudge_menu->set_name ("ArdourContextMenu");
2096 edit_items.push_back (SeparatorElem());
2097 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2098 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2099 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2100 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2102 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2106 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2108 using namespace Menu_Helpers;
2112 Menu *play_menu = manage (new Menu);
2113 MenuList& play_items = play_menu->items();
2114 play_menu->set_name ("ArdourContextMenu");
2116 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2117 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2118 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2122 Menu *select_menu = manage (new Menu);
2123 MenuList& select_items = select_menu->items();
2124 select_menu->set_name ("ArdourContextMenu");
2126 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2127 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2128 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2129 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2130 select_items.push_back (SeparatorElem());
2131 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2132 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2133 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2134 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2136 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2140 Menu *cutnpaste_menu = manage (new Menu);
2141 MenuList& cutnpaste_items = cutnpaste_menu->items();
2142 cutnpaste_menu->set_name ("ArdourContextMenu");
2144 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2145 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2146 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2148 Menu *nudge_menu = manage (new Menu());
2149 MenuList& nudge_items = nudge_menu->items();
2150 nudge_menu->set_name ("ArdourContextMenu");
2152 edit_items.push_back (SeparatorElem());
2153 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2154 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2155 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2156 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2158 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2162 Editor::snap_type() const
2168 Editor::snap_musical() const
2170 switch (_snap_type) {
2171 case SnapToBeatDiv128:
2172 case SnapToBeatDiv64:
2173 case SnapToBeatDiv32:
2174 case SnapToBeatDiv28:
2175 case SnapToBeatDiv24:
2176 case SnapToBeatDiv20:
2177 case SnapToBeatDiv16:
2178 case SnapToBeatDiv14:
2179 case SnapToBeatDiv12:
2180 case SnapToBeatDiv10:
2181 case SnapToBeatDiv8:
2182 case SnapToBeatDiv7:
2183 case SnapToBeatDiv6:
2184 case SnapToBeatDiv5:
2185 case SnapToBeatDiv4:
2186 case SnapToBeatDiv3:
2187 case SnapToBeatDiv2:
2199 Editor::snap_mode() const
2205 Editor::set_snap_to (SnapType st)
2207 unsigned int snap_ind = (unsigned int)st;
2209 if (internal_editing()) {
2210 internal_snap_type = st;
2212 pre_internal_snap_type = st;
2217 if (snap_ind > snap_type_strings.size() - 1) {
2219 _snap_type = (SnapType)snap_ind;
2222 string str = snap_type_strings[snap_ind];
2224 if (str != snap_type_selector.get_text()) {
2225 snap_type_selector.set_text (str);
2230 switch (_snap_type) {
2231 case SnapToBeatDiv128:
2232 case SnapToBeatDiv64:
2233 case SnapToBeatDiv32:
2234 case SnapToBeatDiv28:
2235 case SnapToBeatDiv24:
2236 case SnapToBeatDiv20:
2237 case SnapToBeatDiv16:
2238 case SnapToBeatDiv14:
2239 case SnapToBeatDiv12:
2240 case SnapToBeatDiv10:
2241 case SnapToBeatDiv8:
2242 case SnapToBeatDiv7:
2243 case SnapToBeatDiv6:
2244 case SnapToBeatDiv5:
2245 case SnapToBeatDiv4:
2246 case SnapToBeatDiv3:
2247 case SnapToBeatDiv2: {
2248 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2249 update_tempo_based_rulers ();
2253 case SnapToRegionStart:
2254 case SnapToRegionEnd:
2255 case SnapToRegionSync:
2256 case SnapToRegionBoundary:
2257 build_region_boundary_cache ();
2265 redisplay_tempo (false);
2267 SnapChanged (); /* EMIT SIGNAL */
2271 Editor::set_snap_mode (SnapMode mode)
2273 string str = snap_mode_strings[(int)mode];
2275 if (internal_editing()) {
2276 internal_snap_mode = mode;
2278 pre_internal_snap_mode = mode;
2283 if (str != snap_mode_selector.get_text ()) {
2284 snap_mode_selector.set_text (str);
2291 Editor::set_edit_point_preference (EditPoint ep, bool force)
2293 bool changed = (_edit_point != ep);
2296 if (Profile->get_mixbus())
2297 if (ep == EditAtSelectedMarker)
2298 ep = EditAtPlayhead;
2300 string str = edit_point_strings[(int)ep];
2301 if (str != edit_point_selector.get_text ()) {
2302 edit_point_selector.set_text (str);
2305 update_all_enter_cursors();
2307 if (!force && !changed) {
2311 const char* action=NULL;
2313 switch (_edit_point) {
2314 case EditAtPlayhead:
2315 action = "edit-at-playhead";
2317 case EditAtSelectedMarker:
2318 action = "edit-at-marker";
2321 action = "edit-at-mouse";
2325 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2327 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2331 bool in_track_canvas;
2333 if (!mouse_frame (foo, in_track_canvas)) {
2334 in_track_canvas = false;
2337 reset_canvas_action_sensitivity (in_track_canvas);
2338 sensitize_the_right_region_actions (false);
2344 Editor::set_state (const XMLNode& node, int version)
2346 XMLProperty const * prop;
2348 PBD::Unwinder<bool> nsi (no_save_instant, true);
2351 Tabbable::set_state (node, version);
2353 if (_session && (prop = node.property ("playhead"))) {
2355 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2357 playhead_cursor->set_position (pos);
2359 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2360 playhead_cursor->set_position (0);
2363 playhead_cursor->set_position (0);
2366 if ((prop = node.property ("mixer-width"))) {
2367 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2370 if ((prop = node.property ("zoom-focus"))) {
2371 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2373 zoom_focus_selection_done (zoom_focus);
2376 if ((prop = node.property ("zoom"))) {
2377 /* older versions of ardour used floating point samples_per_pixel */
2378 double f = PBD::atof (prop->value());
2379 reset_zoom (llrintf (f));
2381 reset_zoom (samples_per_pixel);
2384 if ((prop = node.property ("visible-track-count"))) {
2385 set_visible_track_count (PBD::atoi (prop->value()));
2388 if ((prop = node.property ("snap-to"))) {
2389 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2390 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2392 set_snap_to (_snap_type);
2395 if ((prop = node.property ("snap-mode"))) {
2396 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2397 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2398 * snap_mode_selection_done() will only mark an already active item as active
2399 * which does not trigger set_text().
2401 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2403 set_snap_mode (_snap_mode);
2406 if ((prop = node.property ("internal-snap-to"))) {
2407 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2410 if ((prop = node.property ("internal-snap-mode"))) {
2411 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2414 if ((prop = node.property ("pre-internal-snap-to"))) {
2415 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2418 if ((prop = node.property ("pre-internal-snap-mode"))) {
2419 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2422 if ((prop = node.property ("mouse-mode"))) {
2423 MouseMode m = str2mousemode(prop->value());
2424 set_mouse_mode (m, true);
2426 set_mouse_mode (MouseObject, true);
2429 if ((prop = node.property ("left-frame")) != 0) {
2431 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2435 reset_x_origin (pos);
2439 if ((prop = node.property ("y-origin")) != 0) {
2440 reset_y_origin (atof (prop->value ()));
2443 if ((prop = node.property ("join-object-range"))) {
2444 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2445 bool yn = string_is_affirmative (prop->value());
2447 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2448 tact->set_active (!yn);
2449 tact->set_active (yn);
2451 set_mouse_mode(mouse_mode, true);
2454 if ((prop = node.property ("edit-point"))) {
2455 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2457 set_edit_point_preference (_edit_point);
2460 if ((prop = node.property ("show-measures"))) {
2461 bool yn = string_is_affirmative (prop->value());
2462 _show_measures = yn;
2465 if ((prop = node.property ("follow-playhead"))) {
2466 bool yn = string_is_affirmative (prop->value());
2467 set_follow_playhead (yn);
2470 if ((prop = node.property ("stationary-playhead"))) {
2471 bool yn = string_is_affirmative (prop->value());
2472 set_stationary_playhead (yn);
2475 if ((prop = node.property ("region-list-sort-type"))) {
2476 RegionListSortType st;
2477 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2480 if ((prop = node.property ("show-editor-mixer"))) {
2482 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2485 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2486 bool yn = string_is_affirmative (prop->value());
2488 /* do it twice to force the change */
2490 tact->set_active (!yn);
2491 tact->set_active (yn);
2494 if ((prop = node.property ("show-editor-list"))) {
2496 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2499 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2500 bool yn = string_is_affirmative (prop->value());
2502 /* do it twice to force the change */
2504 tact->set_active (!yn);
2505 tact->set_active (yn);
2508 if ((prop = node.property (X_("editor-list-page")))) {
2509 _the_notebook.set_current_page (atoi (prop->value ()));
2512 if ((prop = node.property (X_("show-marker-lines")))) {
2513 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2515 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2516 bool yn = string_is_affirmative (prop->value ());
2518 tact->set_active (!yn);
2519 tact->set_active (yn);
2522 XMLNodeList children = node.children ();
2523 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2524 selection->set_state (**i, Stateful::current_state_version);
2525 _regions->set_state (**i);
2526 _locations->set_state (**i);
2529 if ((prop = node.property ("maximised"))) {
2530 bool yn = string_is_affirmative (prop->value());
2531 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2533 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2534 bool fs = tact && tact->get_active();
2536 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2540 if ((prop = node.property ("nudge-clock-value"))) {
2542 sscanf (prop->value().c_str(), "%" PRId64, &f);
2543 nudge_clock->set (f);
2545 nudge_clock->set_mode (AudioClock::Timecode);
2546 nudge_clock->set (_session->frame_rate() * 5, true);
2551 * Not all properties may have been in XML, but
2552 * those that are linked to a private variable may need changing
2557 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2559 yn = _show_measures;
2560 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2561 /* do it twice to force the change */
2562 tact->set_active (!yn);
2563 tact->set_active (yn);
2566 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2567 yn = _follow_playhead;
2569 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2570 if (tact->get_active() != yn) {
2571 tact->set_active (yn);
2575 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2576 yn = _stationary_playhead;
2578 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2579 if (tact->get_active() != yn) {
2580 tact->set_active (yn);
2585 return LuaInstance::instance()->set_state(node);
2589 Editor::get_state ()
2591 XMLNode* node = new XMLNode (X_("Editor"));
2595 id().print (buf, sizeof (buf));
2596 node->add_property ("id", buf);
2598 node->add_child_nocopy (Tabbable::get_state());
2600 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2601 node->add_property("edit-horizontal-pane-pos", string(buf));
2602 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2603 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2604 node->add_property("edit-vertical-pane-pos", string(buf));
2606 maybe_add_mixer_strip_width (*node);
2608 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2610 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2611 node->add_property ("zoom", buf);
2612 node->add_property ("snap-to", enum_2_string (_snap_type));
2613 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2614 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2615 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2616 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2617 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2618 node->add_property ("edit-point", enum_2_string (_edit_point));
2619 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2620 node->add_property ("visible-track-count", buf);
2622 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2623 node->add_property ("playhead", buf);
2624 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2625 node->add_property ("left-frame", buf);
2626 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2627 node->add_property ("y-origin", buf);
2629 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2630 node->add_property ("maximised", _maximised ? "yes" : "no");
2631 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2632 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2633 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2634 node->add_property ("mouse-mode", enum2str(mouse_mode));
2635 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2637 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2639 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2640 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2643 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2645 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2646 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2649 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2650 node->add_property (X_("editor-list-page"), buf);
2652 if (button_bindings) {
2653 XMLNode* bb = new XMLNode (X_("Buttons"));
2654 button_bindings->save (*bb);
2655 node->add_child_nocopy (*bb);
2658 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2660 node->add_child_nocopy (selection->get_state ());
2661 node->add_child_nocopy (_regions->get_state ());
2663 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2664 node->add_property ("nudge-clock-value", buf);
2666 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2667 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2668 node->add_child_nocopy (_locations->get_state ());
2673 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2674 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2676 * @return pair: TimeAxisView that y is over, layer index.
2678 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2679 * in stacked or expanded region display mode, otherwise 0.
2681 std::pair<TimeAxisView *, double>
2682 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2684 if (!trackview_relative_offset) {
2685 y -= _trackview_group->canvas_origin().y;
2689 return std::make_pair ( (TimeAxisView *) 0, 0);
2692 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2694 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2701 return std::make_pair ( (TimeAxisView *) 0, 0);
2704 /** Snap a position to the grid, if appropriate, taking into account current
2705 * grid settings and also the state of any snap modifier keys that may be pressed.
2706 * @param start Position to snap.
2707 * @param event Event to get current key modifier information from, or 0.
2710 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2712 if (!_session || !event) {
2716 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2717 if (_snap_mode == SnapOff) {
2718 snap_to_internal (start, direction, for_mark);
2720 start.set (start.frame, 0);
2723 if (_snap_mode != SnapOff) {
2724 snap_to_internal (start, direction, for_mark);
2725 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2726 /* SnapOff, but we pressed the snap_delta modifier */
2727 snap_to_internal (start, direction, for_mark);
2729 start.set (start.frame, 0);
2735 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2737 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2738 start.set (start.frame, 0);
2742 snap_to_internal (start, direction, for_mark, ensure_snap);
2746 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2748 framepos_t start = pos.frame;
2749 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2750 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2752 switch (_snap_type) {
2753 case SnapToTimecodeFrame:
2754 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2755 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2756 /* start is already on a whole timecode frame, do nothing */
2757 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2758 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2760 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2764 case SnapToTimecodeSeconds:
2765 if (_session->config.get_timecode_offset_negative()) {
2766 start += _session->config.get_timecode_offset ();
2768 start -= _session->config.get_timecode_offset ();
2770 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2771 (start % one_timecode_second == 0)) {
2772 /* start is already on a whole second, do nothing */
2773 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2774 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2776 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2779 if (_session->config.get_timecode_offset_negative()) {
2780 start -= _session->config.get_timecode_offset ();
2782 start += _session->config.get_timecode_offset ();
2786 case SnapToTimecodeMinutes:
2787 if (_session->config.get_timecode_offset_negative()) {
2788 start += _session->config.get_timecode_offset ();
2790 start -= _session->config.get_timecode_offset ();
2792 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2793 (start % one_timecode_minute == 0)) {
2794 /* start is already on a whole minute, do nothing */
2795 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2796 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2798 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2800 if (_session->config.get_timecode_offset_negative()) {
2801 start -= _session->config.get_timecode_offset ();
2803 start += _session->config.get_timecode_offset ();
2807 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2808 abort(); /*NOTREACHED*/
2815 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2817 const framepos_t one_second = _session->frame_rate();
2818 const framepos_t one_minute = _session->frame_rate() * 60;
2819 framepos_t presnap = start.frame;
2823 switch (_snap_type) {
2824 case SnapToTimecodeFrame:
2825 case SnapToTimecodeSeconds:
2826 case SnapToTimecodeMinutes:
2827 return timecode_snap_to_internal (start, direction, for_mark);
2830 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2831 start.frame % (one_second/75) == 0) {
2832 /* start is already on a whole CD frame, do nothing */
2833 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2834 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2836 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2839 start.set (start.frame, 0);
2844 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2845 start.frame % one_second == 0) {
2846 /* start is already on a whole second, do nothing */
2847 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2848 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2850 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2853 start.set (start.frame, 0);
2858 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2859 start.frame % one_minute == 0) {
2860 /* start is already on a whole minute, do nothing */
2861 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2862 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2864 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2867 start.set (start.frame, 0);
2872 start = _session->tempo_map().round_to_bar (start.frame, direction);
2876 start = _session->tempo_map().round_to_beat (start.frame, direction);
2879 case SnapToBeatDiv128:
2880 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2882 case SnapToBeatDiv64:
2883 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2885 case SnapToBeatDiv32:
2886 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2888 case SnapToBeatDiv28:
2889 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2891 case SnapToBeatDiv24:
2892 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2894 case SnapToBeatDiv20:
2895 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2897 case SnapToBeatDiv16:
2898 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2900 case SnapToBeatDiv14:
2901 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2903 case SnapToBeatDiv12:
2904 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2906 case SnapToBeatDiv10:
2907 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2909 case SnapToBeatDiv8:
2910 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2912 case SnapToBeatDiv7:
2913 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2915 case SnapToBeatDiv6:
2916 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2918 case SnapToBeatDiv5:
2919 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2921 case SnapToBeatDiv4:
2922 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2924 case SnapToBeatDiv3:
2925 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2927 case SnapToBeatDiv2:
2928 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2936 _session->locations()->marks_either_side (start.frame, before, after);
2938 if (before == max_framepos && after == max_framepos) {
2939 /* No marks to snap to, so just don't snap */
2941 } else if (before == max_framepos) {
2942 start.frame = after;
2943 } else if (after == max_framepos) {
2944 start.frame = before;
2945 } else if (before != max_framepos && after != max_framepos) {
2946 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2947 start.frame = after;
2948 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2949 start.frame = before;
2950 else if (direction == 0 ) {
2951 if ((start.frame - before) < (after - start.frame)) {
2952 start.frame = before;
2954 start.frame = after;
2959 start.set (start.frame, 0);
2963 case SnapToRegionStart:
2964 case SnapToRegionEnd:
2965 case SnapToRegionSync:
2966 case SnapToRegionBoundary:
2967 if (!region_boundary_cache.empty()) {
2969 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2970 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2972 if (direction > 0) {
2973 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2975 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2978 if (next != region_boundary_cache.begin ()) {
2983 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2984 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2986 if (start.frame > (p + n) / 2) {
2993 start.set (start.frame, 0);
2998 switch (_snap_mode) {
3008 if (presnap > start.frame) {
3009 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
3010 start.set (presnap, 0);
3013 } else if (presnap < start.frame) {
3014 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
3015 start.set (presnap, 0);
3020 /* handled at entry */
3027 Editor::setup_toolbar ()
3029 HBox* mode_box = manage(new HBox);
3030 mode_box->set_border_width (2);
3031 mode_box->set_spacing(2);
3033 HBox* mouse_mode_box = manage (new HBox);
3034 HBox* mouse_mode_hbox = manage (new HBox);
3035 VBox* mouse_mode_vbox = manage (new VBox);
3036 Alignment* mouse_mode_align = manage (new Alignment);
3038 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3039 mouse_mode_size_group->add_widget (smart_mode_button);
3040 mouse_mode_size_group->add_widget (mouse_move_button);
3041 mouse_mode_size_group->add_widget (mouse_cut_button);
3042 mouse_mode_size_group->add_widget (mouse_select_button);
3043 mouse_mode_size_group->add_widget (mouse_timefx_button);
3044 mouse_mode_size_group->add_widget (mouse_audition_button);
3045 mouse_mode_size_group->add_widget (mouse_draw_button);
3046 mouse_mode_size_group->add_widget (mouse_content_button);
3048 if (!Profile->get_mixbus()) {
3049 mouse_mode_size_group->add_widget (zoom_in_button);
3050 mouse_mode_size_group->add_widget (zoom_out_button);
3051 mouse_mode_size_group->add_widget (zoom_out_full_button);
3052 mouse_mode_size_group->add_widget (zoom_focus_selector);
3053 mouse_mode_size_group->add_widget (tav_shrink_button);
3054 mouse_mode_size_group->add_widget (tav_expand_button);
3056 mouse_mode_size_group->add_widget (zoom_preset_selector);
3057 mouse_mode_size_group->add_widget (visible_tracks_selector);
3060 mouse_mode_size_group->add_widget (snap_type_selector);
3061 mouse_mode_size_group->add_widget (snap_mode_selector);
3063 mouse_mode_size_group->add_widget (edit_point_selector);
3064 mouse_mode_size_group->add_widget (edit_mode_selector);
3066 mouse_mode_size_group->add_widget (*nudge_clock);
3067 mouse_mode_size_group->add_widget (nudge_forward_button);
3068 mouse_mode_size_group->add_widget (nudge_backward_button);
3070 mouse_mode_hbox->set_spacing (2);
3072 if (!ARDOUR::Profile->get_trx()) {
3073 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3076 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3077 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3079 if (!ARDOUR::Profile->get_mixbus()) {
3080 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3083 if (!ARDOUR::Profile->get_trx()) {
3084 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3085 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3086 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3087 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3090 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3092 mouse_mode_align->add (*mouse_mode_vbox);
3093 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3095 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3097 edit_mode_selector.set_name ("mouse mode button");
3099 if (!ARDOUR::Profile->get_trx()) {
3100 mode_box->pack_start (edit_mode_selector, false, false);
3103 mode_box->pack_start (*mouse_mode_box, false, false);
3107 _zoom_box.set_spacing (2);
3108 _zoom_box.set_border_width (2);
3112 zoom_preset_selector.set_name ("zoom button");
3113 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3115 zoom_in_button.set_name ("zoom button");
3116 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3117 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3118 zoom_in_button.set_related_action (act);
3120 zoom_out_button.set_name ("zoom button");
3121 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3122 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3123 zoom_out_button.set_related_action (act);
3125 zoom_out_full_button.set_name ("zoom button");
3126 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3127 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3128 zoom_out_full_button.set_related_action (act);
3130 zoom_focus_selector.set_name ("zoom button");
3132 if (ARDOUR::Profile->get_mixbus()) {
3133 _zoom_box.pack_start (zoom_preset_selector, false, false);
3134 } else if (ARDOUR::Profile->get_trx()) {
3135 mode_box->pack_start (zoom_out_button, false, false);
3136 mode_box->pack_start (zoom_in_button, false, false);
3138 _zoom_box.pack_start (zoom_out_button, false, false);
3139 _zoom_box.pack_start (zoom_in_button, false, false);
3140 _zoom_box.pack_start (zoom_out_full_button, false, false);
3141 _zoom_box.pack_start (zoom_focus_selector, false, false);
3144 /* Track zoom buttons */
3145 _track_box.set_spacing (2);
3146 _track_box.set_border_width (2);
3148 visible_tracks_selector.set_name ("zoom button");
3149 if (Profile->get_mixbus()) {
3150 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3152 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3155 tav_expand_button.set_name ("zoom button");
3156 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3157 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3158 tav_expand_button.set_related_action (act);
3160 tav_shrink_button.set_name ("zoom button");
3161 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3162 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3163 tav_shrink_button.set_related_action (act);
3165 if (ARDOUR::Profile->get_mixbus()) {
3166 _track_box.pack_start (visible_tracks_selector);
3167 } else if (ARDOUR::Profile->get_trx()) {
3168 _track_box.pack_start (tav_shrink_button);
3169 _track_box.pack_start (tav_expand_button);
3171 _track_box.pack_start (visible_tracks_selector);
3172 _track_box.pack_start (tav_shrink_button);
3173 _track_box.pack_start (tav_expand_button);
3176 snap_box.set_spacing (2);
3177 snap_box.set_border_width (2);
3179 snap_type_selector.set_name ("mouse mode button");
3181 snap_mode_selector.set_name ("mouse mode button");
3183 edit_point_selector.set_name ("mouse mode button");
3185 snap_box.pack_start (snap_mode_selector, false, false);
3186 snap_box.pack_start (snap_type_selector, false, false);
3189 HBox *ep_box = manage (new HBox);
3190 ep_box->set_spacing (2);
3191 ep_box->set_border_width (2);
3193 ep_box->pack_start (edit_point_selector, false, false);
3197 HBox *nudge_box = manage (new HBox);
3198 nudge_box->set_spacing (2);
3199 nudge_box->set_border_width (2);
3201 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3202 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3204 nudge_box->pack_start (nudge_backward_button, false, false);
3205 nudge_box->pack_start (nudge_forward_button, false, false);
3206 nudge_box->pack_start (*nudge_clock, false, false);
3209 /* Pack everything in... */
3211 toolbar_hbox.set_spacing (2);
3212 toolbar_hbox.set_border_width (2);
3214 toolbar_hbox.pack_start (*mode_box, false, false);
3216 if (!ARDOUR::Profile->get_trx()) {
3218 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3220 toolbar_hbox.pack_start (_zoom_box, false, false);
3222 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3224 toolbar_hbox.pack_start (_track_box, false, false);
3226 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3228 toolbar_hbox.pack_start (snap_box, false, false);
3230 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3232 toolbar_hbox.pack_start (*ep_box, false, false);
3234 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3236 toolbar_hbox.pack_start (*nudge_box, false, false);
3239 toolbar_hbox.show_all ();
3243 Editor::build_edit_point_menu ()
3245 using namespace Menu_Helpers;
3247 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3248 if(!Profile->get_mixbus())
3249 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3250 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3252 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3256 Editor::build_edit_mode_menu ()
3258 using namespace Menu_Helpers;
3260 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3261 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3262 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3263 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3265 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3269 Editor::build_snap_mode_menu ()
3271 using namespace Menu_Helpers;
3273 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3274 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3275 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3277 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3281 Editor::build_snap_type_menu ()
3283 using namespace Menu_Helpers;
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3287 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3288 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3289 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3290 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3291 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3292 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3293 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3294 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3295 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3296 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3297 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3298 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3299 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3300 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3301 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3302 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3303 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3304 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3305 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3306 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3307 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3308 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3309 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3310 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3311 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3312 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3313 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3314 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3316 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3321 Editor::setup_tooltips ()
3323 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3324 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3325 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3326 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3327 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3328 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3329 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3330 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3331 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3332 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3333 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3334 set_tooltip (zoom_in_button, _("Zoom In"));
3335 set_tooltip (zoom_out_button, _("Zoom Out"));
3336 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3337 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3338 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3339 set_tooltip (tav_expand_button, _("Expand Tracks"));
3340 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3341 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3342 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3343 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3344 set_tooltip (edit_point_selector, _("Edit Point"));
3345 set_tooltip (edit_mode_selector, _("Edit Mode"));
3346 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3350 Editor::convert_drop_to_paths (
3351 vector<string>& paths,
3352 const RefPtr<Gdk::DragContext>& /*context*/,
3355 const SelectionData& data,
3359 if (_session == 0) {
3363 vector<string> uris = data.get_uris();
3367 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3368 are actually URI lists. So do it by hand.
3371 if (data.get_target() != "text/plain") {
3375 /* Parse the "uri-list" format that Nautilus provides,
3376 where each pathname is delimited by \r\n.
3378 THERE MAY BE NO NULL TERMINATING CHAR!!!
3381 string txt = data.get_text();
3385 p = (char *) malloc (txt.length() + 1);
3386 txt.copy (p, txt.length(), 0);
3387 p[txt.length()] = '\0';
3393 while (g_ascii_isspace (*p))
3397 while (*q && (*q != '\n') && (*q != '\r')) {
3404 while (q > p && g_ascii_isspace (*q))
3409 uris.push_back (string (p, q - p + 1));
3413 p = strchr (p, '\n');
3425 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3426 if ((*i).substr (0,7) == "file://") {
3427 paths.push_back (Glib::filename_from_uri (*i));
3435 Editor::new_tempo_section ()
3440 Editor::map_transport_state ()
3442 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3444 if (_session && _session->transport_stopped()) {
3445 have_pending_keyboard_selection = false;
3448 update_loop_range_view ();
3454 Editor::begin_selection_op_history ()
3456 selection_op_cmd_depth = 0;
3457 selection_op_history_it = 0;
3459 while(!selection_op_history.empty()) {
3460 delete selection_op_history.front();
3461 selection_op_history.pop_front();
3464 selection_undo_action->set_sensitive (false);
3465 selection_redo_action->set_sensitive (false);
3466 selection_op_history.push_front (&_selection_memento->get_state ());
3470 Editor::begin_reversible_selection_op (string name)
3473 //cerr << name << endl;
3474 /* begin/commit pairs can be nested */
3475 selection_op_cmd_depth++;
3480 Editor::commit_reversible_selection_op ()
3483 if (selection_op_cmd_depth == 1) {
3485 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3487 The user has undone some selection ops and then made a new one,
3488 making anything earlier in the list invalid.
3491 list<XMLNode *>::iterator it = selection_op_history.begin();
3492 list<XMLNode *>::iterator e_it = it;
3493 advance (e_it, selection_op_history_it);
3495 for ( ; it != e_it; ++it) {
3498 selection_op_history.erase (selection_op_history.begin(), e_it);
3501 selection_op_history.push_front (&_selection_memento->get_state ());
3502 selection_op_history_it = 0;
3504 selection_undo_action->set_sensitive (true);
3505 selection_redo_action->set_sensitive (false);
3508 if (selection_op_cmd_depth > 0) {
3509 selection_op_cmd_depth--;
3515 Editor::undo_selection_op ()
3518 selection_op_history_it++;
3520 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3521 if (n == selection_op_history_it) {
3522 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3523 selection_redo_action->set_sensitive (true);
3527 /* is there an earlier entry? */
3528 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3529 selection_undo_action->set_sensitive (false);
3535 Editor::redo_selection_op ()
3538 if (selection_op_history_it > 0) {
3539 selection_op_history_it--;
3542 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3543 if (n == selection_op_history_it) {
3544 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3545 selection_undo_action->set_sensitive (true);
3550 if (selection_op_history_it == 0) {
3551 selection_redo_action->set_sensitive (false);
3557 Editor::begin_reversible_command (string name)
3560 before.push_back (&_selection_memento->get_state ());
3561 _session->begin_reversible_command (name);
3566 Editor::begin_reversible_command (GQuark q)
3569 before.push_back (&_selection_memento->get_state ());
3570 _session->begin_reversible_command (q);
3575 Editor::abort_reversible_command ()
3578 while(!before.empty()) {
3579 delete before.front();
3582 _session->abort_reversible_command ();
3587 Editor::commit_reversible_command ()
3590 if (before.size() == 1) {
3591 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3592 redo_action->set_sensitive(false);
3593 undo_action->set_sensitive(true);
3594 begin_selection_op_history ();
3597 if (before.empty()) {
3598 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3603 _session->commit_reversible_command ();
3608 Editor::history_changed ()
3612 if (undo_action && _session) {
3613 if (_session->undo_depth() == 0) {
3614 label = S_("Command|Undo");
3616 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3618 undo_action->property_label() = label;
3621 if (redo_action && _session) {
3622 if (_session->redo_depth() == 0) {
3624 redo_action->set_sensitive (false);
3626 label = string_compose(_("Redo (%1)"), _session->next_redo());
3627 redo_action->set_sensitive (true);
3629 redo_action->property_label() = label;
3634 Editor::duplicate_range (bool with_dialog)
3638 RegionSelection rs = get_regions_from_selection_and_entered ();
3640 if ( selection->time.length() == 0 && rs.empty()) {
3646 ArdourDialog win (_("Duplicate"));
3647 Label label (_("Number of duplications:"));
3648 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3649 SpinButton spinner (adjustment, 0.0, 1);
3652 win.get_vbox()->set_spacing (12);
3653 win.get_vbox()->pack_start (hbox);
3654 hbox.set_border_width (6);
3655 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3657 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3658 place, visually. so do this by hand.
3661 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3662 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3663 spinner.grab_focus();
3669 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3670 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3671 win.set_default_response (RESPONSE_ACCEPT);
3673 spinner.grab_focus ();
3675 switch (win.run ()) {
3676 case RESPONSE_ACCEPT:
3682 times = adjustment.get_value();
3685 if ((current_mouse_mode() == Editing::MouseRange)) {
3686 if (selection->time.length()) {
3687 duplicate_selection (times);
3689 } else if (get_smart_mode()) {
3690 if (selection->time.length()) {
3691 duplicate_selection (times);
3693 duplicate_some_regions (rs, times);
3695 duplicate_some_regions (rs, times);
3700 Editor::set_edit_mode (EditMode m)
3702 Config->set_edit_mode (m);
3706 Editor::cycle_edit_mode ()
3708 switch (Config->get_edit_mode()) {
3710 Config->set_edit_mode (Ripple);
3714 Config->set_edit_mode (Lock);
3717 Config->set_edit_mode (Slide);
3723 Editor::edit_mode_selection_done ( EditMode m )
3725 Config->set_edit_mode ( m );
3729 Editor::snap_type_selection_done (SnapType snaptype)
3731 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3733 ract->set_active ();
3738 Editor::snap_mode_selection_done (SnapMode mode)
3740 RefPtr<RadioAction> ract = snap_mode_action (mode);
3743 ract->set_active (true);
3748 Editor::cycle_edit_point (bool with_marker)
3750 if(Profile->get_mixbus())
3751 with_marker = false;
3753 switch (_edit_point) {
3755 set_edit_point_preference (EditAtPlayhead);
3757 case EditAtPlayhead:
3759 set_edit_point_preference (EditAtSelectedMarker);
3761 set_edit_point_preference (EditAtMouse);
3764 case EditAtSelectedMarker:
3765 set_edit_point_preference (EditAtMouse);
3771 Editor::edit_point_selection_done (EditPoint ep)
3773 set_edit_point_preference ( ep );
3777 Editor::build_zoom_focus_menu ()
3779 using namespace Menu_Helpers;
3781 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3782 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3783 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3784 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3785 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3786 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3788 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3792 Editor::zoom_focus_selection_done ( ZoomFocus f )
3794 RefPtr<RadioAction> ract = zoom_focus_action (f);
3796 ract->set_active ();
3801 Editor::build_track_count_menu ()
3803 using namespace Menu_Helpers;
3805 if (!Profile->get_mixbus()) {
3806 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3807 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3808 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3809 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3810 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3811 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3812 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3813 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3814 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3815 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3816 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3817 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3818 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3820 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3821 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3822 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3823 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3824 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3825 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3826 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3827 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3828 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3829 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3831 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3832 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3833 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3834 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3835 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3836 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3837 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3838 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3839 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3840 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3841 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3846 Editor::set_zoom_preset (int64_t ms)
3849 temporal_zoom_session();
3853 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3854 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3858 Editor::set_visible_track_count (int32_t n)
3860 _visible_track_count = n;
3862 /* if the canvas hasn't really been allocated any size yet, just
3863 record the desired number of visible tracks and return. when canvas
3864 allocation happens, we will get called again and then we can do the
3868 if (_visible_canvas_height <= 1) {
3874 DisplaySuspender ds;
3876 if (_visible_track_count > 0) {
3877 h = trackviews_height() / _visible_track_count;
3878 std::ostringstream s;
3879 s << _visible_track_count;
3881 } else if (_visible_track_count == 0) {
3883 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3884 if ((*i)->marked_for_display()) {
3888 h = trackviews_height() / n;
3891 /* negative value means that the visible track count has
3892 been overridden by explicit track height changes.
3894 visible_tracks_selector.set_text (X_("*"));
3898 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3899 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3902 if (str != visible_tracks_selector.get_text()) {
3903 visible_tracks_selector.set_text (str);
3908 Editor::override_visible_track_count ()
3910 _visible_track_count = -1;
3911 visible_tracks_selector.set_text ( _("*") );
3915 Editor::edit_controls_button_release (GdkEventButton* ev)
3917 if (Keyboard::is_context_menu_event (ev)) {
3918 ARDOUR_UI::instance()->add_route ();
3919 } else if (ev->button == 1) {
3920 selection->clear_tracks ();
3927 Editor::mouse_select_button_release (GdkEventButton* ev)
3929 /* this handles just right-clicks */
3931 if (ev->button != 3) {
3939 Editor::set_zoom_focus (ZoomFocus f)
3941 string str = zoom_focus_strings[(int)f];
3943 if (str != zoom_focus_selector.get_text()) {
3944 zoom_focus_selector.set_text (str);
3947 if (zoom_focus != f) {
3954 Editor::cycle_zoom_focus ()
3956 switch (zoom_focus) {
3958 set_zoom_focus (ZoomFocusRight);
3960 case ZoomFocusRight:
3961 set_zoom_focus (ZoomFocusCenter);
3963 case ZoomFocusCenter:
3964 set_zoom_focus (ZoomFocusPlayhead);
3966 case ZoomFocusPlayhead:
3967 set_zoom_focus (ZoomFocusMouse);
3969 case ZoomFocusMouse:
3970 set_zoom_focus (ZoomFocusEdit);
3973 set_zoom_focus (ZoomFocusLeft);
3979 Editor::set_show_measures (bool yn)
3981 if (_show_measures != yn) {
3984 if ((_show_measures = yn) == true) {
3986 tempo_lines->show();
3989 std::vector<TempoMap::BBTPoint> grid;
3990 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3991 draw_measures (grid);
3999 Editor::toggle_follow_playhead ()
4001 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4003 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4004 set_follow_playhead (tact->get_active());
4008 /** @param yn true to follow playhead, otherwise false.
4009 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4012 Editor::set_follow_playhead (bool yn, bool catch_up)
4014 if (_follow_playhead != yn) {
4015 if ((_follow_playhead = yn) == true && catch_up) {
4017 reset_x_origin_to_follow_playhead ();
4024 Editor::toggle_stationary_playhead ()
4026 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4028 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4029 set_stationary_playhead (tact->get_active());
4034 Editor::set_stationary_playhead (bool yn)
4036 if (_stationary_playhead != yn) {
4037 if ((_stationary_playhead = yn) == true) {
4039 // FIXME need a 3.0 equivalent of this 2.X call
4040 // update_current_screen ();
4047 Editor::playlist_selector () const
4049 return *_playlist_selector;
4053 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4055 if (paste_count == 0) {
4056 /* don't bother calculating an offset that will be zero anyway */
4060 /* calculate basic unsnapped multi-paste offset */
4061 framecnt_t offset = paste_count * duration;
4063 /* snap offset so pos + offset is aligned to the grid */
4064 MusicFrame offset_pos (pos + offset, 0);
4065 snap_to(offset_pos, RoundUpMaybe);
4066 offset = offset_pos.frame - pos;
4072 Editor::get_grid_beat_divisions(framepos_t position)
4074 switch (_snap_type) {
4075 case SnapToBeatDiv128: return 128;
4076 case SnapToBeatDiv64: return 64;
4077 case SnapToBeatDiv32: return 32;
4078 case SnapToBeatDiv28: return 28;
4079 case SnapToBeatDiv24: return 24;
4080 case SnapToBeatDiv20: return 20;
4081 case SnapToBeatDiv16: return 16;
4082 case SnapToBeatDiv14: return 14;
4083 case SnapToBeatDiv12: return 12;
4084 case SnapToBeatDiv10: return 10;
4085 case SnapToBeatDiv8: return 8;
4086 case SnapToBeatDiv7: return 7;
4087 case SnapToBeatDiv6: return 6;
4088 case SnapToBeatDiv5: return 5;
4089 case SnapToBeatDiv4: return 4;
4090 case SnapToBeatDiv3: return 3;
4091 case SnapToBeatDiv2: return 2;
4097 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4098 if the grid is non-musical, returns 0.
4099 if the grid is snapped to bars, returns -1.
4100 @param event_state the current keyboard modifier mask.
4103 Editor::get_grid_music_divisions (uint32_t event_state)
4105 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4109 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4113 switch (_snap_type) {
4114 case SnapToBeatDiv128: return 128;
4115 case SnapToBeatDiv64: return 64;
4116 case SnapToBeatDiv32: return 32;
4117 case SnapToBeatDiv28: return 28;
4118 case SnapToBeatDiv24: return 24;
4119 case SnapToBeatDiv20: return 20;
4120 case SnapToBeatDiv16: return 16;
4121 case SnapToBeatDiv14: return 14;
4122 case SnapToBeatDiv12: return 12;
4123 case SnapToBeatDiv10: return 10;
4124 case SnapToBeatDiv8: return 8;
4125 case SnapToBeatDiv7: return 7;
4126 case SnapToBeatDiv6: return 6;
4127 case SnapToBeatDiv5: return 5;
4128 case SnapToBeatDiv4: return 4;
4129 case SnapToBeatDiv3: return 3;
4130 case SnapToBeatDiv2: return 2;
4131 case SnapToBeat: return 1;
4132 case SnapToBar : return -1;
4139 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4143 const unsigned divisions = get_grid_beat_divisions(position);
4145 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4148 switch (_snap_type) {
4150 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4153 const Meter& m = _session->tempo_map().meter_at_frame (position);
4154 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4162 return Evoral::Beats();
4166 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4170 ret = nudge_clock->current_duration (pos);
4171 next = ret + 1; /* XXXX fix me */
4177 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4179 ArdourDialog dialog (_("Playlist Deletion"));
4180 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4181 "If it is kept, its audio files will not be cleaned.\n"
4182 "If it is deleted, audio files used by it alone will be cleaned."),
4185 dialog.set_position (WIN_POS_CENTER);
4186 dialog.get_vbox()->pack_start (label);
4190 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4191 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4192 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4193 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4194 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4196 // by default gtk uses the left most button
4197 keep->grab_focus ();
4199 switch (dialog.run ()) {
4201 /* keep this and all remaining ones */
4206 /* delete this and all others */
4210 case RESPONSE_ACCEPT:
4211 /* delete the playlist */
4215 case RESPONSE_REJECT:
4216 /* keep the playlist */
4228 Editor::audio_region_selection_covers (framepos_t where)
4230 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4231 if ((*a)->region()->covers (where)) {
4240 Editor::prepare_for_cleanup ()
4242 cut_buffer->clear_regions ();
4243 cut_buffer->clear_playlists ();
4245 selection->clear_regions ();
4246 selection->clear_playlists ();
4248 _regions->suspend_redisplay ();
4252 Editor::finish_cleanup ()
4254 _regions->resume_redisplay ();
4258 Editor::transport_loop_location()
4261 return _session->locations()->auto_loop_location();
4268 Editor::transport_punch_location()
4271 return _session->locations()->auto_punch_location();
4278 Editor::control_layout_scroll (GdkEventScroll* ev)
4280 /* Just forward to the normal canvas scroll method. The coordinate
4281 systems are different but since the canvas is always larger than the
4282 track headers, and aligned with the trackview area, this will work.
4284 In the not too distant future this layout is going away anyway and
4285 headers will be on the canvas.
4287 return canvas_scroll_event (ev, false);
4291 Editor::session_state_saved (string)
4294 _snapshots->redisplay ();
4298 Editor::maximise_editing_space ()
4304 Gtk::Window* toplevel = current_toplevel();
4307 toplevel->fullscreen ();
4313 Editor::restore_editing_space ()
4319 Gtk::Window* toplevel = current_toplevel();
4322 toplevel->unfullscreen();
4328 * Make new playlists for a given track and also any others that belong
4329 * to the same active route group with the `select' property.
4334 Editor::new_playlists (TimeAxisView* v)
4336 begin_reversible_command (_("new playlists"));
4337 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4338 _session->playlists->get (playlists);
4339 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4340 commit_reversible_command ();
4344 * Use a copy of the current playlist for a given track and also any others that belong
4345 * to the same active route group with the `select' property.
4350 Editor::copy_playlists (TimeAxisView* v)
4352 begin_reversible_command (_("copy playlists"));
4353 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4354 _session->playlists->get (playlists);
4355 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4356 commit_reversible_command ();
4359 /** Clear the current playlist for a given track and also any others that belong
4360 * to the same active route group with the `select' property.
4365 Editor::clear_playlists (TimeAxisView* v)
4367 begin_reversible_command (_("clear playlists"));
4368 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4369 _session->playlists->get (playlists);
4370 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4371 commit_reversible_command ();
4375 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4377 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4381 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4383 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4387 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4389 atv.clear_playlist ();
4393 Editor::get_y_origin () const
4395 return vertical_adjustment.get_value ();
4398 /** Queue up a change to the viewport x origin.
4399 * @param frame New x origin.
4402 Editor::reset_x_origin (framepos_t frame)
4404 pending_visual_change.add (VisualChange::TimeOrigin);
4405 pending_visual_change.time_origin = frame;
4406 ensure_visual_change_idle_handler ();
4410 Editor::reset_y_origin (double y)
4412 pending_visual_change.add (VisualChange::YOrigin);
4413 pending_visual_change.y_origin = y;
4414 ensure_visual_change_idle_handler ();
4418 Editor::reset_zoom (framecnt_t spp)
4420 if (spp == samples_per_pixel) {
4424 pending_visual_change.add (VisualChange::ZoomLevel);
4425 pending_visual_change.samples_per_pixel = spp;
4426 ensure_visual_change_idle_handler ();
4430 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4432 reset_x_origin (frame);
4435 if (!no_save_visual) {
4436 undo_visual_stack.push_back (current_visual_state(false));
4440 Editor::VisualState::VisualState (bool with_tracks)
4441 : gui_state (with_tracks ? new GUIObjectState : 0)
4445 Editor::VisualState::~VisualState ()
4450 Editor::VisualState*
4451 Editor::current_visual_state (bool with_tracks)
4453 VisualState* vs = new VisualState (with_tracks);
4454 vs->y_position = vertical_adjustment.get_value();
4455 vs->samples_per_pixel = samples_per_pixel;
4456 vs->leftmost_frame = leftmost_frame;
4457 vs->zoom_focus = zoom_focus;
4460 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4467 Editor::undo_visual_state ()
4469 if (undo_visual_stack.empty()) {
4473 VisualState* vs = undo_visual_stack.back();
4474 undo_visual_stack.pop_back();
4477 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4480 use_visual_state (*vs);
4485 Editor::redo_visual_state ()
4487 if (redo_visual_stack.empty()) {
4491 VisualState* vs = redo_visual_stack.back();
4492 redo_visual_stack.pop_back();
4494 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4495 // why do we check here?
4496 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4499 use_visual_state (*vs);
4504 Editor::swap_visual_state ()
4506 if (undo_visual_stack.empty()) {
4507 redo_visual_state ();
4509 undo_visual_state ();
4514 Editor::use_visual_state (VisualState& vs)
4516 PBD::Unwinder<bool> nsv (no_save_visual, true);
4517 DisplaySuspender ds;
4519 vertical_adjustment.set_value (vs.y_position);
4521 set_zoom_focus (vs.zoom_focus);
4522 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4525 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4527 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4528 (*i)->clear_property_cache();
4529 (*i)->reset_visual_state ();
4533 _routes->update_visibility ();
4536 /** This is the core function that controls the zoom level of the canvas. It is called
4537 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4538 * @param spp new number of samples per pixel
4541 Editor::set_samples_per_pixel (framecnt_t spp)
4547 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4548 const framecnt_t lots_of_pixels = 4000;
4550 /* if the zoom level is greater than what you'd get trying to display 3
4551 * days of audio on a really big screen, then it's too big.
4554 if (spp * lots_of_pixels > three_days) {
4558 samples_per_pixel = spp;
4561 tempo_lines->tempo_map_changed();
4564 bool const showing_time_selection = selection->time.length() > 0;
4566 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4567 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4568 (*i)->reshow_selection (selection->time);
4572 ZoomChanged (); /* EMIT_SIGNAL */
4574 ArdourCanvas::GtkCanvasViewport* c;
4576 c = get_track_canvas();
4578 c->canvas()->zoomed ();
4581 if (playhead_cursor) {
4582 playhead_cursor->set_position (playhead_cursor->current_frame ());
4585 refresh_location_display();
4586 _summary->set_overlays_dirty ();
4588 update_marker_labels ();
4594 Editor::playhead_cursor_sample () const
4596 return playhead_cursor->current_frame();
4600 Editor::queue_visual_videotimeline_update ()
4603 * pending_visual_change.add (VisualChange::VideoTimeline);
4604 * or maybe even more specific: which videotimeline-image
4605 * currently it calls update_video_timeline() to update
4606 * _all outdated_ images on the video-timeline.
4607 * see 'exposeimg()' in video_image_frame.cc
4609 ensure_visual_change_idle_handler ();
4613 Editor::ensure_visual_change_idle_handler ()
4615 if (pending_visual_change.idle_handler_id < 0) {
4616 // see comment in add_to_idle_resize above.
4617 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4618 pending_visual_change.being_handled = false;
4623 Editor::_idle_visual_changer (void* arg)
4625 return static_cast<Editor*>(arg)->idle_visual_changer ();
4629 Editor::idle_visual_changer ()
4631 /* set_horizontal_position() below (and maybe other calls) call
4632 gtk_main_iteration(), so it's possible that a signal will be handled
4633 half-way through this method. If this signal wants an
4634 idle_visual_changer we must schedule another one after this one, so
4635 mark the idle_handler_id as -1 here to allow that. Also make a note
4636 that we are doing the visual change, so that changes in response to
4637 super-rapid-screen-update can be dropped if we are still processing
4641 pending_visual_change.idle_handler_id = -1;
4642 pending_visual_change.being_handled = true;
4644 VisualChange vc = pending_visual_change;
4646 pending_visual_change.pending = (VisualChange::Type) 0;
4648 visual_changer (vc);
4650 pending_visual_change.being_handled = false;
4652 return 0; /* this is always a one-shot call */
4656 Editor::visual_changer (const VisualChange& vc)
4658 double const last_time_origin = horizontal_position ();
4660 if (vc.pending & VisualChange::ZoomLevel) {
4661 set_samples_per_pixel (vc.samples_per_pixel);
4663 compute_fixed_ruler_scale ();
4665 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4666 update_tempo_based_rulers ();
4668 update_video_timeline();
4671 if (vc.pending & VisualChange::TimeOrigin) {
4672 set_horizontal_position (sample_to_pixel_unrounded (vc.time_origin));
4675 if (vc.pending & VisualChange::YOrigin) {
4676 vertical_adjustment.set_value (vc.y_origin);
4679 if (last_time_origin == horizontal_position ()) {
4680 /* changed signal not emitted */
4681 update_fixed_rulers ();
4682 redisplay_tempo (true);
4685 if (!(vc.pending & VisualChange::ZoomLevel)) {
4686 update_video_timeline();
4689 _summary->set_overlays_dirty ();
4692 struct EditorOrderTimeAxisSorter {
4693 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4694 return a->order () < b->order ();
4699 Editor::sort_track_selection (TrackViewList& sel)
4701 EditorOrderTimeAxisSorter cmp;
4706 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4709 framepos_t where = 0;
4710 EditPoint ep = _edit_point;
4712 if (Profile->get_mixbus()) {
4713 if (ep == EditAtSelectedMarker) {
4714 ep = EditAtPlayhead;
4718 if (from_outside_canvas && (ep == EditAtMouse)) {
4719 ep = EditAtPlayhead;
4720 } else if (from_context_menu && (ep == EditAtMouse)) {
4721 return canvas_event_sample (&context_click_event, 0, 0);
4724 if (entered_marker) {
4725 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4726 return entered_marker->position();
4729 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4730 ep = EditAtSelectedMarker;
4733 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4734 ep = EditAtPlayhead;
4737 MusicFrame snap_mf (0, 0);
4740 case EditAtPlayhead:
4741 if (_dragging_playhead) {
4742 where = *_control_scroll_target;
4744 where = _session->audible_frame();
4746 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4749 case EditAtSelectedMarker:
4750 if (!selection->markers.empty()) {
4752 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4755 where = loc->start();
4759 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4767 if (!mouse_frame (where, ignored)) {
4768 /* XXX not right but what can we do ? */
4771 snap_mf.frame = where;
4773 where = snap_mf.frame;
4774 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4782 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4784 if (!_session) return;
4786 begin_reversible_command (cmd);
4790 if ((tll = transport_loop_location()) == 0) {
4791 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4792 XMLNode &before = _session->locations()->get_state();
4793 _session->locations()->add (loc, true);
4794 _session->set_auto_loop_location (loc);
4795 XMLNode &after = _session->locations()->get_state();
4796 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4798 XMLNode &before = tll->get_state();
4799 tll->set_hidden (false, this);
4800 tll->set (start, end);
4801 XMLNode &after = tll->get_state();
4802 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4805 commit_reversible_command ();
4809 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4811 if (!_session) return;
4813 begin_reversible_command (cmd);
4817 if ((tpl = transport_punch_location()) == 0) {
4818 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4819 XMLNode &before = _session->locations()->get_state();
4820 _session->locations()->add (loc, true);
4821 _session->set_auto_punch_location (loc);
4822 XMLNode &after = _session->locations()->get_state();
4823 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4825 XMLNode &before = tpl->get_state();
4826 tpl->set_hidden (false, this);
4827 tpl->set (start, end);
4828 XMLNode &after = tpl->get_state();
4829 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4832 commit_reversible_command ();
4835 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4836 * @param rs List to which found regions are added.
4837 * @param where Time to look at.
4838 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4841 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4843 const TrackViewList* tracks;
4846 tracks = &track_views;
4851 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4853 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4856 boost::shared_ptr<Track> tr;
4857 boost::shared_ptr<Playlist> pl;
4859 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4861 boost::shared_ptr<RegionList> regions = pl->regions_at (
4862 (framepos_t) floor ( (double) where * tr->speed()));
4864 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4865 RegionView* rv = rtv->view()->find_view (*i);
4876 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4878 const TrackViewList* tracks;
4881 tracks = &track_views;
4886 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4887 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4889 boost::shared_ptr<Track> tr;
4890 boost::shared_ptr<Playlist> pl;
4892 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4894 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4895 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4897 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4899 RegionView* rv = rtv->view()->find_view (*i);
4910 /** Get regions using the following method:
4912 * Make a region list using:
4913 * (a) any selected regions
4914 * (b) the intersection of any selected tracks and the edit point(*)
4915 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4917 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4919 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4923 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4925 RegionSelection regions;
4927 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4928 regions.add (entered_regionview);
4930 regions = selection->regions;
4933 if ( regions.empty() ) {
4934 TrackViewList tracks = selection->tracks;
4936 if (!tracks.empty()) {
4937 /* no region selected or entered, but some selected tracks:
4938 * act on all regions on the selected tracks at the edit point
4940 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4941 get_regions_at(regions, where, tracks);
4948 /** Get regions using the following method:
4950 * Make a region list using:
4951 * (a) any selected regions
4952 * (b) the intersection of any selected tracks and the edit point(*)
4953 * (c) if neither exists, then whatever region is under the mouse
4955 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4957 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4960 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4962 RegionSelection regions;
4964 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4965 regions.add (entered_regionview);
4967 regions = selection->regions;
4970 if ( regions.empty() ) {
4971 TrackViewList tracks = selection->tracks;
4973 if (!tracks.empty()) {
4974 /* no region selected or entered, but some selected tracks:
4975 * act on all regions on the selected tracks at the edit point
4977 get_regions_at(regions, pos, tracks);
4984 /** Start with regions that are selected, or the entered regionview if none are selected.
4985 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4986 * of the regions that we started with.
4990 Editor::get_regions_from_selection_and_entered () const
4992 RegionSelection regions = selection->regions;
4994 if (regions.empty() && entered_regionview) {
4995 regions.add (entered_regionview);
5002 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5004 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5005 RouteTimeAxisView* rtav;
5007 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5008 boost::shared_ptr<Playlist> pl;
5009 std::vector<boost::shared_ptr<Region> > results;
5010 boost::shared_ptr<Track> tr;
5012 if ((tr = rtav->track()) == 0) {
5017 if ((pl = (tr->playlist())) != 0) {
5018 boost::shared_ptr<Region> r = pl->region_by_id (id);
5020 RegionView* rv = rtav->view()->find_view (r);
5022 regions.push_back (rv);
5031 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5034 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5035 MidiTimeAxisView* mtav;
5037 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5039 mtav->get_per_region_note_selection (selection);
5046 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5048 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5050 RouteTimeAxisView* tatv;
5052 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5054 boost::shared_ptr<Playlist> pl;
5055 vector<boost::shared_ptr<Region> > results;
5057 boost::shared_ptr<Track> tr;
5059 if ((tr = tatv->track()) == 0) {
5064 if ((pl = (tr->playlist())) != 0) {
5065 if (src_comparison) {
5066 pl->get_source_equivalent_regions (region, results);
5068 pl->get_region_list_equivalent_regions (region, results);
5072 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5073 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5074 regions.push_back (marv);
5083 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5085 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5086 RouteTimeAxisView* tatv;
5087 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5088 if (!tatv->track()) {
5091 RegionView* marv = tatv->view()->find_view (region);
5101 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5103 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5104 RouteTimeAxisView* rtav;
5105 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5106 if (rtav->route() == route) {
5115 Editor::show_rhythm_ferret ()
5117 if (rhythm_ferret == 0) {
5118 rhythm_ferret = new RhythmFerret(*this);
5121 rhythm_ferret->set_session (_session);
5122 rhythm_ferret->show ();
5123 rhythm_ferret->present ();
5127 Editor::first_idle ()
5129 MessageDialog* dialog = 0;
5131 if (track_views.size() > 1) {
5132 Timers::TimerSuspender t;
5133 dialog = new MessageDialog (
5134 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5138 ARDOUR_UI::instance()->flush_pending (60);
5141 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5145 // first idle adds route children (automation tracks), so we need to redisplay here
5146 _routes->redisplay ();
5150 if (_session->undo_depth() == 0) {
5151 undo_action->set_sensitive(false);
5153 redo_action->set_sensitive(false);
5154 begin_selection_op_history ();
5160 Editor::_idle_resize (gpointer arg)
5162 return ((Editor*)arg)->idle_resize ();
5166 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5168 if (resize_idle_id < 0) {
5169 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5170 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5171 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5173 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5174 _pending_resize_amount = 0;
5177 /* make a note of the smallest resulting height, so that we can clamp the
5178 lower limit at TimeAxisView::hSmall */
5180 int32_t min_resulting = INT32_MAX;
5182 _pending_resize_amount += h;
5183 _pending_resize_view = view;
5185 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5187 if (selection->tracks.contains (_pending_resize_view)) {
5188 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5189 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5193 if (min_resulting < 0) {
5198 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5199 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5203 /** Handle pending resizing of tracks */
5205 Editor::idle_resize ()
5207 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5209 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5210 selection->tracks.contains (_pending_resize_view)) {
5212 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5213 if (*i != _pending_resize_view) {
5214 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5219 _pending_resize_amount = 0;
5220 _group_tabs->set_dirty ();
5221 resize_idle_id = -1;
5229 ENSURE_GUI_THREAD (*this, &Editor::located);
5232 playhead_cursor->set_position (_session->audible_frame ());
5233 if (_follow_playhead && !_pending_initial_locate) {
5234 reset_x_origin_to_follow_playhead ();
5238 _pending_locate_request = false;
5239 _pending_initial_locate = false;
5243 Editor::region_view_added (RegionView * rv)
5245 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5246 if (rv->region ()->id () == (*pr)) {
5247 selection->add (rv);
5248 selection->regions.pending.erase (pr);
5253 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5255 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5256 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5257 if (rv->region()->id () == (*rnote).first) {
5258 mrv->select_notes ((*rnote).second);
5259 selection->pending_midi_note_selection.erase(rnote);
5265 _summary->set_background_dirty ();
5269 Editor::region_view_removed ()
5271 _summary->set_background_dirty ();
5275 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5277 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5278 if ((*j)->stripable() == s) {
5288 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5292 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5293 TimeAxisView* tv = axis_view_from_stripable (*i);
5303 Editor::suspend_route_redisplay ()
5306 _routes->suspend_redisplay();
5311 Editor::resume_route_redisplay ()
5314 _routes->redisplay(); // queue redisplay
5315 _routes->resume_redisplay();
5320 Editor::add_vcas (VCAList& vlist)
5324 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5325 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5328 add_stripables (sl);
5332 Editor::add_routes (RouteList& rlist)
5336 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5340 add_stripables (sl);
5344 Editor::add_stripables (StripableList& sl)
5346 list<TimeAxisView*> new_views;
5347 boost::shared_ptr<VCA> v;
5348 boost::shared_ptr<Route> r;
5349 TrackViewList new_selection;
5350 bool from_scratch = (track_views.size() == 0);
5352 sl.sort (StripablePresentationInfoSorter());
5354 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5356 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5358 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5360 new_views.push_back (vtv);
5362 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5364 if (r->is_auditioner() || r->is_monitor()) {
5368 RouteTimeAxisView* rtv;
5369 DataType dt = r->input()->default_type();
5371 if (dt == ARDOUR::DataType::AUDIO) {
5372 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5374 } else if (dt == ARDOUR::DataType::MIDI) {
5375 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5378 throw unknown_type();
5381 new_views.push_back (rtv);
5382 track_views.push_back (rtv);
5383 new_selection.push_back (rtv);
5385 rtv->effective_gain_display ();
5387 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5388 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5392 if (new_views.size() > 0) {
5393 _routes->time_axis_views_added (new_views);
5394 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5397 /* note: !new_selection.empty() means that we got some routes rather
5401 if (!from_scratch && !new_selection.empty()) {
5402 selection->set (new_selection);
5403 begin_selection_op_history();
5406 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5407 show_editor_mixer (true);
5410 editor_list_button.set_sensitive (true);
5414 Editor::timeaxisview_deleted (TimeAxisView *tv)
5416 if (tv == entered_track) {
5420 if (_session && _session->deletion_in_progress()) {
5421 /* the situation is under control */
5425 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5427 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5429 _routes->route_removed (tv);
5431 TimeAxisView::Children c = tv->get_child_list ();
5432 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5433 if (entered_track == i->get()) {
5438 /* remove it from the list of track views */
5440 TrackViewList::iterator i;
5442 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5443 i = track_views.erase (i);
5446 /* update whatever the current mixer strip is displaying, if revelant */
5448 boost::shared_ptr<Route> route;
5451 route = rtav->route ();
5454 if (current_mixer_strip && current_mixer_strip->route() == route) {
5456 TimeAxisView* next_tv;
5458 if (track_views.empty()) {
5460 } else if (i == track_views.end()) {
5461 next_tv = track_views.front();
5466 // skip VCAs (cannot be selected, n/a in editor-mixer)
5467 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5468 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5469 next_tv = track_views.front();
5471 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5472 /* just in case: no master, only a VCA remains */
5478 set_selected_mixer_strip (*next_tv);
5480 /* make the editor mixer strip go away setting the
5481 * button to inactive (which also unticks the menu option)
5484 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5490 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5495 if (apply_to_selection) {
5496 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5498 TrackSelection::iterator j = i;
5501 hide_track_in_display (*i, false);
5506 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5508 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5509 // this will hide the mixer strip
5510 set_selected_mixer_strip (*tv);
5513 _routes->hide_track_in_display (*tv);
5518 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5523 _routes->show_track_in_display (*tv);
5524 if (move_into_view) {
5525 ensure_time_axis_view_is_visible (*tv, false);
5530 Editor::sync_track_view_list_and_routes ()
5532 track_views = TrackViewList (_routes->views ());
5534 _summary->set_background_dirty();
5535 _group_tabs->set_dirty ();
5537 return false; // do not call again (until needed)
5541 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5543 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5548 /** Find a RouteTimeAxisView by the ID of its route */
5550 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5552 RouteTimeAxisView* v;
5554 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5555 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5556 if(v->route()->id() == id) {
5566 Editor::fit_route_group (RouteGroup *g)
5568 TrackViewList ts = axis_views_from_routes (g->route_list ());
5573 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5575 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5578 _session->cancel_audition ();
5582 if (_session->is_auditioning()) {
5583 _session->cancel_audition ();
5584 if (r == last_audition_region) {
5589 _session->audition_region (r);
5590 last_audition_region = r;
5595 Editor::hide_a_region (boost::shared_ptr<Region> r)
5597 r->set_hidden (true);
5601 Editor::show_a_region (boost::shared_ptr<Region> r)
5603 r->set_hidden (false);
5607 Editor::audition_region_from_region_list ()
5609 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5613 Editor::hide_region_from_region_list ()
5615 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5619 Editor::show_region_in_region_list ()
5621 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5625 Editor::step_edit_status_change (bool yn)
5628 start_step_editing ();
5630 stop_step_editing ();
5635 Editor::start_step_editing ()
5637 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5641 Editor::stop_step_editing ()
5643 step_edit_connection.disconnect ();
5647 Editor::check_step_edit ()
5649 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5650 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5652 mtv->check_step_edit ();
5656 return true; // do it again, till we stop
5660 Editor::scroll_press (Direction dir)
5662 ++_scroll_callbacks;
5664 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5665 /* delay the first auto-repeat */
5671 scroll_backward (1);
5679 scroll_up_one_track ();
5683 scroll_down_one_track ();
5687 /* do hacky auto-repeat */
5688 if (!_scroll_connection.connected ()) {
5690 _scroll_connection = Glib::signal_timeout().connect (
5691 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5694 _scroll_callbacks = 0;
5701 Editor::scroll_release ()
5703 _scroll_connection.disconnect ();
5706 /** Queue a change for the Editor viewport x origin to follow the playhead */
5708 Editor::reset_x_origin_to_follow_playhead ()
5710 framepos_t const frame = playhead_cursor->current_frame ();
5712 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5714 if (_session->transport_speed() < 0) {
5716 if (frame > (current_page_samples() / 2)) {
5717 center_screen (frame-(current_page_samples()/2));
5719 center_screen (current_page_samples()/2);
5726 if (frame < leftmost_frame) {
5728 if (_session->transport_rolling()) {
5729 /* rolling; end up with the playhead at the right of the page */
5730 l = frame - current_page_samples ();
5732 /* not rolling: end up with the playhead 1/4 of the way along the page */
5733 l = frame - current_page_samples() / 4;
5737 if (_session->transport_rolling()) {
5738 /* rolling: end up with the playhead on the left of the page */
5741 /* not rolling: end up with the playhead 3/4 of the way along the page */
5742 l = frame - 3 * current_page_samples() / 4;
5750 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5756 Editor::super_rapid_screen_update ()
5758 if (!_session || !_session->engine().running()) {
5762 /* METERING / MIXER STRIPS */
5764 /* update track meters, if required */
5765 if (contents().is_mapped() && meters_running) {
5766 RouteTimeAxisView* rtv;
5767 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5768 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5769 rtv->fast_update ();
5774 /* and any current mixer strip */
5775 if (current_mixer_strip) {
5776 current_mixer_strip->fast_update ();
5779 /* PLAYHEAD AND VIEWPORT */
5781 /* There are a few reasons why we might not update the playhead / viewport stuff:
5783 * 1. we don't update things when there's a pending locate request, otherwise
5784 * when the editor requests a locate there is a chance that this method
5785 * will move the playhead before the locate request is processed, causing
5787 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5788 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5790 if (_pending_locate_request || _session->transport_speed() == 0) {
5791 _last_update_time = 0;
5795 if (_dragging_playhead) {
5796 _last_update_time = 0;
5800 framepos_t frame = _session->audible_frame();
5801 const int64_t now = g_get_monotonic_time ();
5804 if (_last_update_time > 0) {
5805 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6;
5806 framepos_t guess = playhead_cursor->current_frame () + rint (ds);
5807 err = frame - guess;
5809 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5810 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5813 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5815 err, _err_screen_engine);
5820 _err_screen_engine = 0;
5824 // in case of x-runs or freewheeling
5825 _last_update_time = 0;
5827 _last_update_time = now;
5830 if (playhead_cursor->current_frame () == frame) {
5834 playhead_cursor->set_position (frame);
5836 if (_session->requested_return_frame() >= 0) {
5837 _last_update_time = 0;
5841 if (!_follow_playhead || pending_visual_change.being_handled) {
5842 /* We only do this if we aren't already
5843 * handling a visual change (ie if
5844 * pending_visual_change.being_handled is
5845 * false) so that these requests don't stack
5846 * up there are too many of them to handle in
5852 if (!_stationary_playhead) {
5853 reset_x_origin_to_follow_playhead ();
5855 framepos_t const frame = playhead_cursor->current_frame ();
5856 double target = ((double)frame - (double)current_page_samples() / 2.0);
5857 if (target <= 0.0) {
5860 // compare to EditorCursor::set_position()
5861 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5862 double const new_pos = sample_to_pixel_unrounded (target);
5863 if (rint (new_pos) != rint (old_pos)) {
5864 reset_x_origin (pixel_to_sample (new_pos));
5871 Editor::session_going_away ()
5873 _have_idled = false;
5875 _session_connections.drop_connections ();
5877 super_rapid_screen_update_connection.disconnect ();
5879 selection->clear ();
5880 cut_buffer->clear ();
5882 clicked_regionview = 0;
5883 clicked_axisview = 0;
5884 clicked_routeview = 0;
5885 entered_regionview = 0;
5887 _last_update_time = 0;
5890 playhead_cursor->hide ();
5892 /* rip everything out of the list displays */
5896 _route_groups->clear ();
5898 /* do this first so that deleting a track doesn't reset cms to null
5899 and thus cause a leak.
5902 if (current_mixer_strip) {
5903 if (current_mixer_strip->get_parent() != 0) {
5904 global_hpacker.remove (*current_mixer_strip);
5906 delete current_mixer_strip;
5907 current_mixer_strip = 0;
5910 /* delete all trackviews */
5912 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5915 track_views.clear ();
5917 nudge_clock->set_session (0);
5919 editor_list_button.set_active(false);
5920 editor_list_button.set_sensitive(false);
5922 /* clear tempo/meter rulers */
5923 remove_metric_marks ();
5925 clear_marker_display ();
5927 stop_step_editing ();
5931 /* get rid of any existing editor mixer strip */
5933 WindowTitle title(Glib::get_application_name());
5934 title += _("Editor");
5936 own_window()->set_title (title.get_string());
5939 SessionHandlePtr::session_going_away ();
5943 Editor::trigger_script (int i)
5945 LuaInstance::instance()-> call_action (i);
5949 Editor::show_editor_list (bool yn)
5952 _editor_list_vbox.show ();
5954 _editor_list_vbox.hide ();
5959 Editor::change_region_layering_order (bool from_context_menu)
5961 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5963 if (!clicked_routeview) {
5964 if (layering_order_editor) {
5965 layering_order_editor->hide ();
5970 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5976 boost::shared_ptr<Playlist> pl = track->playlist();
5982 if (layering_order_editor == 0) {
5983 layering_order_editor = new RegionLayeringOrderEditor (*this);
5986 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5987 layering_order_editor->maybe_present ();
5991 Editor::update_region_layering_order_editor ()
5993 if (layering_order_editor && layering_order_editor->is_visible ()) {
5994 change_region_layering_order (true);
5999 Editor::setup_fade_images ()
6001 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6002 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6003 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6004 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6005 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6007 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6008 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6009 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6010 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6011 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6015 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6017 Editor::action_menu_item (std::string const & name)
6019 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6022 return *manage (a->create_menu_item ());
6026 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6028 EventBox* b = manage (new EventBox);
6029 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6030 Label* l = manage (new Label (name));
6034 _the_notebook.append_page (widget, *b);
6038 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6040 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6041 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6044 if (ev->type == GDK_2BUTTON_PRESS) {
6046 /* double-click on a notebook tab shrinks or expands the notebook */
6048 if (_notebook_shrunk) {
6049 if (pre_notebook_shrink_pane_width) {
6050 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6052 _notebook_shrunk = false;
6054 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6056 /* this expands the LHS of the edit pane to cover the notebook
6057 PAGE but leaves the tabs visible.
6059 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6060 _notebook_shrunk = true;
6068 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6070 using namespace Menu_Helpers;
6072 MenuList& items = _control_point_context_menu.items ();
6075 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6076 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6077 if (!can_remove_control_point (item)) {
6078 items.back().set_sensitive (false);
6081 _control_point_context_menu.popup (event->button.button, event->button.time);
6085 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6087 using namespace Menu_Helpers;
6089 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6094 /* We need to get the selection here and pass it to the operations, since
6095 popping up the menu will cause a region leave event which clears
6096 entered_regionview. */
6098 MidiRegionView& mrv = note->region_view();
6099 const RegionSelection rs = get_regions_from_selection_and_entered ();
6100 const uint32_t sel_size = mrv.selection_size ();
6102 MenuList& items = _note_context_menu.items();
6106 items.push_back(MenuElem(_("Delete"),
6107 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6110 items.push_back(MenuElem(_("Edit..."),
6111 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6112 if (sel_size != 1) {
6113 items.back().set_sensitive (false);
6116 items.push_back(MenuElem(_("Transpose..."),
6117 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6120 items.push_back(MenuElem(_("Legatize"),
6121 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6123 items.back().set_sensitive (false);
6126 items.push_back(MenuElem(_("Quantize..."),
6127 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6129 items.push_back(MenuElem(_("Remove Overlap"),
6130 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6132 items.back().set_sensitive (false);
6135 items.push_back(MenuElem(_("Transform..."),
6136 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6138 _note_context_menu.popup (event->button.button, event->button.time);
6142 Editor::zoom_vertical_modifier_released()
6144 _stepping_axis_view = 0;
6148 Editor::ui_parameter_changed (string parameter)
6150 if (parameter == "icon-set") {
6151 while (!_cursor_stack.empty()) {
6152 _cursor_stack.pop_back();
6154 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6155 _cursor_stack.push_back(_cursors->grabber);
6156 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6157 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6159 } else if (parameter == "draggable-playhead") {
6160 if (_verbose_cursor) {
6161 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6167 Editor::use_own_window (bool and_fill_it)
6169 bool new_window = !own_window();
6171 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6173 if (win && new_window) {
6174 win->set_name ("EditorWindow");
6176 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6178 // win->signal_realize().connect (*this, &Editor::on_realize);
6179 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6180 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6181 win->set_data ("ardour-bindings", bindings);
6186 DisplaySuspender ds;
6187 contents().show_all ();
6189 /* XXX: this is a bit unfortunate; it would probably
6190 be nicer if we could just call show () above rather
6191 than needing the show_all ()
6194 /* re-hide stuff if necessary */
6195 editor_list_button_toggled ();
6196 parameter_changed ("show-summary");
6197 parameter_changed ("show-group-tabs");
6198 parameter_changed ("show-zoom-tools");
6200 /* now reset all audio_time_axis heights, because widgets might need
6206 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6207 tv = (static_cast<TimeAxisView*>(*i));
6208 tv->reset_height ();
6211 if (current_mixer_strip) {
6212 current_mixer_strip->hide_things ();
6213 current_mixer_strip->parameter_changed ("mixer-element-visibility");