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/gtk_ui.h"
61 #include "gtkmm2ext/keyboard.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
66 #include "ardour/analysis_graph.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
78 #include "ardour/vca_manager.h"
79 #include "ardour/vca.h"
81 #include "canvas/debug.h"
82 #include "canvas/text.h"
84 #include "widgets/ardour_spacer.h"
85 #include "widgets/eventboxext.h"
86 #include "widgets/tooltips.h"
88 #include "control_protocol/control_protocol.h"
91 #include "analysis_window.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"
101 #include "editing_convert.h"
103 #include "editor_cursors.h"
104 #include "editor_drag.h"
105 #include "editor_group_tabs.h"
106 #include "editor_locations.h"
107 #include "editor_regions.h"
108 #include "editor_route_groups.h"
109 #include "editor_routes.h"
110 #include "editor_snapshots.h"
111 #include "editor_summary.h"
112 #include "enums_convert.h"
113 #include "export_report.h"
114 #include "global_port_matrix.h"
115 #include "gui_object.h"
116 #include "gui_thread.h"
117 #include "keyboard.h"
118 #include "luainstance.h"
120 #include "midi_region_view.h"
121 #include "midi_time_axis.h"
122 #include "mixer_strip.h"
123 #include "mixer_ui.h"
124 #include "mouse_cursors.h"
125 #include "note_base.h"
126 #include "playlist_selector.h"
127 #include "public_editor.h"
128 #include "quantize_dialog.h"
129 #include "region_layering_order_editor.h"
130 #include "rgb_macros.h"
131 #include "rhythm_ferret.h"
132 #include "route_sorter.h"
133 #include "selection.h"
134 #include "simple_progress_dialog.h"
136 #include "tempo_lines.h"
137 #include "time_axis_view.h"
138 #include "time_info_box.h"
140 #include "ui_config.h"
142 #include "vca_time_axis.h"
143 #include "verbose_cursor.h"
145 #include "pbd/i18n.h"
148 using namespace ARDOUR;
149 using namespace ArdourWidgets;
150 using namespace ARDOUR_UI_UTILS;
153 using namespace Glib;
154 using namespace Gtkmm2ext;
155 using namespace Editing;
157 using PBD::internationalize;
159 using Gtkmm2ext::Keyboard;
161 double Editor::timebar_height = 15.0;
163 static const gchar *_snap_type_strings[] = {
197 static const gchar *_snap_mode_strings[] = {
204 static const gchar *_edit_point_strings[] = {
211 static const gchar *_edit_mode_strings[] = {
219 static const gchar *_zoom_focus_strings[] = {
229 #ifdef USE_RUBBERBAND
230 static const gchar *_rb_opt_strings[] = {
233 N_("Balanced multitimbral mixture"),
234 N_("Unpitched percussion with stable notes"),
235 N_("Crisp monophonic instrumental"),
236 N_("Unpitched solo percussion"),
237 N_("Resample without preserving pitch"),
242 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
245 : PublicEditor (global_hpacker)
246 , editor_mixer_strip_width (Wide)
247 , constructed (false)
248 , _playlist_selector (0)
250 , no_save_visual (false)
251 , _leftmost_sample (0)
252 , samples_per_pixel (2048)
253 , zoom_focus (ZoomFocusPlayhead)
254 , mouse_mode (MouseObject)
255 , pre_internal_snap_type (SnapToBeat)
256 , pre_internal_snap_mode (SnapOff)
257 , internal_snap_type (SnapToBeat)
258 , internal_snap_mode (SnapOff)
259 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
260 , _notebook_shrunk (false)
261 , location_marker_color (0)
262 , location_range_color (0)
263 , location_loop_color (0)
264 , location_punch_color (0)
265 , location_cd_marker_color (0)
267 , _show_marker_lines (false)
268 , clicked_axisview (0)
269 , clicked_routeview (0)
270 , clicked_regionview (0)
271 , clicked_selection (0)
272 , clicked_control_point (0)
273 , button_release_can_deselect (true)
274 , _mouse_changed_selection (false)
275 , region_edit_menu_split_item (0)
276 , region_edit_menu_split_multichannel_item (0)
277 , track_region_edit_playlist_menu (0)
278 , track_edit_playlist_submenu (0)
279 , track_selection_edit_playlist_submenu (0)
280 , _popup_region_menu_item (0)
282 , _track_canvas_viewport (0)
283 , within_track_canvas (false)
284 , _verbose_cursor (0)
288 , range_marker_group (0)
289 , transport_marker_group (0)
290 , cd_marker_group (0)
291 , _time_markers_group (0)
292 , hv_scroll_group (0)
294 , cursor_scroll_group (0)
295 , no_scroll_group (0)
296 , _trackview_group (0)
297 , _drag_motion_group (0)
298 , _canvas_drop_zone (0)
299 , no_ruler_shown_update (false)
300 , ruler_grabbed_widget (0)
302 , minsec_mark_interval (0)
303 , minsec_mark_modulo (0)
305 , timecode_ruler_scale (timecode_show_many_hours)
306 , timecode_mark_modulo (0)
307 , timecode_nmarks (0)
308 , _samples_ruler_interval (0)
309 , bbt_ruler_scale (bbt_show_many)
312 , bbt_bar_helper_on (0)
313 , bbt_accent_modulo (0)
318 , visible_timebars (0)
319 , editor_ruler_menu (0)
323 , range_marker_bar (0)
324 , transport_marker_bar (0)
326 , minsec_label (_("Mins:Secs"))
327 , bbt_label (_("Bars:Beats"))
328 , timecode_label (_("Timecode"))
329 , samples_label (_("Samples"))
330 , tempo_label (_("Tempo"))
331 , meter_label (_("Meter"))
332 , mark_label (_("Location Markers"))
333 , range_mark_label (_("Range Markers"))
334 , transport_mark_label (_("Loop/Punch Ranges"))
335 , cd_mark_label (_("CD Markers"))
336 , videotl_label (_("Video Timeline"))
338 , playhead_cursor (0)
339 , edit_packer (4, 4, true)
340 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
341 , horizontal_adjustment (0.0, 0.0, 1e16)
342 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
343 , controls_layout (unused_adjustment, vertical_adjustment)
344 , _scroll_callbacks (0)
345 , _visible_canvas_width (0)
346 , _visible_canvas_height (0)
347 , _full_canvas_height (0)
348 , edit_controls_left_menu (0)
349 , edit_controls_right_menu (0)
350 , visual_change_queued(false)
351 , _last_update_time (0)
352 , _err_screen_engine (0)
353 , cut_buffer_start (0)
354 , cut_buffer_length (0)
355 , button_bindings (0)
356 , last_paste_pos (-1)
359 , current_interthread_info (0)
360 , analysis_window (0)
361 , select_new_marker (false)
363 , scrubbing_direction (0)
364 , scrub_reversals (0)
365 , scrub_reverse_distance (0)
366 , have_pending_keyboard_selection (false)
367 , pending_keyboard_selection_start (0)
368 , _snap_type (SnapToBeat)
369 , _snap_mode (SnapOff)
370 , snap_threshold (5.0)
371 , ignore_gui_changes (false)
372 , _drags (new DragManager (this))
374 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
375 , _dragging_playhead (false)
376 , _dragging_edit_point (false)
377 , _show_measures (true)
378 , _follow_playhead (true)
379 , _stationary_playhead (false)
382 , global_rect_group (0)
383 , time_line_group (0)
384 , tempo_marker_menu (0)
385 , meter_marker_menu (0)
387 , range_marker_menu (0)
388 , transport_marker_menu (0)
389 , new_transport_marker_menu (0)
391 , marker_menu_item (0)
392 , bbt_beat_subdivision (4)
393 , _visible_track_count (-1)
394 , toolbar_selection_clock_table (2,3)
395 , automation_mode_button (_("mode"))
396 , selection (new Selection (this, true))
397 , cut_buffer (new Selection (this, false))
398 , _selection_memento (new SelectionMemento())
399 , _all_region_actions_sensitized (false)
400 , _ignore_region_action (false)
401 , _last_region_menu_was_main (false)
402 , _track_selection_change_without_scroll (false)
403 , cd_marker_bar_drag_rect (0)
404 , range_bar_drag_rect (0)
405 , transport_bar_drag_rect (0)
406 , transport_bar_range_rect (0)
407 , transport_bar_preroll_rect (0)
408 , transport_bar_postroll_rect (0)
409 , transport_loop_range_rect (0)
410 , transport_punch_range_rect (0)
411 , transport_punchin_line (0)
412 , transport_punchout_line (0)
413 , transport_preroll_rect (0)
414 , transport_postroll_rect (0)
416 , rubberband_rect (0)
422 , autoscroll_horizontal_allowed (false)
423 , autoscroll_vertical_allowed (false)
425 , autoscroll_widget (0)
426 , show_gain_after_trim (false)
427 , selection_op_cmd_depth (0)
428 , selection_op_history_it (0)
429 , no_save_instant (false)
431 , current_mixer_strip (0)
432 , show_editor_mixer_when_tracks_arrive (false)
433 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
434 , current_stepping_trackview (0)
435 , last_track_height_step_timestamp (0)
437 , entered_regionview (0)
438 , clear_entered_track (false)
439 , _edit_point (EditAtMouse)
440 , meters_running (false)
442 , _have_idled (false)
443 , resize_idle_id (-1)
444 , _pending_resize_amount (0)
445 , _pending_resize_view (0)
446 , _pending_locate_request (false)
447 , _pending_initial_locate (false)
451 , layering_order_editor (0)
452 , _last_cut_copy_source_track (0)
453 , _region_selection_change_updates_region_list (true)
455 , _following_mixer_selection (false)
456 , _control_point_toggled_on_press (false)
457 , _stepping_axis_view (0)
458 , quantize_dialog (0)
459 , _main_menu_disabler (0)
460 , myactions (X_("editor"))
462 /* we are a singleton */
464 PublicEditor::_instance = this;
468 last_event_time.tv_sec = 0;
469 last_event_time.tv_usec = 0;
471 selection_op_history.clear();
474 snap_type_strings = I18N (_snap_type_strings);
475 snap_mode_strings = I18N (_snap_mode_strings);
476 zoom_focus_strings = I18N (_zoom_focus_strings);
477 edit_mode_strings = I18N (_edit_mode_strings);
478 edit_point_strings = I18N (_edit_point_strings);
479 #ifdef USE_RUBBERBAND
480 rb_opt_strings = I18N (_rb_opt_strings);
484 build_edit_mode_menu();
485 build_zoom_focus_menu();
486 build_track_count_menu();
487 build_snap_mode_menu();
488 build_snap_type_menu();
489 build_edit_point_menu();
491 location_marker_color = UIConfiguration::instance().color ("location marker");
492 location_range_color = UIConfiguration::instance().color ("location range");
493 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
494 location_loop_color = UIConfiguration::instance().color ("location loop");
495 location_punch_color = UIConfiguration::instance().color ("location punch");
497 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
499 TimeAxisView::setup_sizes ();
500 ArdourMarker::setup_sizes (timebar_height);
501 TempoCurve::setup_sizes (timebar_height);
503 bbt_label.set_name ("EditorRulerLabel");
504 bbt_label.set_size_request (-1, (int)timebar_height);
505 bbt_label.set_alignment (1.0, 0.5);
506 bbt_label.set_padding (5,0);
508 bbt_label.set_no_show_all();
509 minsec_label.set_name ("EditorRulerLabel");
510 minsec_label.set_size_request (-1, (int)timebar_height);
511 minsec_label.set_alignment (1.0, 0.5);
512 minsec_label.set_padding (5,0);
513 minsec_label.hide ();
514 minsec_label.set_no_show_all();
515 timecode_label.set_name ("EditorRulerLabel");
516 timecode_label.set_size_request (-1, (int)timebar_height);
517 timecode_label.set_alignment (1.0, 0.5);
518 timecode_label.set_padding (5,0);
519 timecode_label.hide ();
520 timecode_label.set_no_show_all();
521 samples_label.set_name ("EditorRulerLabel");
522 samples_label.set_size_request (-1, (int)timebar_height);
523 samples_label.set_alignment (1.0, 0.5);
524 samples_label.set_padding (5,0);
525 samples_label.hide ();
526 samples_label.set_no_show_all();
528 tempo_label.set_name ("EditorRulerLabel");
529 tempo_label.set_size_request (-1, (int)timebar_height);
530 tempo_label.set_alignment (1.0, 0.5);
531 tempo_label.set_padding (5,0);
533 tempo_label.set_no_show_all();
535 meter_label.set_name ("EditorRulerLabel");
536 meter_label.set_size_request (-1, (int)timebar_height);
537 meter_label.set_alignment (1.0, 0.5);
538 meter_label.set_padding (5,0);
540 meter_label.set_no_show_all();
542 if (Profile->get_trx()) {
543 mark_label.set_text (_("Markers"));
545 mark_label.set_name ("EditorRulerLabel");
546 mark_label.set_size_request (-1, (int)timebar_height);
547 mark_label.set_alignment (1.0, 0.5);
548 mark_label.set_padding (5,0);
550 mark_label.set_no_show_all();
552 cd_mark_label.set_name ("EditorRulerLabel");
553 cd_mark_label.set_size_request (-1, (int)timebar_height);
554 cd_mark_label.set_alignment (1.0, 0.5);
555 cd_mark_label.set_padding (5,0);
556 cd_mark_label.hide();
557 cd_mark_label.set_no_show_all();
559 videotl_bar_height = 4;
560 videotl_label.set_name ("EditorRulerLabel");
561 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
562 videotl_label.set_alignment (1.0, 0.5);
563 videotl_label.set_padding (5,0);
564 videotl_label.hide();
565 videotl_label.set_no_show_all();
567 range_mark_label.set_name ("EditorRulerLabel");
568 range_mark_label.set_size_request (-1, (int)timebar_height);
569 range_mark_label.set_alignment (1.0, 0.5);
570 range_mark_label.set_padding (5,0);
571 range_mark_label.hide();
572 range_mark_label.set_no_show_all();
574 transport_mark_label.set_name ("EditorRulerLabel");
575 transport_mark_label.set_size_request (-1, (int)timebar_height);
576 transport_mark_label.set_alignment (1.0, 0.5);
577 transport_mark_label.set_padding (5,0);
578 transport_mark_label.hide();
579 transport_mark_label.set_no_show_all();
581 initialize_canvas ();
583 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
585 _summary = new EditorSummary (this);
587 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
589 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
591 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
592 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
594 edit_controls_vbox.set_spacing (0);
595 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
596 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
598 HBox* h = manage (new HBox);
599 _group_tabs = new EditorGroupTabs (this);
600 if (!ARDOUR::Profile->get_trx()) {
601 h->pack_start (*_group_tabs, PACK_SHRINK);
603 h->pack_start (edit_controls_vbox);
604 controls_layout.add (*h);
606 controls_layout.set_name ("EditControlsBase");
607 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
608 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
609 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
611 _cursors = new MouseCursors;
612 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
613 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
615 /* Push default cursor to ever-present bottom of cursor stack. */
616 push_canvas_cursor(_cursors->grabber);
618 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
620 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
621 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
622 pad_line_1->set_outline_color (0xFF0000FF);
628 edit_packer.set_col_spacings (0);
629 edit_packer.set_row_spacings (0);
630 edit_packer.set_homogeneous (false);
631 edit_packer.set_border_width (0);
632 edit_packer.set_name ("EditorWindow");
634 time_bars_event_box.add (time_bars_vbox);
635 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
636 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
638 /* labels for the time bars */
639 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
641 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
643 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
645 bottom_hbox.set_border_width (2);
646 bottom_hbox.set_spacing (3);
648 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
650 _route_groups = new EditorRouteGroups (this);
651 _routes = new EditorRoutes (this);
652 _regions = new EditorRegions (this);
653 _snapshots = new EditorSnapshots (this);
654 _locations = new EditorLocations (this);
655 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
657 /* these are static location signals */
659 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
660 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
661 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
663 add_notebook_page (_("Regions"), _regions->widget ());
664 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
665 add_notebook_page (_("Snapshots"), _snapshots->widget ());
666 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
667 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
669 _the_notebook.set_show_tabs (true);
670 _the_notebook.set_scrollable (true);
671 _the_notebook.popup_disable ();
672 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
673 _the_notebook.show_all ();
675 _notebook_shrunk = false;
678 /* Pick up some settings we need to cache, early */
680 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
683 settings->get_property ("notebook-shrunk", _notebook_shrunk);
686 editor_summary_pane.set_check_divider_position (true);
687 editor_summary_pane.add (edit_packer);
689 Button* summary_arrow_left = manage (new Button);
690 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
691 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
692 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
694 Button* summary_arrow_right = manage (new Button);
695 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
696 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
697 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
699 VBox* summary_arrows_left = manage (new VBox);
700 summary_arrows_left->pack_start (*summary_arrow_left);
702 VBox* summary_arrows_right = manage (new VBox);
703 summary_arrows_right->pack_start (*summary_arrow_right);
705 Frame* summary_sample = manage (new Frame);
706 summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
708 summary_sample->add (*_summary);
709 summary_sample->show ();
711 _summary_hbox.pack_start (*summary_arrows_left, false, false);
712 _summary_hbox.pack_start (*summary_sample, true, true);
713 _summary_hbox.pack_start (*summary_arrows_right, false, false);
715 if (!ARDOUR::Profile->get_trx()) {
716 editor_summary_pane.add (_summary_hbox);
719 edit_pane.set_check_divider_position (true);
720 edit_pane.add (editor_summary_pane);
721 if (!ARDOUR::Profile->get_trx()) {
722 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
723 _editor_list_vbox.pack_start (_the_notebook);
724 edit_pane.add (_editor_list_vbox);
725 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
728 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
729 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
732 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
733 /* initial allocation is 90% to canvas, 10% to notebook */
736 edit_pane.set_divider (0, fract);
738 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
739 /* initial allocation is 90% to canvas, 10% to summary */
742 editor_summary_pane.set_divider (0, fract);
744 global_vpacker.set_spacing (2);
745 global_vpacker.set_border_width (0);
747 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
749 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
750 ebox->set_name("EditorWindow");
751 ebox->add (toolbar_hbox);
753 Gtk::EventBox* epane_box = manage (new EventBoxExt); //a themeable box
754 epane_box->set_name("EditorWindow");
755 epane_box->add (edit_pane);
757 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); //a themeable box
758 epane_box2->set_name("EditorWindow");
759 epane_box2->add (global_vpacker);
761 global_vpacker.pack_start (*ebox, false, false);
762 global_vpacker.pack_start (*epane_box, true, true);
763 global_hpacker.pack_start (*epane_box2, true, true);
765 /* need to show the "contents" widget so that notebook will show if tab is switched to
768 global_hpacker.show ();
770 /* register actions now so that set_state() can find them and set toggles/checks etc */
777 _playlist_selector = new PlaylistSelector();
778 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
780 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
784 nudge_forward_button.set_name ("nudge button");
785 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
787 nudge_backward_button.set_name ("nudge button");
788 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
790 fade_context_menu.set_name ("ArdourContextMenu");
792 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
794 /* allow external control surfaces/protocols to do various things */
796 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
797 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
798 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
799 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
800 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
801 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
802 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
803 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
804 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
805 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
806 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
807 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
808 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
809 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
811 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
812 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
813 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
814 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
815 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
817 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
821 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
823 /* problematic: has to return a value and thus cannot be x-thread */
825 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
827 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
828 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
830 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
832 _ignore_region_action = false;
833 _last_region_menu_was_main = false;
834 _popup_region_menu_item = 0;
836 _show_marker_lines = false;
838 /* Button bindings */
840 button_bindings = new Bindings ("editor-mouse");
842 XMLNode* node = button_settings();
844 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
845 button_bindings->load_operation (**i);
851 /* grab current parameter state */
852 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
853 UIConfiguration::instance().map_parameters (pc);
855 setup_fade_images ();
862 delete button_bindings;
864 delete _route_groups;
865 delete _track_canvas_viewport;
868 delete _verbose_cursor;
869 delete quantize_dialog;
875 delete _playlist_selector;
876 delete _time_info_box;
881 LuaInstance::destroy_instance ();
883 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
886 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
889 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
895 Editor::button_settings () const
897 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
898 XMLNode* node = find_named_node (*settings, X_("Buttons"));
901 node = new XMLNode (X_("Buttons"));
908 Editor::get_smart_mode () const
910 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
914 Editor::catch_vanishing_regionview (RegionView *rv)
916 /* note: the selection will take care of the vanishing
917 audioregionview by itself.
920 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
924 if (clicked_regionview == rv) {
925 clicked_regionview = 0;
928 if (entered_regionview == rv) {
929 set_entered_regionview (0);
932 if (!_all_region_actions_sensitized) {
933 sensitize_all_region_actions (true);
938 Editor::set_entered_regionview (RegionView* rv)
940 if (rv == entered_regionview) {
944 if (entered_regionview) {
945 entered_regionview->exited ();
948 entered_regionview = rv;
950 if (entered_regionview != 0) {
951 entered_regionview->entered ();
954 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
955 /* This RegionView entry might have changed what region actions
956 are allowed, so sensitize them all in case a key is pressed.
958 sensitize_all_region_actions (true);
963 Editor::set_entered_track (TimeAxisView* tav)
966 entered_track->exited ();
972 entered_track->entered ();
977 Editor::instant_save ()
979 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
984 _session->add_instant_xml(get_state());
986 Config->add_instant_xml(get_state());
991 Editor::control_vertical_zoom_in_all ()
993 tav_zoom_smooth (false, true);
997 Editor::control_vertical_zoom_out_all ()
999 tav_zoom_smooth (true, true);
1003 Editor::control_vertical_zoom_in_selected ()
1005 tav_zoom_smooth (false, false);
1009 Editor::control_vertical_zoom_out_selected ()
1011 tav_zoom_smooth (true, false);
1015 Editor::control_view (uint32_t view)
1017 goto_visual_state (view);
1021 Editor::control_unselect ()
1023 selection->clear_tracks ();
1027 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1029 TimeAxisView* tav = time_axis_view_from_stripable (s);
1033 case Selection::Add:
1034 selection->add (tav);
1036 case Selection::Toggle:
1037 selection->toggle (tav);
1039 case Selection::Extend:
1041 case Selection::Set:
1042 selection->set (tav);
1046 selection->clear_tracks ();
1051 Editor::control_step_tracks_up ()
1053 scroll_tracks_up_line ();
1057 Editor::control_step_tracks_down ()
1059 scroll_tracks_down_line ();
1063 Editor::control_scroll (float fraction)
1065 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1071 double step = fraction * current_page_samples();
1074 _control_scroll_target is an optional<T>
1076 it acts like a pointer to an samplepos_t, with
1077 a operator conversion to boolean to check
1078 that it has a value could possibly use
1079 playhead_cursor->current_sample to store the
1080 value and a boolean in the class to know
1081 when it's out of date
1084 if (!_control_scroll_target) {
1085 _control_scroll_target = _session->transport_sample();
1086 _dragging_playhead = true;
1089 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1090 *_control_scroll_target = 0;
1091 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1092 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1094 *_control_scroll_target += (samplepos_t) trunc (step);
1097 /* move visuals, we'll catch up with it later */
1099 playhead_cursor->set_position (*_control_scroll_target);
1100 UpdateAllTransportClocks (*_control_scroll_target);
1102 if (*_control_scroll_target > (current_page_samples() / 2)) {
1103 /* try to center PH in window */
1104 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1110 Now we do a timeout to actually bring the session to the right place
1111 according to the playhead. This is to avoid reading disk buffers on every
1112 call to control_scroll, which is driven by ScrollTimeline and therefore
1113 probably by a control surface wheel which can generate lots of events.
1115 /* cancel the existing timeout */
1117 control_scroll_connection.disconnect ();
1119 /* add the next timeout */
1121 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1125 Editor::deferred_control_scroll (samplepos_t /*target*/)
1127 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1128 // reset for next stream
1129 _control_scroll_target = boost::none;
1130 _dragging_playhead = false;
1135 Editor::access_action (const std::string& action_group, const std::string& action_item)
1141 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1144 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1152 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1154 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1158 Editor::on_realize ()
1162 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1163 start_lock_event_timing ();
1168 Editor::start_lock_event_timing ()
1170 /* check if we should lock the GUI every 30 seconds */
1172 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1176 Editor::generic_event_handler (GdkEvent* ev)
1179 case GDK_BUTTON_PRESS:
1180 case GDK_BUTTON_RELEASE:
1181 case GDK_MOTION_NOTIFY:
1183 case GDK_KEY_RELEASE:
1184 if (contents().is_mapped()) {
1185 gettimeofday (&last_event_time, 0);
1189 case GDK_LEAVE_NOTIFY:
1190 switch (ev->crossing.detail) {
1191 case GDK_NOTIFY_UNKNOWN:
1192 case GDK_NOTIFY_INFERIOR:
1193 case GDK_NOTIFY_ANCESTOR:
1195 case GDK_NOTIFY_VIRTUAL:
1196 case GDK_NOTIFY_NONLINEAR:
1197 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1198 /* leaving window, so reset focus, thus ending any and
1199 all text entry operations.
1201 ARDOUR_UI::instance()->reset_focus (&contents());
1214 Editor::lock_timeout_callback ()
1216 struct timeval now, delta;
1218 gettimeofday (&now, 0);
1220 timersub (&now, &last_event_time, &delta);
1222 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1224 /* don't call again. Returning false will effectively
1225 disconnect us from the timer callback.
1227 unlock() will call start_lock_event_timing() to get things
1237 Editor::map_position_change (samplepos_t sample)
1239 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1241 if (_session == 0) {
1245 if (_follow_playhead) {
1246 center_screen (sample);
1249 playhead_cursor->set_position (sample);
1253 Editor::center_screen (samplepos_t sample)
1255 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1257 /* if we're off the page, then scroll.
1260 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1261 center_screen_internal (sample, page);
1266 Editor::center_screen_internal (samplepos_t sample, float page)
1270 if (sample > page) {
1271 sample -= (samplepos_t) page;
1276 reset_x_origin (sample);
1281 Editor::update_title ()
1283 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1285 if (!own_window()) {
1290 bool dirty = _session->dirty();
1292 string session_name;
1294 if (_session->snap_name() != _session->name()) {
1295 session_name = _session->snap_name();
1297 session_name = _session->name();
1301 session_name = "*" + session_name;
1304 WindowTitle title(session_name);
1305 title += S_("Window|Editor");
1306 title += Glib::get_application_name();
1307 own_window()->set_title (title.get_string());
1309 /* ::session_going_away() will have taken care of it */
1314 Editor::set_session (Session *t)
1316 SessionHandlePtr::set_session (t);
1322 //initialize _leftmost_sample to the extents of the session
1323 //this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample before the visible state has been loaded from instant.xml
1324 _leftmost_sample = session_gui_extents().first;
1326 _playlist_selector->set_session (_session);
1327 nudge_clock->set_session (_session);
1328 _summary->set_session (_session);
1329 _group_tabs->set_session (_session);
1330 _route_groups->set_session (_session);
1331 _regions->set_session (_session);
1332 _snapshots->set_session (_session);
1333 _routes->set_session (_session);
1334 _locations->set_session (_session);
1335 _time_info_box->set_session (_session);
1337 if (rhythm_ferret) {
1338 rhythm_ferret->set_session (_session);
1341 if (analysis_window) {
1342 analysis_window->set_session (_session);
1346 sfbrowser->set_session (_session);
1349 compute_fixed_ruler_scale ();
1351 /* Make sure we have auto loop and auto punch ranges */
1353 Location* loc = _session->locations()->auto_loop_location();
1355 loc->set_name (_("Loop"));
1358 loc = _session->locations()->auto_punch_location();
1361 loc->set_name (_("Punch"));
1364 refresh_location_display ();
1366 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1367 the selected Marker; this needs the LocationMarker list to be available.
1369 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1370 set_state (*node, Stateful::loading_state_version);
1372 /* catch up on selection state, etc. */
1375 sc.add (Properties::selected);
1376 presentation_info_changed (sc);
1378 /* catch up with the playhead */
1380 _session->request_locate (playhead_cursor->current_sample ());
1381 _pending_initial_locate = true;
1385 /* These signals can all be emitted by a non-GUI thread. Therefore the
1386 handlers for them must not attempt to directly interact with the GUI,
1387 but use PBD::Signal<T>::connect() which accepts an event loop
1388 ("context") where the handler will be asked to run.
1391 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1392 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1393 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1394 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1395 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1396 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1397 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1398 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1399 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1400 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1401 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1402 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1403 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1404 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1405 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1406 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1408 playhead_cursor->show ();
1410 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1411 Config->map_parameters (pc);
1412 _session->config.map_parameters (pc);
1414 restore_ruler_visibility ();
1415 //tempo_map_changed (PropertyChange (0));
1416 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1418 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1419 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1422 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1423 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1426 switch (_snap_type) {
1427 case SnapToRegionStart:
1428 case SnapToRegionEnd:
1429 case SnapToRegionSync:
1430 case SnapToRegionBoundary:
1431 build_region_boundary_cache ();
1438 /* register for undo history */
1439 _session->register_with_memento_command_factory(id(), this);
1440 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1442 LuaInstance::instance()->set_session(_session);
1444 start_updating_meters ();
1448 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1450 using namespace Menu_Helpers;
1452 void (Editor::*emf)(FadeShape);
1453 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1456 images = &_xfade_in_images;
1457 emf = &Editor::set_fade_in_shape;
1459 images = &_xfade_out_images;
1460 emf = &Editor::set_fade_out_shape;
1465 _("Linear (for highly correlated material)"),
1466 *(*images)[FadeLinear],
1467 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1471 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 _("Constant power"),
1476 *(*images)[FadeConstantPower],
1477 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 *(*images)[FadeSymmetric],
1486 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1490 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 *(*images)[FadeSlow],
1496 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1499 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1504 *(*images)[FadeFast],
1505 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 /** Pop up a context menu for when the user clicks on a start crossfade */
1513 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1515 using namespace Menu_Helpers;
1516 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1521 MenuList& items (xfade_in_context_menu.items());
1524 if (arv->audio_region()->fade_in_active()) {
1525 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1527 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1530 items.push_back (SeparatorElem());
1531 fill_xfade_menu (items, true);
1533 xfade_in_context_menu.popup (button, time);
1536 /** Pop up a context menu for when the user clicks on an end crossfade */
1538 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1540 using namespace Menu_Helpers;
1541 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1546 MenuList& items (xfade_out_context_menu.items());
1549 if (arv->audio_region()->fade_out_active()) {
1550 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1552 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1555 items.push_back (SeparatorElem());
1556 fill_xfade_menu (items, false);
1558 xfade_out_context_menu.popup (button, time);
1562 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1564 using namespace Menu_Helpers;
1565 Menu* (Editor::*build_menu_function)();
1568 switch (item_type) {
1570 case RegionViewName:
1571 case RegionViewNameHighlight:
1572 case LeftFrameHandle:
1573 case RightFrameHandle:
1574 if (with_selection) {
1575 build_menu_function = &Editor::build_track_selection_context_menu;
1577 build_menu_function = &Editor::build_track_region_context_menu;
1582 if (with_selection) {
1583 build_menu_function = &Editor::build_track_selection_context_menu;
1585 build_menu_function = &Editor::build_track_context_menu;
1590 if (clicked_routeview->track()) {
1591 build_menu_function = &Editor::build_track_context_menu;
1593 build_menu_function = &Editor::build_track_bus_context_menu;
1598 /* probably shouldn't happen but if it does, we don't care */
1602 menu = (this->*build_menu_function)();
1603 menu->set_name ("ArdourContextMenu");
1605 /* now handle specific situations */
1607 switch (item_type) {
1609 case RegionViewName:
1610 case RegionViewNameHighlight:
1611 case LeftFrameHandle:
1612 case RightFrameHandle:
1613 if (!with_selection) {
1614 if (region_edit_menu_split_item) {
1615 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1616 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1618 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1621 if (region_edit_menu_split_multichannel_item) {
1622 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1623 region_edit_menu_split_multichannel_item->set_sensitive (true);
1625 region_edit_menu_split_multichannel_item->set_sensitive (false);
1638 /* probably shouldn't happen but if it does, we don't care */
1642 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1644 /* Bounce to disk */
1646 using namespace Menu_Helpers;
1647 MenuList& edit_items = menu->items();
1649 edit_items.push_back (SeparatorElem());
1651 switch (clicked_routeview->audio_track()->freeze_state()) {
1652 case AudioTrack::NoFreeze:
1653 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1656 case AudioTrack::Frozen:
1657 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1660 case AudioTrack::UnFrozen:
1661 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1667 if (item_type == StreamItem && clicked_routeview) {
1668 clicked_routeview->build_underlay_menu(menu);
1671 /* When the region menu is opened, we setup the actions so that they look right
1674 sensitize_the_right_region_actions (false);
1675 _last_region_menu_was_main = false;
1677 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1678 menu->popup (button, time);
1682 Editor::build_track_context_menu ()
1684 using namespace Menu_Helpers;
1686 MenuList& edit_items = track_context_menu.items();
1689 add_dstream_context_items (edit_items);
1690 return &track_context_menu;
1694 Editor::build_track_bus_context_menu ()
1696 using namespace Menu_Helpers;
1698 MenuList& edit_items = track_context_menu.items();
1701 add_bus_context_items (edit_items);
1702 return &track_context_menu;
1706 Editor::build_track_region_context_menu ()
1708 using namespace Menu_Helpers;
1709 MenuList& edit_items = track_region_context_menu.items();
1712 /* we've just cleared the track region context menu, so the menu that these
1713 two items were on will have disappeared; stop them dangling.
1715 region_edit_menu_split_item = 0;
1716 region_edit_menu_split_multichannel_item = 0;
1718 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1721 boost::shared_ptr<Track> tr;
1722 boost::shared_ptr<Playlist> pl;
1724 if ((tr = rtv->track())) {
1725 add_region_context_items (edit_items, tr);
1729 add_dstream_context_items (edit_items);
1731 return &track_region_context_menu;
1735 Editor::loudness_analyze_region_selection ()
1740 Selection& s (PublicEditor::instance ().get_selection ());
1741 RegionSelection ars = s.regions;
1742 ARDOUR::AnalysisGraph ag (_session);
1743 samplecnt_t total_work = 0;
1745 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1746 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1750 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1753 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1754 total_work += arv->region ()->length ();
1757 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1759 ag.set_total_samples (total_work);
1760 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1763 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1764 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1768 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1772 ag.analyze_region (ar);
1775 if (!ag.canceled ()) {
1776 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1782 Editor::loudness_analyze_range_selection ()
1787 Selection& s (PublicEditor::instance ().get_selection ());
1788 TimeSelection ts = s.time;
1789 ARDOUR::AnalysisGraph ag (_session);
1790 samplecnt_t total_work = 0;
1792 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1793 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1797 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1801 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1802 total_work += j->length ();
1806 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1808 ag.set_total_samples (total_work);
1809 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1812 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1813 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1817 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1821 ag.analyze_range (rui->route (), pl, ts);
1824 if (!ag.canceled ()) {
1825 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1831 Editor::spectral_analyze_region_selection ()
1833 if (analysis_window == 0) {
1834 analysis_window = new AnalysisWindow();
1837 analysis_window->set_session(_session);
1839 analysis_window->show_all();
1842 analysis_window->set_regionmode();
1843 analysis_window->analyze();
1845 analysis_window->present();
1849 Editor::spectral_analyze_range_selection()
1851 if (analysis_window == 0) {
1852 analysis_window = new AnalysisWindow();
1855 analysis_window->set_session(_session);
1857 analysis_window->show_all();
1860 analysis_window->set_rangemode();
1861 analysis_window->analyze();
1863 analysis_window->present();
1867 Editor::build_track_selection_context_menu ()
1869 using namespace Menu_Helpers;
1870 MenuList& edit_items = track_selection_context_menu.items();
1871 edit_items.clear ();
1873 add_selection_context_items (edit_items);
1874 // edit_items.push_back (SeparatorElem());
1875 // add_dstream_context_items (edit_items);
1877 return &track_selection_context_menu;
1881 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1883 using namespace Menu_Helpers;
1885 /* OK, stick the region submenu at the top of the list, and then add
1889 RegionSelection rs = get_regions_from_selection_and_entered ();
1891 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1893 if (_popup_region_menu_item == 0) {
1894 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1895 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1896 _popup_region_menu_item->show ();
1898 _popup_region_menu_item->set_label (menu_item_name);
1901 /* No layering allowed in later is higher layering model */
1902 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1903 if (act && Config->get_layer_model() == LaterHigher) {
1904 act->set_sensitive (false);
1906 act->set_sensitive (true);
1909 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1911 edit_items.push_back (*_popup_region_menu_item);
1912 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1913 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1915 edit_items.push_back (SeparatorElem());
1918 /** Add context menu items relevant to selection ranges.
1919 * @param edit_items List to add the items to.
1922 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1924 using namespace Menu_Helpers;
1926 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1927 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1929 edit_items.push_back (SeparatorElem());
1930 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1932 edit_items.push_back (SeparatorElem());
1933 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1934 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1936 edit_items.push_back (SeparatorElem());
1938 edit_items.push_back (
1940 _("Move Range Start to Previous Region Boundary"),
1941 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1945 edit_items.push_back (
1947 _("Move Range Start to Next Region Boundary"),
1948 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1952 edit_items.push_back (
1954 _("Move Range End to Previous Region Boundary"),
1955 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1959 edit_items.push_back (
1961 _("Move Range End to Next Region Boundary"),
1962 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1966 edit_items.push_back (SeparatorElem());
1967 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1968 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1970 edit_items.push_back (SeparatorElem());
1971 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1973 edit_items.push_back (SeparatorElem());
1974 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1975 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1976 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1978 edit_items.push_back (SeparatorElem());
1979 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1981 edit_items.push_back (SeparatorElem());
1982 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1983 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1985 edit_items.push_back (SeparatorElem());
1986 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1987 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1988 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1989 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1990 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1991 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1992 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1998 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2000 using namespace Menu_Helpers;
2004 Menu *play_menu = manage (new Menu);
2005 MenuList& play_items = play_menu->items();
2006 play_menu->set_name ("ArdourContextMenu");
2008 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2009 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2010 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2011 play_items.push_back (SeparatorElem());
2012 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2014 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2018 Menu *select_menu = manage (new Menu);
2019 MenuList& select_items = select_menu->items();
2020 select_menu->set_name ("ArdourContextMenu");
2022 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2023 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2024 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2025 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2026 select_items.push_back (SeparatorElem());
2027 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2028 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2029 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2030 select_items.push_back (SeparatorElem());
2031 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2032 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2033 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2034 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2035 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2036 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2037 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2039 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2043 Menu *cutnpaste_menu = manage (new Menu);
2044 MenuList& cutnpaste_items = cutnpaste_menu->items();
2045 cutnpaste_menu->set_name ("ArdourContextMenu");
2047 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2048 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2049 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2051 cutnpaste_items.push_back (SeparatorElem());
2053 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2054 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2056 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2058 /* Adding new material */
2060 edit_items.push_back (SeparatorElem());
2061 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2062 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2066 Menu *nudge_menu = manage (new Menu());
2067 MenuList& nudge_items = nudge_menu->items();
2068 nudge_menu->set_name ("ArdourContextMenu");
2070 edit_items.push_back (SeparatorElem());
2071 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2072 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2074 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2076 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2080 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2082 using namespace Menu_Helpers;
2086 Menu *play_menu = manage (new Menu);
2087 MenuList& play_items = play_menu->items();
2088 play_menu->set_name ("ArdourContextMenu");
2090 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2091 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2092 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2096 Menu *select_menu = manage (new Menu);
2097 MenuList& select_items = select_menu->items();
2098 select_menu->set_name ("ArdourContextMenu");
2100 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2101 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2102 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2103 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2104 select_items.push_back (SeparatorElem());
2105 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2106 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2107 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2108 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2110 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2114 Menu *cutnpaste_menu = manage (new Menu);
2115 MenuList& cutnpaste_items = cutnpaste_menu->items();
2116 cutnpaste_menu->set_name ("ArdourContextMenu");
2118 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2119 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2120 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2122 Menu *nudge_menu = manage (new Menu());
2123 MenuList& nudge_items = nudge_menu->items();
2124 nudge_menu->set_name ("ArdourContextMenu");
2126 edit_items.push_back (SeparatorElem());
2127 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2128 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2129 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2130 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2132 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2136 Editor::snap_type() const
2142 Editor::snap_musical() const
2144 switch (_snap_type) {
2145 case SnapToBeatDiv128:
2146 case SnapToBeatDiv64:
2147 case SnapToBeatDiv32:
2148 case SnapToBeatDiv28:
2149 case SnapToBeatDiv24:
2150 case SnapToBeatDiv20:
2151 case SnapToBeatDiv16:
2152 case SnapToBeatDiv14:
2153 case SnapToBeatDiv12:
2154 case SnapToBeatDiv10:
2155 case SnapToBeatDiv8:
2156 case SnapToBeatDiv7:
2157 case SnapToBeatDiv6:
2158 case SnapToBeatDiv5:
2159 case SnapToBeatDiv4:
2160 case SnapToBeatDiv3:
2161 case SnapToBeatDiv2:
2173 Editor::snap_mode() const
2179 Editor::set_snap_to (SnapType st)
2181 unsigned int snap_ind = (unsigned int)st;
2183 if (internal_editing()) {
2184 internal_snap_type = st;
2186 pre_internal_snap_type = st;
2191 if (snap_ind > snap_type_strings.size() - 1) {
2193 _snap_type = (SnapType)snap_ind;
2196 string str = snap_type_strings[snap_ind];
2198 if (str != snap_type_selector.get_text()) {
2199 snap_type_selector.set_text (str);
2204 switch (_snap_type) {
2205 case SnapToBeatDiv128:
2206 case SnapToBeatDiv64:
2207 case SnapToBeatDiv32:
2208 case SnapToBeatDiv28:
2209 case SnapToBeatDiv24:
2210 case SnapToBeatDiv20:
2211 case SnapToBeatDiv16:
2212 case SnapToBeatDiv14:
2213 case SnapToBeatDiv12:
2214 case SnapToBeatDiv10:
2215 case SnapToBeatDiv8:
2216 case SnapToBeatDiv7:
2217 case SnapToBeatDiv6:
2218 case SnapToBeatDiv5:
2219 case SnapToBeatDiv4:
2220 case SnapToBeatDiv3:
2221 case SnapToBeatDiv2: {
2222 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2223 update_tempo_based_rulers ();
2227 case SnapToRegionStart:
2228 case SnapToRegionEnd:
2229 case SnapToRegionSync:
2230 case SnapToRegionBoundary:
2231 build_region_boundary_cache ();
2239 redisplay_tempo (false);
2241 SnapChanged (); /* EMIT SIGNAL */
2245 Editor::set_snap_mode (SnapMode mode)
2247 string str = snap_mode_strings[(int)mode];
2249 if (internal_editing()) {
2250 internal_snap_mode = mode;
2252 pre_internal_snap_mode = mode;
2257 if (str != snap_mode_selector.get_text ()) {
2258 snap_mode_selector.set_text (str);
2265 Editor::set_edit_point_preference (EditPoint ep, bool force)
2267 bool changed = (_edit_point != ep);
2270 if (Profile->get_mixbus())
2271 if (ep == EditAtSelectedMarker)
2272 ep = EditAtPlayhead;
2274 string str = edit_point_strings[(int)ep];
2275 if (str != edit_point_selector.get_text ()) {
2276 edit_point_selector.set_text (str);
2279 update_all_enter_cursors();
2281 if (!force && !changed) {
2285 const char* action=NULL;
2287 switch (_edit_point) {
2288 case EditAtPlayhead:
2289 action = "edit-at-playhead";
2291 case EditAtSelectedMarker:
2292 action = "edit-at-marker";
2295 action = "edit-at-mouse";
2299 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2301 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2305 bool in_track_canvas;
2307 if (!mouse_sample (foo, in_track_canvas)) {
2308 in_track_canvas = false;
2311 reset_canvas_action_sensitivity (in_track_canvas);
2312 sensitize_the_right_region_actions (false);
2318 Editor::set_state (const XMLNode& node, int version)
2321 PBD::Unwinder<bool> nsi (no_save_instant, true);
2324 Tabbable::set_state (node, version);
2327 if (_session && node.get_property ("playhead", ph_pos)) {
2329 playhead_cursor->set_position (ph_pos);
2331 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2332 playhead_cursor->set_position (0);
2335 playhead_cursor->set_position (0);
2338 node.get_property ("mixer-width", editor_mixer_strip_width);
2340 node.get_property ("zoom-focus", zoom_focus);
2341 zoom_focus_selection_done (zoom_focus);
2344 if (node.get_property ("zoom", z)) {
2345 /* older versions of ardour used floating point samples_per_pixel */
2346 reset_zoom (llrintf (z));
2348 reset_zoom (samples_per_pixel);
2352 if (node.get_property ("visible-track-count", cnt)) {
2353 set_visible_track_count (cnt);
2357 if (!node.get_property ("snap-to", snap_type)) {
2358 snap_type = _snap_type;
2360 set_snap_to (snap_type);
2363 if (node.get_property ("snap-mode", sm)) {
2364 snap_mode_selection_done(sm);
2365 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2366 * snap_mode_selection_done() will only mark an already active item as active
2367 * which does not trigger set_text().
2371 set_snap_mode (_snap_mode);
2374 node.get_property ("internal-snap-to", internal_snap_type);
2375 node.get_property ("internal-snap-mode", internal_snap_mode);
2376 node.get_property ("pre-internal-snap-to", pre_internal_snap_type);
2377 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2380 if (node.get_property ("mouse-mode", mm_str)) {
2381 MouseMode m = str2mousemode(mm_str);
2382 set_mouse_mode (m, true);
2384 set_mouse_mode (MouseObject, true);
2388 if (node.get_property ("left-frame", lf_pos)) {
2392 reset_x_origin (lf_pos);
2396 if (node.get_property ("y-origin", y_origin)) {
2397 reset_y_origin (y_origin);
2400 if (node.get_property ("join-object-range", yn)) {
2401 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2403 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2404 tact->set_active (!yn);
2405 tact->set_active (yn);
2407 set_mouse_mode(mouse_mode, true);
2411 if (node.get_property ("edit-point", ep)) {
2412 set_edit_point_preference (ep, true);
2414 set_edit_point_preference (_edit_point);
2417 node.get_property ("show-measures", _show_measures);
2419 if (node.get_property ("follow-playhead", yn)) {
2420 set_follow_playhead (yn);
2423 if (node.get_property ("stationary-playhead", yn)) {
2424 set_stationary_playhead (yn);
2427 RegionListSortType sort_type;
2428 if (node.get_property ("region-list-sort-type", sort_type)) {
2429 _regions->reset_sort_type (sort_type, true);
2432 if (node.get_property ("show-editor-mixer", yn)) {
2434 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2437 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2439 /* do it twice to force the change */
2441 tact->set_active (!yn);
2442 tact->set_active (yn);
2445 if (node.get_property ("show-editor-list", yn)) {
2447 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2450 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2452 /* do it twice to force the change */
2454 tact->set_active (!yn);
2455 tact->set_active (yn);
2459 if (node.get_property (X_("editor-list-page"), el_page)) {
2460 _the_notebook.set_current_page (el_page);
2463 if (node.get_property (X_("show-marker-lines"), yn)) {
2464 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2466 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2468 tact->set_active (!yn);
2469 tact->set_active (yn);
2472 XMLNodeList children = node.children ();
2473 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2474 selection->set_state (**i, Stateful::current_state_version);
2475 _regions->set_state (**i);
2476 _locations->set_state (**i);
2479 if (node.get_property ("maximised", yn)) {
2480 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2482 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2483 bool fs = tact && tact->get_active();
2485 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2489 samplepos_t nudge_clock_value;
2490 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2491 nudge_clock->set (nudge_clock_value);
2493 nudge_clock->set_mode (AudioClock::Timecode);
2494 nudge_clock->set (_session->sample_rate() * 5, true);
2499 * Not all properties may have been in XML, but
2500 * those that are linked to a private variable may need changing
2504 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2506 yn = _show_measures;
2507 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2508 /* do it twice to force the change */
2509 tact->set_active (!yn);
2510 tact->set_active (yn);
2513 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2514 yn = _follow_playhead;
2516 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2517 if (tact->get_active() != yn) {
2518 tact->set_active (yn);
2522 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2523 yn = _stationary_playhead;
2525 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2526 if (tact->get_active() != yn) {
2527 tact->set_active (yn);
2532 return LuaInstance::instance()->set_state(node);
2536 Editor::get_state ()
2538 XMLNode* node = new XMLNode (X_("Editor"));
2540 node->set_property ("id", id().to_s ());
2542 node->add_child_nocopy (Tabbable::get_state());
2544 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2545 node->set_property("notebook-shrunk", _notebook_shrunk);
2546 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2548 maybe_add_mixer_strip_width (*node);
2550 node->set_property ("zoom-focus", zoom_focus);
2552 node->set_property ("zoom", samples_per_pixel);
2553 node->set_property ("snap-to", _snap_type);
2554 node->set_property ("snap-mode", _snap_mode);
2555 node->set_property ("internal-snap-to", internal_snap_type);
2556 node->set_property ("internal-snap-mode", internal_snap_mode);
2557 node->set_property ("pre-internal-snap-to", pre_internal_snap_type);
2558 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2559 node->set_property ("edit-point", _edit_point);
2560 node->set_property ("visible-track-count", _visible_track_count);
2562 node->set_property ("playhead", playhead_cursor->current_sample ());
2563 node->set_property ("left-frame", _leftmost_sample);
2564 node->set_property ("y-origin", vertical_adjustment.get_value ());
2566 node->set_property ("show-measures", _show_measures);
2567 node->set_property ("maximised", _maximised);
2568 node->set_property ("follow-playhead", _follow_playhead);
2569 node->set_property ("stationary-playhead", _stationary_playhead);
2570 node->set_property ("region-list-sort-type", _regions->sort_type ());
2571 node->set_property ("mouse-mode", mouse_mode);
2572 node->set_property ("join-object-range", smart_mode_action->get_active ());
2574 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2576 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2577 node->set_property (X_("show-editor-mixer"), tact->get_active());
2580 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2582 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2583 node->set_property (X_("show-editor-list"), tact->get_active());
2586 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2588 if (button_bindings) {
2589 XMLNode* bb = new XMLNode (X_("Buttons"));
2590 button_bindings->save (*bb);
2591 node->add_child_nocopy (*bb);
2594 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2596 node->add_child_nocopy (selection->get_state ());
2597 node->add_child_nocopy (_regions->get_state ());
2599 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2601 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2602 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2603 node->add_child_nocopy (_locations->get_state ());
2608 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2609 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2611 * @return pair: TimeAxisView that y is over, layer index.
2613 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2614 * in stacked or expanded region display mode, otherwise 0.
2616 std::pair<TimeAxisView *, double>
2617 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2619 if (!trackview_relative_offset) {
2620 y -= _trackview_group->canvas_origin().y;
2624 return std::make_pair ( (TimeAxisView *) 0, 0);
2627 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2629 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2636 return std::make_pair ( (TimeAxisView *) 0, 0);
2639 /** Snap a position to the grid, if appropriate, taking into account current
2640 * grid settings and also the state of any snap modifier keys that may be pressed.
2641 * @param start Position to snap.
2642 * @param event Event to get current key modifier information from, or 0.
2645 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2647 if (!_session || !event) {
2651 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2652 if (_snap_mode == SnapOff) {
2653 snap_to_internal (start, direction, for_mark);
2655 start.set (start.sample, 0);
2658 if (_snap_mode != SnapOff) {
2659 snap_to_internal (start, direction, for_mark);
2660 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2661 /* SnapOff, but we pressed the snap_delta modifier */
2662 snap_to_internal (start, direction, for_mark);
2664 start.set (start.sample, 0);
2670 Editor::snap_to (MusicSample& start, RoundMode direction, bool for_mark, bool ensure_snap)
2672 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2673 start.set (start.sample, 0);
2677 snap_to_internal (start, direction, for_mark, ensure_snap);
2681 Editor::timecode_snap_to_internal (MusicSample& pos, RoundMode direction, bool /*for_mark*/)
2683 samplepos_t start = pos.sample;
2684 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2685 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2687 switch (_snap_type) {
2688 case SnapToTimecodeFrame:
2689 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2690 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2691 /* start is already on a whole timecode frame, do nothing */
2692 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2693 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2695 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2699 case SnapToTimecodeSeconds:
2700 if (_session->config.get_timecode_offset_negative()) {
2701 start += _session->config.get_timecode_offset ();
2703 start -= _session->config.get_timecode_offset ();
2705 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2706 (start % one_timecode_second == 0)) {
2707 /* start is already on a whole second, do nothing */
2708 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2709 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2711 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2714 if (_session->config.get_timecode_offset_negative()) {
2715 start -= _session->config.get_timecode_offset ();
2717 start += _session->config.get_timecode_offset ();
2721 case SnapToTimecodeMinutes:
2722 if (_session->config.get_timecode_offset_negative()) {
2723 start += _session->config.get_timecode_offset ();
2725 start -= _session->config.get_timecode_offset ();
2727 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2728 (start % one_timecode_minute == 0)) {
2729 /* start is already on a whole minute, do nothing */
2730 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2731 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2733 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2735 if (_session->config.get_timecode_offset_negative()) {
2736 start -= _session->config.get_timecode_offset ();
2738 start += _session->config.get_timecode_offset ();
2742 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2743 abort(); /*NOTREACHED*/
2750 Editor::snap_to_internal (MusicSample& start, RoundMode direction, bool for_mark, bool ensure_snap)
2752 const samplepos_t one_second = _session->sample_rate();
2753 const samplepos_t one_minute = _session->sample_rate() * 60;
2754 samplepos_t presnap = start.sample;
2758 switch (_snap_type) {
2759 case SnapToTimecodeFrame:
2760 case SnapToTimecodeSeconds:
2761 case SnapToTimecodeMinutes:
2762 return timecode_snap_to_internal (start, direction, for_mark);
2765 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2766 start.sample % (one_second/75) == 0) {
2767 /* start is already on a whole CD sample, do nothing */
2768 } else if (((direction == 0) && (start.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2769 start.sample = (samplepos_t) ceil ((double) start.sample / (one_second / 75)) * (one_second / 75);
2771 start.sample = (samplepos_t) floor ((double) start.sample / (one_second / 75)) * (one_second / 75);
2774 start.set (start.sample, 0);
2779 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2780 start.sample % one_second == 0) {
2781 /* start is already on a whole second, do nothing */
2782 } else if (((direction == 0) && (start.sample % one_second > one_second / 2)) || (direction > 0)) {
2783 start.sample = (samplepos_t) ceil ((double) start.sample / one_second) * one_second;
2785 start.sample = (samplepos_t) floor ((double) start.sample / one_second) * one_second;
2788 start.set (start.sample, 0);
2793 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2794 start.sample % one_minute == 0) {
2795 /* start is already on a whole minute, do nothing */
2796 } else if (((direction == 0) && (start.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2797 start.sample = (samplepos_t) ceil ((double) start.sample / one_minute) * one_minute;
2799 start.sample = (samplepos_t) floor ((double) start.sample / one_minute) * one_minute;
2802 start.set (start.sample, 0);
2807 start = _session->tempo_map().round_to_bar (start.sample, direction);
2811 start = _session->tempo_map().round_to_beat (start.sample, direction);
2814 case SnapToBeatDiv128:
2815 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 128, direction);
2817 case SnapToBeatDiv64:
2818 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 64, direction);
2820 case SnapToBeatDiv32:
2821 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 32, direction);
2823 case SnapToBeatDiv28:
2824 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 28, direction);
2826 case SnapToBeatDiv24:
2827 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 24, direction);
2829 case SnapToBeatDiv20:
2830 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 20, direction);
2832 case SnapToBeatDiv16:
2833 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 16, direction);
2835 case SnapToBeatDiv14:
2836 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 14, direction);
2838 case SnapToBeatDiv12:
2839 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 12, direction);
2841 case SnapToBeatDiv10:
2842 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 10, direction);
2844 case SnapToBeatDiv8:
2845 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 8, direction);
2847 case SnapToBeatDiv7:
2848 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 7, direction);
2850 case SnapToBeatDiv6:
2851 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 6, direction);
2853 case SnapToBeatDiv5:
2854 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 5, direction);
2856 case SnapToBeatDiv4:
2857 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 4, direction);
2859 case SnapToBeatDiv3:
2860 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 3, direction);
2862 case SnapToBeatDiv2:
2863 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 2, direction);
2871 _session->locations()->marks_either_side (start.sample, before, after);
2873 if (before == max_samplepos && after == max_samplepos) {
2874 /* No marks to snap to, so just don't snap */
2876 } else if (before == max_samplepos) {
2877 start.sample = after;
2878 } else if (after == max_samplepos) {
2879 start.sample = before;
2880 } else if (before != max_samplepos && after != max_samplepos) {
2881 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2882 start.sample = after;
2883 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2884 start.sample = before;
2885 else if (direction == 0 ) {
2886 if ((start.sample - before) < (after - start.sample)) {
2887 start.sample = before;
2889 start.sample = after;
2894 start.set (start.sample, 0);
2898 case SnapToRegionStart:
2899 case SnapToRegionEnd:
2900 case SnapToRegionSync:
2901 case SnapToRegionBoundary:
2902 if (!region_boundary_cache.empty()) {
2904 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2905 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2907 if (direction > 0) {
2908 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.sample);
2910 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.sample);
2913 if (next != region_boundary_cache.begin ()) {
2918 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2919 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2921 if (start.sample > (p + n) / 2) {
2928 start.set (start.sample, 0);
2933 switch (_snap_mode) {
2943 if (presnap > start.sample) {
2944 if (presnap > (start.sample + pixel_to_sample(snap_threshold))) {
2945 start.set (presnap, 0);
2948 } else if (presnap < start.sample) {
2949 if (presnap < (start.sample - pixel_to_sample(snap_threshold))) {
2950 start.set (presnap, 0);
2955 /* handled at entry */
2962 Editor::setup_toolbar ()
2964 HBox* mode_box = manage(new HBox);
2965 mode_box->set_border_width (2);
2966 mode_box->set_spacing(2);
2968 HBox* mouse_mode_box = manage (new HBox);
2969 HBox* mouse_mode_hbox = manage (new HBox);
2970 VBox* mouse_mode_vbox = manage (new VBox);
2971 Alignment* mouse_mode_align = manage (new Alignment);
2973 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2974 mouse_mode_size_group->add_widget (smart_mode_button);
2975 mouse_mode_size_group->add_widget (mouse_move_button);
2976 mouse_mode_size_group->add_widget (mouse_cut_button);
2977 mouse_mode_size_group->add_widget (mouse_select_button);
2978 mouse_mode_size_group->add_widget (mouse_timefx_button);
2979 mouse_mode_size_group->add_widget (mouse_audition_button);
2980 mouse_mode_size_group->add_widget (mouse_draw_button);
2981 mouse_mode_size_group->add_widget (mouse_content_button);
2983 if (!Profile->get_mixbus()) {
2984 mouse_mode_size_group->add_widget (zoom_in_button);
2985 mouse_mode_size_group->add_widget (zoom_out_button);
2986 mouse_mode_size_group->add_widget (zoom_out_full_button);
2987 mouse_mode_size_group->add_widget (zoom_focus_selector);
2988 mouse_mode_size_group->add_widget (tav_shrink_button);
2989 mouse_mode_size_group->add_widget (tav_expand_button);
2991 mouse_mode_size_group->add_widget (zoom_preset_selector);
2992 mouse_mode_size_group->add_widget (visible_tracks_selector);
2995 mouse_mode_size_group->add_widget (snap_type_selector);
2996 mouse_mode_size_group->add_widget (snap_mode_selector);
2998 mouse_mode_size_group->add_widget (edit_point_selector);
2999 mouse_mode_size_group->add_widget (edit_mode_selector);
3001 mouse_mode_size_group->add_widget (*nudge_clock);
3002 mouse_mode_size_group->add_widget (nudge_forward_button);
3003 mouse_mode_size_group->add_widget (nudge_backward_button);
3005 mouse_mode_hbox->set_spacing (2);
3007 if (!ARDOUR::Profile->get_trx()) {
3008 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3011 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3012 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3014 if (!ARDOUR::Profile->get_mixbus()) {
3015 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3018 if (!ARDOUR::Profile->get_trx()) {
3019 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3020 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3021 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3022 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3025 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3027 mouse_mode_align->add (*mouse_mode_vbox);
3028 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3030 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3032 edit_mode_selector.set_name ("mouse mode button");
3034 if (!ARDOUR::Profile->get_trx()) {
3035 mode_box->pack_start (edit_mode_selector, false, false);
3038 mode_box->pack_start (*mouse_mode_box, false, false);
3042 _zoom_box.set_spacing (2);
3043 _zoom_box.set_border_width (2);
3047 zoom_preset_selector.set_name ("zoom button");
3048 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3050 zoom_in_button.set_name ("zoom button");
3051 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3052 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3053 zoom_in_button.set_related_action (act);
3055 zoom_out_button.set_name ("zoom button");
3056 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3057 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3058 zoom_out_button.set_related_action (act);
3060 zoom_out_full_button.set_name ("zoom button");
3061 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3062 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3063 zoom_out_full_button.set_related_action (act);
3065 zoom_focus_selector.set_name ("zoom button");
3067 if (ARDOUR::Profile->get_mixbus()) {
3068 _zoom_box.pack_start (zoom_preset_selector, false, false);
3069 } else if (ARDOUR::Profile->get_trx()) {
3070 mode_box->pack_start (zoom_out_button, false, false);
3071 mode_box->pack_start (zoom_in_button, false, false);
3073 _zoom_box.pack_start (zoom_out_button, false, false);
3074 _zoom_box.pack_start (zoom_in_button, false, false);
3075 _zoom_box.pack_start (zoom_out_full_button, false, false);
3076 _zoom_box.pack_start (zoom_focus_selector, false, false);
3079 /* Track zoom buttons */
3080 _track_box.set_spacing (2);
3081 _track_box.set_border_width (2);
3083 visible_tracks_selector.set_name ("zoom button");
3084 if (Profile->get_mixbus()) {
3085 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3087 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3090 tav_expand_button.set_name ("zoom button");
3091 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3092 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3093 tav_expand_button.set_related_action (act);
3095 tav_shrink_button.set_name ("zoom button");
3096 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3097 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3098 tav_shrink_button.set_related_action (act);
3100 if (ARDOUR::Profile->get_mixbus()) {
3101 _track_box.pack_start (visible_tracks_selector);
3102 } else if (ARDOUR::Profile->get_trx()) {
3103 _track_box.pack_start (tav_shrink_button);
3104 _track_box.pack_start (tav_expand_button);
3106 _track_box.pack_start (visible_tracks_selector);
3107 _track_box.pack_start (tav_shrink_button);
3108 _track_box.pack_start (tav_expand_button);
3111 snap_box.set_spacing (2);
3112 snap_box.set_border_width (2);
3114 snap_type_selector.set_name ("mouse mode button");
3116 snap_mode_selector.set_name ("mouse mode button");
3118 edit_point_selector.set_name ("mouse mode button");
3120 snap_box.pack_start (snap_mode_selector, false, false);
3121 snap_box.pack_start (snap_type_selector, false, false);
3124 HBox *ep_box = manage (new HBox);
3125 ep_box->set_spacing (2);
3126 ep_box->set_border_width (2);
3128 ep_box->pack_start (edit_point_selector, false, false);
3132 HBox *nudge_box = manage (new HBox);
3133 nudge_box->set_spacing (2);
3134 nudge_box->set_border_width (2);
3136 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3137 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3139 nudge_box->pack_start (nudge_backward_button, false, false);
3140 nudge_box->pack_start (nudge_forward_button, false, false);
3141 nudge_box->pack_start (*nudge_clock, false, false);
3144 /* Pack everything in... */
3146 toolbar_hbox.set_spacing (2);
3147 toolbar_hbox.set_border_width (2);
3149 toolbar_hbox.pack_start (*mode_box, false, false);
3151 if (!ARDOUR::Profile->get_trx()) {
3153 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3155 toolbar_hbox.pack_start (_zoom_box, false, false);
3157 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3159 toolbar_hbox.pack_start (_track_box, false, false);
3161 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3163 toolbar_hbox.pack_start (snap_box, false, false);
3165 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3167 toolbar_hbox.pack_start (*ep_box, false, false);
3169 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3171 toolbar_hbox.pack_start (*nudge_box, false, false);
3174 toolbar_hbox.show_all ();
3178 Editor::build_edit_point_menu ()
3180 using namespace Menu_Helpers;
3182 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3183 if(!Profile->get_mixbus())
3184 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3185 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3187 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3191 Editor::build_edit_mode_menu ()
3193 using namespace Menu_Helpers;
3195 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3196 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3197 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3198 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3200 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3204 Editor::build_snap_mode_menu ()
3206 using namespace Menu_Helpers;
3208 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3209 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3210 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3212 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3216 Editor::build_snap_type_menu ()
3218 using namespace Menu_Helpers;
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3251 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3256 Editor::setup_tooltips ()
3258 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3259 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3260 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3261 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3262 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3263 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3264 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3265 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3266 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3267 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3268 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3269 set_tooltip (zoom_in_button, _("Zoom In"));
3270 set_tooltip (zoom_out_button, _("Zoom Out"));
3271 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3272 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3273 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3274 set_tooltip (tav_expand_button, _("Expand Tracks"));
3275 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3276 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3277 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3278 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3279 set_tooltip (edit_point_selector, _("Edit Point"));
3280 set_tooltip (edit_mode_selector, _("Edit Mode"));
3281 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3285 Editor::convert_drop_to_paths (
3286 vector<string>& paths,
3287 const RefPtr<Gdk::DragContext>& /*context*/,
3290 const SelectionData& data,
3294 if (_session == 0) {
3298 vector<string> uris = data.get_uris();
3302 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3303 are actually URI lists. So do it by hand.
3306 if (data.get_target() != "text/plain") {
3310 /* Parse the "uri-list" format that Nautilus provides,
3311 where each pathname is delimited by \r\n.
3313 THERE MAY BE NO NULL TERMINATING CHAR!!!
3316 string txt = data.get_text();
3320 p = (char *) malloc (txt.length() + 1);
3321 txt.copy (p, txt.length(), 0);
3322 p[txt.length()] = '\0';
3328 while (g_ascii_isspace (*p))
3332 while (*q && (*q != '\n') && (*q != '\r')) {
3339 while (q > p && g_ascii_isspace (*q))
3344 uris.push_back (string (p, q - p + 1));
3348 p = strchr (p, '\n');
3360 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3361 if ((*i).substr (0,7) == "file://") {
3362 paths.push_back (Glib::filename_from_uri (*i));
3370 Editor::new_tempo_section ()
3375 Editor::map_transport_state ()
3377 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3379 if (_session && _session->transport_stopped()) {
3380 have_pending_keyboard_selection = false;
3383 update_loop_range_view ();
3387 Editor::transport_looped ()
3389 /* reset Playhead position interpolation.
3390 * see Editor::super_rapid_screen_update
3392 _last_update_time = 0;
3398 Editor::begin_selection_op_history ()
3400 selection_op_cmd_depth = 0;
3401 selection_op_history_it = 0;
3403 while(!selection_op_history.empty()) {
3404 delete selection_op_history.front();
3405 selection_op_history.pop_front();
3408 selection_undo_action->set_sensitive (false);
3409 selection_redo_action->set_sensitive (false);
3410 selection_op_history.push_front (&_selection_memento->get_state ());
3414 Editor::begin_reversible_selection_op (string name)
3417 //cerr << name << endl;
3418 /* begin/commit pairs can be nested */
3419 selection_op_cmd_depth++;
3424 Editor::commit_reversible_selection_op ()
3427 if (selection_op_cmd_depth == 1) {
3429 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3431 The user has undone some selection ops and then made a new one,
3432 making anything earlier in the list invalid.
3435 list<XMLNode *>::iterator it = selection_op_history.begin();
3436 list<XMLNode *>::iterator e_it = it;
3437 advance (e_it, selection_op_history_it);
3439 for ( ; it != e_it; ++it) {
3442 selection_op_history.erase (selection_op_history.begin(), e_it);
3445 selection_op_history.push_front (&_selection_memento->get_state ());
3446 selection_op_history_it = 0;
3448 selection_undo_action->set_sensitive (true);
3449 selection_redo_action->set_sensitive (false);
3452 if (selection_op_cmd_depth > 0) {
3453 selection_op_cmd_depth--;
3459 Editor::undo_selection_op ()
3462 selection_op_history_it++;
3464 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3465 if (n == selection_op_history_it) {
3466 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3467 selection_redo_action->set_sensitive (true);
3471 /* is there an earlier entry? */
3472 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3473 selection_undo_action->set_sensitive (false);
3479 Editor::redo_selection_op ()
3482 if (selection_op_history_it > 0) {
3483 selection_op_history_it--;
3486 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3487 if (n == selection_op_history_it) {
3488 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3489 selection_undo_action->set_sensitive (true);
3494 if (selection_op_history_it == 0) {
3495 selection_redo_action->set_sensitive (false);
3501 Editor::begin_reversible_command (string name)
3504 before.push_back (&_selection_memento->get_state ());
3505 _session->begin_reversible_command (name);
3510 Editor::begin_reversible_command (GQuark q)
3513 before.push_back (&_selection_memento->get_state ());
3514 _session->begin_reversible_command (q);
3519 Editor::abort_reversible_command ()
3522 while(!before.empty()) {
3523 delete before.front();
3526 _session->abort_reversible_command ();
3531 Editor::commit_reversible_command ()
3534 if (before.size() == 1) {
3535 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3536 redo_action->set_sensitive(false);
3537 undo_action->set_sensitive(true);
3538 begin_selection_op_history ();
3541 if (before.empty()) {
3542 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3547 _session->commit_reversible_command ();
3552 Editor::history_changed ()
3556 if (undo_action && _session) {
3557 if (_session->undo_depth() == 0) {
3558 label = S_("Command|Undo");
3560 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3562 undo_action->property_label() = label;
3565 if (redo_action && _session) {
3566 if (_session->redo_depth() == 0) {
3568 redo_action->set_sensitive (false);
3570 label = string_compose(_("Redo (%1)"), _session->next_redo());
3571 redo_action->set_sensitive (true);
3573 redo_action->property_label() = label;
3578 Editor::duplicate_range (bool with_dialog)
3582 RegionSelection rs = get_regions_from_selection_and_entered ();
3584 if ( selection->time.length() == 0 && rs.empty()) {
3590 ArdourDialog win (_("Duplicate"));
3591 Label label (_("Number of duplications:"));
3592 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3593 SpinButton spinner (adjustment, 0.0, 1);
3596 win.get_vbox()->set_spacing (12);
3597 win.get_vbox()->pack_start (hbox);
3598 hbox.set_border_width (6);
3599 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3601 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3602 place, visually. so do this by hand.
3605 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3606 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3607 spinner.grab_focus();
3613 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3614 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3615 win.set_default_response (RESPONSE_ACCEPT);
3617 spinner.grab_focus ();
3619 switch (win.run ()) {
3620 case RESPONSE_ACCEPT:
3626 times = adjustment.get_value();
3629 if ((current_mouse_mode() == Editing::MouseRange)) {
3630 if (selection->time.length()) {
3631 duplicate_selection (times);
3633 } else if (get_smart_mode()) {
3634 if (selection->time.length()) {
3635 duplicate_selection (times);
3637 duplicate_some_regions (rs, times);
3639 duplicate_some_regions (rs, times);
3644 Editor::set_edit_mode (EditMode m)
3646 Config->set_edit_mode (m);
3650 Editor::cycle_edit_mode ()
3652 switch (Config->get_edit_mode()) {
3654 Config->set_edit_mode (Ripple);
3658 Config->set_edit_mode (Lock);
3661 Config->set_edit_mode (Slide);
3667 Editor::edit_mode_selection_done ( EditMode m )
3669 Config->set_edit_mode ( m );
3673 Editor::snap_type_selection_done (SnapType snaptype)
3675 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3677 ract->set_active ();
3682 Editor::snap_mode_selection_done (SnapMode mode)
3684 RefPtr<RadioAction> ract = snap_mode_action (mode);
3687 ract->set_active (true);
3692 Editor::cycle_edit_point (bool with_marker)
3694 if(Profile->get_mixbus())
3695 with_marker = false;
3697 switch (_edit_point) {
3699 set_edit_point_preference (EditAtPlayhead);
3701 case EditAtPlayhead:
3703 set_edit_point_preference (EditAtSelectedMarker);
3705 set_edit_point_preference (EditAtMouse);
3708 case EditAtSelectedMarker:
3709 set_edit_point_preference (EditAtMouse);
3715 Editor::edit_point_selection_done (EditPoint ep)
3717 set_edit_point_preference ( ep );
3721 Editor::build_zoom_focus_menu ()
3723 using namespace Menu_Helpers;
3725 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3726 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3727 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3728 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3729 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3730 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3732 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3736 Editor::zoom_focus_selection_done ( ZoomFocus f )
3738 RefPtr<RadioAction> ract = zoom_focus_action (f);
3740 ract->set_active ();
3745 Editor::build_track_count_menu ()
3747 using namespace Menu_Helpers;
3749 if (!Profile->get_mixbus()) {
3750 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3751 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3752 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3753 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3754 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3755 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3756 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3757 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3758 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3759 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3760 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3764 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3775 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3776 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3777 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3778 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3779 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3780 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3781 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3782 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3783 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3784 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3785 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3786 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3791 Editor::set_zoom_preset (int64_t ms)
3794 temporal_zoom_session();
3798 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3799 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3803 Editor::set_visible_track_count (int32_t n)
3805 _visible_track_count = n;
3807 /* if the canvas hasn't really been allocated any size yet, just
3808 record the desired number of visible tracks and return. when canvas
3809 allocation happens, we will get called again and then we can do the
3813 if (_visible_canvas_height <= 1) {
3819 DisplaySuspender ds;
3821 if (_visible_track_count > 0) {
3822 h = trackviews_height() / _visible_track_count;
3823 std::ostringstream s;
3824 s << _visible_track_count;
3826 } else if (_visible_track_count == 0) {
3828 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3829 if ((*i)->marked_for_display()) {
3831 TimeAxisView::Children cl ((*i)->get_child_list ());
3832 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3833 if ((*j)->marked_for_display()) {
3840 visible_tracks_selector.set_text (X_("*"));
3843 h = trackviews_height() / n;
3846 /* negative value means that the visible track count has
3847 been overridden by explicit track height changes.
3849 visible_tracks_selector.set_text (X_("*"));
3853 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3854 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3857 if (str != visible_tracks_selector.get_text()) {
3858 visible_tracks_selector.set_text (str);
3863 Editor::override_visible_track_count ()
3865 _visible_track_count = -1;
3866 visible_tracks_selector.set_text ( _("*") );
3870 Editor::edit_controls_button_release (GdkEventButton* ev)
3872 if (Keyboard::is_context_menu_event (ev)) {
3873 ARDOUR_UI::instance()->add_route ();
3874 } else if (ev->button == 1) {
3875 selection->clear_tracks ();
3882 Editor::mouse_select_button_release (GdkEventButton* ev)
3884 /* this handles just right-clicks */
3886 if (ev->button != 3) {
3894 Editor::set_zoom_focus (ZoomFocus f)
3896 string str = zoom_focus_strings[(int)f];
3898 if (str != zoom_focus_selector.get_text()) {
3899 zoom_focus_selector.set_text (str);
3902 if (zoom_focus != f) {
3909 Editor::cycle_zoom_focus ()
3911 switch (zoom_focus) {
3913 set_zoom_focus (ZoomFocusRight);
3915 case ZoomFocusRight:
3916 set_zoom_focus (ZoomFocusCenter);
3918 case ZoomFocusCenter:
3919 set_zoom_focus (ZoomFocusPlayhead);
3921 case ZoomFocusPlayhead:
3922 set_zoom_focus (ZoomFocusMouse);
3924 case ZoomFocusMouse:
3925 set_zoom_focus (ZoomFocusEdit);
3928 set_zoom_focus (ZoomFocusLeft);
3934 Editor::set_show_measures (bool yn)
3936 if (_show_measures != yn) {
3939 if ((_show_measures = yn) == true) {
3941 tempo_lines->show();
3944 std::vector<TempoMap::BBTPoint> grid;
3945 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3946 draw_measures (grid);
3954 Editor::toggle_follow_playhead ()
3956 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3958 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3959 set_follow_playhead (tact->get_active());
3963 /** @param yn true to follow playhead, otherwise false.
3964 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3967 Editor::set_follow_playhead (bool yn, bool catch_up)
3969 if (_follow_playhead != yn) {
3970 if ((_follow_playhead = yn) == true && catch_up) {
3972 reset_x_origin_to_follow_playhead ();
3979 Editor::toggle_stationary_playhead ()
3981 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3983 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3984 set_stationary_playhead (tact->get_active());
3989 Editor::set_stationary_playhead (bool yn)
3991 if (_stationary_playhead != yn) {
3992 if ((_stationary_playhead = yn) == true) {
3994 // FIXME need a 3.0 equivalent of this 2.X call
3995 // update_current_screen ();
4002 Editor::playlist_selector () const
4004 return *_playlist_selector;
4008 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4010 if (paste_count == 0) {
4011 /* don't bother calculating an offset that will be zero anyway */
4015 /* calculate basic unsnapped multi-paste offset */
4016 samplecnt_t offset = paste_count * duration;
4018 /* snap offset so pos + offset is aligned to the grid */
4019 MusicSample offset_pos (pos + offset, 0);
4020 snap_to(offset_pos, RoundUpMaybe);
4021 offset = offset_pos.sample - pos;
4027 Editor::get_grid_beat_divisions(samplepos_t position)
4029 switch (_snap_type) {
4030 case SnapToBeatDiv128: return 128;
4031 case SnapToBeatDiv64: return 64;
4032 case SnapToBeatDiv32: return 32;
4033 case SnapToBeatDiv28: return 28;
4034 case SnapToBeatDiv24: return 24;
4035 case SnapToBeatDiv20: return 20;
4036 case SnapToBeatDiv16: return 16;
4037 case SnapToBeatDiv14: return 14;
4038 case SnapToBeatDiv12: return 12;
4039 case SnapToBeatDiv10: return 10;
4040 case SnapToBeatDiv8: return 8;
4041 case SnapToBeatDiv7: return 7;
4042 case SnapToBeatDiv6: return 6;
4043 case SnapToBeatDiv5: return 5;
4044 case SnapToBeatDiv4: return 4;
4045 case SnapToBeatDiv3: return 3;
4046 case SnapToBeatDiv2: return 2;
4052 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4053 if the grid is non-musical, returns 0.
4054 if the grid is snapped to bars, returns -1.
4055 @param event_state the current keyboard modifier mask.
4058 Editor::get_grid_music_divisions (uint32_t event_state)
4060 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4064 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4068 switch (_snap_type) {
4069 case SnapToBeatDiv128: return 128;
4070 case SnapToBeatDiv64: return 64;
4071 case SnapToBeatDiv32: return 32;
4072 case SnapToBeatDiv28: return 28;
4073 case SnapToBeatDiv24: return 24;
4074 case SnapToBeatDiv20: return 20;
4075 case SnapToBeatDiv16: return 16;
4076 case SnapToBeatDiv14: return 14;
4077 case SnapToBeatDiv12: return 12;
4078 case SnapToBeatDiv10: return 10;
4079 case SnapToBeatDiv8: return 8;
4080 case SnapToBeatDiv7: return 7;
4081 case SnapToBeatDiv6: return 6;
4082 case SnapToBeatDiv5: return 5;
4083 case SnapToBeatDiv4: return 4;
4084 case SnapToBeatDiv3: return 3;
4085 case SnapToBeatDiv2: return 2;
4086 case SnapToBeat: return 1;
4087 case SnapToBar : return -1;
4094 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4098 const unsigned divisions = get_grid_beat_divisions(position);
4100 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4103 switch (_snap_type) {
4105 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4108 const Meter& m = _session->tempo_map().meter_at_sample (position);
4109 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4117 return Evoral::Beats();
4121 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4125 ret = nudge_clock->current_duration (pos);
4126 next = ret + 1; /* XXXX fix me */
4132 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4134 ArdourDialog dialog (_("Playlist Deletion"));
4135 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4136 "If it is kept, its audio files will not be cleaned.\n"
4137 "If it is deleted, audio files used by it alone will be cleaned."),
4140 dialog.set_position (WIN_POS_CENTER);
4141 dialog.get_vbox()->pack_start (label);
4145 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4146 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4147 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4148 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4149 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4151 // by default gtk uses the left most button
4152 keep->grab_focus ();
4154 switch (dialog.run ()) {
4156 /* keep this and all remaining ones */
4161 /* delete this and all others */
4165 case RESPONSE_ACCEPT:
4166 /* delete the playlist */
4170 case RESPONSE_REJECT:
4171 /* keep the playlist */
4183 Editor::audio_region_selection_covers (samplepos_t where)
4185 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4186 if ((*a)->region()->covers (where)) {
4195 Editor::prepare_for_cleanup ()
4197 cut_buffer->clear_regions ();
4198 cut_buffer->clear_playlists ();
4200 selection->clear_regions ();
4201 selection->clear_playlists ();
4203 _regions->suspend_redisplay ();
4207 Editor::finish_cleanup ()
4209 _regions->resume_redisplay ();
4213 Editor::transport_loop_location()
4216 return _session->locations()->auto_loop_location();
4223 Editor::transport_punch_location()
4226 return _session->locations()->auto_punch_location();
4233 Editor::control_layout_scroll (GdkEventScroll* ev)
4235 /* Just forward to the normal canvas scroll method. The coordinate
4236 systems are different but since the canvas is always larger than the
4237 track headers, and aligned with the trackview area, this will work.
4239 In the not too distant future this layout is going away anyway and
4240 headers will be on the canvas.
4242 return canvas_scroll_event (ev, false);
4246 Editor::session_state_saved (string)
4249 _snapshots->redisplay ();
4253 Editor::maximise_editing_space ()
4259 Gtk::Window* toplevel = current_toplevel();
4262 toplevel->fullscreen ();
4268 Editor::restore_editing_space ()
4274 Gtk::Window* toplevel = current_toplevel();
4277 toplevel->unfullscreen();
4283 * Make new playlists for a given track and also any others that belong
4284 * to the same active route group with the `select' property.
4289 Editor::new_playlists (TimeAxisView* v)
4291 begin_reversible_command (_("new playlists"));
4292 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4293 _session->playlists->get (playlists);
4294 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4295 commit_reversible_command ();
4299 * Use a copy of the current playlist for a given track and also any others that belong
4300 * to the same active route group with the `select' property.
4305 Editor::copy_playlists (TimeAxisView* v)
4307 begin_reversible_command (_("copy playlists"));
4308 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4309 _session->playlists->get (playlists);
4310 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4311 commit_reversible_command ();
4314 /** Clear the current playlist for a given track and also any others that belong
4315 * to the same active route group with the `select' property.
4320 Editor::clear_playlists (TimeAxisView* v)
4322 begin_reversible_command (_("clear playlists"));
4323 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4324 _session->playlists->get (playlists);
4325 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4326 commit_reversible_command ();
4330 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4332 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4336 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4338 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4342 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4344 atv.clear_playlist ();
4348 Editor::get_y_origin () const
4350 return vertical_adjustment.get_value ();
4353 /** Queue up a change to the viewport x origin.
4354 * @param sample New x origin.
4357 Editor::reset_x_origin (samplepos_t sample)
4359 pending_visual_change.add (VisualChange::TimeOrigin);
4360 pending_visual_change.time_origin = sample;
4361 ensure_visual_change_idle_handler ();
4365 Editor::reset_y_origin (double y)
4367 pending_visual_change.add (VisualChange::YOrigin);
4368 pending_visual_change.y_origin = y;
4369 ensure_visual_change_idle_handler ();
4373 Editor::reset_zoom (samplecnt_t spp)
4375 if (spp == samples_per_pixel) {
4379 pending_visual_change.add (VisualChange::ZoomLevel);
4380 pending_visual_change.samples_per_pixel = spp;
4381 ensure_visual_change_idle_handler ();
4385 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4387 reset_x_origin (sample);
4390 if (!no_save_visual) {
4391 undo_visual_stack.push_back (current_visual_state(false));
4395 Editor::VisualState::VisualState (bool with_tracks)
4396 : gui_state (with_tracks ? new GUIObjectState : 0)
4400 Editor::VisualState::~VisualState ()
4405 Editor::VisualState*
4406 Editor::current_visual_state (bool with_tracks)
4408 VisualState* vs = new VisualState (with_tracks);
4409 vs->y_position = vertical_adjustment.get_value();
4410 vs->samples_per_pixel = samples_per_pixel;
4411 vs->_leftmost_sample = _leftmost_sample;
4412 vs->zoom_focus = zoom_focus;
4415 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4422 Editor::undo_visual_state ()
4424 if (undo_visual_stack.empty()) {
4428 VisualState* vs = undo_visual_stack.back();
4429 undo_visual_stack.pop_back();
4432 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4435 use_visual_state (*vs);
4440 Editor::redo_visual_state ()
4442 if (redo_visual_stack.empty()) {
4446 VisualState* vs = redo_visual_stack.back();
4447 redo_visual_stack.pop_back();
4449 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4450 // why do we check here?
4451 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4454 use_visual_state (*vs);
4459 Editor::swap_visual_state ()
4461 if (undo_visual_stack.empty()) {
4462 redo_visual_state ();
4464 undo_visual_state ();
4469 Editor::use_visual_state (VisualState& vs)
4471 PBD::Unwinder<bool> nsv (no_save_visual, true);
4472 DisplaySuspender ds;
4474 vertical_adjustment.set_value (vs.y_position);
4476 set_zoom_focus (vs.zoom_focus);
4477 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4480 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4482 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4483 (*i)->clear_property_cache();
4484 (*i)->reset_visual_state ();
4488 _routes->update_visibility ();
4491 /** This is the core function that controls the zoom level of the canvas. It is called
4492 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4493 * @param spp new number of samples per pixel
4496 Editor::set_samples_per_pixel (samplecnt_t spp)
4502 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4503 const samplecnt_t lots_of_pixels = 4000;
4505 /* if the zoom level is greater than what you'd get trying to display 3
4506 * days of audio on a really big screen, then it's too big.
4509 if (spp * lots_of_pixels > three_days) {
4513 samples_per_pixel = spp;
4517 Editor::on_samples_per_pixel_changed ()
4520 tempo_lines->tempo_map_changed(_session->tempo_map().music_origin());
4523 bool const showing_time_selection = selection->time.length() > 0;
4525 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4526 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4527 (*i)->reshow_selection (selection->time);
4531 ZoomChanged (); /* EMIT_SIGNAL */
4533 ArdourCanvas::GtkCanvasViewport* c;
4535 c = get_track_canvas();
4537 c->canvas()->zoomed ();
4540 if (playhead_cursor) {
4541 playhead_cursor->set_position (playhead_cursor->current_sample ());
4544 refresh_location_display();
4545 _summary->set_overlays_dirty ();
4547 update_marker_labels ();
4553 Editor::playhead_cursor_sample () const
4555 return playhead_cursor->current_sample();
4559 Editor::queue_visual_videotimeline_update ()
4561 pending_visual_change.add (VisualChange::VideoTimeline);
4562 ensure_visual_change_idle_handler ();
4566 Editor::ensure_visual_change_idle_handler ()
4568 if (pending_visual_change.idle_handler_id < 0) {
4569 // see comment in add_to_idle_resize above.
4570 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4571 pending_visual_change.being_handled = false;
4576 Editor::_idle_visual_changer (void* arg)
4578 return static_cast<Editor*>(arg)->idle_visual_changer ();
4582 Editor::pre_render ()
4584 visual_change_queued = false;
4586 if (pending_visual_change.pending != 0) {
4587 ensure_visual_change_idle_handler();
4592 Editor::idle_visual_changer ()
4594 pending_visual_change.idle_handler_id = -1;
4596 if (pending_visual_change.pending == 0) {
4600 /* set_horizontal_position() below (and maybe other calls) call
4601 gtk_main_iteration(), so it's possible that a signal will be handled
4602 half-way through this method. If this signal wants an
4603 idle_visual_changer we must schedule another one after this one, so
4604 mark the idle_handler_id as -1 here to allow that. Also make a note
4605 that we are doing the visual change, so that changes in response to
4606 super-rapid-screen-update can be dropped if we are still processing
4610 if (visual_change_queued) {
4614 pending_visual_change.being_handled = true;
4616 VisualChange vc = pending_visual_change;
4618 pending_visual_change.pending = (VisualChange::Type) 0;
4620 visual_changer (vc);
4622 pending_visual_change.being_handled = false;
4624 visual_change_queued = true;
4626 return 0; /* this is always a one-shot call */
4630 Editor::visual_changer (const VisualChange& vc)
4633 * Changed first so the correct horizontal canvas position is calculated in
4634 * Editor::set_horizontal_position
4636 if (vc.pending & VisualChange::ZoomLevel) {
4637 set_samples_per_pixel (vc.samples_per_pixel);
4640 if (vc.pending & VisualChange::TimeOrigin) {
4641 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4642 set_horizontal_position (new_time_origin);
4645 if (vc.pending & VisualChange::YOrigin) {
4646 vertical_adjustment.set_value (vc.y_origin);
4650 * Now the canvas is in the final state before render the canvas items that
4651 * support the Item::prepare_for_render interface can calculate the correct
4652 * item to visible canvas intersection.
4654 if (vc.pending & VisualChange::ZoomLevel) {
4655 on_samples_per_pixel_changed ();
4657 compute_fixed_ruler_scale ();
4659 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4660 update_tempo_based_rulers ();
4663 if (!(vc.pending & VisualChange::ZoomLevel)) {
4665 * If the canvas is not being zoomed then the canvas items will not change
4666 * and cause Item::prepare_for_render to be called so do it here manually.
4668 * Not ideal, but I can't think of a better solution atm.
4670 _track_canvas->prepare_for_render();
4673 // If we are only scrolling vertically there is no need to update these
4674 if (vc.pending != VisualChange::YOrigin) {
4675 update_fixed_rulers ();
4676 redisplay_tempo (true);
4678 /* video frames & position need to be updated for zoom, horiz-scroll
4679 * and (explicitly) VisualChange::VideoTimeline.
4681 update_video_timeline();
4684 _summary->set_overlays_dirty ();
4687 struct EditorOrderTimeAxisSorter {
4688 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4689 return a->order () < b->order ();
4694 Editor::sort_track_selection (TrackViewList& sel)
4696 EditorOrderTimeAxisSorter cmp;
4701 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4704 samplepos_t where = 0;
4705 EditPoint ep = _edit_point;
4707 if (Profile->get_mixbus()) {
4708 if (ep == EditAtSelectedMarker) {
4709 ep = EditAtPlayhead;
4713 if (from_outside_canvas && (ep == EditAtMouse)) {
4714 ep = EditAtPlayhead;
4715 } else if (from_context_menu && (ep == EditAtMouse)) {
4716 return canvas_event_sample (&context_click_event, 0, 0);
4719 if (entered_marker) {
4720 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4721 return entered_marker->position();
4724 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4725 ep = EditAtSelectedMarker;
4728 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4729 ep = EditAtPlayhead;
4732 MusicSample snap_mf (0, 0);
4735 case EditAtPlayhead:
4736 if (_dragging_playhead && _control_scroll_target) {
4737 where = *_control_scroll_target;
4739 where = _session->audible_sample();
4741 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4744 case EditAtSelectedMarker:
4745 if (!selection->markers.empty()) {
4747 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4750 where = loc->start();
4754 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4762 if (!mouse_sample (where, ignored)) {
4763 /* XXX not right but what can we do ? */
4766 snap_mf.sample = where;
4768 where = snap_mf.sample;
4769 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4777 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4779 if (!_session) return;
4781 begin_reversible_command (cmd);
4785 if ((tll = transport_loop_location()) == 0) {
4786 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4787 XMLNode &before = _session->locations()->get_state();
4788 _session->locations()->add (loc, true);
4789 _session->set_auto_loop_location (loc);
4790 XMLNode &after = _session->locations()->get_state();
4791 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4793 XMLNode &before = tll->get_state();
4794 tll->set_hidden (false, this);
4795 tll->set (start, end);
4796 XMLNode &after = tll->get_state();
4797 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4800 commit_reversible_command ();
4804 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4806 if (!_session) return;
4808 begin_reversible_command (cmd);
4812 if ((tpl = transport_punch_location()) == 0) {
4813 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4814 XMLNode &before = _session->locations()->get_state();
4815 _session->locations()->add (loc, true);
4816 _session->set_auto_punch_location (loc);
4817 XMLNode &after = _session->locations()->get_state();
4818 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4820 XMLNode &before = tpl->get_state();
4821 tpl->set_hidden (false, this);
4822 tpl->set (start, end);
4823 XMLNode &after = tpl->get_state();
4824 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4827 commit_reversible_command ();
4830 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4831 * @param rs List to which found regions are added.
4832 * @param where Time to look at.
4833 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4836 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4838 const TrackViewList* tracks;
4841 tracks = &track_views;
4846 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4848 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4851 boost::shared_ptr<Track> tr;
4852 boost::shared_ptr<Playlist> pl;
4854 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4856 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4858 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4859 RegionView* rv = rtv->view()->find_view (*i);
4870 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4872 const TrackViewList* tracks;
4875 tracks = &track_views;
4880 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4881 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4883 boost::shared_ptr<Track> tr;
4884 boost::shared_ptr<Playlist> pl;
4886 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4888 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4890 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4892 RegionView* rv = rtv->view()->find_view (*i);
4903 /** Get regions using the following method:
4905 * Make a region list using:
4906 * (a) any selected regions
4907 * (b) the intersection of any selected tracks and the edit point(*)
4908 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4910 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4912 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4916 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4918 RegionSelection regions;
4920 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4921 regions.add (entered_regionview);
4923 regions = selection->regions;
4926 if ( regions.empty() ) {
4927 TrackViewList tracks = selection->tracks;
4929 if (!tracks.empty()) {
4930 /* no region selected or entered, but some selected tracks:
4931 * act on all regions on the selected tracks at the edit point
4933 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4934 get_regions_at(regions, where, tracks);
4941 /** Get regions using the following method:
4943 * Make a region list using:
4944 * (a) any selected regions
4945 * (b) the intersection of any selected tracks and the edit point(*)
4946 * (c) if neither exists, then whatever region is under the mouse
4948 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4950 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4953 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4955 RegionSelection regions;
4957 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4958 regions.add (entered_regionview);
4960 regions = selection->regions;
4963 if ( regions.empty() ) {
4964 TrackViewList tracks = selection->tracks;
4966 if (!tracks.empty()) {
4967 /* no region selected or entered, but some selected tracks:
4968 * act on all regions on the selected tracks at the edit point
4970 get_regions_at(regions, pos, tracks);
4977 /** Start with regions that are selected, or the entered regionview if none are selected.
4978 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4979 * of the regions that we started with.
4983 Editor::get_regions_from_selection_and_entered () const
4985 RegionSelection regions = selection->regions;
4987 if (regions.empty() && entered_regionview) {
4988 regions.add (entered_regionview);
4995 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4997 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4998 RouteTimeAxisView* rtav;
5000 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5001 boost::shared_ptr<Playlist> pl;
5002 std::vector<boost::shared_ptr<Region> > results;
5003 boost::shared_ptr<Track> tr;
5005 if ((tr = rtav->track()) == 0) {
5010 if ((pl = (tr->playlist())) != 0) {
5011 boost::shared_ptr<Region> r = pl->region_by_id (id);
5013 RegionView* rv = rtav->view()->find_view (r);
5015 regions.push_back (rv);
5024 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5027 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5028 MidiTimeAxisView* mtav;
5030 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5032 mtav->get_per_region_note_selection (selection);
5039 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5041 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5043 RouteTimeAxisView* tatv;
5045 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5047 boost::shared_ptr<Playlist> pl;
5048 vector<boost::shared_ptr<Region> > results;
5050 boost::shared_ptr<Track> tr;
5052 if ((tr = tatv->track()) == 0) {
5057 if ((pl = (tr->playlist())) != 0) {
5058 if (src_comparison) {
5059 pl->get_source_equivalent_regions (region, results);
5061 pl->get_region_list_equivalent_regions (region, results);
5065 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5066 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5067 regions.push_back (marv);
5076 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5078 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5079 RouteTimeAxisView* tatv;
5080 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5081 if (!tatv->track()) {
5084 RegionView* marv = tatv->view()->find_view (region);
5094 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5096 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5097 RouteTimeAxisView* rtav;
5098 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5099 if (rtav->route() == route) {
5108 Editor::show_rhythm_ferret ()
5110 if (rhythm_ferret == 0) {
5111 rhythm_ferret = new RhythmFerret(*this);
5114 rhythm_ferret->set_session (_session);
5115 rhythm_ferret->show ();
5116 rhythm_ferret->present ();
5120 Editor::first_idle ()
5122 MessageDialog* dialog = 0;
5124 if (track_views.size() > 1) {
5125 Timers::TimerSuspender t;
5126 dialog = new MessageDialog (
5127 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5131 ARDOUR_UI::instance()->flush_pending (60);
5134 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5138 /* now that all regionviews should exist, setup region selection */
5142 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5143 /* this is cumulative: rs is NOT cleared each time */
5144 get_regionviews_by_id (*pr, rs);
5147 selection->set (rs);
5149 // first idle adds route children (automation tracks), so we need to redisplay here
5150 _routes->redisplay ();
5154 if (_session->undo_depth() == 0) {
5155 undo_action->set_sensitive(false);
5157 redo_action->set_sensitive(false);
5158 begin_selection_op_history ();
5164 Editor::_idle_resize (gpointer arg)
5166 return ((Editor*)arg)->idle_resize ();
5170 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5172 if (resize_idle_id < 0) {
5173 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5174 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5175 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5177 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5178 _pending_resize_amount = 0;
5181 /* make a note of the smallest resulting height, so that we can clamp the
5182 lower limit at TimeAxisView::hSmall */
5184 int32_t min_resulting = INT32_MAX;
5186 _pending_resize_amount += h;
5187 _pending_resize_view = view;
5189 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5191 if (selection->tracks.contains (_pending_resize_view)) {
5192 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5193 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5197 if (min_resulting < 0) {
5202 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5203 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5207 /** Handle pending resizing of tracks */
5209 Editor::idle_resize ()
5211 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5213 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5214 selection->tracks.contains (_pending_resize_view)) {
5216 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5217 if (*i != _pending_resize_view) {
5218 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5223 _pending_resize_amount = 0;
5224 _group_tabs->set_dirty ();
5225 resize_idle_id = -1;
5233 ENSURE_GUI_THREAD (*this, &Editor::located);
5236 playhead_cursor->set_position (_session->audible_sample ());
5237 if (_follow_playhead && !_pending_initial_locate) {
5238 reset_x_origin_to_follow_playhead ();
5242 _pending_locate_request = false;
5243 _pending_initial_locate = false;
5244 _last_update_time = 0;
5248 Editor::region_view_added (RegionView * rv)
5250 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5252 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5253 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5254 if (rv->region()->id () == (*rnote).first) {
5255 mrv->select_notes ((*rnote).second);
5256 selection->pending_midi_note_selection.erase(rnote);
5262 _summary->set_background_dirty ();
5266 Editor::region_view_removed ()
5268 _summary->set_background_dirty ();
5272 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5274 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5275 if ((*j)->stripable() == s) {
5284 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5286 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5287 if ((*j)->control() == c) {
5291 TimeAxisView::Children kids = (*j)->get_child_list ();
5293 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5294 if ((*k)->control() == c) {
5304 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5308 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5309 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5319 Editor::suspend_route_redisplay ()
5322 _routes->suspend_redisplay();
5327 Editor::resume_route_redisplay ()
5330 _routes->redisplay(); // queue redisplay
5331 _routes->resume_redisplay();
5336 Editor::add_vcas (VCAList& vlist)
5340 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5341 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5344 add_stripables (sl);
5348 Editor::add_routes (RouteList& rlist)
5352 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5356 add_stripables (sl);
5360 Editor::add_stripables (StripableList& sl)
5362 list<TimeAxisView*> new_views;
5363 boost::shared_ptr<VCA> v;
5364 boost::shared_ptr<Route> r;
5365 TrackViewList new_selection;
5366 bool from_scratch = (track_views.size() == 0);
5368 sl.sort (Stripable::Sorter());
5370 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5372 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5374 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5376 new_views.push_back (vtv);
5378 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5380 if (r->is_auditioner() || r->is_monitor()) {
5384 RouteTimeAxisView* rtv;
5385 DataType dt = r->input()->default_type();
5387 if (dt == ARDOUR::DataType::AUDIO) {
5388 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5390 } else if (dt == ARDOUR::DataType::MIDI) {
5391 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5394 throw unknown_type();
5397 new_views.push_back (rtv);
5398 track_views.push_back (rtv);
5399 new_selection.push_back (rtv);
5401 rtv->effective_gain_display ();
5403 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5404 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5408 if (new_views.size() > 0) {
5409 _routes->time_axis_views_added (new_views);
5410 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5413 /* note: !new_selection.empty() means that we got some routes rather
5417 if (!from_scratch && !new_selection.empty()) {
5418 selection->set (new_selection);
5419 begin_selection_op_history();
5422 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5423 show_editor_mixer (true);
5426 editor_list_button.set_sensitive (true);
5430 Editor::timeaxisview_deleted (TimeAxisView *tv)
5432 if (tv == entered_track) {
5436 if (_session && _session->deletion_in_progress()) {
5437 /* the situation is under control */
5441 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5443 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5445 _routes->route_removed (tv);
5447 TimeAxisView::Children c = tv->get_child_list ();
5448 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5449 if (entered_track == i->get()) {
5454 /* remove it from the list of track views */
5456 TrackViewList::iterator i;
5458 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5459 i = track_views.erase (i);
5462 /* update whatever the current mixer strip is displaying, if revelant */
5464 boost::shared_ptr<Route> route;
5467 route = rtav->route ();
5470 if (current_mixer_strip && current_mixer_strip->route() == route) {
5472 TimeAxisView* next_tv;
5474 if (track_views.empty()) {
5476 } else if (i == track_views.end()) {
5477 next_tv = track_views.front();
5482 // skip VCAs (cannot be selected, n/a in editor-mixer)
5483 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5484 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5485 next_tv = track_views.front();
5487 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5488 /* just in case: no master, only a VCA remains */
5494 set_selected_mixer_strip (*next_tv);
5496 /* make the editor mixer strip go away setting the
5497 * button to inactive (which also unticks the menu option)
5500 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5506 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5512 DisplaySuspender ds;
5513 PresentationInfo::ChangeSuspender cs;
5515 if (apply_to_selection) {
5516 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5518 TrackSelection::iterator j = i;
5521 hide_track_in_display (*i, false);
5526 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5528 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5529 // this will hide the mixer strip
5530 set_selected_mixer_strip (*tv);
5533 _routes->hide_track_in_display (*tv);
5538 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5543 _routes->show_track_in_display (*tv);
5544 if (move_into_view) {
5545 ensure_time_axis_view_is_visible (*tv, false);
5550 Editor::sync_track_view_list_and_routes ()
5552 track_views = TrackViewList (_routes->views ());
5554 _summary->set_background_dirty();
5555 _group_tabs->set_dirty ();
5557 return false; // do not call again (until needed)
5561 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5563 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5568 /** Find a StripableTimeAxisView by the ID of its stripable */
5569 StripableTimeAxisView*
5570 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5572 StripableTimeAxisView* v;
5574 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5575 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5576 if(v->stripable()->id() == id) {
5586 Editor::fit_route_group (RouteGroup *g)
5588 TrackViewList ts = axis_views_from_routes (g->route_list ());
5593 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5595 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5598 _session->cancel_audition ();
5602 if (_session->is_auditioning()) {
5603 _session->cancel_audition ();
5604 if (r == last_audition_region) {
5609 _session->audition_region (r);
5610 last_audition_region = r;
5615 Editor::hide_a_region (boost::shared_ptr<Region> r)
5617 r->set_hidden (true);
5621 Editor::show_a_region (boost::shared_ptr<Region> r)
5623 r->set_hidden (false);
5627 Editor::audition_region_from_region_list ()
5629 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5633 Editor::hide_region_from_region_list ()
5635 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5639 Editor::show_region_in_region_list ()
5641 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5645 Editor::step_edit_status_change (bool yn)
5648 start_step_editing ();
5650 stop_step_editing ();
5655 Editor::start_step_editing ()
5657 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5661 Editor::stop_step_editing ()
5663 step_edit_connection.disconnect ();
5667 Editor::check_step_edit ()
5669 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5670 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5672 mtv->check_step_edit ();
5676 return true; // do it again, till we stop
5680 Editor::scroll_press (Direction dir)
5682 ++_scroll_callbacks;
5684 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5685 /* delay the first auto-repeat */
5691 scroll_backward (1);
5699 scroll_up_one_track ();
5703 scroll_down_one_track ();
5707 /* do hacky auto-repeat */
5708 if (!_scroll_connection.connected ()) {
5710 _scroll_connection = Glib::signal_timeout().connect (
5711 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5714 _scroll_callbacks = 0;
5721 Editor::scroll_release ()
5723 _scroll_connection.disconnect ();
5726 /** Queue a change for the Editor viewport x origin to follow the playhead */
5728 Editor::reset_x_origin_to_follow_playhead ()
5730 samplepos_t const sample = playhead_cursor->current_sample ();
5732 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5734 if (_session->transport_speed() < 0) {
5736 if (sample > (current_page_samples() / 2)) {
5737 center_screen (sample-(current_page_samples()/2));
5739 center_screen (current_page_samples()/2);
5746 if (sample < _leftmost_sample) {
5748 if (_session->transport_rolling()) {
5749 /* rolling; end up with the playhead at the right of the page */
5750 l = sample - current_page_samples ();
5752 /* not rolling: end up with the playhead 1/4 of the way along the page */
5753 l = sample - current_page_samples() / 4;
5757 if (_session->transport_rolling()) {
5758 /* rolling: end up with the playhead on the left of the page */
5761 /* not rolling: end up with the playhead 3/4 of the way along the page */
5762 l = sample - 3 * current_page_samples() / 4;
5770 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5776 Editor::super_rapid_screen_update ()
5778 if (!_session || !_session->engine().running()) {
5782 /* METERING / MIXER STRIPS */
5784 /* update track meters, if required */
5785 if (contents().is_mapped() && meters_running) {
5786 RouteTimeAxisView* rtv;
5787 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5788 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5789 rtv->fast_update ();
5794 /* and any current mixer strip */
5795 if (current_mixer_strip) {
5796 current_mixer_strip->fast_update ();
5799 /* PLAYHEAD AND VIEWPORT */
5801 /* There are a few reasons why we might not update the playhead / viewport stuff:
5803 * 1. we don't update things when there's a pending locate request, otherwise
5804 * when the editor requests a locate there is a chance that this method
5805 * will move the playhead before the locate request is processed, causing
5807 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5808 * 3. if we're still at the same sample that we were last time, there's nothing to do.
5810 if (_pending_locate_request || !_session->transport_rolling ()) {
5811 _last_update_time = 0;
5815 if (_dragging_playhead) {
5816 _last_update_time = 0;
5820 bool latent_locate = false;
5821 samplepos_t sample = _session->audible_sample (&latent_locate);
5822 const int64_t now = g_get_monotonic_time ();
5825 if (_session->exporting ()) {
5826 /* freewheel/export may be faster or slower than transport_speed() / SR.
5827 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5829 _last_update_time = 0;
5832 if (_last_update_time > 0) {
5833 /* interpolate and smoothen playhead position */
5834 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5835 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5836 err = sample - guess;
5838 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5839 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5842 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5844 err, _err_screen_engine);
5849 _err_screen_engine = 0;
5852 if (err > 8192 || latent_locate) {
5853 // in case of x-runs or freewheeling
5854 _last_update_time = 0;
5855 sample = _session->audible_sample ();
5857 _last_update_time = now;
5860 if (playhead_cursor->current_sample () == sample) {
5864 playhead_cursor->set_position (sample);
5866 if (_session->requested_return_sample() >= 0) {
5867 _last_update_time = 0;
5871 if (!_follow_playhead || pending_visual_change.being_handled) {
5872 /* We only do this if we aren't already
5873 * handling a visual change (ie if
5874 * pending_visual_change.being_handled is
5875 * false) so that these requests don't stack
5876 * up there are too many of them to handle in
5882 if (!_stationary_playhead) {
5883 reset_x_origin_to_follow_playhead ();
5885 samplepos_t const sample = playhead_cursor->current_sample ();
5886 double target = ((double)sample - (double)current_page_samples() / 2.0);
5887 if (target <= 0.0) {
5890 // compare to EditorCursor::set_position()
5891 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5892 double const new_pos = sample_to_pixel_unrounded (target);
5893 if (rint (new_pos) != rint (old_pos)) {
5894 reset_x_origin (pixel_to_sample (new_pos));
5901 Editor::session_going_away ()
5903 _have_idled = false;
5905 _session_connections.drop_connections ();
5907 super_rapid_screen_update_connection.disconnect ();
5909 selection->clear ();
5910 cut_buffer->clear ();
5912 clicked_regionview = 0;
5913 clicked_axisview = 0;
5914 clicked_routeview = 0;
5915 entered_regionview = 0;
5917 _last_update_time = 0;
5920 playhead_cursor->hide ();
5922 /* rip everything out of the list displays */
5926 _route_groups->clear ();
5928 /* do this first so that deleting a track doesn't reset cms to null
5929 and thus cause a leak.
5932 if (current_mixer_strip) {
5933 if (current_mixer_strip->get_parent() != 0) {
5934 global_hpacker.remove (*current_mixer_strip);
5936 delete current_mixer_strip;
5937 current_mixer_strip = 0;
5940 /* delete all trackviews */
5942 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5945 track_views.clear ();
5947 nudge_clock->set_session (0);
5949 editor_list_button.set_active(false);
5950 editor_list_button.set_sensitive(false);
5952 /* clear tempo/meter rulers */
5953 remove_metric_marks ();
5955 clear_marker_display ();
5960 stop_step_editing ();
5964 /* get rid of any existing editor mixer strip */
5966 WindowTitle title(Glib::get_application_name());
5967 title += _("Editor");
5969 own_window()->set_title (title.get_string());
5972 SessionHandlePtr::session_going_away ();
5976 Editor::trigger_script (int i)
5978 LuaInstance::instance()-> call_action (i);
5982 Editor::show_editor_list (bool yn)
5985 _editor_list_vbox.show ();
5987 _editor_list_vbox.hide ();
5992 Editor::change_region_layering_order (bool from_context_menu)
5994 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5996 if (!clicked_routeview) {
5997 if (layering_order_editor) {
5998 layering_order_editor->hide ();
6003 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6009 boost::shared_ptr<Playlist> pl = track->playlist();
6015 if (layering_order_editor == 0) {
6016 layering_order_editor = new RegionLayeringOrderEditor (*this);
6019 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6020 layering_order_editor->maybe_present ();
6024 Editor::update_region_layering_order_editor ()
6026 if (layering_order_editor && layering_order_editor->is_visible ()) {
6027 change_region_layering_order (true);
6032 Editor::setup_fade_images ()
6034 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6035 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6036 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6037 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6038 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6040 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6041 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6042 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6043 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6044 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6048 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6050 Editor::action_menu_item (std::string const & name)
6052 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6055 return *manage (a->create_menu_item ());
6059 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6061 EventBox* b = manage (new EventBox);
6062 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6063 Label* l = manage (new Label (name));
6067 _the_notebook.append_page (widget, *b);
6071 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6073 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6074 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6077 if (ev->type == GDK_2BUTTON_PRESS) {
6079 /* double-click on a notebook tab shrinks or expands the notebook */
6081 if (_notebook_shrunk) {
6082 if (pre_notebook_shrink_pane_width) {
6083 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6085 _notebook_shrunk = false;
6087 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6089 /* this expands the LHS of the edit pane to cover the notebook
6090 PAGE but leaves the tabs visible.
6092 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6093 _notebook_shrunk = true;
6101 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6103 using namespace Menu_Helpers;
6105 MenuList& items = _control_point_context_menu.items ();
6108 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6109 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6110 if (!can_remove_control_point (item)) {
6111 items.back().set_sensitive (false);
6114 _control_point_context_menu.popup (event->button.button, event->button.time);
6118 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6120 using namespace Menu_Helpers;
6122 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6127 /* We need to get the selection here and pass it to the operations, since
6128 popping up the menu will cause a region leave event which clears
6129 entered_regionview. */
6131 MidiRegionView& mrv = note->region_view();
6132 const RegionSelection rs = get_regions_from_selection_and_entered ();
6133 const uint32_t sel_size = mrv.selection_size ();
6135 MenuList& items = _note_context_menu.items();
6139 items.push_back(MenuElem(_("Delete"),
6140 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6143 items.push_back(MenuElem(_("Edit..."),
6144 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6145 if (sel_size != 1) {
6146 items.back().set_sensitive (false);
6149 items.push_back(MenuElem(_("Transpose..."),
6150 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6153 items.push_back(MenuElem(_("Legatize"),
6154 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6156 items.back().set_sensitive (false);
6159 items.push_back(MenuElem(_("Quantize..."),
6160 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6162 items.push_back(MenuElem(_("Remove Overlap"),
6163 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6165 items.back().set_sensitive (false);
6168 items.push_back(MenuElem(_("Transform..."),
6169 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6171 _note_context_menu.popup (event->button.button, event->button.time);
6175 Editor::zoom_vertical_modifier_released()
6177 _stepping_axis_view = 0;
6181 Editor::ui_parameter_changed (string parameter)
6183 if (parameter == "icon-set") {
6184 while (!_cursor_stack.empty()) {
6185 _cursor_stack.pop_back();
6187 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6188 _cursor_stack.push_back(_cursors->grabber);
6189 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6190 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6192 } else if (parameter == "draggable-playhead") {
6193 if (_verbose_cursor) {
6194 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6200 Editor::use_own_window (bool and_fill_it)
6202 bool new_window = !own_window();
6204 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6206 if (win && new_window) {
6207 win->set_name ("EditorWindow");
6209 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6211 // win->signal_realize().connect (*this, &Editor::on_realize);
6212 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6213 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6214 win->set_data ("ardour-bindings", bindings);
6219 DisplaySuspender ds;
6220 contents().show_all ();
6222 /* XXX: this is a bit unfortunate; it would probably
6223 be nicer if we could just call show () above rather
6224 than needing the show_all ()
6227 /* re-hide stuff if necessary */
6228 editor_list_button_toggled ();
6229 parameter_changed ("show-summary");
6230 parameter_changed ("show-group-tabs");
6231 parameter_changed ("show-zoom-tools");
6233 /* now reset all audio_time_axis heights, because widgets might need
6239 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6240 tv = (static_cast<TimeAxisView*>(*i));
6241 tv->reset_height ();
6244 if (current_mixer_strip) {
6245 current_mixer_strip->hide_things ();
6246 current_mixer_strip->parameter_changed ("mixer-element-visibility");